From c77dd45c9c7745a3a07eb927f49af481c1fef860 Mon Sep 17 00:00:00 2001 From: Alex Tiernan-Berry Date: Sun, 13 Oct 2024 00:24:25 +0100 Subject: [PATCH] feat: generate cameras for m2 model --- src/lib/index.ts | 1 + src/lib/map/DoodadManager.ts | 4 +-- src/lib/model/ModelManager.ts | 34 +++++++++++++++++++++-- src/lib/model/loader/ModelLoaderWorker.ts | 2 ++ src/lib/model/loader/types.ts | 2 ++ src/lib/model/util.ts | 4 ++- 6 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/lib/index.ts b/src/lib/index.ts index 2805d74..312ae92 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -6,6 +6,7 @@ export * from './db/DbManager.js'; export * from './light/SceneLight.js'; export * from './map/MapManager.js'; export * from './model/ModelManager.js'; +export * from './model/Model.js'; export * from './sound/SoundManager.js'; export * from './texture/TextureManager.js'; export * from './util.js'; diff --git a/src/lib/map/DoodadManager.ts b/src/lib/map/DoodadManager.ts index 5a4ed56..6ce7369 100644 --- a/src/lib/map/DoodadManager.ts +++ b/src/lib/map/DoodadManager.ts @@ -153,9 +153,9 @@ class DoodadManager { const areaBounds = new THREE.Sphere(); - const doodadModels = await Promise.all( + const doodadModels = (await Promise.all( doodadDefs.map((doodadDef) => this.#modelManager.get(doodadDef.name)), - ); + )).map(({model}) => model); for (let i = 0; i < doodadDefs.length; i++) { const model = doodadModels[i]; diff --git a/src/lib/model/ModelManager.ts b/src/lib/model/ModelManager.ts index 4037f01..f3c2381 100644 --- a/src/lib/model/ModelManager.ts +++ b/src/lib/model/ModelManager.ts @@ -10,6 +10,7 @@ import ModelLoader from './loader/ModelLoader.js'; import { MaterialSpec, ModelSpec, TextureSpec } from './loader/types.js'; import SceneLight from '../light/SceneLight.js'; import ModelAnimator from './ModelAnimator.js'; +import { DEFAULT_UP } from './util.js'; type ModelResources = { name: string; @@ -17,6 +18,7 @@ type ModelResources = { materials: MaterialSpec[]; animator: ModelAnimator; skinned: boolean; + cameras: THREE.PerspectiveCamera[]; }; type ModelManagerOptions = { @@ -45,7 +47,13 @@ class ModelManager { async get(path: string) { const resources = await this.#getResources(path); - return this.#createModel(resources); + const [model] = await Promise.all([ + this.#createModel(resources), + ]); + return { + model, + cameras: resources.cameras, + } } update(deltaTime: number, camera: THREE.Camera) { @@ -77,9 +85,9 @@ class ModelManager { async #loadResources(refId: string, path: string) { const spec = await this.#loader.loadSpec(path); - const animator = this.#createAnimator(spec); const geometry = this.#createGeometry(spec); + const cameras = this.#createCameras(spec); const resources: ModelResources = { name: spec.name, @@ -87,6 +95,7 @@ class ModelManager { materials: spec.materials, animator, skinned: spec.skinned, + cameras: cameras, }; this.#loaded.set(refId, resources); @@ -297,6 +306,27 @@ class ModelManager { return animator; } + + #createCameras(spec: ModelSpec): THREE.PerspectiveCamera[] { + const ASPECT_RATIO = 1; + return spec.cameras.map((cameraSpec) => { + const camera = new THREE.PerspectiveCamera( + (cameraSpec.fieldOfView / Math.sqrt(1.0 + Math.pow(ASPECT_RATIO, 2.0)) * 57.2958), + ASPECT_RATIO, + cameraSpec.nearClip, + cameraSpec.farClip, + ); + camera.userData.fov = cameraSpec.fieldOfView; + camera.up = DEFAULT_UP; + + const [x, y, z] = cameraSpec.positionBase; + camera.position.set(x, y, z); + + const [targetX, targetY, targetZ] = cameraSpec.targetBase; + camera.lookAt(targetX, targetY, targetZ); + return camera; + }); + } } export default ModelManager; diff --git a/src/lib/model/loader/ModelLoaderWorker.ts b/src/lib/model/loader/ModelLoaderWorker.ts index 36fc5b6..a2cc045 100644 --- a/src/lib/model/loader/ModelLoaderWorker.ts +++ b/src/lib/model/loader/ModelLoaderWorker.ts @@ -35,6 +35,7 @@ class ModelLoaderWorker extends SceneWorker { const textureWeights = model.textureWeights; const textureTransforms = model.textureTransforms; const materialColors = model.colors; + const cameras = model.cameras.map((c) => c.toObject()); // Expand geometry bounds by sequence bounds to produce model bounds const extent = geometry.bounds.extent.slice(0); @@ -57,6 +58,7 @@ class ModelLoaderWorker extends SceneWorker { textureWeights, textureTransforms, materialColors, + cameras, }; const transfer = [spec.geometry.vertexBuffer, spec.geometry.indexBuffer, ...boneBuffers]; diff --git a/src/lib/model/loader/types.ts b/src/lib/model/loader/types.ts index 7816392..c5b2fe9 100644 --- a/src/lib/model/loader/types.ts +++ b/src/lib/model/loader/types.ts @@ -7,6 +7,7 @@ import { M2TextureTransform, M2TextureWeight, M2Track, + M2Camera, } from '@wowserhq/format'; type ModelBounds = { @@ -79,6 +80,7 @@ type ModelSpec = { textureWeights: M2TextureWeight[]; textureTransforms: M2TextureTransform[]; materialColors: M2Color[]; + cameras: M2Camera[]; }; export { ModelBounds, ModelSpec, BoneSpec, MaterialSpec, TextureSpec, SequenceSpec }; diff --git a/src/lib/model/util.ts b/src/lib/model/util.ts index e8abde2..08d1498 100644 --- a/src/lib/model/util.ts +++ b/src/lib/model/util.ts @@ -15,4 +15,6 @@ const getTrackInterpolation = (trackType: number): THREE.InterpolationModes => { } }; -export { getTrackInterpolation }; +const DEFAULT_UP = new THREE.Vector3(0, 0, 1); + +export { getTrackInterpolation, DEFAULT_UP };