2
0
Эх сурвалжийг харах

Merge pull request #20903 from Mcgode/edge-split-keep-normals

EdgeSplitModifier - Keep normals
Mr.doob 4 жил өмнө
parent
commit
ecf862c499

+ 27 - 1
examples/js/modifiers/EdgeSplitModifier.js

@@ -7,6 +7,7 @@ THREE.EdgeSplitModifier = function () {
 	var positions, normals;
 	var indexes;
 	var pointToIndexMap, splitIndexes;
+	let oldNormals;
 
 
 	function computeNormals() {
@@ -150,7 +151,7 @@ THREE.EdgeSplitModifier = function () {
 	}
 
 
-	this.modify = function ( geometry, cutOffAngle ) {
+	this.modify = function ( geometry, cutOffAngle, tryKeepNormals = true ) {
 
 		const wasNotBufferGeometry = geometry.isBufferGeometry === undefined;
 		if ( ! geometry.isBufferGeometry ) {
@@ -161,6 +162,7 @@ THREE.EdgeSplitModifier = function () {
 
 
 		let hadNormals = false;
+		oldNormals = null;
 		if ( geometry.attributes.normal ) {
 
 			hadNormals = true;
@@ -168,6 +170,9 @@ THREE.EdgeSplitModifier = function () {
 			if ( wasNotBufferGeometry === false )
 				geometry = geometry.clone();
 
+			if ( tryKeepNormals && geometry.index )
+				oldNormals = geometry.attributes.normal.array;
+
 			geometry.deleteAttribute( 'normal' );
 
 		}
@@ -249,6 +254,27 @@ THREE.EdgeSplitModifier = function () {
 
 			geometry.computeVertexNormals();
 
+			if ( oldNormals !== null ) {
+
+				const changedNormals = new Array( oldNormals.length / 3 ).fill( false );
+
+				for ( const splitData of splitIndexes )
+					changedNormals[ splitData.original ] = true;
+
+				for ( let i = 0; i < changedNormals.length; i ++ ) {
+
+					if ( changedNormals[ i ] === false ) {
+
+						for ( let j = 0; j < 3; j ++ )
+							geometry.attributes.normal.array[ 3 * i + j ] = oldNormals[ 3 * i + j ];
+
+					}
+
+				}
+
+
+			}
+
 		}
 
 		return geometry;

+ 15 - 1
examples/jsm/modifiers/EdgeSplitModifier.d.ts

@@ -3,6 +3,20 @@ import { BufferGeometry, Geometry } from '../../../src/Three';
 export class EdgeSplitModifier {
 
 	constructor();
-	modify( geometry: Geometry, cutOffPoint: number ): BufferGeometry;
+
+
+	/**
+	 * @param geometry					The geometry to modify by splitting edges.
+	 * 									This geometry can be any of any type: Geometry or BufferGeometry, indexed or
+	 * 									not...
+	 *
+	 * @param cutOffPoint				The cutoff angle in radians. If the angle between two face normals is higher
+	 * 									than this value, a split will be made.
+	 *
+	 * @param [tryKeepNormals = true]	Set to true to keep the normal values for vertices that won't be split.
+	 * 									To use this feature, you also need to pass an indexed geometry with a 'normal'
+	 * 									BufferAttribute.
+	 */
+	modify( geometry: Geometry, cutOffPoint: number, tryKeepNormals: boolean ): BufferGeometry;
 
 }

+ 28 - 1
examples/jsm/modifiers/EdgeSplitModifier.js

@@ -16,6 +16,8 @@ var EdgeSplitModifier = function () {
 	var indexes;
 	var pointToIndexMap, splitIndexes;
 
+	let oldNormals;
+
 
 	function computeNormals() {
 
@@ -158,7 +160,7 @@ var EdgeSplitModifier = function () {
 	}
 
 
-	this.modify = function ( geometry, cutOffAngle ) {
+	this.modify = function ( geometry, cutOffAngle, tryKeepNormals = true ) {
 
 		const wasNotBufferGeometry = geometry.isBufferGeometry === undefined;
 		if ( ! geometry.isBufferGeometry ) {
@@ -169,6 +171,7 @@ var EdgeSplitModifier = function () {
 
 
 		let hadNormals = false;
+		oldNormals = null;
 		if ( geometry.attributes.normal ) {
 
 			hadNormals = true;
@@ -176,6 +179,9 @@ var EdgeSplitModifier = function () {
 			if ( wasNotBufferGeometry === false )
 				geometry = geometry.clone();
 
+			if ( tryKeepNormals && geometry.index )
+				oldNormals = geometry.attributes.normal.array;
+
 			geometry.deleteAttribute( 'normal' );
 
 		}
@@ -257,6 +263,27 @@ var EdgeSplitModifier = function () {
 
 			geometry.computeVertexNormals();
 
+			if ( oldNormals !== null ) {
+
+				const changedNormals = new Array( oldNormals.length / 3 ).fill( false );
+
+				for ( const splitData of splitIndexes )
+					changedNormals[ splitData.original ] = true;
+
+				for ( let i = 0; i < changedNormals.length; i ++ ) {
+
+					if ( changedNormals[ i ] === false ) {
+
+						for ( let j = 0; j < 3; j ++ )
+							geometry.attributes.normal.array[ 3 * i + j ] = oldNormals[ 3 * i + j ];
+
+					}
+
+				}
+
+
+			}
+
 		}
 
 		return geometry;

+ 9 - 2
examples/webgl_modifier_edgesplit.html

@@ -15,6 +15,7 @@
 			import { OrbitControls } from './jsm/controls/OrbitControls.js';
 			import { OBJLoader } from './jsm/loaders/OBJLoader.js';
 			import { EdgeSplitModifier } from './jsm/modifiers/EdgeSplitModifier.js';
+			import { BufferGeometryUtils } from './jsm/utils/BufferGeometryUtils.js';
 
 			import { GUI } from './jsm/libs/dat.gui.module.js';
 
@@ -27,6 +28,7 @@
 				edgeSplit: true,
 				cutOffAngle: 20,
 				showMap: false,
+				tryKeepNormals: true,
 			};
 
 			init();
@@ -68,7 +70,7 @@
 						const modelGeometry = cerberus.geometry;
 
 						modifier = new EdgeSplitModifier();
-						baseGeometry = modelGeometry;
+						baseGeometry = BufferGeometryUtils.mergeVertices( modelGeometry );
 
 						mesh = new THREE.Mesh( getGeometry(), new THREE.MeshStandardMaterial() );
 						mesh.material.flatShading = ! params.smoothShading;
@@ -111,6 +113,7 @@
 				gui.add( params, 'smoothShading' ).onFinishChange( updateMesh );
 				gui.add( params, 'edgeSplit' ).onFinishChange( updateMesh );
 				gui.add( params, 'cutOffAngle' ).min( 0 ).max( 180 ).onFinishChange( updateMesh );
+				gui.add( params, 'tryKeepNormals' ).onFinishChange( updateMesh );
 
 			}
 
@@ -132,7 +135,11 @@
 
 				if ( params.edgeSplit ) {
 
-					geometry = modifier.modify( baseGeometry, params.cutOffAngle * Math.PI / 180 );
+					geometry = modifier.modify(
+						baseGeometry,
+						params.cutOffAngle * Math.PI / 180,
+						params.tryKeepNormals
+					);
 
 				} else {
 

+ 1 - 1
package-lock.json

@@ -3105,7 +3105,7 @@
     },
     "path-is-absolute": {
       "version": "1.0.1",
-      "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
       "dev": true
     },