reze-engine 0.6.5 → 0.6.7

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.
package/README.md CHANGED
@@ -2,17 +2,20 @@
2
2
 
3
3
  A lightweight engine built with WebGPU and TypeScript for real-time 3D anime character MMD model rendering.
4
4
 
5
+ ![screenshot](./screenshot.png)
6
+
5
7
  ## Features
6
8
 
7
- - Physics
9
+ - Blinn-Phong lighting
8
10
  - Alpha blending
9
- - Post alpha eye rendering
11
+ - Post alpha eye rendering (the see-through eyes)
10
12
  - Rim lighting
11
13
  - Outlines
12
14
  - MSAA 4x anti-aliasing
13
- - Bone and morph api
15
+ - Bone and morph API
14
16
  - VMD animation
15
- - Ik solver
17
+ - IK solver
18
+ - Ammo/Bullet physics
16
19
 
17
20
  ## Usage
18
21
 
@@ -24,10 +27,10 @@ export default function Scene() {
24
27
  const initEngine = useCallback(async () => {
25
28
  if (canvasRef.current) {
26
29
  try {
27
- const engine = new Engine(canvasRef.current)
30
+ const engine = new Engine(canvasRef.current, {})
28
31
  engineRef.current = engine
29
32
  await engine.init()
30
- await engine.loadModel("/models/塞尔凯特/塞尔凯特.pmx")
33
+ await engine.loadModel("/models/reze/reze.pmx")
31
34
 
32
35
  engine.runRenderLoop(() => {})
33
36
  } catch (error) {
@@ -52,11 +55,76 @@ export default function Scene() {
52
55
  }
53
56
  ```
54
57
 
58
+ Engine options
59
+
60
+ ```javascript
61
+ const DEFAULT_ENGINE_OPTIONS: RequiredEngineOptions = {
62
+ ambientColor: new Vec3(0.82, 0.82, 0.82),
63
+ directionalLightIntensity: 0.2,
64
+ minSpecularIntensity: 0.3,
65
+ rimLightIntensity: 0.4,
66
+ cameraDistance: 26.6,
67
+ cameraTarget: new Vec3(0, 12.5, 0),
68
+ cameraFov: Math.PI / 4,
69
+ onRaycast: undefined,
70
+ }
71
+ ```
72
+
73
+ ## API
74
+
75
+ ### Animation Playback
76
+
77
+ Load and play VMD animation files.
78
+
79
+ ```javascript
80
+ await engine.loadAnimation("/animations/dance.vmd")
81
+ engine.playAnimation()
82
+ engine.pauseAnimation()
83
+ engine.stopAnimation()
84
+ engine.seekAnimation(2.5) // seek to 2.5 seconds
85
+
86
+ const { current, duration, percentage } = engine.getAnimationProgress()
87
+ ```
88
+
89
+ ### Bone and Morph Tweening
90
+
91
+ Rotate and move bones with optional tween duration. Translations are VMD-style (relative to bind pose world position).
92
+
93
+ ```javascript
94
+ engine.rotateBones({ "首": neckQuat, "頭": headQuat }, 300)
95
+ engine.moveBones({ "センター": centerVec }, 300)
96
+ engine.setMorphWeight("まばたき", 1.0, 300)
97
+
98
+ engine.resetAllBones()
99
+ engine.resetAllMorphs()
100
+ ```
101
+
102
+ ### Atomic Pose Setting
103
+
104
+ Set rotations, translations, and morphs in a single atomic pass — for animation editors, motion capture, or any use case that needs precise, immediate pose updates matching the quality of internal VMD playback.
105
+
106
+ ```javascript
107
+ engine.setPose(
108
+ { "首": neckQuat, "頭": headQuat, "左腕": leftArmQuat },
109
+ { "センター": centerVec },
110
+ { "まばたき": 0.5, "あ": 0.3 }
111
+ )
112
+ ```
113
+
114
+ All three parameters are optional. Pass only what you need:
115
+
116
+ ```javascript
117
+ engine.setPose(rotations) // rotations only
118
+ engine.setPose(undefined, translations) // translations only
119
+ engine.setPose(undefined, undefined, morphs) // morphs only
120
+ ```
121
+
55
122
  ## Projects Using This Engine
56
123
 
57
124
  - **[MiKaPo](https://mikapo.vercel.app)** - Online real-time motion capture for MMD using webcam and MediaPipe
58
125
  - **[Popo](https://popo.love)** - Fine-tuned LLM that generates MMD poses from natural language descriptions
59
126
  - **[MPL](https://mmd-mpl.vercel.app)** - Semantic motion programming language for scripting MMD animations with intuitive syntax
127
+ - **[Mixamo-MMD](https://mixamo-mmd.vercel.app)** - Retarget Mixamo FBX animation to VMD in one click
60
128
 
61
129
  ## Tutorial
62
130
 
package/dist/engine.d.ts CHANGED
@@ -129,6 +129,7 @@ export declare class Engine {
129
129
  loadModel(path: string): Promise<void>;
130
130
  rotateBones(boneRotations: Record<string, Quat>, durationMs?: number): void;
131
131
  moveBones(boneTranslations: Record<string, Vec3>, durationMs?: number): void;
132
+ setPose(rotations?: Record<string, Quat>, translations?: Record<string, Vec3>, morphs?: Record<string, number>): void;
132
133
  resetAllBones(): void;
133
134
  resetAllMorphs(): void;
134
135
  setMorphWeight(name: string, weight: number, durationMs?: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
package/dist/engine.js CHANGED
@@ -987,6 +987,9 @@ export class Engine {
987
987
  moveBones(boneTranslations, durationMs) {
988
988
  this.currentModel?.moveBones(boneTranslations, durationMs);
989
989
  }
990
+ setPose(rotations, translations, morphs) {
991
+ this.currentModel?.setPose(rotations, translations, morphs);
992
+ }
990
993
  resetAllBones() {
991
994
  this.currentModel?.resetAllBones();
992
995
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { Mat4, Quat, Vec3 } from "./math";
7
7
  import { Bone, IKSolver, IKChainInfo } from "./model";
8
+ export type UpdateWorldMatrixFn = (boneIndex: number, applyIK: boolean) => void;
8
9
  /**
9
10
  * Solve IK chains for a model
10
11
  */
@@ -14,7 +15,7 @@ export declare class IKSolverSystem {
14
15
  /**
15
16
  * Solve all IK chains
16
17
  */
17
- static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Quat[], localTranslations: Vec3[], worldMatrices: Mat4[], ikChainInfo: IKChainInfo[]): void;
18
+ static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Quat[], localTranslations: Vec3[], worldMatrices: Mat4[], ikChainInfo: IKChainInfo[], updateWorldMatrix?: UpdateWorldMatrixFn): void;
18
19
  private static solveIK;
19
20
  private static solveChain;
20
21
  private static limitAngle;
@@ -1 +1 @@
1
- {"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,EAAE,IAAI,EAAU,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAoE7D;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAS;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAuB;IAExD;;OAEG;WACW,KAAK,CACjB,SAAS,EAAE,QAAQ,EAAE,EACrB,KAAK,EAAE,IAAI,EAAE,EACb,cAAc,EAAE,IAAI,EAAE,EACtB,iBAAiB,EAAE,IAAI,EAAE,EACzB,aAAa,EAAE,IAAI,EAAE,EACrB,WAAW,EAAE,WAAW,EAAE,GACzB,IAAI;IAMP,OAAO,CAAC,MAAM,CAAC,OAAO;IA2EtB,OAAO,CAAC,MAAM,CAAC,UAAU;IA4FzB,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB,OAAO,CAAC,MAAM,CAAC,WAAW;IAM1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAKlC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAmCjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAQ/B,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAqBvC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAc3C,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAoCjC"}
1
+ {"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,EAAE,IAAI,EAAU,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG7D,MAAM,MAAM,mBAAmB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;AAoE/E;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAS;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAuB;IAExD;;OAEG;WACW,KAAK,CACjB,SAAS,EAAE,QAAQ,EAAE,EACrB,KAAK,EAAE,IAAI,EAAE,EACb,cAAc,EAAE,IAAI,EAAE,EACtB,iBAAiB,EAAE,IAAI,EAAE,EACzB,aAAa,EAAE,IAAI,EAAE,EACrB,WAAW,EAAE,WAAW,EAAE,EAC1B,iBAAiB,CAAC,EAAE,mBAAmB,GACtC,IAAI;IAMP,OAAO,CAAC,MAAM,CAAC,OAAO;IAoFtB,OAAO,CAAC,MAAM,CAAC,UAAU;IAqGzB,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB,OAAO,CAAC,MAAM,CAAC,WAAW;IAM1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAKlC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAmCjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAQ/B,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAqBvC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAc3C,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAoCjC"}
package/dist/ik-solver.js CHANGED
@@ -74,12 +74,12 @@ export class IKSolverSystem {
74
74
  /**
75
75
  * Solve all IK chains
76
76
  */
77
- static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
77
+ static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix) {
78
78
  for (const solver of ikSolvers) {
79
- this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
79
+ this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix);
80
80
  }
81
81
  }
82
- static solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
82
+ static solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix) {
83
83
  if (solver.links.length === 0)
84
84
  return;
85
85
  const ikBoneIndex = solver.ikBoneIndex;
@@ -99,10 +99,18 @@ export class IKSolverSystem {
99
99
  chains.push(new IKChain(link.boneIndex, link));
100
100
  }
101
101
  // Update chain bones and target bone world matrices (initial state, no IK yet)
102
- for (let i = chains.length - 1; i >= 0; i--) {
103
- this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
102
+ if (updateWorldMatrix) {
103
+ for (let i = chains.length - 1; i >= 0; i--) {
104
+ updateWorldMatrix(chains[i].boneIndex, false);
105
+ }
106
+ updateWorldMatrix(targetBoneIndex, false);
107
+ }
108
+ else {
109
+ for (let i = chains.length - 1; i >= 0; i--) {
110
+ this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
111
+ }
112
+ this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
104
113
  }
105
- this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
106
114
  if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
107
115
  return;
108
116
  // Solve iteratively
@@ -112,7 +120,7 @@ export class IKSolverSystem {
112
120
  for (let chainIndex = 0; chainIndex < chains.length; chainIndex++) {
113
121
  const chain = chains[chainIndex];
114
122
  if (chain.solveAxis !== InternalSolveAxis.Fixed) {
115
- this.solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, i < halfIteration);
123
+ this.solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, i < halfIteration, updateWorldMatrix);
116
124
  }
117
125
  }
118
126
  if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
@@ -128,7 +136,7 @@ export class IKSolverSystem {
128
136
  }
129
137
  }
130
138
  }
131
- static solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, useAxis) {
139
+ static solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, useAxis, updateWorldMatrix) {
132
140
  const chainBoneIndex = chain.boneIndex;
133
141
  const chainPosition = this.getWorldTranslation(chainBoneIndex, worldMatrices);
134
142
  const ikPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
@@ -191,13 +199,22 @@ export class IKSolverSystem {
191
199
  chainInfo.ikRotation = chainInfo.ikRotation.multiply(localRot.clone().conjugate().normalize());
192
200
  }
193
201
  }
194
- // Update world matrices for affected bones (using IK-modified rotations)
195
- for (let i = chainIndex; i >= 0; i--) {
196
- const link = solver.links[i];
197
- this.updateWorldMatrix(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
202
+ // Update world matrices for affected bones (using callback - handles append correctly)
203
+ if (updateWorldMatrix) {
204
+ for (let i = chainIndex; i >= 0; i--) {
205
+ const link = solver.links[i];
206
+ updateWorldMatrix(link.boneIndex, true); // applyIK = true
207
+ }
208
+ updateWorldMatrix(targetBoneIndex, false);
209
+ }
210
+ else {
211
+ for (let i = chainIndex; i >= 0; i--) {
212
+ const link = solver.links[i];
213
+ this.updateWorldMatrix(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
214
+ }
215
+ this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
216
+ this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
198
217
  }
199
- this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
200
- this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
201
218
  }
202
219
  static limitAngle(angle, min, max, useAxis) {
203
220
  if (angle < min) {
package/dist/model.d.ts CHANGED
@@ -146,12 +146,23 @@ export declare class Model {
146
146
  /**
147
147
  * Convert VMD-style relative translation (relative to bind pose world position) to local translation
148
148
  * This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
149
+ * @param boneIdx - Bone index
150
+ * @param vmdRelativeTranslation - VMD relative translation
151
+ * @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
152
+ * Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
149
153
  */
150
154
  private convertVMDTranslationToLocal;
151
155
  getBoneWorldMatrices(): Float32Array;
152
156
  getBoneInverseBindMatrices(): Float32Array;
153
157
  getSkinMatrices(): Float32Array;
154
158
  setMorphWeight(name: string, weight: number, durationMs?: number): void;
159
+ /**
160
+ * Atomic pose setter for external animation editors.
161
+ * Sets bone rotations, translations, and morph weights in a single pass,
162
+ * identical to how getPoseAtTime applies VMD poses during playback.
163
+ * Cancels any active tweens on affected bones/morphs.
164
+ */
165
+ setPose(rotations?: Record<string, Quat>, translations?: Record<string, Vec3>, morphs?: Record<string, number>): void;
155
166
  private applyMorphs;
156
167
  /**
157
168
  * Load VMD animation file
@@ -208,6 +219,8 @@ export declare class Model {
208
219
  */
209
220
  update(deltaTime: number): boolean;
210
221
  private solveIKChains;
222
+ private ikComputedSet;
223
+ private computeSingleBoneWorldMatrix;
211
224
  private computeWorldMatrices;
212
225
  }
213
226
  //# sourceMappingURL=model.d.ts.map
@@ -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
@@ -31,6 +31,8 @@ export class Model {
31
31
  // IK and Physics enable flags
32
32
  this.ikEnabled = true;
33
33
  this.physicsEnabled = true;
34
+ // Cached set to track which bones are being computed in current IK pass (to avoid infinite recursion)
35
+ this.ikComputedSet = new Set();
34
36
  // Store base vertex data (original positions before morphing)
35
37
  this.baseVertexData = new Float32Array(vertexData);
36
38
  this.vertexData = vertexData;
@@ -346,8 +348,12 @@ export class Model {
346
348
  /**
347
349
  * Convert VMD-style relative translation (relative to bind pose world position) to local translation
348
350
  * This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
351
+ * @param boneIdx - Bone index
352
+ * @param vmdRelativeTranslation - VMD relative translation
353
+ * @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
354
+ * Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
349
355
  */
350
- convertVMDTranslationToLocal(boneIdx, vmdRelativeTranslation) {
356
+ convertVMDTranslationToLocal(boneIdx, vmdRelativeTranslation, rotation) {
351
357
  const skeleton = this.skeleton;
352
358
  const bones = skeleton.bones;
353
359
  const localRot = this.runtimeSkeleton.localRotations;
@@ -383,7 +389,9 @@ export class Model {
383
389
  // Subtract bindTranslation to get position after bind translation
384
390
  const afterBindTranslation = parentSpacePos.subtract(new Vec3(bone.bindTranslation[0], bone.bindTranslation[1], bone.bindTranslation[2]));
385
391
  // Apply inverse rotation to get local translation
386
- const localRotation = localRot[boneIdx];
392
+ // Use provided rotation (animation rotation) or fall back to current localRotation
393
+ // Using animation rotation prevents conflicts when IK modifies the rotation
394
+ const localRotation = rotation ?? localRot[boneIdx];
387
395
  // Clone to avoid mutating, then conjugate and normalize
388
396
  const invRotation = localRotation.clone().conjugate().normalize();
389
397
  const rotationMat = Mat4.fromQuat(invRotation.x, invRotation.y, invRotation.z, invRotation.w);
@@ -456,6 +464,49 @@ export class Model {
456
464
  this.runtimeMorph.weights[idx] = startWeight;
457
465
  this.applyMorphs();
458
466
  }
467
+ /**
468
+ * Atomic pose setter for external animation editors.
469
+ * Sets bone rotations, translations, and morph weights in a single pass,
470
+ * identical to how getPoseAtTime applies VMD poses during playback.
471
+ * Cancels any active tweens on affected bones/morphs.
472
+ */
473
+ setPose(rotations, translations, morphs) {
474
+ const state = this.tweenState;
475
+ if (rotations) {
476
+ for (const [name, quat] of Object.entries(rotations)) {
477
+ const idx = this.runtimeSkeleton.nameIndex[name] ?? -1;
478
+ if (idx < 0 || idx >= this.skeleton.bones.length)
479
+ continue;
480
+ this.runtimeSkeleton.localRotations[idx].set(quat.clone().normalize());
481
+ state.rotActive[idx] = 0;
482
+ }
483
+ }
484
+ if (translations) {
485
+ for (const [name, vec] of Object.entries(translations)) {
486
+ const idx = this.runtimeSkeleton.nameIndex[name] ?? -1;
487
+ if (idx < 0 || idx >= this.skeleton.bones.length)
488
+ continue;
489
+ const rotation = rotations?.[name]?.clone().normalize();
490
+ const localTranslation = this.convertVMDTranslationToLocal(idx, vec, rotation);
491
+ this.runtimeSkeleton.localTranslations[idx].set(localTranslation);
492
+ state.transActive[idx] = 0;
493
+ }
494
+ }
495
+ if (morphs) {
496
+ let morphChanged = false;
497
+ for (const [name, weight] of Object.entries(morphs)) {
498
+ const idx = this.runtimeMorph.nameIndex[name] ?? -1;
499
+ if (idx < 0 || idx >= this.runtimeMorph.weights.length)
500
+ continue;
501
+ this.runtimeMorph.weights[idx] = Math.max(0, Math.min(1, weight));
502
+ state.morphActive[idx] = 0;
503
+ morphChanged = true;
504
+ }
505
+ if (morphChanged) {
506
+ this.applyMorphs();
507
+ }
508
+ }
509
+ }
459
510
  applyMorphs() {
460
511
  // Reset vertex data to base positions
461
512
  this.vertexData.set(this.baseVertexData);
@@ -714,9 +765,12 @@ export class Model {
714
765
  const localTrans = this.runtimeSkeleton.localTranslations[boneIdx];
715
766
  if (!frameB) {
716
767
  // No interpolation needed - direct assignment
717
- localRot.set(frameA.rotation);
718
- // Convert VMD relative translation to local translation
719
- const localTranslation = this.convertVMDTranslationToLocal(boneIdx, frameA.translation);
768
+ // Use animation frame's rotation for translation conversion to ensure consistency
769
+ // This prevents conflicts when IK later modifies the rotation
770
+ const frameRotation = frameA.rotation;
771
+ localRot.set(frameRotation);
772
+ // Convert VMD relative translation to local translation using animation rotation
773
+ const localTranslation = this.convertVMDTranslationToLocal(boneIdx, frameA.translation, frameRotation);
720
774
  localTrans.set(localTranslation);
721
775
  }
722
776
  else {
@@ -737,8 +791,10 @@ export class Model {
737
791
  const tzWeight = getWeight(32);
738
792
  // Interpolate VMD relative translations (relative to bind pose world position)
739
793
  const interpolatedVMDTranslation = new Vec3(frameA.translation.x + (frameB.translation.x - frameA.translation.x) * txWeight, frameA.translation.y + (frameB.translation.y - frameA.translation.y) * tyWeight, frameA.translation.z + (frameB.translation.z - frameA.translation.z) * tzWeight);
740
- // Convert interpolated VMD translation to local translation
741
- const localTranslation = this.convertVMDTranslationToLocal(boneIdx, interpolatedVMDTranslation);
794
+ // Convert interpolated VMD translation to local translation using animation rotation
795
+ // This ensures translation is computed for the animation rotation, not the runtime rotation
796
+ // that will be modified by IK, preventing conflicts
797
+ const localTranslation = this.convertVMDTranslationToLocal(boneIdx, interpolatedVMDTranslation, rotation);
742
798
  // Direct property writes to avoid object allocation
743
799
  localRot.set(rotation);
744
800
  localTrans.set(localTranslation);
@@ -821,7 +877,111 @@ export class Model {
821
877
  const ikChainInfo = this.runtimeSkeleton.ikChainInfo;
822
878
  if (!ikChainInfo)
823
879
  return;
824
- IKSolverSystem.solve(ikSolvers, this.skeleton.bones, this.runtimeSkeleton.localRotations, this.runtimeSkeleton.localTranslations, this.runtimeSkeleton.worldMatrices, ikChainInfo);
880
+ // Solve each IK solver sequentially, ensuring consistent state between solvers
881
+ for (const solver of ikSolvers) {
882
+ // Recompute ALL world matrices before each solver starts
883
+ // This ensures each solver sees the effects of previous solvers on localRotations
884
+ this.computeWorldMatrices();
885
+ // Clear computed set for this solver's pass
886
+ this.ikComputedSet.clear();
887
+ // Solve this IK chain
888
+ // Pass callback that uses model's world matrix computation (handles append correctly)
889
+ IKSolverSystem.solve([solver], // Solve one at a time
890
+ this.skeleton.bones, this.runtimeSkeleton.localRotations, this.runtimeSkeleton.localTranslations, this.runtimeSkeleton.worldMatrices, ikChainInfo, (boneIndex, applyIK) => {
891
+ // Clear computed set for each bone update to allow recomputation in same iteration
892
+ this.ikComputedSet.delete(boneIndex);
893
+ this.computeSingleBoneWorldMatrix(boneIndex, applyIK);
894
+ });
895
+ }
896
+ }
897
+ // Add this new method to compute a single bone's world matrix
898
+ // Recursively ensures parents are computed first to avoid using stale parent matrices
899
+ computeSingleBoneWorldMatrix(boneIndex, applyIK) {
900
+ const bones = this.skeleton.bones;
901
+ const localRot = this.runtimeSkeleton.localRotations;
902
+ const localTrans = this.runtimeSkeleton.localTranslations;
903
+ const worldMats = this.runtimeSkeleton.worldMatrices;
904
+ const ikChainInfo = this.runtimeSkeleton.ikChainInfo;
905
+ const b = bones[boneIndex];
906
+ // Prevent infinite recursion: if this bone is already being computed in this call chain, skip
907
+ if (this.ikComputedSet.has(boneIndex)) {
908
+ return;
909
+ }
910
+ // Mark this bone as being computed to prevent infinite recursion
911
+ this.ikComputedSet.add(boneIndex);
912
+ // Recursively compute parent first if it exists (ensures parent matrix is up-to-date)
913
+ if (b.parentIndex >= 0) {
914
+ this.computeSingleBoneWorldMatrix(b.parentIndex, applyIK);
915
+ }
916
+ // Get base rotation
917
+ let boneRot = localRot[boneIndex];
918
+ // Apply IK rotation if requested
919
+ if (applyIK && ikChainInfo) {
920
+ const chainInfo = ikChainInfo[boneIndex];
921
+ if (chainInfo?.ikRotation) {
922
+ boneRot = chainInfo.ikRotation.multiply(boneRot).normalize();
923
+ }
924
+ }
925
+ let rotateM = Mat4.fromQuat(boneRot.x, boneRot.y, boneRot.z, boneRot.w);
926
+ let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0;
927
+ // Handle append transformations (same logic as computeWorldMatrices)
928
+ const appendParentIdx = b.appendParentIndex;
929
+ const hasAppend = b.appendRotate &&
930
+ appendParentIdx !== undefined &&
931
+ appendParentIdx >= 0 &&
932
+ appendParentIdx < bones.length;
933
+ if (hasAppend) {
934
+ const ratio = b.appendRatio === undefined ? 1 : Math.max(-1, Math.min(1, b.appendRatio));
935
+ const hasRatio = Math.abs(ratio) > 1e-6;
936
+ if (hasRatio) {
937
+ if (b.appendRotate) {
938
+ // Get append parent's rotation
939
+ // During IK solving, use only base local rotation (not IK rotations) to avoid
940
+ // conflicts with IK rotations that are still being computed incrementally
941
+ // IK rotations will be applied to localRotations after IK solving completes
942
+ if (appendParentIdx >= 0) {
943
+ // Compute append parent's world matrix for dependency order, but use base rotation for append
944
+ this.computeSingleBoneWorldMatrix(appendParentIdx, applyIK);
945
+ }
946
+ // Use append parent's base local rotation only (IK rotations are applied after solving)
947
+ let appendRot = localRot[appendParentIdx];
948
+ let ax = appendRot.x, ay = appendRot.y, az = appendRot.z;
949
+ const aw = appendRot.w;
950
+ const absRatio = ratio < 0 ? -ratio : ratio;
951
+ if (ratio < 0) {
952
+ ax = -ax;
953
+ ay = -ay;
954
+ az = -az;
955
+ }
956
+ const appendQuat = new Quat(ax, ay, az, aw);
957
+ const result = Quat.slerp(Quat.identity(), appendQuat, absRatio);
958
+ rotateM = Mat4.fromQuat(result.x, result.y, result.z, result.w).multiply(rotateM);
959
+ }
960
+ if (b.appendMove) {
961
+ const appendTrans = localTrans[appendParentIdx];
962
+ addLocalTx = appendTrans.x * ratio;
963
+ addLocalTy = appendTrans.y * ratio;
964
+ addLocalTz = appendTrans.z * ratio;
965
+ }
966
+ }
967
+ }
968
+ const boneTrans = localTrans[boneIndex];
969
+ const localTx = boneTrans.x + addLocalTx;
970
+ const localTy = boneTrans.y + addLocalTy;
971
+ const localTz = boneTrans.z + addLocalTz;
972
+ this.cachedIdentityMat1
973
+ .setIdentity()
974
+ .translateInPlace(b.bindTranslation[0], b.bindTranslation[1], b.bindTranslation[2]);
975
+ this.cachedIdentityMat2.setIdentity().translateInPlace(localTx, localTy, localTz);
976
+ const localM = this.cachedIdentityMat1.multiply(rotateM).multiply(this.cachedIdentityMat2);
977
+ const worldMat = worldMats[boneIndex];
978
+ if (b.parentIndex >= 0) {
979
+ const parentMat = worldMats[b.parentIndex];
980
+ Mat4.multiplyArrays(parentMat.values, 0, localM.values, 0, worldMat.values, 0);
981
+ }
982
+ else {
983
+ worldMat.values.set(localM.values);
984
+ }
825
985
  }
826
986
  computeWorldMatrices() {
827
987
  const bones = this.skeleton.bones;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "A WebGPU-based MMD model renderer",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/engine.ts CHANGED
@@ -1155,6 +1155,14 @@ export class Engine {
1155
1155
  this.currentModel?.moveBones(boneTranslations, durationMs)
1156
1156
  }
1157
1157
 
1158
+ public setPose(
1159
+ rotations?: Record<string, Quat>,
1160
+ translations?: Record<string, Vec3>,
1161
+ morphs?: Record<string, number>
1162
+ ): void {
1163
+ this.currentModel?.setPose(rotations, translations, morphs)
1164
+ }
1165
+
1158
1166
  public resetAllBones() {
1159
1167
  this.currentModel?.resetAllBones()
1160
1168
  }