123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- /**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
- THREE.GeometryUtils = {
- applyMatrix: function ( geometry, matrix ) {
- var matrixRotation = new THREE.Matrix4();
- matrixRotation.extractRotation( matrix, new THREE.Vector3( 1, 1, 1 ) );
- for ( var i = 0, il = geometry.vertices.length; i < il; i ++ ) {
- var vertex = geometry.vertices[ i ];
- matrix.multiplyVector3( vertex.position );
- }
- for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
- var face = geometry.faces[ i ];
- matrixRotation.multiplyVector3( face.normal );
- for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
- matrixRotation.multiplyVector3( face.vertexNormals[ j ] );
- }
- matrix.multiplyVector3( face.centroid );
- }
- },
- merge: function ( geometry1, object2 /* mesh | geometry */ ) {
- var matrix, matrixRotation,
- vertexOffset = geometry1.vertices.length,
- uvPosition = geometry1.faceVertexUvs[ 0 ].length,
- geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2,
- vertices1 = geometry1.vertices,
- vertices2 = geometry2.vertices,
- faces1 = geometry1.faces,
- faces2 = geometry2.faces,
- uvs1 = geometry1.faceVertexUvs[ 0 ],
- uvs2 = geometry2.faceVertexUvs[ 0 ];
- if ( object2 instanceof THREE.Mesh ) {
- object2.matrixAutoUpdate && object2.updateMatrix();
- matrix = object2.matrix;
- matrixRotation = new THREE.Matrix4();
- matrixRotation.extractRotation( matrix, object2.scale );
- }
- // vertices
- for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
- var vertex = vertices2[ i ];
- var vertexCopy = new THREE.Vertex( vertex.position.clone() );
- if ( matrix ) matrix.multiplyVector3( vertexCopy.position );
- vertices1.push( vertexCopy );
- }
- // faces
- for ( i = 0, il = faces2.length; i < il; i ++ ) {
- var face = faces2[ i ], faceCopy, normal, color,
- faceVertexNormals = face.vertexNormals,
- faceVertexColors = face.vertexColors;
- if ( face instanceof THREE.Face3 ) {
- faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
- } else if ( face instanceof THREE.Face4 ) {
- faceCopy = new THREE.Face4( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset, face.d + vertexOffset );
- }
- faceCopy.normal.copy( face.normal );
- if ( matrixRotation ) matrixRotation.multiplyVector3( faceCopy.normal );
- for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
- normal = faceVertexNormals[ j ].clone();
- if ( matrixRotation ) matrixRotation.multiplyVector3( normal );
- faceCopy.vertexNormals.push( normal );
- }
- faceCopy.color.copy( face.color );
- for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
- color = faceVertexColors[ j ];
- faceCopy.vertexColors.push( color.clone() );
- }
- faceCopy.materials = face.materials.slice();
- faceCopy.centroid.copy( face.centroid );
- if ( matrix ) matrix.multiplyVector3( faceCopy.centroid );
- faces1.push( faceCopy );
- }
- // uvs
- for ( i = 0, il = uvs2.length; i < il; i ++ ) {
- var uv = uvs2[ i ], uvCopy = [];
- for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
- uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );
- }
- uvs1.push( uvCopy );
- }
- },
- clone: function ( geometry ) {
- var cloneGeo = new THREE.Geometry();
- var i, il;
- var vertices = geometry.vertices,
- faces = geometry.faces,
- uvs = geometry.faceVertexUvs[ 0 ];
- // vertices
- for ( i = 0, il = vertices.length; i < il; i ++ ) {
- var vertex = vertices[ i ];
- var vertexCopy = new THREE.Vertex( vertex.position.clone() );
- cloneGeo.vertices.push( vertexCopy );
- }
- // faces
- for ( i = 0, il = faces.length; i < il; i ++ ) {
- var face = faces[ i ], faceCopy, normal, color,
- faceVertexNormals = face.vertexNormals,
- faceVertexColors = face.vertexColors;
- if ( face instanceof THREE.Face3 ) {
- faceCopy = new THREE.Face3( face.a, face.b, face.c );
- } else if ( face instanceof THREE.Face4 ) {
- faceCopy = new THREE.Face4( face.a, face.b, face.c, face.d );
- }
- faceCopy.normal.copy( face.normal );
- for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
- normal = faceVertexNormals[ j ];
- faceCopy.vertexNormals.push( normal.clone() );
- }
- faceCopy.color.copy( face.color );
- for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
- color = faceVertexColors[ j ];
- faceCopy.vertexColors.push( color.clone() );
- }
- faceCopy.materials = face.materials.slice();
- faceCopy.centroid.copy( face.centroid );
- cloneGeo.faces.push( faceCopy );
- }
- // uvs
- for ( i = 0, il = uvs.length; i < il; i ++ ) {
- var uv = uvs[ i ], uvCopy = [];
- for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
- uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );
- }
- cloneGeo.faceVertexUvs[ 0 ].push( uvCopy );
- }
- return cloneGeo;
- },
- // Get random point in triangle (via barycentric coordinates)
- // (uniform distribution)
- // http://www.cgafaq.info/wiki/Random_Point_In_Triangle
- randomPointInTriangle: function( vectorA, vectorB, vectorC ) {
- var a, b, c,
- point = new THREE.Vector3(),
- tmp = THREE.GeometryUtils.__v1;
- a = THREE.GeometryUtils.random();
- b = THREE.GeometryUtils.random();
- if ( ( a + b ) > 1 ) {
- a = 1 - a;
- b = 1 - b;
- }
- c = 1 - a - b;
- point.copy( vectorA );
- point.multiplyScalar( a );
- tmp.copy( vectorB );
- tmp.multiplyScalar( b );
- point.addSelf( tmp );
- tmp.copy( vectorC );
- tmp.multiplyScalar( c );
- point.addSelf( tmp );
- return point;
- },
- // Get random point in face (triangle / quad)
- // (uniform distribution)
- randomPointInFace: function( face, geometry, useCachedAreas ) {
- var vA, vB, vC, vD;
- if ( face instanceof THREE.Face3 ) {
- vA = geometry.vertices[ face.a ].position;
- vB = geometry.vertices[ face.b ].position;
- vC = geometry.vertices[ face.c ].position;
- return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
- } else if ( face instanceof THREE.Face4 ) {
- vA = geometry.vertices[ face.a ].position;
- vB = geometry.vertices[ face.b ].position;
- vC = geometry.vertices[ face.c ].position;
- vD = geometry.vertices[ face.d ].position;
- var area1, area2;
- if ( useCachedAreas ) {
- if ( face._area1 && face._area2 ) {
- area1 = face._area1;
- area2 = face._area2;
- } else {
- area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
- area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
- face._area1 = area1;
- face._area2 = area2;
- }
- } else {
- area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ),
- area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
- }
- var r = THREE.GeometryUtils.random() * ( area1 + area2 );
- if ( r < area1 ) {
- return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vD );
- } else {
- return THREE.GeometryUtils.randomPointInTriangle( vB, vC, vD );
- }
- }
- },
- // Get uniformly distributed random points in mesh
- // - create array with cumulative sums of face areas
- // - pick random number from 0 to total area
- // - find corresponding place in area array by binary search
- // - get random point in face
- randomPointsInGeometry: function( geometry, n ) {
- var face, i,
- faces = geometry.faces,
- vertices = geometry.vertices,
- il = faces.length,
- totalArea = 0,
- cumulativeAreas = [],
- vA, vB, vC, vD;
- // precompute face areas
- for ( i = 0; i < il; i ++ ) {
- face = faces[ i ];
- if ( face instanceof THREE.Face3 ) {
- vA = vertices[ face.a ].position;
- vB = vertices[ face.b ].position;
- vC = vertices[ face.c ].position;
- face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
- } else if ( face instanceof THREE.Face4 ) {
- vA = vertices[ face.a ].position;
- vB = vertices[ face.b ].position;
- vC = vertices[ face.c ].position;
- vD = vertices[ face.d ].position;
- face._area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
- face._area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
- face._area = face._area1 + face._area2;
- }
- totalArea += face._area;
- cumulativeAreas[ i ] = totalArea;
- }
- // binary search cumulative areas array
- function binarySearchIndices( value ) {
- function binarySearch( start, end ) {
- // return closest larger index
- // if exact number is not found
- if ( end < start )
- return start;
- var mid = start + Math.floor( ( end - start ) / 2 );
- if ( cumulativeAreas[ mid ] > value ) {
- return binarySearch( start, mid - 1 );
- } else if ( cumulativeAreas[ mid ] < value ) {
- return binarySearch( mid + 1, end );
- } else {
- return mid;
- }
- }
- var result = binarySearch( 0, cumulativeAreas.length - 1 )
- return result;
- }
- // pick random face weighted by face area
- var r, index,
- result = [];
- var stats = {};
- for ( i = 0; i < n; i ++ ) {
- r = THREE.GeometryUtils.random() * totalArea;
- index = binarySearchIndices( r );
- result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
- if ( ! stats[ index ] ) {
- stats[ index ] = 1;
- } else {
- stats[ index ] += 1;
- }
- }
- return result;
- },
- // Get triangle area (by Heron's formula)
- // http://en.wikipedia.org/wiki/Heron%27s_formula
- triangleArea: function( vectorA, vectorB, vectorC ) {
- var s, a, b, c,
- tmp = THREE.GeometryUtils.__v1;
- tmp.sub( vectorA, vectorB );
- a = tmp.length();
- tmp.sub( vectorA, vectorC );
- b = tmp.length();
- tmp.sub( vectorB, vectorC );
- c = tmp.length();
- s = 0.5 * ( a + b + c );
- return Math.sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
- },
- // Get 16 bits of randomness
- // (standard Math.random() creates repetitive patterns when applied over larger space)
- random16: function() {
- return ( 65280 * Math.random() + 255 * Math.random() ) / 65535;
- }
- };
- THREE.GeometryUtils.random = THREE.GeometryUtils.random16;
- THREE.GeometryUtils.__v1 = new THREE.Vector3();
|