reze-engine 0.21.2 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
package/dist/model.js CHANGED
@@ -29,6 +29,15 @@ export class Model {
29
29
  get rotation() {
30
30
  return this._rotation;
31
31
  }
32
+ /** Uniform scale (default 1). Used to fit a stage.pmx to the character. */
33
+ get scale() {
34
+ return this._scale;
35
+ }
36
+ /** Whether this model renders. Hidden models skip the main, shadow, and pick passes;
37
+ * physics keeps running so they resume consistently. */
38
+ get visible() {
39
+ return this._visible;
40
+ }
32
41
  setPosition(position) {
33
42
  this._position.set(position);
34
43
  this.rootMatrixDirty = true;
@@ -37,6 +46,13 @@ export class Model {
37
46
  this._rotation.set(rotation);
38
47
  this.rootMatrixDirty = true;
39
48
  }
49
+ setScale(scale) {
50
+ this._scale = scale;
51
+ this.rootMatrixDirty = true;
52
+ }
53
+ setVisible(visible) {
54
+ this._visible = visible;
55
+ }
40
56
  /** Called by Engine when registering the model; enables loadVmd to resolve relative paths for folder uploads. */
41
57
  setAssetContext(reader, basePath) {
42
58
  this.assetReader = reader;
@@ -67,6 +83,8 @@ export class Model {
67
83
  // Skip-when-identity flag avoids the extra mat mul per bone when unused.
68
84
  this._position = Vec3.zeros();
69
85
  this._rotation = Quat.identity();
86
+ this._scale = 1;
87
+ this._visible = true;
70
88
  this.rootMatrixValues = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
71
89
  this.rootMatrixDirty = false;
72
90
  this.rootIsIdentity = true;
@@ -564,11 +582,11 @@ export class Model {
564
582
  const skinMatrices = this.skinMatricesArray;
565
583
  // Rebuild root matrix + cache identity-shortcut flag only when pos/rot changed.
566
584
  if (this.rootMatrixDirty) {
567
- const p = this._position, r = this._rotation;
568
- Mat4.fromPositionRotationInto(p.x, p.y, p.z, r.x, r.y, r.z, r.w, this.rootMatrixValues);
585
+ const p = this._position, r = this._rotation, s = this._scale;
586
+ Mat4.fromPositionRotationScaleInto(p.x, p.y, p.z, r.x, r.y, r.z, r.w, s, this.rootMatrixValues);
569
587
  this.rootIsIdentity =
570
588
  p.x === 0 && p.y === 0 && p.z === 0 &&
571
- r.x === 0 && r.y === 0 && r.z === 0 && r.w === 1;
589
+ r.x === 0 && r.y === 0 && r.z === 0 && r.w === 1 && s === 1;
572
590
  this.rootMatrixDirty = false;
573
591
  }
574
592
  if (this.rootIsIdentity) {
@@ -16,6 +16,17 @@ export interface VMDKeyFrame {
16
16
  boneFrames: BoneFrame[];
17
17
  morphFrames: MorphFrame[];
18
18
  }
19
+ /** One MMD camera keyframe. The camera looks at `target` from `distance` away, oriented by
20
+ * `rotation` (euler radians), with `fov` degrees. `interpolation` is 24 bytes: 6 channels
21
+ * (posX, posY, posZ, rotation, distance, fov) × 4 bezier bytes (x1, x2, y1, y2). */
22
+ export interface CameraKeyframe {
23
+ frame: number;
24
+ distance: number;
25
+ target: Vec3;
26
+ rotation: Vec3;
27
+ fov: number;
28
+ interpolation: Uint8Array;
29
+ }
19
30
  export declare class VMDLoader {
20
31
  private view;
21
32
  private offset;
@@ -23,6 +34,11 @@ export declare class VMDLoader {
23
34
  private constructor();
24
35
  static load(url: string): Promise<VMDKeyFrame[]>;
25
36
  static loadFromBuffer(buffer: ArrayBuffer): VMDKeyFrame[];
37
+ /** Parse only the camera track (a dedicated camera VMD, or the camera block of any VMD).
38
+ * Returns [] if the file has no camera block (motion-only VMDs end after the morph block). */
39
+ static loadCamera(url: string): Promise<CameraKeyframe[]>;
40
+ static loadCameraFromBuffer(buffer: ArrayBuffer): CameraKeyframe[];
41
+ private parseCamera;
26
42
  private parse;
27
43
  private readBoneFrame;
28
44
  private readMorphFrame;
@@ -1 +1 @@
1
- {"version":3,"file":"vmd-loader.d.ts","sourceRoot":"","sources":["../src/vmd-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAEnC,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,IAAI,CAAA;IACd,WAAW,EAAE,IAAI,CAAA;IACjB,aAAa,EAAE,UAAU,CAAA;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAa;IAE5B,OAAO;WAWM,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,EAAE;IAKzD,OAAO,CAAC,KAAK;IAgGb,OAAO,CAAC,aAAa;IAuDrB,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,IAAI;CAMb"}
1
+ {"version":3,"file":"vmd-loader.d.ts","sourceRoot":"","sources":["../src/vmd-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAEnC,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,IAAI,CAAA;IACd,WAAW,EAAE,IAAI,CAAA;IACjB,aAAa,EAAE,UAAU,CAAA;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED;;qFAEqF;AACrF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,IAAI,CAAA;IACZ,QAAQ,EAAE,IAAI,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,UAAU,CAAA;CAC1B;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAa;IAE5B,OAAO;WAWM,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,EAAE;IAKzD;mGAC+F;WAClF,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAK/D,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,EAAE;IAOlE,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,KAAK;IAgGb,OAAO,CAAC,aAAa;IAuDrB,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,IAAI;CAMb"}
@@ -20,6 +20,47 @@ export class VMDLoader {
20
20
  const loader = new VMDLoader(buffer);
21
21
  return loader.parse();
22
22
  }
23
+ /** Parse only the camera track (a dedicated camera VMD, or the camera block of any VMD).
24
+ * Returns [] if the file has no camera block (motion-only VMDs end after the morph block). */
25
+ static async loadCamera(url) {
26
+ const loader = new VMDLoader(await fetch(url).then((r) => r.arrayBuffer()));
27
+ return loader.parseCamera();
28
+ }
29
+ static loadCameraFromBuffer(buffer) {
30
+ return new VMDLoader(buffer).parseCamera();
31
+ }
32
+ // Seek past the bone + morph blocks (fixed record sizes) to the camera block, then read it.
33
+ // bone frame = 111 B (15 name + 4 frame + 12 pos + 16 rot + 64 interp); morph = 23 B
34
+ // (15 name + 4 frame + 4 weight); camera = 61 B.
35
+ parseCamera() {
36
+ this.offset = 0;
37
+ const header = this.getString(30);
38
+ if (!header.startsWith("Vocaloid Motion Data"))
39
+ throw new Error("Invalid VMD file header");
40
+ this.skip(20);
41
+ const boneCount = this.getUint32();
42
+ this.skip(boneCount * 111);
43
+ const morphCount = this.getUint32();
44
+ this.skip(morphCount * 23);
45
+ if (this.offset + 4 > this.view.buffer.byteLength)
46
+ return []; // no camera block
47
+ const cameraCount = this.getUint32();
48
+ const frames = [];
49
+ for (let i = 0; i < cameraCount; i++) {
50
+ const frame = this.getUint32();
51
+ const distance = this.getFloat32();
52
+ const target = new Vec3(this.getFloat32(), this.getFloat32(), this.getFloat32());
53
+ const rotation = new Vec3(this.getFloat32(), this.getFloat32(), this.getFloat32());
54
+ const interpolation = new Uint8Array(24);
55
+ for (let j = 0; j < 24; j++)
56
+ interpolation[j] = this.getUint8();
57
+ const fov = this.getUint32();
58
+ this.skip(1); // perspective flag (0 = perspective) — unused
59
+ frames.push({ frame, distance, target, rotation, fov, interpolation });
60
+ }
61
+ frames.sort((a, b) => a.frame - b.frame);
62
+ return frames;
63
+ }
23
64
  parse() {
24
65
  // Read header (30 bytes)
25
66
  const header = this.getString(30);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.21.2",
3
+ "version": "0.22.0",
4
4
  "description": "A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,93 @@
1
+ // Samples an MMD camera track (from a VMD) at a playback time. Four bezier-interpolated
2
+ // channels — target (Vec3), rotation (Vec3 euler), distance, fov — driven off the same
3
+ // clock as the model motion so the shot stays synced to the dance.
4
+
5
+ import { Vec3 } from "./math"
6
+ import { bezierInterpolate } from "./animation"
7
+ import type { CameraKeyframe } from "./vmd-loader"
8
+
9
+ const FPS = 30
10
+ const DEG2RAD = Math.PI / 180
11
+
12
+ /** A sampled camera pose. `rotation` is euler radians; `fov` is radians. */
13
+ export interface CameraPose {
14
+ target: Vec3
15
+ rotation: Vec3
16
+ distance: number
17
+ fov: number
18
+ }
19
+
20
+ // MMD camera interpolation is 24 bytes, stored CONTIGUOUS per channel — each channel's 4
21
+ // bezier bytes are [x1, x2, y1, y2] in order. Channels: 0=posX 1=posY 2=posZ 3=rotation
22
+ // 4=distance 5=fov. So channel c lives at bytes [4c .. 4c+3]. (Matches babylon-mmd, which
23
+ // slices these into position/rotation/distance/fov interpolation buffers.)
24
+ function bez(ip: Uint8Array, c: number, t: number): number {
25
+ const b = c * 4
26
+ return bezierInterpolate(ip[b] / 127, ip[b + 1] / 127, ip[b + 2] / 127, ip[b + 3] / 127, t)
27
+ }
28
+
29
+ const lerp = (a: number, b: number, w: number): number => a + (b - a) * w
30
+
31
+ export class CameraAnimation {
32
+ private readonly frames: CameraKeyframe[]
33
+ /** Track length in seconds (last keyframe). */
34
+ readonly duration: number
35
+
36
+ constructor(frames: CameraKeyframe[]) {
37
+ this.frames = frames
38
+ this.duration = frames.length ? frames[frames.length - 1].frame / FPS : 0
39
+ }
40
+
41
+ get frameCount(): number {
42
+ return this.frames.length
43
+ }
44
+
45
+ /** Sample the camera pose at time `t` (seconds). Clamps to the track ends; null if empty. */
46
+ sample(t: number): CameraPose | null {
47
+ const frames = this.frames
48
+ const n = frames.length
49
+ if (n === 0) return null
50
+
51
+ const frame = t * FPS
52
+ if (frame <= frames[0].frame) return this.pose(frames[0])
53
+ if (frame >= frames[n - 1].frame) return this.pose(frames[n - 1])
54
+
55
+ // Binary search for the segment [a, b] with a.frame <= frame < b.frame.
56
+ let lo = 0
57
+ let hi = n - 1
58
+ while (hi - lo > 1) {
59
+ const mid = (lo + hi) >> 1
60
+ if (frames[mid].frame <= frame) lo = mid
61
+ else hi = mid
62
+ }
63
+ const a = frames[lo]
64
+ const b = frames[hi]
65
+ const span = b.frame - a.frame
66
+ const localT = span > 0 ? (frame - a.frame) / span : 0
67
+ // The incoming interpolation curve is stored on the segment's end keyframe (b).
68
+ const ip = b.interpolation
69
+
70
+ return {
71
+ target: new Vec3(
72
+ lerp(a.target.x, b.target.x, bez(ip, 0, localT)),
73
+ lerp(a.target.y, b.target.y, bez(ip, 1, localT)),
74
+ lerp(a.target.z, b.target.z, bez(ip, 2, localT)),
75
+ ),
76
+ // MMD rotation animates as one channel (single bezier for all three euler components).
77
+ rotation: (() => {
78
+ const w = bez(ip, 3, localT)
79
+ return new Vec3(
80
+ lerp(a.rotation.x, b.rotation.x, w),
81
+ lerp(a.rotation.y, b.rotation.y, w),
82
+ lerp(a.rotation.z, b.rotation.z, w),
83
+ )
84
+ })(),
85
+ distance: lerp(a.distance, b.distance, bez(ip, 4, localT)),
86
+ fov: lerp(a.fov * DEG2RAD, b.fov * DEG2RAD, bez(ip, 5, localT)),
87
+ }
88
+ }
89
+
90
+ private pose(f: CameraKeyframe): CameraPose {
91
+ return { target: f.target, rotation: f.rotation, distance: f.distance, fov: f.fov * DEG2RAD }
92
+ }
93
+ }
package/src/camera.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { Mat4, Vec3 } from "./math"
1
+ import { Mat4, Quat, Vec3 } from "./math"
2
+ import type { CameraPose } from "./camera-animation"
2
3
 
3
4
  /** Far cap / zoom limit; large enough for wide shots without clipping distant ground */
4
5
  const FAR_CAP = 8000
@@ -41,6 +42,16 @@ export class Camera {
41
42
  private _viewMat = new Mat4(new Float32Array(16))
42
43
  private _projMat = new Mat4(new Float32Array(16))
43
44
 
45
+ // ── VMD camera drive ──
46
+ // When vmdDriven, getViewMatrix builds the shot from a sampled MMD camera pose (target /
47
+ // rotation-euler / distance / fov) instead of the orbit params. Toggled by the engine.
48
+ vmdDriven: boolean = false
49
+ private _vmdTarget = new Vec3(0, 0, 0)
50
+ private _vmdRotation = new Vec3(0, 0, 0) // euler radians
51
+ private _vmdDistance = -45
52
+ private _savedFov = Math.PI / 4
53
+ private _quatScratch = new Float32Array(16)
54
+
44
55
  constructor(alpha: number, beta: number, radius: number, target: Vec3, fov: number = Math.PI / 4) {
45
56
  this.alpha = alpha
46
57
  this.beta = beta
@@ -68,7 +79,40 @@ export class Camera {
68
79
  return new Vec3(x, y, z)
69
80
  }
70
81
 
82
+ /** Enter/leave VMD-camera drive. Backs up the orbit fov on enter, restores it on leave
83
+ * (the VMD camera animates fov, so orbit's value would otherwise be clobbered). */
84
+ setVmdDriven(enabled: boolean): void {
85
+ if (enabled === this.vmdDriven) return
86
+ if (enabled) this._savedFov = this.fov
87
+ else this.fov = this._savedFov
88
+ this.vmdDriven = enabled
89
+ }
90
+
91
+ /** Feed the next sampled MMD camera pose (engine calls this each frame while driving). */
92
+ setVmdPose(pose: CameraPose): void {
93
+ this._vmdTarget.set(pose.target)
94
+ this._vmdRotation.set(pose.rotation)
95
+ this._vmdDistance = pose.distance
96
+ this.fov = pose.fov // drives the projection
97
+ }
98
+
71
99
  getViewMatrix(): Mat4 {
100
+ if (this.vmdDriven) {
101
+ // MMD camera: look at `target` from `distance` back, oriented by the euler rotation.
102
+ // forward = q·(0,0,1) (LH), up = q·(0,1,0) — read as columns 2 and 1 of the rot matrix.
103
+ // eye = target + forward·distance (distance is negative in VMD, so eye sits behind).
104
+ // NOTE: euler sign/order follows the engine's fromEuler; if a loaded shot looks
105
+ // mirrored or rolled, this is the one line to flip (negate axes / reorder).
106
+ const r = this._vmdRotation
107
+ const q = Quat.fromEuler(r.x, r.y, r.z)
108
+ Mat4.fromQuatInto(q.x, q.y, q.z, q.w, this._quatScratch, 0)
109
+ const s = this._quatScratch
110
+ const t = this._vmdTarget
111
+ const d = this._vmdDistance
112
+ const ex = t.x + s[8] * d, ey = t.y + s[9] * d, ez = t.z + s[10] * d
113
+ Mat4.lookAtInto(this._viewMat.values, ex, ey, ez, t.x, t.y, t.z, s[4], s[5], s[6])
114
+ return this._viewMat
115
+ }
72
116
  const eye = this.getPosition()
73
117
  const t = this.target
74
118
  Mat4.lookAtInto(this._viewMat.values, eye.x, eye.y, eye.z, t.x, t.y, t.z, 0, 1, 0)
package/src/engine.ts CHANGED
@@ -3,6 +3,8 @@ import { Mat4, Quat, Vec3 } from "./math"
3
3
  import { Model, type Material } from "./model"
4
4
  import { MORPH_COMPUTE_WGSL } from "./shaders/passes/morph"
5
5
  import { decodeTga } from "./tga-loader"
6
+ import { VMDLoader } from "./vmd-loader"
7
+ import { CameraAnimation } from "./camera-animation"
6
8
  import { PmxLoader } from "./pmx-loader"
7
9
  import { RezePhysics } from "./physics"
8
10
  import {
@@ -197,6 +199,16 @@ export type WorldOptions = {
197
199
  strength?: number
198
200
  }
199
201
 
202
+ /** A model's scene placement — root offset baked into skinning + visibility. Serializable
203
+ * into a scene descriptor via getModelTransform. */
204
+ export type ModelTransform = {
205
+ position: Vec3
206
+ rotation: Quat
207
+ /** Uniform scale (default 1). */
208
+ scale: number
209
+ visible: boolean
210
+ }
211
+
200
212
  export type SunOptions = {
201
213
  /** Linear color of the sun lamp (Blender: Light > Color). */
202
214
  color?: Vec3
@@ -606,6 +618,10 @@ export class Engine {
606
618
  // GPU vertex-morph path. Set false BEFORE loadModel to fall back to the CPU path (A/B).
607
619
  private useGpuMorphs = true
608
620
 
621
+ // VMD camera track (a dedicated camera VMD). When loaded + enabled it drives the shot,
622
+ // sampled off the animated model's clock so it stays synced to the dance.
623
+ private cameraAnimation: CameraAnimation | null = null
624
+
609
625
  // Camera target binding (Babylon/Three style: camera follows model)
610
626
  private cameraTargetModel: Model | null = null
611
627
  private cameraTargetBoneName = "全ての親"
@@ -2161,6 +2177,59 @@ export class Engine {
2161
2177
  this.cameraTargetOffset.z = offset?.z ?? 0
2162
2178
  }
2163
2179
 
2180
+ // ── VMD camera track ──
2181
+ // A dedicated camera VMD (target / rotation / distance / fov animated). Motion VMDs loaded
2182
+ // via model.loadVmd never touch the camera — the camera shot is opt-in through here.
2183
+
2184
+ /** Load a camera VMD (dedicated camera file, or any VMD's camera block) and drive the shot
2185
+ * from it. Default-on once a non-empty track loads; toggle with setCameraVmdEnabled. */
2186
+ async loadCameraVmd(url: string): Promise<void> {
2187
+ const frames = await VMDLoader.loadCamera(url)
2188
+ this.cameraAnimation = frames.length ? new CameraAnimation(frames) : null
2189
+ this.camera.setVmdDriven(this.cameraAnimation !== null)
2190
+ }
2191
+
2192
+ /** Load a camera VMD from an already-fetched buffer (e.g. a File the user dropped). */
2193
+ loadCameraVmdFromBuffer(buffer: ArrayBuffer): void {
2194
+ const frames = VMDLoader.loadCameraFromBuffer(buffer)
2195
+ this.cameraAnimation = frames.length ? new CameraAnimation(frames) : null
2196
+ this.camera.setVmdDriven(this.cameraAnimation !== null)
2197
+ }
2198
+
2199
+ /** Turn the loaded camera VMD on/off (falls back to orbit when off). No-op if none loaded. */
2200
+ setCameraVmdEnabled(enabled: boolean): void {
2201
+ this.camera.setVmdDriven(enabled && this.cameraAnimation !== null)
2202
+ }
2203
+
2204
+ /** True while the loaded camera VMD is actively driving the shot. */
2205
+ isCameraVmdEnabled(): boolean {
2206
+ return this.camera.vmdDriven
2207
+ }
2208
+
2209
+ /** True if a (non-empty) camera VMD is loaded, regardless of enabled state. */
2210
+ hasCameraVmd(): boolean {
2211
+ return this.cameraAnimation !== null
2212
+ }
2213
+
2214
+ /** Drop the loaded camera VMD and return to orbit control. */
2215
+ clearCameraVmd(): void {
2216
+ this.cameraAnimation = null
2217
+ this.camera.setVmdDriven(false)
2218
+ }
2219
+
2220
+ // Clock the camera VMD runs on: the first model with an active clip (playing or scrubbed),
2221
+ // so a static stage in the scene never freezes the shot at frame 0. Falls back to the first
2222
+ // model, then to 0 (empty scene).
2223
+ private cameraClockTime(): number {
2224
+ let first: number | null = null
2225
+ for (const inst of this.modelInstances.values()) {
2226
+ const p = inst.model.getAnimationProgress()
2227
+ if (first === null) first = p.current
2228
+ if (p.playing || p.paused) return p.current
2229
+ }
2230
+ return first ?? 0
2231
+ }
2232
+
2164
2233
  getCameraDistance(): number {
2165
2234
  return this.camera.radius
2166
2235
  }
@@ -2421,6 +2490,35 @@ export class Engine {
2421
2490
  return this.modelInstances.get(name)?.model ?? null
2422
2491
  }
2423
2492
 
2493
+ /**
2494
+ * Place a model in the scene — position, rotation, uniform scale, visibility. The
2495
+ * transform is a root offset baked into skinning (moves the whole rig), so it composes
2496
+ * with animation. Use it to sit a `stage.pmx` with a character, or to fit/hide either.
2497
+ * Scale is **uniform** (normals renormalize in-shader). Don't scale a physics-driven
2498
+ * character — its colliders won't scale; scale stages (which are typically physics-free).
2499
+ */
2500
+ setModelTransform(name: string, transform: Partial<ModelTransform>): void {
2501
+ const model = this.modelInstances.get(name)?.model
2502
+ if (!model) return
2503
+ if (transform.position) model.setPosition(transform.position)
2504
+ if (transform.rotation) model.setRotation(transform.rotation)
2505
+ if (transform.scale !== undefined) model.setScale(transform.scale)
2506
+ if (transform.visible !== undefined) model.setVisible(transform.visible)
2507
+ }
2508
+
2509
+ /** Read a model's scene transform (for serialization into a scene descriptor). */
2510
+ getModelTransform(name: string): ModelTransform | null {
2511
+ const model = this.modelInstances.get(name)?.model
2512
+ if (!model) return null
2513
+ const p = model.position
2514
+ return {
2515
+ position: new Vec3(p.x, p.y, p.z),
2516
+ rotation: model.rotation.clone(),
2517
+ scale: model.scale,
2518
+ visible: model.visible,
2519
+ }
2520
+ }
2521
+
2424
2522
  markVertexBufferDirty(modelNameOrModel?: string | Model): void {
2425
2523
  if (modelNameOrModel === undefined) return
2426
2524
  if (typeof modelNameOrModel === "string") {
@@ -3727,6 +3825,7 @@ export class Engine {
3727
3825
  pass.setBindGroup(0, this.pickPerFrameBindGroup)
3728
3826
 
3729
3827
  this.forEachInstance((inst) => {
3828
+ if (!inst.model.visible) return // hidden models aren't pickable
3730
3829
  pass.setVertexBuffer(0, inst.vertexBuffer)
3731
3830
  pass.setVertexBuffer(1, inst.jointsBuffer)
3732
3831
  pass.setVertexBuffer(2, inst.weightsBuffer)
@@ -3828,6 +3927,12 @@ export class Engine {
3828
3927
  }
3829
3928
  }
3830
3929
 
3930
+ // Drive the shot from the camera VMD (synced to the animated model's clock).
3931
+ if (this.camera.vmdDriven && this.cameraAnimation) {
3932
+ const pose = this.cameraAnimation.sample(this.cameraClockTime())
3933
+ if (pose) this.camera.setVmdPose(pose)
3934
+ }
3935
+
3831
3936
  this.updateCameraUniforms()
3832
3937
  this.updateShadowLightVP()
3833
3938
 
@@ -3848,12 +3953,17 @@ export class Engine {
3848
3953
  },
3849
3954
  })
3850
3955
  sp.setPipeline(this.shadowDepthPipeline)
3851
- this.forEachInstance((inst) => this.drawInstanceShadow(sp, inst))
3956
+ this.forEachInstance((inst) => {
3957
+ if (inst.model.visible) this.drawInstanceShadow(sp, inst)
3958
+ })
3852
3959
  sp.end()
3853
3960
  }
3854
3961
 
3855
3962
  const pass = encoder.beginRenderPass(this.renderPassDescriptor)
3856
- if (hasModels) this.forEachInstance((inst) => this.renderOneModel(pass, inst))
3963
+ if (hasModels)
3964
+ this.forEachInstance((inst) => {
3965
+ if (inst.model.visible) this.renderOneModel(pass, inst)
3966
+ })
3857
3967
  if (this.hasGround) this.renderGround(pass)
3858
3968
  pass.end()
3859
3969
 
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export {
9
9
  type LoadModelFromFilesOptions,
10
10
  type MaterialPreset,
11
11
  type MaterialPresetMap,
12
+ type ModelTransform,
12
13
  type GizmoDragEvent,
13
14
  type GizmoDragCallback,
14
15
  type GizmoDragKind,
@@ -59,4 +60,6 @@ export type {
59
60
  ControlPoint,
60
61
  } from "./animation"
61
62
  export { FPS } from "./animation"
63
+ export { VMDLoader, type CameraKeyframe } from "./vmd-loader"
64
+ export { CameraAnimation, type CameraPose } from "./camera-animation"
62
65
  export { RezePhysics } from "./physics"
package/src/math.ts CHANGED
@@ -535,6 +535,23 @@ export class Mat4 {
535
535
  out[14] = pz
536
536
  }
537
537
 
538
+ // Position + rotation + UNIFORM scale. Scales the rotation basis (columns 0–2) by s;
539
+ // uniform scale keeps normals correct after the shader's normalize() (no inverse-transpose).
540
+ static fromPositionRotationScaleInto(
541
+ px: number, py: number, pz: number,
542
+ qx: number, qy: number, qz: number, qw: number,
543
+ s: number,
544
+ out: Float32Array
545
+ ): void {
546
+ Mat4.fromQuatInto(qx, qy, qz, qw, out, 0)
547
+ out[0] *= s; out[1] *= s; out[2] *= s
548
+ out[4] *= s; out[5] *= s; out[6] *= s
549
+ out[8] *= s; out[9] *= s; out[10] *= s
550
+ out[12] = px
551
+ out[13] = py
552
+ out[14] = pz
553
+ }
554
+
538
555
  // In-place 4x4 inverse into out array. Returns true on success, false if singular (out untouched).
539
556
  static inverseInto(m: Float32Array, out: Float32Array): boolean {
540
557
  const a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3]
package/src/model.ts CHANGED
@@ -199,6 +199,17 @@ export class Model {
199
199
  return this._rotation
200
200
  }
201
201
 
202
+ /** Uniform scale (default 1). Used to fit a stage.pmx to the character. */
203
+ get scale(): number {
204
+ return this._scale
205
+ }
206
+
207
+ /** Whether this model renders. Hidden models skip the main, shadow, and pick passes;
208
+ * physics keeps running so they resume consistently. */
209
+ get visible(): boolean {
210
+ return this._visible
211
+ }
212
+
202
213
  setPosition(position: Vec3): void {
203
214
  this._position.set(position)
204
215
  this.rootMatrixDirty = true
@@ -209,6 +220,15 @@ export class Model {
209
220
  this.rootMatrixDirty = true
210
221
  }
211
222
 
223
+ setScale(scale: number): void {
224
+ this._scale = scale
225
+ this.rootMatrixDirty = true
226
+ }
227
+
228
+ setVisible(visible: boolean): void {
229
+ this._visible = visible
230
+ }
231
+
212
232
  private vertexData: Float32Array<ArrayBuffer>
213
233
  private baseVertexData: Float32Array<ArrayBuffer> // Original vertex data before morphing
214
234
  private vertexCount: number
@@ -254,6 +274,8 @@ export class Model {
254
274
  // Skip-when-identity flag avoids the extra mat mul per bone when unused.
255
275
  private _position: Vec3 = Vec3.zeros()
256
276
  private _rotation: Quat = Quat.identity()
277
+ private _scale: number = 1
278
+ private _visible: boolean = true
257
279
  private rootMatrixValues: Float32Array = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1])
258
280
  private rootMatrixDirty: boolean = false
259
281
  private rootIsIdentity: boolean = true
@@ -851,11 +873,11 @@ export class Model {
851
873
 
852
874
  // Rebuild root matrix + cache identity-shortcut flag only when pos/rot changed.
853
875
  if (this.rootMatrixDirty) {
854
- const p = this._position, r = this._rotation
855
- Mat4.fromPositionRotationInto(p.x, p.y, p.z, r.x, r.y, r.z, r.w, this.rootMatrixValues)
876
+ const p = this._position, r = this._rotation, s = this._scale
877
+ Mat4.fromPositionRotationScaleInto(p.x, p.y, p.z, r.x, r.y, r.z, r.w, s, this.rootMatrixValues)
856
878
  this.rootIsIdentity =
857
879
  p.x === 0 && p.y === 0 && p.z === 0 &&
858
- r.x === 0 && r.y === 0 && r.z === 0 && r.w === 1
880
+ r.x === 0 && r.y === 0 && r.z === 0 && r.w === 1 && s === 1
859
881
  this.rootMatrixDirty = false
860
882
  }
861
883