Skip to content

Commit

Permalink
chore(model): document skeleton animation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak committed Feb 8, 2024
1 parent eaae801 commit b0bd6f9
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
10 changes: 10 additions & 0 deletions src/lib/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ class Model extends THREE.Mesh {
this.#updateSize();
}

updateSkeleton(camera: THREE.Camera) {
// Calculate current model view matrix. This calculation is also performed by the Three.js
// renderer, but since model skeleton calculations need a current model view matrix and run
// before the render call, we can't rely on the model view matrix update in the renderer.
this.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, this.matrixWorld);

// Calculate bone matrices
this.animation.skeleton.update();
}

#updateBounds() {
this.#boundingSphereWorld.copy(this.boundingSphere).applyMatrix4(this.matrixWorld);
}
Expand Down
3 changes: 1 addition & 2 deletions src/lib/model/ModelAnimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,8 @@ class ModelAnimator {
continue;
}

// Ensure bone matrices are updated (matrix world auto-updates are disabled)
if (model.skinned) {
model.animation.skeleton.updateBones(camera);
model.updateSkeleton(camera);
}
}
}
Expand Down
25 changes: 17 additions & 8 deletions src/lib/model/ModelSkeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,23 @@ class ModelSkeleton {
}
}

updateBones(camera: THREE.Camera) {
// Ensure model view matrix is synchronized
this.#root.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, this.#root.matrixWorld);

/**
* Calculate current bone matrices for all bones in skeleton. Each bone matrix is composed of
* the current bone translation, rotation, and scale, and is adjusted to reflect parent
* transformations within the bone hierarchy. Note that bone translation, rotation, and scale may
* be animated.
*
* Depending on bone flags, certain bone matrices may be modified to reflect spherical or
* cylindrical billboarding. Billboarding ensures vertices attached to the bone match the camera
* view, and is often used in lighting effects (eg. a quad with a yellow circle texture may be
* spherically billboarded to give the illusion of an orb of light).
*/
update() {
for (const [index, bone] of this.#bones.entries()) {
// Calculate bone matrix
updateBone(this.#root, bone);

// Copy bone matrix into the skeleton's bone texture
bone.matrix.toArray(this.#boneMatrices, index * 16);
}

Expand All @@ -51,18 +62,16 @@ class ModelSkeleton {
size = Math.ceil(size / 4) * 4;
size = Math.max(size, 4);

const boneMatrices = new Float32Array(size * size * 4);
this.#boneMatrices = new Float32Array(size * size * 4);

const boneTexture = new THREE.DataTexture(
boneMatrices,
this.#boneMatrices,
size,
size,
THREE.RGBAFormat,
THREE.FloatType,
);
boneTexture.needsUpdate = true;

this.#boneMatrices = boneMatrices;
this.#boneTexture = boneTexture;
}
}
Expand Down

0 comments on commit b0bd6f9

Please sign in to comment.