ソースを参照

Add Mesh.getVertexPosition (#25049)

* added getUpdatedVertex

* addressing feedback

* added reduceVertices doc

* addressing feedback
Emmett Lalish 2 年 前
コミット
87223b87ed

+ 6 - 0
docs/api/en/objects/Mesh.html

@@ -72,6 +72,12 @@
 		<h3>[method:Mesh clone]()</h3>
 		<p>Returns a clone of this [name] object and its descendants.</p>
 
+    <h3>[method:Vector3 getVertexPosition]( [param:Integer vert], [param:Vector3 target] )</h3>
+		<p>
+		Get the current position of the indicated vertex in local space, taking into account the
+		current animation state of both morph targets and skinning.
+		</p>
+
 		<h3>[method:undefined raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
 		<p>
 		Get intersections between a casted ray and this mesh.

+ 14 - 0
docs/examples/en/utils/SceneUtils.html

@@ -40,6 +40,20 @@
 		This is mostly useful for objects that need both a material and a wireframe implementation.
 		</p>
 
+    <h3>[method:T reduceVertices]( [param:Object3D object], [param:function func], [param:T initialValue] )</h3>
+		<p>
+		object -- The object to traverse (uses [page:Object3D.traverseVisible traverseVisible] internally). <br />
+		func -- The binary function applied for the reduction. Must have the signature: (value: T, vertex: Vector3): T. <br />
+    initialValue -- The value to initialize the reduction with. This is required
+    as it also sets the reduction type, which is not required to be Vector3.
+		</p>
+		<p>
+		Akin to Array.prototype.reduce(), but operating on the vertices of all the
+		visible descendant objects, in world space. Additionally, it can operate as a
+		transform-reduce, returning a different type T than the Vector3 input. This
+		can be useful for e.g. fitting a viewing frustum to the scene.
+		</p>
+
 		<h3>[method:undefined sortInstancedMesh]( [param:InstancedMesh mesh], [param:Function compareFn] )</h3>
 		<p>
 		mesh -- InstancedMesh in which instances will be sorted. <br />

+ 8 - 4
examples/jsm/utils/SceneUtils.js

@@ -143,14 +143,18 @@ function reduceVertices( object, func, initialValue ) {
 
 				for ( let i = 0, l = position.count; i < l; i ++ ) {
 
-					vertex.fromBufferAttribute( position, i );
+					if ( child.isMesh ) {
 
-					if ( child.isSkinnedMesh ) {
-
-						child.boneTransform( i, vertex );
+						child.getVertexPosition( i, vertex );
 
 					} else {
 
+						vertex.fromBufferAttribute( position, i );
+
+					}
+
+					if ( ! child.isSkinnedMesh ) {
+
 						vertex.applyMatrix4( child.matrixWorld );
 
 					}

+ 58 - 64
src/objects/Mesh.js

@@ -18,12 +18,7 @@ const _vB = /*@__PURE__*/ new Vector3();
 const _vC = /*@__PURE__*/ new Vector3();
 
 const _tempA = /*@__PURE__*/ new Vector3();
-const _tempB = /*@__PURE__*/ new Vector3();
-const _tempC = /*@__PURE__*/ new Vector3();
-
 const _morphA = /*@__PURE__*/ new Vector3();
-const _morphB = /*@__PURE__*/ new Vector3();
-const _morphC = /*@__PURE__*/ new Vector3();
 
 const _uvA = /*@__PURE__*/ new Vector2();
 const _uvB = /*@__PURE__*/ new Vector2();
@@ -103,6 +98,56 @@ class Mesh extends Object3D {
 
 	}
 
+	getVertexPosition( vert, target ) {
+
+		const geometry = this.geometry;
+		const position = geometry.attributes.position;
+		const morphPosition = geometry.morphAttributes.position;
+		const morphTargetsRelative = geometry.morphTargetsRelative;
+
+		target.fromBufferAttribute( position, vert );
+
+		const morphInfluences = this.morphTargetInfluences;
+
+		if ( morphPosition && morphInfluences ) {
+
+			_morphA.set( 0, 0, 0 );
+
+			for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
+
+				const influence = morphInfluences[ i ];
+				const morphAttribute = morphPosition[ i ];
+
+				if ( influence === 0 ) continue;
+
+				_tempA.fromBufferAttribute( morphAttribute, vert );
+
+				if ( morphTargetsRelative ) {
+
+					_morphA.addScaledVector( _tempA, influence );
+
+				} else {
+
+					_morphA.addScaledVector( _tempA.sub( target ), influence );
+
+				}
+
+			}
+
+			target.add( _morphA );
+
+		}
+
+		if ( this.isSkinnedMesh ) {
+
+			this.boneTransform( vert, target );
+
+		}
+
+		return target;
+
+	}
+
 	raycast( raycaster, intersects ) {
 
 		const geometry = this.geometry;
@@ -137,8 +182,6 @@ class Mesh extends Object3D {
 
 		const index = geometry.index;
 		const position = geometry.attributes.position;
-		const morphPosition = geometry.morphAttributes.position;
-		const morphTargetsRelative = geometry.morphTargetsRelative;
 		const uv = geometry.attributes.uv;
 		const uv2 = geometry.attributes.uv2;
 		const groups = geometry.groups;
@@ -164,7 +207,7 @@ class Mesh extends Object3D {
 						const b = index.getX( j + 1 );
 						const c = index.getX( j + 2 );
 
-						intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
+						intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, uv, uv2, a, b, c );
 
 						if ( intersection ) {
 
@@ -189,7 +232,7 @@ class Mesh extends Object3D {
 					const b = index.getX( i + 1 );
 					const c = index.getX( i + 2 );
 
-					intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
+					intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, uv, uv2, a, b, c );
 
 					if ( intersection ) {
 
@@ -222,7 +265,7 @@ class Mesh extends Object3D {
 						const b = j + 1;
 						const c = j + 2;
 
-						intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
+						intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, uv, uv2, a, b, c );
 
 						if ( intersection ) {
 
@@ -247,7 +290,7 @@ class Mesh extends Object3D {
 					const b = i + 1;
 					const c = i + 2;
 
-					intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
+					intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, uv, uv2, a, b, c );
 
 					if ( intersection ) {
 
@@ -297,60 +340,11 @@ function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point
 
 }
 
-function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
-
-	_vA.fromBufferAttribute( position, a );
-	_vB.fromBufferAttribute( position, b );
-	_vC.fromBufferAttribute( position, c );
-
-	const morphInfluences = object.morphTargetInfluences;
-
-	if ( morphPosition && morphInfluences ) {
-
-		_morphA.set( 0, 0, 0 );
-		_morphB.set( 0, 0, 0 );
-		_morphC.set( 0, 0, 0 );
-
-		for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
-
-			const influence = morphInfluences[ i ];
-			const morphAttribute = morphPosition[ i ];
-
-			if ( influence === 0 ) continue;
-
-			_tempA.fromBufferAttribute( morphAttribute, a );
-			_tempB.fromBufferAttribute( morphAttribute, b );
-			_tempC.fromBufferAttribute( morphAttribute, c );
-
-			if ( morphTargetsRelative ) {
+function checkBufferGeometryIntersection( object, material, raycaster, ray, uv, uv2, a, b, c ) {
 
-				_morphA.addScaledVector( _tempA, influence );
-				_morphB.addScaledVector( _tempB, influence );
-				_morphC.addScaledVector( _tempC, influence );
-
-			} else {
-
-				_morphA.addScaledVector( _tempA.sub( _vA ), influence );
-				_morphB.addScaledVector( _tempB.sub( _vB ), influence );
-				_morphC.addScaledVector( _tempC.sub( _vC ), influence );
-
-			}
-
-		}
-
-		_vA.add( _morphA );
-		_vB.add( _morphB );
-		_vC.add( _morphC );
-
-	}
-
-	if ( object.isSkinnedMesh ) {
-
-		object.boneTransform( a, _vA );
-		object.boneTransform( b, _vB );
-		object.boneTransform( c, _vC );
-
-	}
+	object.getVertexPosition( a, _vA );
+	object.getVertexPosition( b, _vB );
+	object.getVertexPosition( c, _vC );
 
 	const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );