Skip to content

Commit 87223b8

Browse files
authored
Add Mesh.getVertexPosition (#25049)
* added getUpdatedVertex * addressing feedback * added reduceVertices doc * addressing feedback
1 parent 31bcc6d commit 87223b8

File tree

4 files changed

+86
-68
lines changed

4 files changed

+86
-68
lines changed

docs/api/en/objects/Mesh.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ <h2>Methods</h2>
7272
<h3>[method:Mesh clone]()</h3>
7373
<p>Returns a clone of this [name] object and its descendants.</p>
7474

75+
<h3>[method:Vector3 getVertexPosition]( [param:Integer vert], [param:Vector3 target] )</h3>
76+
<p>
77+
Get the current position of the indicated vertex in local space, taking into account the
78+
current animation state of both morph targets and skinning.
79+
</p>
80+
7581
<h3>[method:undefined raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
7682
<p>
7783
Get intersections between a casted ray and this mesh.

docs/examples/en/utils/SceneUtils.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ <h3>[method:Group createMultiMaterialObject]( [param:BufferGeometry geometry], [
4040
This is mostly useful for objects that need both a material and a wireframe implementation.
4141
</p>
4242

43+
<h3>[method:T reduceVertices]( [param:Object3D object], [param:function func], [param:T initialValue] )</h3>
44+
<p>
45+
object -- The object to traverse (uses [page:Object3D.traverseVisible traverseVisible] internally). <br />
46+
func -- The binary function applied for the reduction. Must have the signature: (value: T, vertex: Vector3): T. <br />
47+
initialValue -- The value to initialize the reduction with. This is required
48+
as it also sets the reduction type, which is not required to be Vector3.
49+
</p>
50+
<p>
51+
Akin to Array.prototype.reduce(), but operating on the vertices of all the
52+
visible descendant objects, in world space. Additionally, it can operate as a
53+
transform-reduce, returning a different type T than the Vector3 input. This
54+
can be useful for e.g. fitting a viewing frustum to the scene.
55+
</p>
56+
4357
<h3>[method:undefined sortInstancedMesh]( [param:InstancedMesh mesh], [param:Function compareFn] )</h3>
4458
<p>
4559
mesh -- InstancedMesh in which instances will be sorted. <br />

examples/jsm/utils/SceneUtils.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,18 @@ function reduceVertices( object, func, initialValue ) {
143143

144144
for ( let i = 0, l = position.count; i < l; i ++ ) {
145145

146-
vertex.fromBufferAttribute( position, i );
146+
if ( child.isMesh ) {
147147

148-
if ( child.isSkinnedMesh ) {
149-
150-
child.boneTransform( i, vertex );
148+
child.getVertexPosition( i, vertex );
151149

152150
} else {
153151

152+
vertex.fromBufferAttribute( position, i );
153+
154+
}
155+
156+
if ( ! child.isSkinnedMesh ) {
157+
154158
vertex.applyMatrix4( child.matrixWorld );
155159

156160
}

src/objects/Mesh.js

Lines changed: 58 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,7 @@ const _vB = /*@__PURE__*/ new Vector3();
1818
const _vC = /*@__PURE__*/ new Vector3();
1919

2020
const _tempA = /*@__PURE__*/ new Vector3();
21-
const _tempB = /*@__PURE__*/ new Vector3();
22-
const _tempC = /*@__PURE__*/ new Vector3();
23-
2421
const _morphA = /*@__PURE__*/ new Vector3();
25-
const _morphB = /*@__PURE__*/ new Vector3();
26-
const _morphC = /*@__PURE__*/ new Vector3();
2722

2823
const _uvA = /*@__PURE__*/ new Vector2();
2924
const _uvB = /*@__PURE__*/ new Vector2();
@@ -103,6 +98,56 @@ class Mesh extends Object3D {
10398

10499
}
105100

101+
getVertexPosition( vert, target ) {
102+
103+
const geometry = this.geometry;
104+
const position = geometry.attributes.position;
105+
const morphPosition = geometry.morphAttributes.position;
106+
const morphTargetsRelative = geometry.morphTargetsRelative;
107+
108+
target.fromBufferAttribute( position, vert );
109+
110+
const morphInfluences = this.morphTargetInfluences;
111+
112+
if ( morphPosition && morphInfluences ) {
113+
114+
_morphA.set( 0, 0, 0 );
115+
116+
for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
117+
118+
const influence = morphInfluences[ i ];
119+
const morphAttribute = morphPosition[ i ];
120+
121+
if ( influence === 0 ) continue;
122+
123+
_tempA.fromBufferAttribute( morphAttribute, vert );
124+
125+
if ( morphTargetsRelative ) {
126+
127+
_morphA.addScaledVector( _tempA, influence );
128+
129+
} else {
130+
131+
_morphA.addScaledVector( _tempA.sub( target ), influence );
132+
133+
}
134+
135+
}
136+
137+
target.add( _morphA );
138+
139+
}
140+
141+
if ( this.isSkinnedMesh ) {
142+
143+
this.boneTransform( vert, target );
144+
145+
}
146+
147+
return target;
148+
149+
}
150+
106151
raycast( raycaster, intersects ) {
107152

108153
const geometry = this.geometry;
@@ -137,8 +182,6 @@ class Mesh extends Object3D {
137182

138183
const index = geometry.index;
139184
const position = geometry.attributes.position;
140-
const morphPosition = geometry.morphAttributes.position;
141-
const morphTargetsRelative = geometry.morphTargetsRelative;
142185
const uv = geometry.attributes.uv;
143186
const uv2 = geometry.attributes.uv2;
144187
const groups = geometry.groups;
@@ -164,7 +207,7 @@ class Mesh extends Object3D {
164207
const b = index.getX( j + 1 );
165208
const c = index.getX( j + 2 );
166209

167-
intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
210+
intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, uv, uv2, a, b, c );
168211

169212
if ( intersection ) {
170213

@@ -189,7 +232,7 @@ class Mesh extends Object3D {
189232
const b = index.getX( i + 1 );
190233
const c = index.getX( i + 2 );
191234

192-
intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
235+
intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, uv, uv2, a, b, c );
193236

194237
if ( intersection ) {
195238

@@ -222,7 +265,7 @@ class Mesh extends Object3D {
222265
const b = j + 1;
223266
const c = j + 2;
224267

225-
intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
268+
intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, uv, uv2, a, b, c );
226269

227270
if ( intersection ) {
228271

@@ -247,7 +290,7 @@ class Mesh extends Object3D {
247290
const b = i + 1;
248291
const c = i + 2;
249292

250-
intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
293+
intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, uv, uv2, a, b, c );
251294

252295
if ( intersection ) {
253296

@@ -297,60 +340,11 @@ function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point
297340

298341
}
299342

300-
function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
301-
302-
_vA.fromBufferAttribute( position, a );
303-
_vB.fromBufferAttribute( position, b );
304-
_vC.fromBufferAttribute( position, c );
305-
306-
const morphInfluences = object.morphTargetInfluences;
307-
308-
if ( morphPosition && morphInfluences ) {
309-
310-
_morphA.set( 0, 0, 0 );
311-
_morphB.set( 0, 0, 0 );
312-
_morphC.set( 0, 0, 0 );
313-
314-
for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
315-
316-
const influence = morphInfluences[ i ];
317-
const morphAttribute = morphPosition[ i ];
318-
319-
if ( influence === 0 ) continue;
320-
321-
_tempA.fromBufferAttribute( morphAttribute, a );
322-
_tempB.fromBufferAttribute( morphAttribute, b );
323-
_tempC.fromBufferAttribute( morphAttribute, c );
324-
325-
if ( morphTargetsRelative ) {
343+
function checkBufferGeometryIntersection( object, material, raycaster, ray, uv, uv2, a, b, c ) {
326344

327-
_morphA.addScaledVector( _tempA, influence );
328-
_morphB.addScaledVector( _tempB, influence );
329-
_morphC.addScaledVector( _tempC, influence );
330-
331-
} else {
332-
333-
_morphA.addScaledVector( _tempA.sub( _vA ), influence );
334-
_morphB.addScaledVector( _tempB.sub( _vB ), influence );
335-
_morphC.addScaledVector( _tempC.sub( _vC ), influence );
336-
337-
}
338-
339-
}
340-
341-
_vA.add( _morphA );
342-
_vB.add( _morphB );
343-
_vC.add( _morphC );
344-
345-
}
346-
347-
if ( object.isSkinnedMesh ) {
348-
349-
object.boneTransform( a, _vA );
350-
object.boneTransform( b, _vB );
351-
object.boneTransform( c, _vC );
352-
353-
}
345+
object.getVertexPosition( a, _vA );
346+
object.getVertexPosition( b, _vB );
347+
object.getVertexPosition( c, _vC );
354348

355349
const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );
356350

0 commit comments

Comments
 (0)