GeometryUtils.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. THREE.GeometryUtils = {
  6. applyMatrix: function ( geometry, matrix ) {
  7. var matrixRotation = new THREE.Matrix4();
  8. matrixRotation.extractRotation( matrix, new THREE.Vector3( 1, 1, 1 ) );
  9. for ( var i = 0, il = geometry.vertices.length; i < il; i ++ ) {
  10. var vertex = geometry.vertices[ i ];
  11. matrix.multiplyVector3( vertex.position );
  12. }
  13. for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
  14. var face = geometry.faces[ i ];
  15. matrixRotation.multiplyVector3( face.normal );
  16. for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
  17. matrixRotation.multiplyVector3( face.vertexNormals[ j ] );
  18. }
  19. matrix.multiplyVector3( face.centroid );
  20. }
  21. },
  22. merge: function ( geometry1, object2 /* mesh | geometry */ ) {
  23. var matrix, matrixRotation,
  24. vertexOffset = geometry1.vertices.length,
  25. uvPosition = geometry1.faceVertexUvs[ 0 ].length,
  26. geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2,
  27. vertices1 = geometry1.vertices,
  28. vertices2 = geometry2.vertices,
  29. faces1 = geometry1.faces,
  30. faces2 = geometry2.faces,
  31. uvs1 = geometry1.faceVertexUvs[ 0 ],
  32. uvs2 = geometry2.faceVertexUvs[ 0 ];
  33. if ( object2 instanceof THREE.Mesh ) {
  34. object2.matrixAutoUpdate && object2.updateMatrix();
  35. matrix = object2.matrix;
  36. matrixRotation = new THREE.Matrix4();
  37. matrixRotation.extractRotation( matrix, object2.scale );
  38. }
  39. // vertices
  40. for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
  41. var vertex = vertices2[ i ];
  42. var vertexCopy = new THREE.Vertex( vertex.position.clone() );
  43. if ( matrix ) matrix.multiplyVector3( vertexCopy.position );
  44. vertices1.push( vertexCopy );
  45. }
  46. // faces
  47. for ( i = 0, il = faces2.length; i < il; i ++ ) {
  48. var face = faces2[ i ], faceCopy, normal, color,
  49. faceVertexNormals = face.vertexNormals,
  50. faceVertexColors = face.vertexColors;
  51. if ( face instanceof THREE.Face3 ) {
  52. faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
  53. } else if ( face instanceof THREE.Face4 ) {
  54. faceCopy = new THREE.Face4( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset, face.d + vertexOffset );
  55. }
  56. faceCopy.normal.copy( face.normal );
  57. if ( matrixRotation ) matrixRotation.multiplyVector3( faceCopy.normal );
  58. for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
  59. normal = faceVertexNormals[ j ].clone();
  60. if ( matrixRotation ) matrixRotation.multiplyVector3( normal );
  61. faceCopy.vertexNormals.push( normal );
  62. }
  63. faceCopy.color.copy( face.color );
  64. for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
  65. color = faceVertexColors[ j ];
  66. faceCopy.vertexColors.push( color.clone() );
  67. }
  68. faceCopy.materials = face.materials.slice();
  69. faceCopy.centroid.copy( face.centroid );
  70. if ( matrix ) matrix.multiplyVector3( faceCopy.centroid );
  71. faces1.push( faceCopy );
  72. }
  73. // uvs
  74. for ( i = 0, il = uvs2.length; i < il; i ++ ) {
  75. var uv = uvs2[ i ], uvCopy = [];
  76. for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
  77. uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );
  78. }
  79. uvs1.push( uvCopy );
  80. }
  81. },
  82. clone: function ( geometry ) {
  83. var cloneGeo = new THREE.Geometry();
  84. var i, il;
  85. var vertices = geometry.vertices,
  86. faces = geometry.faces,
  87. uvs = geometry.faceVertexUvs[ 0 ];
  88. // vertices
  89. for ( i = 0, il = vertices.length; i < il; i ++ ) {
  90. var vertex = vertices[ i ];
  91. var vertexCopy = new THREE.Vertex( vertex.position.clone() );
  92. cloneGeo.vertices.push( vertexCopy );
  93. }
  94. // faces
  95. for ( i = 0, il = faces.length; i < il; i ++ ) {
  96. var face = faces[ i ], faceCopy, normal, color,
  97. faceVertexNormals = face.vertexNormals,
  98. faceVertexColors = face.vertexColors;
  99. if ( face instanceof THREE.Face3 ) {
  100. faceCopy = new THREE.Face3( face.a, face.b, face.c );
  101. } else if ( face instanceof THREE.Face4 ) {
  102. faceCopy = new THREE.Face4( face.a, face.b, face.c, face.d );
  103. }
  104. faceCopy.normal.copy( face.normal );
  105. for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
  106. normal = faceVertexNormals[ j ];
  107. faceCopy.vertexNormals.push( normal.clone() );
  108. }
  109. faceCopy.color.copy( face.color );
  110. for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
  111. color = faceVertexColors[ j ];
  112. faceCopy.vertexColors.push( color.clone() );
  113. }
  114. faceCopy.materials = face.materials.slice();
  115. faceCopy.centroid.copy( face.centroid );
  116. cloneGeo.faces.push( faceCopy );
  117. }
  118. // uvs
  119. for ( i = 0, il = uvs.length; i < il; i ++ ) {
  120. var uv = uvs[ i ], uvCopy = [];
  121. for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
  122. uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );
  123. }
  124. cloneGeo.faceVertexUvs[ 0 ].push( uvCopy );
  125. }
  126. return cloneGeo;
  127. },
  128. // Get random point in triangle (via barycentric coordinates)
  129. // (uniform distribution)
  130. // http://www.cgafaq.info/wiki/Random_Point_In_Triangle
  131. randomPointInTriangle: function( vectorA, vectorB, vectorC ) {
  132. var a, b, c,
  133. point = new THREE.Vector3(),
  134. tmp = THREE.GeometryUtils.__v1;
  135. a = THREE.GeometryUtils.random();
  136. b = THREE.GeometryUtils.random();
  137. if ( ( a + b ) > 1 ) {
  138. a = 1 - a;
  139. b = 1 - b;
  140. }
  141. c = 1 - a - b;
  142. point.copy( vectorA );
  143. point.multiplyScalar( a );
  144. tmp.copy( vectorB );
  145. tmp.multiplyScalar( b );
  146. point.addSelf( tmp );
  147. tmp.copy( vectorC );
  148. tmp.multiplyScalar( c );
  149. point.addSelf( tmp );
  150. return point;
  151. },
  152. // Get random point in face (triangle / quad)
  153. // (uniform distribution)
  154. randomPointInFace: function( face, geometry, useCachedAreas ) {
  155. var vA, vB, vC, vD;
  156. if ( face instanceof THREE.Face3 ) {
  157. vA = geometry.vertices[ face.a ].position;
  158. vB = geometry.vertices[ face.b ].position;
  159. vC = geometry.vertices[ face.c ].position;
  160. return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
  161. } else if ( face instanceof THREE.Face4 ) {
  162. vA = geometry.vertices[ face.a ].position;
  163. vB = geometry.vertices[ face.b ].position;
  164. vC = geometry.vertices[ face.c ].position;
  165. vD = geometry.vertices[ face.d ].position;
  166. var area1, area2;
  167. if ( useCachedAreas ) {
  168. if ( face._area1 && face._area2 ) {
  169. area1 = face._area1;
  170. area2 = face._area2;
  171. } else {
  172. area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
  173. area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
  174. face._area1 = area1;
  175. face._area2 = area2;
  176. }
  177. } else {
  178. area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ),
  179. area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
  180. }
  181. var r = THREE.GeometryUtils.random() * ( area1 + area2 );
  182. if ( r < area1 ) {
  183. return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vD );
  184. } else {
  185. return THREE.GeometryUtils.randomPointInTriangle( vB, vC, vD );
  186. }
  187. }
  188. },
  189. // Get uniformly distributed random points in mesh
  190. // - create array with cumulative sums of face areas
  191. // - pick random number from 0 to total area
  192. // - find corresponding place in area array by binary search
  193. // - get random point in face
  194. randomPointsInGeometry: function( geometry, n ) {
  195. var face, i,
  196. faces = geometry.faces,
  197. vertices = geometry.vertices,
  198. il = faces.length,
  199. totalArea = 0,
  200. cumulativeAreas = [],
  201. vA, vB, vC, vD;
  202. // precompute face areas
  203. for ( i = 0; i < il; i ++ ) {
  204. face = faces[ i ];
  205. if ( face instanceof THREE.Face3 ) {
  206. vA = vertices[ face.a ].position;
  207. vB = vertices[ face.b ].position;
  208. vC = vertices[ face.c ].position;
  209. face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
  210. } else if ( face instanceof THREE.Face4 ) {
  211. vA = vertices[ face.a ].position;
  212. vB = vertices[ face.b ].position;
  213. vC = vertices[ face.c ].position;
  214. vD = vertices[ face.d ].position;
  215. face._area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
  216. face._area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
  217. face._area = face._area1 + face._area2;
  218. }
  219. totalArea += face._area;
  220. cumulativeAreas[ i ] = totalArea;
  221. }
  222. // binary search cumulative areas array
  223. function binarySearchIndices( value ) {
  224. function binarySearch( start, end ) {
  225. // return closest larger index
  226. // if exact number is not found
  227. if ( end < start )
  228. return start;
  229. var mid = start + Math.floor( ( end - start ) / 2 );
  230. if ( cumulativeAreas[ mid ] > value ) {
  231. return binarySearch( start, mid - 1 );
  232. } else if ( cumulativeAreas[ mid ] < value ) {
  233. return binarySearch( mid + 1, end );
  234. } else {
  235. return mid;
  236. }
  237. }
  238. var result = binarySearch( 0, cumulativeAreas.length - 1 )
  239. return result;
  240. }
  241. // pick random face weighted by face area
  242. var r, index,
  243. result = [];
  244. var stats = {};
  245. for ( i = 0; i < n; i ++ ) {
  246. r = THREE.GeometryUtils.random() * totalArea;
  247. index = binarySearchIndices( r );
  248. result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
  249. if ( ! stats[ index ] ) {
  250. stats[ index ] = 1;
  251. } else {
  252. stats[ index ] += 1;
  253. }
  254. }
  255. return result;
  256. },
  257. // Get triangle area (by Heron's formula)
  258. // http://en.wikipedia.org/wiki/Heron%27s_formula
  259. triangleArea: function( vectorA, vectorB, vectorC ) {
  260. var s, a, b, c,
  261. tmp = THREE.GeometryUtils.__v1;
  262. tmp.sub( vectorA, vectorB );
  263. a = tmp.length();
  264. tmp.sub( vectorA, vectorC );
  265. b = tmp.length();
  266. tmp.sub( vectorB, vectorC );
  267. c = tmp.length();
  268. s = 0.5 * ( a + b + c );
  269. return Math.sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
  270. },
  271. // Get 16 bits of randomness
  272. // (standard Math.random() creates repetitive patterns when applied over larger space)
  273. random16: function() {
  274. return ( 65280 * Math.random() + 255 * Math.random() ) / 65535;
  275. }
  276. };
  277. THREE.GeometryUtils.random = THREE.GeometryUtils.random16;
  278. THREE.GeometryUtils.__v1 = new THREE.Vector3();