Просмотр исходного кода

LatheGeometry: Improve normal generation. (#22927)

* Update LatheGeometry.js

Two-step approach:
1. pre-compute normals in 2D-domain (all z = 0) for initial "meridian" of vertices as defined in the points[] array
2. rotate pre-computed normals along with vertices for each additional meridian in lathing
Advantages:
* Considerably reduces computational expense of setting up normals.
* perfect normal precision (within limits of numerical accuracy), avoids considerable deviations from precision in low lathe-segment count situations of current approach
* seam-handling obsoleted by design
This is going to be my first pull request. I hope, I'll be able to add screenshots/scetches later in the process.

* Update LatheGeometry.js

Struggling with my 1st PR and now fixing previously ommitted code lines.

* Update LatheGeometry.js

Fixed linting errors
Chrissie-AI 3 лет назад
Родитель
Сommit
490ce69d63
1 измененных файлов с 70 добавлено и 47 удалено
  1. 70 47
      src/geometries/LatheGeometry.js

+ 70 - 47
src/geometries/LatheGeometry.js

@@ -30,14 +30,75 @@ class LatheGeometry extends BufferGeometry {
 		const indices = [];
 		const vertices = [];
 		const uvs = [];
+		const initNormals = [];
+		const normals = [];
 
 		// helper variables
 
 		const inverseSegments = 1.0 / segments;
 		const vertex = new Vector3();
 		const uv = new Vector2();
+		const normal = new Vector3();
+		const curNormal = new Vector3();
+		const prevNormal = new Vector3();
+		let dx = 0;
+		let dy = 0;
 
-		// generate vertices and uvs
+		// pre-compute normals for initial "meridian"
+
+		for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
+
+			switch ( j ) {
+
+				case 0:				// special handling for 1st vertex on path
+
+					dx = points[ j + 1 ].x - points[ j ].x;
+					dy = points[ j + 1 ].y - points[ j ].y;
+
+					normal.x = dy * 1.0;
+					normal.y = - dx;
+					normal.z = dy * 0.0;
+
+					prevNormal.copy( normal );
+
+					normal.normalize();
+
+					initNormals.push( normal.x, normal.y, normal.z );
+
+					break;
+
+				case ( points.length - 1 ):	// special handling for last Vertex on path
+
+					initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z );
+
+					break;
+
+				default:			// default handling for all vertices in between
+
+					dx = points[ j + 1 ].x - points[ j ].x;
+					dy = points[ j + 1 ].y - points[ j ].y;
+
+					normal.x = dy * 1.0;
+					normal.y = - dx;
+					normal.z = dy * 0.0;
+
+					curNormal.copy( normal );
+
+					normal.x += prevNormal.x;
+					normal.y += prevNormal.y;
+					normal.z += prevNormal.z;
+
+					normal.normalize();
+
+					initNormals.push( normal.x, normal.y, normal.z );
+
+					prevNormal.copy( curNormal );
+
+			}
+
+		}
+
+		// generate vertices, uvs and normals
 
 		for ( let i = 0; i <= segments; i ++ ) {
 
@@ -63,6 +124,13 @@ class LatheGeometry extends BufferGeometry {
 
 				uvs.push( uv.x, uv.y );
 
+				// normal
+
+				const x = initNormals[ 3 * j + 0 ] * sin;
+				const y = initNormals[ 3 * j + 1 ];
+				const z = initNormals[ 3 * j + 0 ] * cos;
+
+				normals.push( x, y, z );
 
 			}
 
@@ -95,52 +163,7 @@ class LatheGeometry extends BufferGeometry {
 		this.setIndex( indices );
 		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
-
-		// generate normals
-
-		this.computeVertexNormals();
-
-		// if the geometry is closed, we need to average the normals along the seam.
-		// because the corresponding vertices are identical (but still have different UVs).
-
-		if ( phiLength === Math.PI * 2 ) {
-
-			const normals = this.attributes.normal.array;
-			const n1 = new Vector3();
-			const n2 = new Vector3();
-			const n = new Vector3();
-
-			// this is the buffer offset for the last line of vertices
-
-			const base = segments * points.length * 3;
-
-			for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) {
-
-				// select the normal of the vertex in the first line
-
-				n1.x = normals[ j + 0 ];
-				n1.y = normals[ j + 1 ];
-				n1.z = normals[ j + 2 ];
-
-				// select the normal of the vertex in the last line
-
-				n2.x = normals[ base + j + 0 ];
-				n2.y = normals[ base + j + 1 ];
-				n2.z = normals[ base + j + 2 ];
-
-				// average normals
-
-				n.addVectors( n1, n2 ).normalize();
-
-				// assign the new values to both normals
-
-				normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
-				normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
-				normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
-
-			}
-
-		}
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 
 	}