GeometryUtils.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. THREE.GeometryUtils = {
  6. // Merge two geometries or geometry and geometry from object (using object's transform)
  7. merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) {
  8. var matrix, normalMatrix,
  9. vertexOffset = geometry1.vertices.length,
  10. uvPosition = geometry1.faceVertexUvs[ 0 ].length,
  11. geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2,
  12. vertices1 = geometry1.vertices,
  13. vertices2 = geometry2.vertices,
  14. faces1 = geometry1.faces,
  15. faces2 = geometry2.faces,
  16. uvs1 = geometry1.faceVertexUvs[ 0 ],
  17. uvs2 = geometry2.faceVertexUvs[ 0 ];
  18. if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
  19. if ( object2 instanceof THREE.Mesh ) {
  20. object2.matrixAutoUpdate && object2.updateMatrix();
  21. matrix = object2.matrix;
  22. normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
  23. }
  24. // vertices
  25. for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
  26. var vertex = vertices2[ i ];
  27. var vertexCopy = vertex.clone();
  28. if ( matrix ) vertexCopy.applyMatrix4( matrix );
  29. vertices1.push( vertexCopy );
  30. }
  31. // faces
  32. for ( i = 0, il = faces2.length; i < il; i ++ ) {
  33. var face = faces2[ i ], faceCopy, normal, color,
  34. faceVertexNormals = face.vertexNormals,
  35. faceVertexColors = face.vertexColors;
  36. faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
  37. faceCopy.normal.copy( face.normal );
  38. if ( normalMatrix ) {
  39. faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
  40. }
  41. for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
  42. normal = faceVertexNormals[ j ].clone();
  43. if ( normalMatrix ) {
  44. normal.applyMatrix3( normalMatrix ).normalize();
  45. }
  46. faceCopy.vertexNormals.push( normal );
  47. }
  48. faceCopy.color.copy( face.color );
  49. for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
  50. color = faceVertexColors[ j ];
  51. faceCopy.vertexColors.push( color.clone() );
  52. }
  53. faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
  54. faceCopy.centroid.copy( face.centroid );
  55. if ( matrix ) {
  56. faceCopy.centroid.applyMatrix4( matrix );
  57. }
  58. faces1.push( faceCopy );
  59. }
  60. // uvs
  61. for ( i = 0, il = uvs2.length; i < il; i ++ ) {
  62. var uv = uvs2[ i ], uvCopy = [];
  63. if ( uv === undefined ) {
  64. continue;
  65. }
  66. for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
  67. uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
  68. }
  69. uvs1.push( uvCopy );
  70. }
  71. },
  72. // Get random point in triangle (via barycentric coordinates)
  73. // (uniform distribution)
  74. // http://www.cgafaq.info/wiki/Random_Point_In_Triangle
  75. randomPointInTriangle: function () {
  76. var vector = new THREE.Vector3();
  77. return function ( vectorA, vectorB, vectorC ) {
  78. var point = new THREE.Vector3();
  79. var a = THREE.Math.random16();
  80. var b = THREE.Math.random16();
  81. if ( ( a + b ) > 1 ) {
  82. a = 1 - a;
  83. b = 1 - b;
  84. }
  85. var c = 1 - a - b;
  86. point.copy( vectorA );
  87. point.multiplyScalar( a );
  88. vector.copy( vectorB );
  89. vector.multiplyScalar( b );
  90. point.add( vector );
  91. vector.copy( vectorC );
  92. vector.multiplyScalar( c );
  93. point.add( vector );
  94. return point;
  95. };
  96. }(),
  97. // Get random point in face (triangle / quad)
  98. // (uniform distribution)
  99. randomPointInFace: function ( face, geometry, useCachedAreas ) {
  100. var vA, vB, vC, vD;
  101. vA = geometry.vertices[ face.a ];
  102. vB = geometry.vertices[ face.b ];
  103. vC = geometry.vertices[ face.c ];
  104. return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
  105. },
  106. // Get uniformly distributed random points in mesh
  107. // - create array with cumulative sums of face areas
  108. // - pick random number from 0 to total area
  109. // - find corresponding place in area array by binary search
  110. // - get random point in face
  111. randomPointsInGeometry: function ( geometry, n ) {
  112. var face, i,
  113. faces = geometry.faces,
  114. vertices = geometry.vertices,
  115. il = faces.length,
  116. totalArea = 0,
  117. cumulativeAreas = [],
  118. vA, vB, vC, vD;
  119. // precompute face areas
  120. for ( i = 0; i < il; i ++ ) {
  121. face = faces[ i ];
  122. vA = vertices[ face.a ];
  123. vB = vertices[ face.b ];
  124. vC = vertices[ face.c ];
  125. face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
  126. totalArea += face._area;
  127. cumulativeAreas[ i ] = totalArea;
  128. }
  129. // binary search cumulative areas array
  130. function binarySearchIndices( value ) {
  131. function binarySearch( start, end ) {
  132. // return closest larger index
  133. // if exact number is not found
  134. if ( end < start )
  135. return start;
  136. var mid = start + Math.floor( ( end - start ) / 2 );
  137. if ( cumulativeAreas[ mid ] > value ) {
  138. return binarySearch( start, mid - 1 );
  139. } else if ( cumulativeAreas[ mid ] < value ) {
  140. return binarySearch( mid + 1, end );
  141. } else {
  142. return mid;
  143. }
  144. }
  145. var result = binarySearch( 0, cumulativeAreas.length - 1 )
  146. return result;
  147. }
  148. // pick random face weighted by face area
  149. var r, index,
  150. result = [];
  151. var stats = {};
  152. for ( i = 0; i < n; i ++ ) {
  153. r = THREE.Math.random16() * totalArea;
  154. index = binarySearchIndices( r );
  155. result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
  156. if ( ! stats[ index ] ) {
  157. stats[ index ] = 1;
  158. } else {
  159. stats[ index ] += 1;
  160. }
  161. }
  162. return result;
  163. },
  164. // Get triangle area (half of parallelogram)
  165. // http://mathworld.wolfram.com/TriangleArea.html
  166. triangleArea: function () {
  167. var vector1 = new THREE.Vector3();
  168. var vector2 = new THREE.Vector3();
  169. return function ( vectorA, vectorB, vectorC ) {
  170. vector1.subVectors( vectorB, vectorA );
  171. vector2.subVectors( vectorC, vectorA );
  172. vector1.cross( vector2 );
  173. return 0.5 * vector1.length();
  174. };
  175. }(),
  176. // Center geometry so that 0,0,0 is in center of bounding box
  177. center: function ( geometry ) {
  178. geometry.computeBoundingBox();
  179. var bb = geometry.boundingBox;
  180. var offset = new THREE.Vector3();
  181. offset.addVectors( bb.min, bb.max );
  182. offset.multiplyScalar( -0.5 );
  183. geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
  184. geometry.computeBoundingBox();
  185. return offset;
  186. },
  187. triangulateQuads: function ( geometry ) {
  188. var i, il, j, jl;
  189. var faces = [];
  190. var faceVertexUvs = [];
  191. for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
  192. faceVertexUvs[ i ] = [];
  193. }
  194. for ( i = 0, il = geometry.faces.length; i < il; i ++ ) {
  195. var face = geometry.faces[ i ];
  196. faces.push( face );
  197. for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) {
  198. faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] );
  199. }
  200. }
  201. geometry.faces = faces;
  202. geometry.faceVertexUvs = faceVertexUvs;
  203. geometry.computeCentroids();
  204. geometry.computeFaceNormals();
  205. geometry.computeVertexNormals();
  206. if ( geometry.hasTangents ) geometry.computeTangents();
  207. }
  208. };