diff --git a/src/lib/map/MapManager.ts b/src/lib/map/MapManager.ts index 30ecf83..9fe9cfe 100644 --- a/src/lib/map/MapManager.ts +++ b/src/lib/map/MapManager.ts @@ -178,8 +178,6 @@ class MapManager extends EventTarget { } update(deltaTime: number, camera: THREE.Camera) { - this.#doodadManager.update(deltaTime); - this.#mapLight.update(camera); // If fog end is closer than the configured view distance, use the fog end plus extension to @@ -197,6 +195,7 @@ class MapManager extends EventTarget { this.#cullGroups(); this.#doodadManager.cull(this.#cullingFrustum); + this.#doodadManager.update(deltaTime); } dispose() { diff --git a/src/lib/model/Model.ts b/src/lib/model/Model.ts index ff22995..01e7472 100644 --- a/src/lib/model/Model.ts +++ b/src/lib/model/Model.ts @@ -11,6 +11,7 @@ class Model extends THREE.Object3D { alpha: 1.0; #mesh: THREE.Mesh; + #skinned: boolean; constructor( geometry: THREE.BufferGeometry, @@ -20,6 +21,8 @@ class Model extends THREE.Object3D { ) { super(); + this.#skinned = skinned; + // Avoid skinning overhead when model does not make use of bone animations if (skinned) { this.#mesh = new THREE.SkinnedMesh(geometry, materials); @@ -53,6 +56,10 @@ class Model extends THREE.Object3D { return this.#mesh.geometry.boundingSphere; } + get skinned() { + return this.#skinned; + } + hide() { if (!this.visible) { return; @@ -83,11 +90,6 @@ class Model extends THREE.Object3D { material: ModelMaterial, group: THREE.Group, ) { - // Ensure bone matrices are updated (matrix world auto-updates are disabled) - if ((this.#mesh as THREE.SkinnedMesh).isSkinnedMesh) { - this.#mesh.updateMatrixWorld(); - } - // Update material uniforms to match animation states material.prepareMaterial(this); } diff --git a/src/lib/model/ModelAnimation.ts b/src/lib/model/ModelAnimation.ts index b0adaa7..c5c2237 100644 --- a/src/lib/model/ModelAnimation.ts +++ b/src/lib/model/ModelAnimation.ts @@ -41,6 +41,8 @@ class ModelAnimation extends THREE.Object3D { this.#animator.clearAction(action); } + this.#animator.clearAnimation(this); + this.#actions.clear(); this.#playingActions.clear(); this.#suspendedActions.clear(); diff --git a/src/lib/model/ModelAnimator.ts b/src/lib/model/ModelAnimator.ts index 395f823..11f2f39 100644 --- a/src/lib/model/ModelAnimator.ts +++ b/src/lib/model/ModelAnimator.ts @@ -28,6 +28,8 @@ class ModelAnimator { #stateCounts: Record = {}; + #modelsByAnimation: Map = new Map(); + constructor(loops: Uint32Array, sequences: SequenceSpec[], bones: BoneSpec[]) { this.#mixer = new THREE.AnimationMixer(new THREE.Object3D()); this.#mixer.timeScale = 1000; @@ -44,7 +46,10 @@ class ModelAnimator { } createAnimation(model: Model) { - return new ModelAnimation(model, this, this.#bones, this.#stateCounts); + const animation = new ModelAnimation(model, this, this.#bones, this.#stateCounts); + this.#modelsByAnimation.set(animation, model); + + return animation; } get loops() { @@ -60,8 +65,23 @@ class ModelAnimator { this.#mixer.uncacheAction(action.getClip()); } + clearAnimation(animation: ModelAnimation) { + this.#modelsByAnimation.delete(animation); + } + update(deltaTime: number) { this.#mixer.update(deltaTime); + + for (const model of this.#modelsByAnimation.values()) { + if (!model.visible) { + continue; + } + + // Ensure bone matrices are updated (matrix world auto-updates are disabled) + if (model.skinned) { + model.updateMatrixWorld(); + } + } } getLoop(root: THREE.Object3D, index: number) {