In the realm of Three.js, we've recently acquired the ability to determine the global position of a vertex in a non-skinned mesh thanks to insights from this question. Now, the query arises - how can one ascertain the global position of a vertex in a skinned mesh adorned with bones and morph targets?
For instance, consider this scenario: how would one output (2.5, 1.5, 0.5)
given the following conditions?
mesh.geometry.vertices[0]
initially resides at (0.5, 0.5, 0.5)
.
Subsequently, bones[1]
relocates the vertex to (2.5, 0.5, 0.5)
.
Lastly, morphing transports the vertex to (2.5, 1.5, 0.5)
.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 200);
camera.position.z = 3;
camera.position.y = 2;
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry(1, 1, 1);
geometry.morphTargets.push({name: "morph", vertices: []});
for (const vertex of geometry.vertices) {
geometry.skinIndices.push(new THREE.Vector4(vertex.x < 0 ? 0 : 1, 0, 0, 0));
geometry.skinWeights.push(new THREE.Vector4(1, 0, 0, 0));
geometry.morphTargets[0].vertices.push(vertex.clone().add(new THREE.Vector3(0, 1, 0)));
}
const material = new THREE.MeshPhongMaterial({
skinning: true,
emissive: 0xffffff,
wireframe: true,
morphTargets: true
});
const mesh = new THREE.SkinnedMesh(geometry, material);
const bones = [new THREE.Bone(), new THREE.Bone()];
for (const bone of bones) {
mesh.add(bone);
}
const skeleton = new THREE.Skeleton(bones);
mesh.bind(skeleton);
bones[0].position.x = -2;
bones[1].position.x = 2;
mesh.morphTargetInfluences[0] = 1;
scene.add(mesh);
// This code assigns (0.5, 0.5, 0.5) to pos,
// but I want to know the code which assigns (2.5, 1.5, 0.5) to pos.
const pos = mesh.geometry.vertices[0].clone().applyMatrix4(mesh.matrixWorld);
console.log(`(${pos.x}, ${pos.y}, ${pos.z})`);
(function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
})();
body {
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>