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/engine.d.ts +2 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +44 -100
- package/dist/ik-solver.d.ts +6 -0
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +98 -101
- package/dist/ik.d.ts +32 -0
- package/dist/ik.d.ts.map +1 -0
- package/dist/ik.js +337 -0
- package/dist/math.d.ts +0 -5
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +0 -55
- package/dist/model.d.ts +1 -3
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +11 -41
- package/dist/player.d.ts +6 -20
- package/dist/player.d.ts.map +1 -1
- package/dist/player.js +88 -191
- package/dist/pool-scene.d.ts +52 -0
- package/dist/pool-scene.d.ts.map +1 -0
- package/dist/pool-scene.js +1122 -0
- package/dist/pool.d.ts +38 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +422 -0
- package/package.json +1 -1
- package/src/engine.ts +54 -101
- package/src/ik-solver.ts +106 -124
- package/src/math.ts +0 -74
- package/src/model.ts +12 -44
- package/src/player.ts +115 -210
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;
|
package/dist/math.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AACA,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,qBAAa,IAAI;IACf,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;gBAEG,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM;IAM3C,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAItB,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAI3B,MAAM,IAAI,MAAM;IAIhB,
|
|
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;
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,IAAI,EAAE,IAAI,EAAa,MAAM,QAAQ,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAK5C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB;AAGD,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,QAAQ,CAAC,EAAE,IAAI,CAAA;CAChB;AAGD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAGD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,IAAI,CAAA;IAChB,aAAa,EAAE,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,mBAAmB,EAAE,YAAY,CAAA;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,UAAU,CAAA;CACpB;AAGD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACzC;AAGD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAGD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,iBAAiB,EAAE,CAAA;IAClC,eAAe,CAAC,EAAE,mBAAmB,EAAE,CAAA;CACxC;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,aAAa,EAAE,YAAY,CAAA;CAC5B;AAGD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,cAAc,EAAE,YAAY,CAAA;IAC5B,iBAAiB,EAAE,YAAY,CAAA;IAC/B,aAAa,EAAE,YAAY,CAAA;IAC3B,WAAW,CAAC,EAAE,WAAW,EAAE,CAAA;IAC3B,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAA;CACvB;AAGD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,OAAO,EAAE,YAAY,CAAA;CACtB;AA6BD,qBAAa,KAAK;IAChB,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAiB;IAElC,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,QAAQ,CAAU;IAG1B,OAAO,CAAC,QAAQ,CAAU;IAG1B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAc;IAG5B,OAAO,CAAC,eAAe,CAAkB;IAGzC,OAAO,CAAC,YAAY,CAAe;IAGnC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,kBAAkB,CAAkB;IAE5C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,eAAe,CAAwB;gBAG7C,UAAU,EAAE,YAAY,CAAC,WAAW,CAAC,EACrC,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,EACnC,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,WAAW,GAAE,SAAS,EAAO,EAC7B,MAAM,GAAE,KAAK,EAAO;IA2BtB,OAAO,CAAC,yBAAyB;IA4BjC,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,yBAAyB;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
16
|
+
private _duration;
|
|
17
17
|
private isPlaying;
|
|
18
18
|
private isPaused;
|
|
19
|
-
private
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|