reze-engine 0.3.5 → 0.3.6

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/dist/ik.js ADDED
@@ -0,0 +1,337 @@
1
+ import { Quat, Vec3, Mat4 } from "./math";
2
+ export class IK {
3
+ constructor(chains = []) {
4
+ // Track last target positions to detect movement
5
+ this.lastTargetPositions = new Map();
6
+ // Track convergence state for each chain (true = converged, skip solving)
7
+ this.convergedChains = new Set();
8
+ // Accumulated IK rotations for each bone (boneIndex -> quaternion)
9
+ this.ikRotations = new Map();
10
+ this.chains = chains;
11
+ }
12
+ // Set the callback to use Model's computeWorldMatrices
13
+ // The callback doesn't need parameters since Model uses its own runtime state
14
+ setComputeWorldMatricesCallback(callback) {
15
+ this.computeWorldMatricesCallback = callback;
16
+ }
17
+ getChains() {
18
+ return this.chains;
19
+ }
20
+ // Enable/disable IK chain by target bone name
21
+ enableChain(targetBoneName, enabled) {
22
+ // Chains are identified by target bone index, but we need to find by name
23
+ // This will be called from Model which has bone name lookup
24
+ for (const chain of this.chains) {
25
+ // We'll need to pass bone names or use indices - for now, this is a placeholder
26
+ // The actual implementation will be in Model class
27
+ }
28
+ }
29
+ // Main IK solve method - modifies bone local rotations in-place
30
+ solve(skeleton, localRotations, localTranslations, worldMatrices) {
31
+ if (this.chains.length === 0)
32
+ return;
33
+ const boneCount = skeleton.bones.length;
34
+ // Reset accumulated IK rotations for all chain bones (as per reference)
35
+ for (const chain of this.chains) {
36
+ for (const link of chain.links) {
37
+ const boneIdx = link.boneIndex;
38
+ if (boneIdx >= 0 && boneIdx < boneCount) {
39
+ this.ikRotations.set(boneIdx, new Quat(0, 0, 0, 1));
40
+ }
41
+ }
42
+ }
43
+ // Use Model's computeWorldMatrices if available (it uses the same arrays)
44
+ // Otherwise fall back to simplified version
45
+ if (this.computeWorldMatricesCallback) {
46
+ this.computeWorldMatricesCallback();
47
+ }
48
+ else {
49
+ // Fallback to simplified version (shouldn't happen in normal usage)
50
+ this.computeWorldMatrices(skeleton, localRotations, localTranslations, worldMatrices);
51
+ }
52
+ // Solve each IK chain
53
+ for (const chain of this.chains) {
54
+ if (!chain.enabled)
55
+ continue;
56
+ const targetBoneIdx = chain.targetBoneIndex;
57
+ const effectorBoneIdx = chain.effectorBoneIndex;
58
+ if (targetBoneIdx < 0 || targetBoneIdx >= boneCount || effectorBoneIdx < 0 || effectorBoneIdx >= boneCount) {
59
+ continue;
60
+ }
61
+ // Get target position (world position of target bone)
62
+ // In MMD, the target bone is the bone that should reach a specific position
63
+ // The target bone's current world position is where we want the effector to reach
64
+ const targetWorldMatIdx = targetBoneIdx * 16;
65
+ const targetWorldMat = new Mat4(worldMatrices.subarray(targetWorldMatIdx, targetWorldMatIdx + 16));
66
+ const targetPos = targetWorldMat.getPosition();
67
+ // Check if target has moved (detect any movement, even small)
68
+ const lastTargetPos = this.lastTargetPositions.get(targetBoneIdx);
69
+ let targetMoved = false;
70
+ if (!lastTargetPos) {
71
+ // First time seeing this target, initialize position and always solve
72
+ this.lastTargetPositions.set(targetBoneIdx, new Vec3(targetPos.x, targetPos.y, targetPos.z));
73
+ targetMoved = true;
74
+ }
75
+ else {
76
+ const targetMoveDistance = targetPos.subtract(lastTargetPos).length();
77
+ targetMoved = targetMoveDistance > 0.001; // Detect any movement > 0.001 units (0.1mm)
78
+ }
79
+ // Get current effector position
80
+ const effectorWorldMatIdx = effectorBoneIdx * 16;
81
+ const effectorWorldMat = new Mat4(worldMatrices.subarray(effectorWorldMatIdx, effectorWorldMatIdx + 16));
82
+ const effectorPos = effectorWorldMat.getPosition();
83
+ // Check distance to target
84
+ const distanceToTarget = effectorPos.subtract(targetPos).length();
85
+ // If target moved, always clear convergence and solve
86
+ if (targetMoved) {
87
+ this.convergedChains.delete(targetBoneIdx);
88
+ this.lastTargetPositions.set(targetBoneIdx, new Vec3(targetPos.x, targetPos.y, targetPos.z));
89
+ // Always solve when target moves, regardless of distance
90
+ }
91
+ else if (distanceToTarget < 0.1) {
92
+ // Target hasn't moved and we're already close, skip solving
93
+ if (!this.convergedChains.has(targetBoneIdx)) {
94
+ this.convergedChains.add(targetBoneIdx);
95
+ }
96
+ continue;
97
+ }
98
+ // Otherwise, solve (target hasn't moved but effector is far from target)
99
+ // Solve using CCD
100
+ // Note: In PMX, links are stored from effector toward root
101
+ // So links[0] is the effector, links[links.length-1] is closest to root
102
+ this.solveCCD(chain, skeleton, localRotations, localTranslations, worldMatrices, targetPos);
103
+ // Recompute world matrices after IK adjustments
104
+ if (this.computeWorldMatricesCallback) {
105
+ this.computeWorldMatricesCallback();
106
+ }
107
+ else {
108
+ this.computeWorldMatrices(skeleton, localRotations, localTranslations, worldMatrices);
109
+ }
110
+ }
111
+ }
112
+ // Cyclic Coordinate Descent IK solver (based on saba MMD implementation)
113
+ solveCCD(chain, skeleton, localRotations, localTranslations, worldMatrices, targetPos) {
114
+ const bones = skeleton.bones;
115
+ const iterationCount = chain.iterationCount;
116
+ const rotationConstraint = chain.rotationConstraint;
117
+ const links = chain.links;
118
+ if (links.length === 0)
119
+ return;
120
+ const effectorBoneIdx = chain.effectorBoneIndex;
121
+ // Get effector position
122
+ const effectorWorldMatIdx = effectorBoneIdx * 16;
123
+ const effectorWorldMat = new Mat4(worldMatrices.subarray(effectorWorldMatIdx, effectorWorldMatIdx + 16));
124
+ let effectorPos = effectorWorldMat.getPosition();
125
+ // Check initial distance - only skip if extremely close (numerical precision threshold)
126
+ const initialDistanceSq = effectorPos.subtract(targetPos).lengthSquared();
127
+ if (initialDistanceSq < 1.0e-10) {
128
+ this.convergedChains.add(chain.targetBoneIndex);
129
+ return;
130
+ }
131
+ const halfIteration = iterationCount >> 1;
132
+ for (let iter = 0; iter < iterationCount; iter++) {
133
+ const useAxis = iter < halfIteration;
134
+ for (let linkIdx = 0; linkIdx < links.length; linkIdx++) {
135
+ const link = links[linkIdx];
136
+ const jointBoneIdx = link.boneIndex;
137
+ if (jointBoneIdx < 0 || jointBoneIdx >= bones.length)
138
+ continue;
139
+ const bone = bones[jointBoneIdx];
140
+ // Get joint world position
141
+ const jointWorldMatIdx = jointBoneIdx * 16;
142
+ const jointWorldMat = new Mat4(worldMatrices.subarray(jointWorldMatIdx, jointWorldMatIdx + 16));
143
+ const jointPos = jointWorldMat.getPosition();
144
+ // Vectors: from joint to target and effector (REVERSED from typical CCD!)
145
+ // This matches the reference implementation
146
+ const chainTargetVector = jointPos.subtract(targetPos).normalize();
147
+ const chainIkVector = jointPos.subtract(effectorPos).normalize();
148
+ // Rotation axis: cross product
149
+ const chainRotationAxis = chainTargetVector.cross(chainIkVector);
150
+ const axisLenSq = chainRotationAxis.lengthSquared();
151
+ // Skip if axis is too small (vectors are parallel)
152
+ if (axisLenSq < 1.0e-8)
153
+ continue;
154
+ const chainRotationAxisNorm = chainRotationAxis.normalize();
155
+ // Get parent's world rotation matrix (rotation part only)
156
+ let parentWorldRot;
157
+ if (bone.parentIndex >= 0 && bone.parentIndex < bones.length) {
158
+ const parentWorldMatIdx = bone.parentIndex * 16;
159
+ const parentWorldMat = new Mat4(worldMatrices.subarray(parentWorldMatIdx, parentWorldMatIdx + 16));
160
+ parentWorldRot = parentWorldMat.toQuat();
161
+ }
162
+ else {
163
+ parentWorldRot = new Quat(0, 0, 0, 1);
164
+ }
165
+ // Transform rotation axis to parent's local space
166
+ // Invert parent rotation: parentWorldRot^-1
167
+ const parentWorldRotInv = parentWorldRot.conjugate();
168
+ // Transform axis: parentWorldRotInv * axis (as vector)
169
+ const localAxis = parentWorldRotInv.rotateVec(chainRotationAxisNorm).normalize();
170
+ // Calculate angle between vectors
171
+ const dot = Math.max(-1.0, Math.min(1.0, chainTargetVector.dot(chainIkVector)));
172
+ const angle = Math.min(rotationConstraint * (linkIdx + 1), Math.acos(dot));
173
+ // Create rotation quaternion from axis and angle
174
+ // q = (sin(angle/2) * axis, cos(angle/2))
175
+ const halfAngle = angle * 0.5;
176
+ const sinHalf = Math.sin(halfAngle);
177
+ const cosHalf = Math.cos(halfAngle);
178
+ const rotationFromAxis = new Quat(localAxis.x * sinHalf, localAxis.y * sinHalf, localAxis.z * sinHalf, cosHalf).normalize();
179
+ // Get accumulated ikRotation for this bone (or identity if first time)
180
+ let accumulatedIkRot = this.ikRotations.get(jointBoneIdx) || new Quat(0, 0, 0, 1);
181
+ // Accumulate rotation: ikRotation = rotationFromAxis * ikRotation
182
+ // Reference: ikRotation.multiplyToRef(chainBone.ikChainInfo!.ikRotation, chainBone.ikChainInfo!.ikRotation)
183
+ // This means: ikRotation = rotationFromAxis * accumulatedIkRot
184
+ accumulatedIkRot = rotationFromAxis.multiply(accumulatedIkRot);
185
+ this.ikRotations.set(jointBoneIdx, accumulatedIkRot);
186
+ // Get current local rotation
187
+ const qi = jointBoneIdx * 4;
188
+ const currentLocalRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
189
+ // Reference: ikRotation.multiplyToRef(chainBone.ikChainInfo!.localRotation, ikRotation)
190
+ // This means: tempRot = accumulatedIkRot * currentLocalRot
191
+ let tempRot = accumulatedIkRot.multiply(currentLocalRot);
192
+ // Apply angle constraints if specified (on the combined rotation)
193
+ if (link.hasLimit && link.minAngle && link.maxAngle) {
194
+ tempRot = this.applyAngleConstraints(tempRot, link.minAngle, link.maxAngle);
195
+ }
196
+ // Reference: ikRotation.multiplyToRef(invertedLocalRotation, ikRotation)
197
+ // This means: accumulatedIkRot = tempRot * currentLocalRot^-1
198
+ // But we need the new local rotation, not the accumulated IK rotation
199
+ // The new local rotation should be: newLocalRot such that accumulatedIkRot * newLocalRot = tempRot
200
+ // So: newLocalRot = accumulatedIkRot^-1 * tempRot
201
+ // But wait, the reference updates ikRotation, not localRotation directly...
202
+ // Actually, looking at the reference, it seems like ikRotation is used to compute the final rotation
203
+ // Let me try a different approach: the reference applies constraints to (ikRotation * localRotation)
204
+ // then extracts the new ikRotation, but we need the new localRotation
205
+ // Actually, I think the issue is that we should apply: newLocalRot = tempRot (the constrained result)
206
+ // But we need to extract what the new local rotation should be
207
+ // If tempRot = accumulatedIkRot * currentLocalRot (after constraints)
208
+ // Then: newLocalRot = accumulatedIkRot^-1 * tempRot
209
+ const accumulatedIkRotInv = accumulatedIkRot.conjugate();
210
+ let newLocalRot = accumulatedIkRotInv.multiply(tempRot);
211
+ // Update local rotation
212
+ const normalized = newLocalRot.normalize();
213
+ localRotations[qi] = normalized.x;
214
+ localRotations[qi + 1] = normalized.y;
215
+ localRotations[qi + 2] = normalized.z;
216
+ localRotations[qi + 3] = normalized.w;
217
+ // Update accumulated IK rotation as per reference
218
+ const localRotInv = currentLocalRot.conjugate();
219
+ accumulatedIkRot = tempRot.multiply(localRotInv);
220
+ this.ikRotations.set(jointBoneIdx, accumulatedIkRot);
221
+ // Update world matrices after this link adjustment (only once per link, not per bone)
222
+ if (this.computeWorldMatricesCallback) {
223
+ this.computeWorldMatricesCallback();
224
+ }
225
+ else {
226
+ this.computeWorldMatrices(skeleton, localRotations, localTranslations, worldMatrices);
227
+ }
228
+ // Update effector position for next link
229
+ const updatedEffectorMat2 = new Mat4(worldMatrices.subarray(effectorWorldMatIdx, effectorWorldMatIdx + 16));
230
+ effectorPos = updatedEffectorMat2.getPosition();
231
+ // Early exit if converged (check against original target position)
232
+ const currentDistanceSq = effectorPos.subtract(targetPos).lengthSquared();
233
+ if (currentDistanceSq < 1.0e-10) {
234
+ this.convergedChains.add(chain.targetBoneIndex);
235
+ return;
236
+ }
237
+ }
238
+ // Check convergence at end of iteration
239
+ const finalEffectorMat = new Mat4(worldMatrices.subarray(effectorWorldMatIdx, effectorWorldMatIdx + 16));
240
+ const finalEffectorPos = finalEffectorMat.getPosition();
241
+ const finalDistanceSq = finalEffectorPos.subtract(targetPos).lengthSquared();
242
+ if (finalDistanceSq < 1.0e-10) {
243
+ this.convergedChains.add(chain.targetBoneIndex);
244
+ break;
245
+ }
246
+ }
247
+ }
248
+ // Apply angle constraints to local rotation (Euler angle limits)
249
+ applyAngleConstraints(localRot, minAngle, maxAngle) {
250
+ // Convert quaternion to Euler angles
251
+ const euler = localRot.toEuler();
252
+ // Clamp each Euler angle component
253
+ let clampedX = Math.max(minAngle.x, Math.min(maxAngle.x, euler.x));
254
+ let clampedY = Math.max(minAngle.y, Math.min(maxAngle.y, euler.y));
255
+ let clampedZ = Math.max(minAngle.z, Math.min(maxAngle.z, euler.z));
256
+ // Convert back to quaternion (ZXY order, left-handed)
257
+ return Quat.fromEuler(clampedX, clampedY, clampedZ);
258
+ }
259
+ // Compute world matrices from local rotations and translations
260
+ // This matches Model.computeWorldMatrices logic (including append transforms)
261
+ computeWorldMatrices(skeleton, localRotations, localTranslations, worldMatrices) {
262
+ const bones = skeleton.bones;
263
+ const boneCount = bones.length;
264
+ const computed = new Array(boneCount).fill(false);
265
+ const computeWorld = (i) => {
266
+ if (computed[i])
267
+ return;
268
+ const bone = bones[i];
269
+ if (bone.parentIndex >= boneCount) {
270
+ console.warn(`[IK] bone ${i} parent out of range: ${bone.parentIndex}`);
271
+ }
272
+ const qi = i * 4;
273
+ const ti = i * 3;
274
+ // Get local rotation
275
+ let rotateM = Mat4.fromQuat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
276
+ let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0;
277
+ // Handle append transforms (same as Model.computeWorldMatrices)
278
+ const appendParentIdx = bone.appendParentIndex;
279
+ const hasAppend = bone.appendRotate && appendParentIdx !== undefined && appendParentIdx >= 0 && appendParentIdx < boneCount;
280
+ if (hasAppend) {
281
+ const ratio = bone.appendRatio === undefined ? 1 : Math.max(-1, Math.min(1, bone.appendRatio));
282
+ const hasRatio = Math.abs(ratio) > 1e-6;
283
+ if (hasRatio) {
284
+ const apQi = appendParentIdx * 4;
285
+ const apTi = appendParentIdx * 3;
286
+ if (bone.appendRotate) {
287
+ let ax = localRotations[apQi];
288
+ let ay = localRotations[apQi + 1];
289
+ let az = localRotations[apQi + 2];
290
+ const aw = localRotations[apQi + 3];
291
+ const absRatio = ratio < 0 ? -ratio : ratio;
292
+ if (ratio < 0) {
293
+ ax = -ax;
294
+ ay = -ay;
295
+ az = -az;
296
+ }
297
+ const identityQuat = new Quat(0, 0, 0, 1);
298
+ const appendQuat = new Quat(ax, ay, az, aw);
299
+ const result = Quat.slerp(identityQuat, appendQuat, absRatio);
300
+ rotateM = Mat4.fromQuat(result.x, result.y, result.z, result.w).multiply(rotateM);
301
+ }
302
+ if (bone.appendMove) {
303
+ const appendRatio = bone.appendRatio ?? 1;
304
+ addLocalTx = localTranslations[apTi] * appendRatio;
305
+ addLocalTy = localTranslations[apTi + 1] * appendRatio;
306
+ addLocalTz = localTranslations[apTi + 2] * appendRatio;
307
+ }
308
+ }
309
+ }
310
+ // Get bone's own translation
311
+ const boneTx = localTranslations[ti];
312
+ const boneTy = localTranslations[ti + 1];
313
+ const boneTz = localTranslations[ti + 2];
314
+ // Build local matrix: bindTranslation + rotation + (bone translation + append translation)
315
+ const localM = Mat4.identity().translateInPlace(bone.bindTranslation[0], bone.bindTranslation[1], bone.bindTranslation[2]);
316
+ const transM = Mat4.identity().translateInPlace(boneTx + addLocalTx, boneTy + addLocalTy, boneTz + addLocalTz);
317
+ const localMatrix = localM.multiply(rotateM).multiply(transM);
318
+ const worldOffset = i * 16;
319
+ if (bone.parentIndex >= 0) {
320
+ const p = bone.parentIndex;
321
+ if (!computed[p])
322
+ computeWorld(p);
323
+ const parentOffset = p * 16;
324
+ const parentWorldMat = new Mat4(worldMatrices.subarray(parentOffset, parentOffset + 16));
325
+ const worldMat = parentWorldMat.multiply(localMatrix);
326
+ worldMatrices.set(worldMat.values, worldOffset);
327
+ }
328
+ else {
329
+ worldMatrices.set(localMatrix.values, worldOffset);
330
+ }
331
+ computed[i] = true;
332
+ };
333
+ // Process all bones
334
+ for (let i = 0; i < boneCount; i++)
335
+ computeWorld(i);
336
+ }
337
+ }
package/dist/math.d.ts CHANGED
@@ -7,12 +7,10 @@ export declare class Vec3 {
7
7
  add(other: Vec3): Vec3;
8
8
  subtract(other: Vec3): Vec3;
9
9
  length(): number;
10
- lengthSquared(): number;
11
10
  normalize(): Vec3;
12
11
  cross(other: Vec3): Vec3;
13
12
  dot(other: Vec3): number;
14
13
  scale(scalar: number): Vec3;
15
- clone(): Vec3;
16
14
  }
17
15
  export declare class Quat {
18
16
  x: number;
@@ -26,13 +24,10 @@ export declare class Quat {
26
24
  conjugate(): Quat;
27
25
  length(): number;
28
26
  normalize(): Quat;
29
- rotateVec(v: Vec3): Vec3;
30
- static fromTo(from: Vec3, to: Vec3): Quat;
31
27
  static fromAxisAngle(axis: Vec3, angle: number): Quat;
32
28
  toArray(): [number, number, number, number];
33
29
  static slerp(a: Quat, b: Quat, t: number): Quat;
34
30
  static fromEuler(rotX: number, rotY: number, rotZ: number): Quat;
35
- toEuler(): Vec3;
36
31
  }
37
32
  export declare class Mat4 {
38
33
  values: Float32Array;
@@ -1 +1 @@
1
- {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"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"}
package/dist/math.js CHANGED
@@ -17,9 +17,6 @@ export class Vec3 {
17
17
  length() {
18
18
  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
19
19
  }
20
- lengthSquared() {
21
- return this.x * this.x + this.y * this.y + this.z * this.z;
22
- }
23
20
  normalize() {
24
21
  const len = this.length();
25
22
  if (len === 0)
@@ -35,9 +32,6 @@ export class Vec3 {
35
32
  scale(scalar) {
36
33
  return new Vec3(this.x * scalar, this.y * scalar, this.z * scalar);
37
34
  }
38
- clone() {
39
- return new Vec3(this.x, this.y, this.z);
40
- }
41
35
  }
42
36
  export class Quat {
43
37
  constructor(x, y, z, w) {
@@ -69,35 +63,6 @@ export class Quat {
69
63
  return new Quat(0, 0, 0, 1);
70
64
  return new Quat(this.x / len, this.y / len, this.z / len, this.w / len);
71
65
  }
72
- // Rotate a vector by this quaternion: result = q * v * q^-1
73
- rotateVec(v) {
74
- // Treat v as pure quaternion (x, y, z, 0)
75
- const qx = this.x, qy = this.y, qz = this.z, qw = this.w;
76
- const vx = v.x, vy = v.y, vz = v.z;
77
- // t = 2 * cross(q.xyz, v)
78
- const tx = 2 * (qy * vz - qz * vy);
79
- const ty = 2 * (qz * vx - qx * vz);
80
- const tz = 2 * (qx * vy - qy * vx);
81
- // result = v + q.w * t + cross(q.xyz, t)
82
- return new Vec3(vx + qw * tx + (qy * tz - qz * ty), vy + qw * ty + (qz * tx - qx * tz), vz + qw * tz + (qx * ty - qy * tx));
83
- }
84
- // Static method: create quaternion that rotates from one direction to another
85
- static fromTo(from, to) {
86
- const dot = from.dot(to);
87
- if (dot > 0.999999)
88
- return new Quat(0, 0, 0, 1); // Already aligned
89
- if (dot < -0.999999) {
90
- // 180 degrees
91
- let axis = from.cross(new Vec3(1, 0, 0));
92
- if (axis.length() < 0.001)
93
- axis = from.cross(new Vec3(0, 1, 0));
94
- return new Quat(axis.x, axis.y, axis.z, 0).normalize();
95
- }
96
- const axis = from.cross(to);
97
- const w = Math.sqrt((1 + dot) * 2);
98
- const invW = 1 / w;
99
- return new Quat(axis.x * invW, axis.y * invW, axis.z * invW, w * 0.5).normalize();
100
- }
101
66
  // Static method: create quaternion from rotation axis and angle
102
67
  static fromAxisAngle(axis, angle) {
103
68
  const normalizedAxis = axis.normalize();
@@ -152,26 +117,6 @@ export class Quat {
152
117
  const z = cy * cx * sz - sy * sx * cz;
153
118
  return new Quat(x, y, z, w).normalize();
154
119
  }
155
- // Convert quaternion to Euler angles (ZXY order, inverse of fromEuler)
156
- toEuler() {
157
- const qx = this.x;
158
- const qy = this.y;
159
- const qz = this.z;
160
- const qw = this.w;
161
- // ZXY order (left-handed)
162
- // Roll (X): rotation around X axis
163
- const sinr_cosp = 2 * (qw * qx + qy * qz);
164
- const cosr_cosp = 1 - 2 * (qx * qx + qy * qy);
165
- const rotX = Math.atan2(sinr_cosp, cosr_cosp);
166
- // Pitch (Y): rotation around Y axis
167
- const sinp = 2 * (qw * qy - qz * qx);
168
- const rotY = Math.abs(sinp) >= 1 ? (sinp >= 0 ? Math.PI / 2 : -Math.PI / 2) : Math.asin(sinp);
169
- // Yaw (Z): rotation around Z axis
170
- const siny_cosp = 2 * (qw * qz + qx * qy);
171
- const cosy_cosp = 1 - 2 * (qy * qy + qz * qz);
172
- const rotZ = Math.atan2(siny_cosp, cosy_cosp);
173
- return new Vec3(rotX, rotY, rotZ);
174
- }
175
120
  }
176
121
  export class Mat4 {
177
122
  constructor(values) {
package/dist/model.d.ts CHANGED
@@ -118,6 +118,7 @@ export declare class Model {
118
118
  private initializeRotTweenBuffers;
119
119
  private initializeTransTweenBuffers;
120
120
  private initializeMorphTweenBuffers;
121
+ private createTweenState;
121
122
  private initializeRuntimeMorph;
122
123
  private updateRotationTweens;
123
124
  private updateTranslationTweens;
@@ -125,7 +126,6 @@ export declare class Model {
125
126
  getVertices(): Float32Array<ArrayBuffer>;
126
127
  getTextures(): Texture[];
127
128
  getMaterials(): Material[];
128
- getVertexCount(): number;
129
129
  getIndices(): Uint32Array<ArrayBuffer>;
130
130
  getSkeleton(): Skeleton;
131
131
  getSkinning(): Skinning;
@@ -133,12 +133,10 @@ export declare class Model {
133
133
  getJoints(): Joint[];
134
134
  getMorphing(): Morphing;
135
135
  getMorphWeights(): Float32Array;
136
- getBoneNames(): string[];
137
136
  rotateBones(names: string[], quats: Quat[], durationMs?: number): void;
138
137
  moveBones(names: string[], relativeTranslations: Vec3[], durationMs?: number): void;
139
138
  getBoneWorldMatrices(): Float32Array;
140
139
  getBoneInverseBindMatrices(): Float32Array;
141
- getMorphNames(): string[];
142
140
  setMorphWeight(name: string, weight: number, durationMs?: number): void;
143
141
  private applyMorphs;
144
142
  evaluatePose(): boolean;
@@ -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
@@ -89,33 +89,21 @@ export class Model {
89
89
  this.runtimeSkeleton.ikSolvers = ikSolvers;
90
90
  }
91
91
  initializeRotTweenBuffers() {
92
- const n = this.skeleton.bones.length;
93
- this.rotTweenState = {
94
- active: new Uint8Array(n),
95
- startQuat: new Float32Array(n * 4),
96
- targetQuat: new Float32Array(n * 4),
97
- startTimeMs: new Float32Array(n),
98
- durationMs: new Float32Array(n),
99
- };
92
+ this.rotTweenState = this.createTweenState(this.skeleton.bones.length, 4, 4);
100
93
  }
101
94
  initializeTransTweenBuffers() {
102
- const n = this.skeleton.bones.length;
103
- this.transTweenState = {
104
- active: new Uint8Array(n),
105
- startVec: new Float32Array(n * 3),
106
- targetVec: new Float32Array(n * 3),
107
- startTimeMs: new Float32Array(n),
108
- durationMs: new Float32Array(n),
109
- };
95
+ this.transTweenState = this.createTweenState(this.skeleton.bones.length, 3, 3);
110
96
  }
111
97
  initializeMorphTweenBuffers() {
112
- const n = this.morphing.morphs.length;
113
- this.morphTweenState = {
114
- active: new Uint8Array(n),
115
- startWeight: new Float32Array(n),
116
- targetWeight: new Float32Array(n),
117
- startTimeMs: new Float32Array(n),
118
- durationMs: new Float32Array(n),
98
+ this.morphTweenState = this.createTweenState(this.morphing.morphs.length, 1, 1);
99
+ }
100
+ createTweenState(count, startSize, targetSize) {
101
+ return {
102
+ active: new Uint8Array(count),
103
+ startQuat: new Float32Array(count * startSize),
104
+ targetQuat: new Float32Array(count * targetSize),
105
+ startTimeMs: new Float32Array(count),
106
+ durationMs: new Float32Array(count),
119
107
  };
120
108
  }
121
109
  initializeRuntimeMorph() {
@@ -194,42 +182,30 @@ export class Model {
194
182
  }
195
183
  return hasActiveTweens;
196
184
  }
197
- // Get interleaved vertex data for GPU upload
198
- // Format: [x,y,z, nx,ny,nz, u,v, x,y,z, nx,ny,nz, u,v, ...]
199
185
  getVertices() {
200
186
  return this.vertexData;
201
187
  }
202
- // Get texture information
203
188
  getTextures() {
204
189
  return this.textures;
205
190
  }
206
- // Get material information
207
191
  getMaterials() {
208
192
  return this.materials;
209
193
  }
210
- // Get vertex count
211
- getVertexCount() {
212
- return this.vertexCount;
213
- }
214
- // Get index data for GPU upload
215
194
  getIndices() {
216
195
  return this.indexData;
217
196
  }
218
- // Accessors for skeleton/skinning
219
197
  getSkeleton() {
220
198
  return this.skeleton;
221
199
  }
222
200
  getSkinning() {
223
201
  return this.skinning;
224
202
  }
225
- // Accessors for physics data
226
203
  getRigidbodies() {
227
204
  return this.rigidbodies;
228
205
  }
229
206
  getJoints() {
230
207
  return this.joints;
231
208
  }
232
- // Accessors for morphing
233
209
  getMorphing() {
234
210
  return this.morphing;
235
211
  }
@@ -237,9 +213,6 @@ export class Model {
237
213
  return this.runtimeMorph.weights;
238
214
  }
239
215
  // ------- Bone helpers (public API) -------
240
- getBoneNames() {
241
- return this.skeleton.bones.map((b) => b.name);
242
- }
243
216
  rotateBones(names, quats, durationMs) {
244
217
  const state = this.rotTweenState;
245
218
  const normalized = quats.map((q) => q.normalize());
@@ -382,9 +355,6 @@ export class Model {
382
355
  getBoneInverseBindMatrices() {
383
356
  return this.skeleton.inverseBindMatrices;
384
357
  }
385
- getMorphNames() {
386
- return this.morphing.morphs.map((m) => m.name);
387
- }
388
358
  setMorphWeight(name, weight, durationMs) {
389
359
  const idx = this.runtimeMorph.nameIndex[name] ?? -1;
390
360
  if (idx < 0 || idx >= this.runtimeMorph.weights.length)
package/dist/player.d.ts CHANGED
@@ -13,13 +13,11 @@ export declare class Player {
13
13
  private frames;
14
14
  private boneTracks;
15
15
  private morphTracks;
16
- private duration;
16
+ private _duration;
17
17
  private isPlaying;
18
18
  private isPaused;
19
- private currentTime;
19
+ private _currentTime;
20
20
  private startTime;
21
- private pausedTime;
22
- private pauseStartTime;
23
21
  /**
24
22
  * Load VMD animation file
25
23
  */
@@ -58,21 +56,9 @@ export declare class Player {
58
56
  * Get current playback progress
59
57
  */
60
58
  getProgress(): AnimationProgress;
61
- /**
62
- * Get current time
63
- */
64
- getCurrentTime(): number;
65
- /**
66
- * Get animation duration
67
- */
68
- getDuration(): number;
69
- /**
70
- * Check if playing
71
- */
72
- isPlayingState(): boolean;
73
- /**
74
- * Check if paused
75
- */
76
- isPausedState(): boolean;
59
+ get currentTime(): number;
60
+ get duration(): number;
61
+ get isPlayingState(): boolean;
62
+ get isPausedState(): boolean;
77
63
  }
78
64
  //# sourceMappingURL=player.d.ts.map