diff --git a/packages/three-vrm/examples/animations.html b/packages/three-vrm/examples/animations.html index cb20fb9f0..bd656feb7 100644 --- a/packages/three-vrm/examples/animations.html +++ b/packages/three-vrm/examples/animations.html @@ -68,6 +68,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); prepareAnimation( vrm ); diff --git a/packages/three-vrm/examples/basic.html b/packages/three-vrm/examples/basic.html index 141e54ef8..3491500f9 100644 --- a/packages/three-vrm/examples/basic.html +++ b/packages/three-vrm/examples/basic.html @@ -70,6 +70,7 @@ scene.add( vrm.scene ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); } ); diff --git a/packages/three-vrm/examples/blendshapes.html b/packages/three-vrm/examples/blendshapes.html index edfc7fd89..d01d12e77 100644 --- a/packages/three-vrm/examples/blendshapes.html +++ b/packages/three-vrm/examples/blendshapes.html @@ -67,6 +67,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); console.log( vrm ); diff --git a/packages/three-vrm/examples/bones.html b/packages/three-vrm/examples/bones.html index e4a7278ed..cc7c0afd0 100644 --- a/packages/three-vrm/examples/bones.html +++ b/packages/three-vrm/examples/bones.html @@ -67,6 +67,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); console.log( vrm ); diff --git a/packages/three-vrm/examples/debug.html b/packages/three-vrm/examples/debug.html index 4c1757eb4..b0a94758d 100644 --- a/packages/three-vrm/examples/debug.html +++ b/packages/three-vrm/examples/debug.html @@ -70,6 +70,7 @@ scene.add( vrm.scene ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); } ); diff --git a/packages/three-vrm/examples/dnd.html b/packages/three-vrm/examples/dnd.html index b253063a6..a7d906c4b 100644 --- a/packages/three-vrm/examples/dnd.html +++ b/packages/three-vrm/examples/dnd.html @@ -77,6 +77,7 @@ scene.add( vrm.scene ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); console.log( vrm ); diff --git a/packages/three-vrm/examples/encoding.html b/packages/three-vrm/examples/encoding.html index 746ba77ec..e2f0cc04a 100644 --- a/packages/three-vrm/examples/encoding.html +++ b/packages/three-vrm/examples/encoding.html @@ -79,6 +79,7 @@ scene.add( vrm.scene ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); } ); diff --git a/packages/three-vrm/examples/envmap.html b/packages/three-vrm/examples/envmap.html index 56e42b624..fdc69390e 100644 --- a/packages/three-vrm/examples/envmap.html +++ b/packages/three-vrm/examples/envmap.html @@ -104,6 +104,7 @@ scene.add( vrm.scene ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); } ); diff --git a/packages/three-vrm/examples/firstperson.html b/packages/three-vrm/examples/firstperson.html index 226bd5b0c..de1a72ec8 100644 --- a/packages/three-vrm/examples/firstperson.html +++ b/packages/three-vrm/examples/firstperson.html @@ -67,6 +67,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); // generate firstperson mesh vrm.firstPerson.setup(); diff --git a/packages/three-vrm/examples/lookat-advanced.html b/packages/three-vrm/examples/lookat-advanced.html index 3c8792fd2..9ee6badd4 100644 --- a/packages/three-vrm/examples/lookat-advanced.html +++ b/packages/three-vrm/examples/lookat-advanced.html @@ -139,6 +139,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); vrm.lookAt.target = camera; diff --git a/packages/three-vrm/examples/lookat.html b/packages/three-vrm/examples/lookat.html index b6386fd0c..1678b820b 100644 --- a/packages/three-vrm/examples/lookat.html +++ b/packages/three-vrm/examples/lookat.html @@ -71,6 +71,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); vrm.lookAt.target = lookAtTarget; diff --git a/packages/three-vrm/examples/materials-debug.html b/packages/three-vrm/examples/materials-debug.html index f2587fa96..658c8ecad 100644 --- a/packages/three-vrm/examples/materials-debug.html +++ b/packages/three-vrm/examples/materials-debug.html @@ -67,6 +67,7 @@ currentVrm = vrm; vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); console.log( vrm ); diff --git a/packages/three-vrm/examples/meta.html b/packages/three-vrm/examples/meta.html index 2cf8327c8..fd68e3b2f 100644 --- a/packages/three-vrm/examples/meta.html +++ b/packages/three-vrm/examples/meta.html @@ -80,6 +80,7 @@ scene.add( vrm.scene ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); // print meta fields Object.keys( vrm.meta ).forEach( ( key ) => { diff --git a/packages/three-vrm/examples/mouse.html b/packages/three-vrm/examples/mouse.html index 7f91c483b..d5ce0c523 100644 --- a/packages/three-vrm/examples/mouse.html +++ b/packages/three-vrm/examples/mouse.html @@ -64,6 +64,7 @@ console.log( vrm ); vrm.humanoid.getBoneNode( THREE.VRMSchema.HumanoidBoneName.Hips ).rotation.y = Math.PI; + vrm.springBoneManager.reset(); } ); diff --git a/packages/three-vrm/src/springbone/VRMSpringBone.ts b/packages/three-vrm/src/springbone/VRMSpringBone.ts index 11b3d8bd2..b8a28d48f 100644 --- a/packages/three-vrm/src/springbone/VRMSpringBone.ts +++ b/packages/three-vrm/src/springbone/VRMSpringBone.ts @@ -200,6 +200,7 @@ export class VRMSpringBone { this._initialLocalChildPosition.copy(firstChild.position); } + // Apply updated position to tail states this.bone.localToWorld(this._currentTail.copy(this._initialLocalChildPosition)); this._prevTail.copy(this._currentTail); this._nextTail.copy(this._currentTail); @@ -241,10 +242,6 @@ export class VRMSpringBone { public update(delta: number): void { if (delta <= 0) return; - // 親スプリングボーンの姿勢は常に変化している。 - // それに基づいて処理直前に自分のworldMatrixを更新しておく - this.bone.matrixWorld.multiplyMatrices(this._getParentMatrixWorld(), this.bone.matrix); - if (this.bone.parent) { // SpringBoneは親から順に処理されていくため、 // 親のmatrixWorldは最新状態の前提でworldMatrixからquaternionを取り出す。 diff --git a/packages/three-vrm/src/springbone/VRMSpringBoneManager.ts b/packages/three-vrm/src/springbone/VRMSpringBoneManager.ts index 22377a10d..d242f9e20 100644 --- a/packages/three-vrm/src/springbone/VRMSpringBoneManager.ts +++ b/packages/three-vrm/src/springbone/VRMSpringBoneManager.ts @@ -42,8 +42,11 @@ export class VRMSpringBoneManager { * @param delta deltaTime */ public lateUpdate(delta: number): void { + const updatedObjectSet = new Set(); + this.springBoneGroupList.forEach((springBoneGroup) => { springBoneGroup.forEach((springBone) => { + this._updateWorldMatrix(updatedObjectSet, springBone.bone); springBone.update(delta); }); }); @@ -53,10 +56,28 @@ export class VRMSpringBoneManager { * Reset every spring bone attached to this manager. */ public reset(): void { + const updatedObjectSet = new Set(); + this.springBoneGroupList.forEach((springBoneGroup) => { springBoneGroup.forEach((springBone) => { + this._updateWorldMatrix(updatedObjectSet, springBone.bone); springBone.reset(); }); }); } + + /** + * Update worldMatrix of given object, respecting its ancestors. + * called before update springbone. + * @param updatedObjectSet Set of node which worldMatrix is updated. + * @param node target bone node. + */ + private _updateWorldMatrix(updatedObjectSet: Set, node: THREE.Object3D): void { + if (updatedObjectSet.has(node)) return; + + if (node.parent) this._updateWorldMatrix(updatedObjectSet, node.parent); + node.updateWorldMatrix(false, false); + + updatedObjectSet.add(node); + } }