canvas
morphtargets / sphere
What this shows
A glTF sphere lit by red and green point lights spins while its blob morph target swings back and forth, with white point sprites following the morphed vertices.
Side by side with the three.js r186 original: webgl_morphtargets_sphere.html
Differences from three.js
- EASEL's GLTFLoader does not read morph targets and its renderer ignores morphTargetInfluences, so the port reads the two POSITION and NORMAL morph deltas from the same glTF buffer and blends them into the shared geometry on the CPU each frame.
- EASEL does not keep a node's Euler rotation in sync when its quaternion is changed in place, so the port copies the glTF node quaternion into mesh.rotation before applying the upstream rotation.z change.
- The glTF PBR material is loaded as an EASEL Lambert material with CPU-baked vertex lighting, so the sphere has no specular response.
- EASEL points are filled discs with an integer pixel radius and no texture sampling or alphaTest, so solid discs of radius 5 (11 pixels across) stand in for the 10-pixel disc.png sprites.
Loading scene…Key API excerpt
Key API excerpt
import * as EASEL from "@xsyetopz/easel";
const gltf = new EASEL.GLTFLoader().parse(sphereGltf, { buffers: [sphereBin] });
const mesh = gltf.scene.getObjectByName("AnimatedMorphSphere");
mesh.rotation.setFromQuaternion(mesh.quaternion);
mesh.rotation.z = Math.PI / 2;
scene.add(mesh);
const points = new EASEL.Points(
mesh.geometry,
new EASEL.PointsMaterial({ size: 5, vertexColors: false }),
);
mesh.add(points);
// EASEL has no morph targets: blend the glTF deltas on the CPU.
const position = mesh.geometry.getAttribute("position");
for (let i = 0; i < position.array.length; i++) {
position.array[i] = base[i] + blobDelta[i] * influence;
}
position.needsUpdate = true;
renderer.prepare(scene, camera);
renderer.render(scene, camera);