|
@@ -1040,6 +1040,107 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+ // Creates a new, non-indexed geometry with smooth normals everywhere except faces that meet at
|
|
|
+ // an angle greater than the crease angle.
|
|
|
+ function toCreasedNormals( geometry, creaseAngle = Math.PI / 3 /* 60 degrees */ ) {
|
|
|
+
|
|
|
+ const creaseDot = Math.cos( creaseAngle );
|
|
|
+ const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
|
|
|
+
|
|
|
+ // reusable vertors
|
|
|
+ const verts = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
|
|
|
+ const tempVec1 = new THREE.Vector3();
|
|
|
+ const tempVec2 = new THREE.Vector3();
|
|
|
+ const tempNorm = new THREE.Vector3();
|
|
|
+ const tempNorm2 = new THREE.Vector3();
|
|
|
+
|
|
|
+ // hashes a vector
|
|
|
+ function hashVertex( v ) {
|
|
|
+
|
|
|
+ const x = ~ ~ ( v.x * hashMultiplier );
|
|
|
+ const y = ~ ~ ( v.y * hashMultiplier );
|
|
|
+ const z = ~ ~ ( v.z * hashMultiplier );
|
|
|
+ return `${x},${y},${z}`;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const resultGeometry = geometry.toNonIndexed();
|
|
|
+ const posAttr = resultGeometry.attributes.position;
|
|
|
+ const vertexMap = {};
|
|
|
+
|
|
|
+ // find all the normals shared by commonly located vertices
|
|
|
+ for ( let i = 0, l = posAttr.count / 3; i < l; i ++ ) {
|
|
|
+
|
|
|
+ const i3 = 3 * i;
|
|
|
+ const a = verts[ 0 ].fromBufferAttribute( posAttr, i3 + 0 );
|
|
|
+ const b = verts[ 1 ].fromBufferAttribute( posAttr, i3 + 1 );
|
|
|
+ const c = verts[ 2 ].fromBufferAttribute( posAttr, i3 + 2 );
|
|
|
+ tempVec1.subVectors( c, b );
|
|
|
+ tempVec2.subVectors( a, b );
|
|
|
+
|
|
|
+ // add the normal to the map for all vertices
|
|
|
+ const normal = new THREE.Vector3().crossVectors( tempVec1, tempVec2 ).normalize();
|
|
|
+ for ( let n = 0; n < 3; n ++ ) {
|
|
|
+
|
|
|
+ const vert = verts[ n ];
|
|
|
+ const hash = hashVertex( vert );
|
|
|
+ if ( ! ( hash in vertexMap ) ) {
|
|
|
+
|
|
|
+ vertexMap[ hash ] = [];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ vertexMap[ hash ].push( normal );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // average normals from all vertices that share a common location if they are within the
|
|
|
+ // provided crease threshold
|
|
|
+ const normalArray = new Float32Array( posAttr.count * 3 );
|
|
|
+ const normAttr = new THREE.BufferAttribute( normalArray, 3, false );
|
|
|
+ for ( let i = 0, l = posAttr.count / 3; i < l; i ++ ) {
|
|
|
+
|
|
|
+ // get the face normal for this vertex
|
|
|
+ const i3 = 3 * i;
|
|
|
+ const a = verts[ 0 ].fromBufferAttribute( posAttr, i3 + 0 );
|
|
|
+ const b = verts[ 1 ].fromBufferAttribute( posAttr, i3 + 1 );
|
|
|
+ const c = verts[ 2 ].fromBufferAttribute( posAttr, i3 + 2 );
|
|
|
+ tempVec1.subVectors( c, b );
|
|
|
+ tempVec2.subVectors( a, b );
|
|
|
+ tempNorm.crossVectors( tempVec1, tempVec2 ).normalize();
|
|
|
+
|
|
|
+ // average all normals that meet the threshold and set the normal value
|
|
|
+ for ( let n = 0; n < 3; n ++ ) {
|
|
|
+
|
|
|
+ const vert = verts[ n ];
|
|
|
+ const hash = hashVertex( vert );
|
|
|
+ const otherNormals = vertexMap[ hash ];
|
|
|
+ tempNorm2.set( 0, 0, 0 );
|
|
|
+ for ( let k = 0, lk = otherNormals.length; k < lk; k ++ ) {
|
|
|
+
|
|
|
+ const otherNorm = otherNormals[ k ];
|
|
|
+ if ( tempNorm.dot( otherNorm ) > creaseDot ) {
|
|
|
+
|
|
|
+ tempNorm2.add( otherNorm );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ tempNorm2.normalize();
|
|
|
+ normAttr.setXYZ( i3 + n, tempNorm2.x, tempNorm2.y, tempNorm2.z );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ resultGeometry.setAttribute( 'normal', normAttr );
|
|
|
+ return resultGeometry;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
THREE.BufferGeometryUtils = {};
|
|
|
THREE.BufferGeometryUtils.computeMikkTSpaceTangents = computeMikkTSpaceTangents;
|
|
|
THREE.BufferGeometryUtils.computeMorphedAttributes = computeMorphedAttributes;
|
|
@@ -1053,6 +1154,7 @@
|
|
|
THREE.BufferGeometryUtils.mergeBufferGeometries = mergeBufferGeometries;
|
|
|
THREE.BufferGeometryUtils.mergeGroups = mergeGroups;
|
|
|
THREE.BufferGeometryUtils.mergeVertices = mergeVertices;
|
|
|
+ THREE.BufferGeometryUtils.toCreasedNormals = toCreasedNormals;
|
|
|
THREE.BufferGeometryUtils.toTrianglesDrawMode = toTrianglesDrawMode;
|
|
|
|
|
|
} )();
|