Skip to content

Commit

Permalink
fix(model): account for sequence bounds when culling models
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak committed Jan 31, 2024
1 parent ee57a0c commit 7f9e0e6
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 27 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
],
"dependencies": {
"@tweenjs/tween.js": "^23.1.1",
"@wowserhq/format": "^0.22.0"
"@wowserhq/format": "^0.23.0"
},
"peerDependencies": {
"three": "^0.160.0"
Expand Down
5 changes: 5 additions & 0 deletions src/lib/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Model extends THREE.Object3D {
this.#mesh = new THREE.Mesh(geometry, materials);
}

this.#mesh.frustumCulled = false;
this.#mesh.onBeforeRender = this.#onBeforeRender.bind(this);
this.add(this.#mesh);

Expand All @@ -44,6 +45,10 @@ class Model extends THREE.Object3D {
this.alpha = 1.0;
}

get boundingBox() {
return this.#mesh.geometry.boundingBox;
}

get boundingSphere() {
return this.#mesh.geometry.boundingSphere;
}
Expand Down
10 changes: 5 additions & 5 deletions src/lib/model/ModelManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,14 @@ class ModelManager {

// Bounds

geometry.boundingBox = new THREE.Box3().setFromArray(spec.geometry.bounds.extent);
geometry.boundingBox = new THREE.Box3().setFromArray(spec.bounds.extent);

const boundsCenter = new THREE.Vector3(
spec.geometry.bounds.center[0],
spec.geometry.bounds.center[1],
spec.geometry.bounds.center[2],
spec.bounds.center[0],
spec.bounds.center[1],
spec.bounds.center[2],
);
geometry.boundingSphere = new THREE.Sphere(boundsCenter, spec.geometry.bounds.radius);
geometry.boundingSphere = new THREE.Sphere(boundsCenter, spec.bounds.radius);

return geometry;
}
Expand Down
54 changes: 40 additions & 14 deletions src/lib/model/loader/ModelLoaderWorker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { M2Batch, M2Model, M2SkinProfile } from '@wowserhq/format';
import { ModelSpec } from './types.js';
import { getBoundsCenter } from './util.js';
import { ModelBounds, ModelSpec, SequenceSpec } from './types.js';
import { expandExtent, getBoundsCenter, getBoundsRadius } from './util.js';
import SceneWorker from '../../worker/SceneWorker.js';
import { AssetHost, loadAsset } from '../../asset.js';

Expand Down Expand Up @@ -30,12 +30,21 @@ class ModelLoaderWorker extends SceneWorker {
const geometry = this.#createGeometrySpec(model, skinProfile);
const materials = this.#createMaterialSpecs(skinProfile);
const { bones, skinned } = this.#createBoneSpecs(model);
const sequences = this.#createSequenceSpecs(model);
const { sequences, sequenceBounds } = this.#createSequenceSpecs(model);
const loops = model.loops;
const textureWeights = model.textureWeights;
const textureTransforms = model.textureTransforms;
const materialColors = model.colors;

// Expand geometry bounds by sequence bounds to produce model bounds
const extent = geometry.bounds.extent.slice(0);
expandExtent(extent, sequenceBounds.extent);
const bounds: ModelBounds = {
extent,
center: getBoundsCenter(extent),
radius: getBoundsRadius(extent),
};

const spec: ModelSpec = {
name: model.name,
geometry,
Expand All @@ -44,6 +53,7 @@ class ModelLoaderWorker extends SceneWorker {
skinned,
loops,
sequences,
bounds,
textureWeights,
textureTransforms,
materialColors,
Expand Down Expand Up @@ -118,17 +128,33 @@ class ModelLoaderWorker extends SceneWorker {
}

#createSequenceSpecs(model: M2Model) {
return model.sequences.map((sequence) => ({
id: sequence.id,
variationIndex: sequence.variationIndex,
duration: sequence.duration,
moveSpeed: sequence.moveSpeed,
flags: sequence.flags,
frequency: sequence.frequency,
blendTime: sequence.blendTime,
variationNext: sequence.variationNext,
aliasNext: sequence.aliasNext,
}));
const extent = new Float32Array(6);
const sequenceSpecs: SequenceSpec[] = [];

for (const sequence of model.sequences) {
expandExtent(extent, sequence.bounds.extent);

sequenceSpecs.push({
id: sequence.id,
variationIndex: sequence.variationIndex,
duration: sequence.duration,
moveSpeed: sequence.moveSpeed,
flags: sequence.flags,
frequency: sequence.frequency,
blendTime: sequence.blendTime,
variationNext: sequence.variationNext,
aliasNext: sequence.aliasNext,
});
}

// Produce bounds that encompass all sequences
const sequenceBounds: ModelBounds = {
extent,
center: getBoundsCenter(extent),
radius: getBoundsRadius(extent),
};

return { sequences: sequenceSpecs, sequenceBounds };
}

#createBoneSpecs(model: M2Model) {
Expand Down
11 changes: 9 additions & 2 deletions src/lib/model/loader/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import {
M2Track,
} from '@wowserhq/format';

type ModelBounds = {
extent: Float32Array;
center: Float32Array;
radius: number;
};

type TextureSpec = {
flags: number;
component: M2_TEXTURE_COMPONENT;
Expand All @@ -33,7 +39,7 @@ type GroupSpec = {
};

type GeometrySpec = {
bounds: { extent: Float32Array; center: Float32Array; radius: number };
bounds: ModelBounds;
vertexBuffer: ArrayBuffer;
indexBuffer: ArrayBuffer;
groups: GroupSpec[];
Expand Down Expand Up @@ -67,10 +73,11 @@ type ModelSpec = {
bones: BoneSpec[];
skinned: boolean;
sequences: SequenceSpec[];
bounds: ModelBounds;
loops: Uint32Array;
textureWeights: M2TextureWeight[];
textureTransforms: M2TextureTransform[];
materialColors: M2Color[];
};

export { ModelSpec, BoneSpec, MaterialSpec, TextureSpec, SequenceSpec };
export { ModelBounds, ModelSpec, BoneSpec, MaterialSpec, TextureSpec, SequenceSpec };
26 changes: 25 additions & 1 deletion src/lib/model/loader/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
const _scratch = new Float32Array(3);

const expandExtent = (extent: Float32Array, expand: Float32Array) => {
extent[0] = Math.min(extent[0], expand[0]);
extent[1] = Math.min(extent[1], expand[1]);
extent[2] = Math.min(extent[2], expand[2]);

extent[3] = Math.max(extent[3], expand[3]);
extent[4] = Math.max(extent[4], expand[4]);
extent[5] = Math.max(extent[5], expand[5]);
};

const getBoundsCenter = (extent: Float32Array) => {
const center = new Float32Array(3);

Expand All @@ -8,4 +20,16 @@ const getBoundsCenter = (extent: Float32Array) => {
return center;
};

export { getBoundsCenter };
const getBoundsRadius = (extent: Float32Array) => {
_scratch[0] = extent[3] - extent[0];
_scratch[1] = extent[4] - extent[1];
_scratch[2] = extent[5] - extent[2];

const size = Math.sqrt(
_scratch[0] * _scratch[0] + _scratch[1] * _scratch[1] + _scratch[2] * _scratch[2],
);

return size * 0.5;
};

export { expandExtent, getBoundsCenter, getBoundsRadius };

0 comments on commit 7f9e0e6

Please sign in to comment.