reze-engine 0.4.5 → 0.4.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/dist/engine.d.ts +3 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +37 -11
- package/dist/ik.d.ts +32 -0
- package/dist/ik.d.ts.map +1 -0
- package/dist/ik.js +337 -0
- package/dist/model.d.ts +6 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +23 -9
- 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/dist/rzm-converter.d.ts +12 -0
- package/dist/rzm-converter.d.ts.map +1 -0
- package/dist/rzm-converter.js +40 -0
- package/dist/rzm-loader.d.ts +24 -0
- package/dist/rzm-loader.d.ts.map +1 -0
- package/dist/rzm-loader.js +488 -0
- package/dist/rzm-writer.d.ts +27 -0
- package/dist/rzm-writer.d.ts.map +1 -0
- package/dist/rzm-writer.js +701 -0
- package/package.json +1 -1
- package/src/engine.ts +52 -11
- package/src/model.ts +25 -9
- package/dist/e.d.ts +0 -1
- package/dist/e.d.ts.map +0 -1
- package/dist/e.js +0 -638
- package/dist/engine_r.d.ts +0 -132
- package/dist/engine_r.d.ts.map +0 -1
- package/dist/engine_r.js +0 -1489
package/dist/engine.d.ts
CHANGED
|
@@ -142,8 +142,9 @@ export declare class Engine {
|
|
|
142
142
|
stopRenderLoop(): void;
|
|
143
143
|
dispose(): void;
|
|
144
144
|
loadModel(path: string): Promise<void>;
|
|
145
|
-
rotateBones(
|
|
146
|
-
moveBones(
|
|
145
|
+
rotateBones(boneRotations: Record<string, Quat>, durationMs?: number): void;
|
|
146
|
+
moveBones(boneTranslations: Record<string, Vec3>, durationMs?: number): void;
|
|
147
|
+
resetAllBones(): void;
|
|
147
148
|
setMorphWeight(name: string, weight: number, durationMs?: number): void;
|
|
148
149
|
setMaterialVisible(name: string, visible: boolean): void;
|
|
149
150
|
toggleMaterialVisible(name: string): void;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -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
|
@@ -238,6 +238,10 @@ export class Engine {
|
|
|
238
238
|
_padding1: f32,
|
|
239
239
|
rimColor: vec3f,
|
|
240
240
|
isOverEyes: f32, // 1.0 if rendering over eyes, 0.0 otherwise
|
|
241
|
+
diffuseColor: vec3f,
|
|
242
|
+
_padding2: f32,
|
|
243
|
+
ambientColor: vec3f,
|
|
244
|
+
_padding3: f32,
|
|
241
245
|
};
|
|
242
246
|
|
|
243
247
|
struct VertexOutput {
|
|
@@ -298,9 +302,11 @@ export class Engine {
|
|
|
298
302
|
}
|
|
299
303
|
|
|
300
304
|
let n = normalize(input.normal);
|
|
301
|
-
let
|
|
305
|
+
let textureColor = textureSample(diffuseTexture, diffuseSampler, input.uv).rgb;
|
|
306
|
+
let albedo = textureColor * material.diffuseColor;
|
|
302
307
|
|
|
303
|
-
// Accumulate light contribution
|
|
308
|
+
// Accumulate light contribution, ignore material.ambientColor
|
|
309
|
+
// var lightAccum = light.ambientColor.xyz * material.ambientColor;
|
|
304
310
|
var lightAccum = light.ambientColor.xyz;
|
|
305
311
|
for (var i = 0u; i < 4u; i++) {
|
|
306
312
|
let intensity = light.lights[i].color.w;
|
|
@@ -1253,12 +1259,15 @@ export class Engine {
|
|
|
1253
1259
|
this.cachedSkinMatricesVersion = -1;
|
|
1254
1260
|
await this.setupModelBuffers(model);
|
|
1255
1261
|
}
|
|
1256
|
-
rotateBones(
|
|
1257
|
-
this.currentModel?.rotateBones(
|
|
1262
|
+
rotateBones(boneRotations, durationMs) {
|
|
1263
|
+
this.currentModel?.rotateBones(boneRotations, durationMs);
|
|
1258
1264
|
}
|
|
1259
1265
|
// moveBones now takes relative translations (VMD-style) by default
|
|
1260
|
-
moveBones(
|
|
1261
|
-
this.currentModel?.moveBones(
|
|
1266
|
+
moveBones(boneTranslations, durationMs) {
|
|
1267
|
+
this.currentModel?.moveBones(boneTranslations, durationMs);
|
|
1268
|
+
}
|
|
1269
|
+
resetAllBones() {
|
|
1270
|
+
this.currentModel?.resetAllBones();
|
|
1262
1271
|
}
|
|
1263
1272
|
setMorphWeight(name, weight, durationMs) {
|
|
1264
1273
|
if (!this.currentModel)
|
|
@@ -1499,7 +1508,7 @@ export class Engine {
|
|
|
1499
1508
|
throw new Error(`Material "${mat.name}" has no diffuse texture`);
|
|
1500
1509
|
const materialAlpha = mat.diffuse[3];
|
|
1501
1510
|
const isTransparent = materialAlpha < 1.0 - 0.001;
|
|
1502
|
-
const materialUniformBuffer = this.createMaterialUniformBuffer(mat.name, materialAlpha, 0.0);
|
|
1511
|
+
const materialUniformBuffer = this.createMaterialUniformBuffer(mat.name, materialAlpha, 0.0, [mat.diffuse[0], mat.diffuse[1], mat.diffuse[2]], mat.ambient);
|
|
1503
1512
|
// Create bind groups using the shared bind group layout - All pipelines (main, eye, hair multiply, hair opaque) use the same shader and layout
|
|
1504
1513
|
const bindGroup = this.device.createBindGroup({
|
|
1505
1514
|
label: `material bind group: ${mat.name}`,
|
|
@@ -1526,7 +1535,7 @@ export class Engine {
|
|
|
1526
1535
|
else if (mat.isHair) {
|
|
1527
1536
|
// Hair materials: create separate bind groups for over-eyes vs over-non-eyes
|
|
1528
1537
|
const createHairBindGroup = (isOverEyes) => {
|
|
1529
|
-
const buffer = this.createMaterialUniformBuffer(`${mat.name} (${isOverEyes ? "over eyes" : "over non-eyes"})`, materialAlpha, isOverEyes ? 1.0 : 0.0);
|
|
1538
|
+
const buffer = this.createMaterialUniformBuffer(`${mat.name} (${isOverEyes ? "over eyes" : "over non-eyes"})`, materialAlpha, isOverEyes ? 1.0 : 0.0, [mat.diffuse[0], mat.diffuse[1], mat.diffuse[2]], mat.ambient);
|
|
1530
1539
|
return this.device.createBindGroup({
|
|
1531
1540
|
label: `material bind group (${isOverEyes ? "over eyes" : "over non-eyes"}): ${mat.name}`,
|
|
1532
1541
|
layout: this.mainBindGroupLayout,
|
|
@@ -1618,9 +1627,26 @@ export class Engine {
|
|
|
1618
1627
|
currentIndexOffset += indexCount;
|
|
1619
1628
|
}
|
|
1620
1629
|
}
|
|
1621
|
-
createMaterialUniformBuffer(label, alpha, isOverEyes) {
|
|
1622
|
-
const data = new Float32Array(
|
|
1623
|
-
data.set([
|
|
1630
|
+
createMaterialUniformBuffer(label, alpha, isOverEyes, diffuseColor, ambientColor) {
|
|
1631
|
+
const data = new Float32Array(16);
|
|
1632
|
+
data.set([
|
|
1633
|
+
alpha,
|
|
1634
|
+
1.0,
|
|
1635
|
+
this.rimLightIntensity,
|
|
1636
|
+
0.0, // alpha, alphaMultiplier, rimIntensity, _padding1
|
|
1637
|
+
1.0,
|
|
1638
|
+
1.0,
|
|
1639
|
+
1.0,
|
|
1640
|
+
isOverEyes, // rimColor (vec3), isOverEyes
|
|
1641
|
+
diffuseColor[0],
|
|
1642
|
+
diffuseColor[1],
|
|
1643
|
+
diffuseColor[2],
|
|
1644
|
+
0.0, // diffuseColor (vec3), _padding2
|
|
1645
|
+
ambientColor[0],
|
|
1646
|
+
ambientColor[1],
|
|
1647
|
+
ambientColor[2],
|
|
1648
|
+
0.0, // ambientColor (vec3), _padding3
|
|
1649
|
+
]);
|
|
1624
1650
|
return this.createUniformBuffer(`material uniform: ${label}`, data);
|
|
1625
1651
|
}
|
|
1626
1652
|
createUniformBuffer(label, data) {
|
package/dist/ik.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Vec3 } from "./math";
|
|
2
|
+
import type { Skeleton } from "./model";
|
|
3
|
+
export interface IKLink {
|
|
4
|
+
boneIndex: number;
|
|
5
|
+
hasLimit: boolean;
|
|
6
|
+
minAngle?: Vec3;
|
|
7
|
+
maxAngle?: Vec3;
|
|
8
|
+
}
|
|
9
|
+
export interface IKChain {
|
|
10
|
+
targetBoneIndex: number;
|
|
11
|
+
effectorBoneIndex: number;
|
|
12
|
+
iterationCount: number;
|
|
13
|
+
rotationConstraint: number;
|
|
14
|
+
links: IKLink[];
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare class IK {
|
|
18
|
+
private chains;
|
|
19
|
+
private computeWorldMatricesCallback?;
|
|
20
|
+
private lastTargetPositions;
|
|
21
|
+
private convergedChains;
|
|
22
|
+
private ikRotations;
|
|
23
|
+
constructor(chains?: IKChain[]);
|
|
24
|
+
setComputeWorldMatricesCallback(callback: () => void): void;
|
|
25
|
+
getChains(): IKChain[];
|
|
26
|
+
enableChain(targetBoneName: string, enabled: boolean): void;
|
|
27
|
+
solve(skeleton: Skeleton, localRotations: Float32Array, localTranslations: Float32Array, worldMatrices: Float32Array): void;
|
|
28
|
+
private solveCCD;
|
|
29
|
+
private applyAngleConstraints;
|
|
30
|
+
private computeWorldMatrices;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ik.d.ts.map
|
package/dist/ik.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik.d.ts","sourceRoot":"","sources":["../src/ik.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,IAAI,EAAQ,MAAM,QAAQ,CAAA;AACzC,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE7C,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;AAED,MAAM,WAAW,OAAO;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,qBAAa,EAAE;IACb,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,4BAA4B,CAAC,CAAY;IAEjD,OAAO,CAAC,mBAAmB,CAA+B;IAE1D,OAAO,CAAC,eAAe,CAAyB;IAEhD,OAAO,CAAC,WAAW,CAA+B;gBAEtC,MAAM,GAAE,OAAO,EAAO;IAMlC,+BAA+B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI3D,SAAS,IAAI,OAAO,EAAE;IAKtB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAU3D,KAAK,CACH,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,YAAY,EAC5B,iBAAiB,EAAE,YAAY,EAC/B,aAAa,EAAE,YAAY,GAC1B,IAAI;IA2FP,OAAO,CAAC,QAAQ;IAqLhB,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,oBAAoB;CAsG7B"}
|
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/model.d.ts
CHANGED
|
@@ -139,8 +139,8 @@ export declare class Model {
|
|
|
139
139
|
getJoints(): Joint[];
|
|
140
140
|
getMorphing(): Morphing;
|
|
141
141
|
getMorphWeights(): Float32Array;
|
|
142
|
-
rotateBones(
|
|
143
|
-
moveBones(
|
|
142
|
+
rotateBones(boneRotations: Record<string, Quat>, durationMs?: number): void;
|
|
143
|
+
moveBones(boneTranslations: Record<string, Vec3>, durationMs?: number): void;
|
|
144
144
|
getBoneWorldMatrices(): Float32Array;
|
|
145
145
|
getBoneInverseBindMatrices(): Float32Array;
|
|
146
146
|
getSkinMatrices(): Float32Array;
|
|
@@ -150,6 +150,10 @@ export declare class Model {
|
|
|
150
150
|
* Load VMD animation file
|
|
151
151
|
*/
|
|
152
152
|
loadVmd(vmdUrl: string): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Reset all bones to their default pose
|
|
155
|
+
*/
|
|
156
|
+
resetAllBones(): void;
|
|
153
157
|
/**
|
|
154
158
|
* Process frames into tracks
|
|
155
159
|
*/
|
package/dist/model.d.ts.map
CHANGED
|
@@ -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":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAqB,MAAM,QAAQ,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,KAAK,EAAW,MAAM,WAAW,CAAA;AAMrD,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,IAAI,EAAE,CAAA;IACtB,iBAAiB,EAAE,IAAI,EAAE,CAAA;IACzB,aAAa,EAAE,IAAI,EAAE,CAAA;IACrB,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;AA2BD,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;IACnC,OAAO,CAAC,WAAW,CAAiB;IAGpC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,kBAAkB,CAAkB;IAG5C,OAAO,CAAC,iBAAiB,CAAC,CAAc;IAExC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAY;IAG/B,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,UAAU,CAAwE;IAC1F,OAAO,CAAC,WAAW,CAA0E;IAC7F,OAAO,CAAC,iBAAiB,CAAY;IACrC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,aAAa,CAAY;IAGjC,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,iBAAiB,CAAiC;IAG1D,OAAO,CAAC,OAAO,CAAuB;gBAGpC,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;IA8BtB,OAAO,CAAC,yBAAyB;IA2BjC,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,sBAAsB;IAwC9B,OAAO,CAAC,sBAAsB;IAc9B,OAAO,CAAC,YAAY;IA6EpB,WAAW,IAAI,YAAY,CAAC,WAAW,CAAC;IAIxC,WAAW,IAAI,OAAO,EAAE;IAIxB,YAAY,IAAI,QAAQ,EAAE;IAI1B,UAAU,IAAI,WAAW,CAAC,WAAW,CAAC;IAItC,WAAW,IAAI,QAAQ;IAIvB,WAAW,IAAI,QAAQ;IAIvB,cAAc,IAAI,SAAS,EAAE;IAI7B,SAAS,IAAI,KAAK,EAAE;IAIpB,WAAW,IAAI,QAAQ;IAIvB,eAAe,IAAI,YAAY;IAM/B,WAAW,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAmD3E,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAoG5E,oBAAoB,IAAI,YAAY;IAWpC,0BAA0B,IAAI,YAAY;IAI1C,eAAe,IAAI,YAAY;IAuB/B,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAwCvE,OAAO,CAAC,WAAW;IAiEnB;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5C;;OAEG;IACI,aAAa,IAAI,IAAI;IAe5B;;OAEG;IACH,OAAO,CAAC,aAAa;IA4DrB,aAAa,IAAI,IAAI;IAYrB,cAAc,IAAI,IAAI;IAKtB,aAAa,IAAI,IAAI;IAMrB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMjC;;OAEG;IACH,oBAAoB,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAUjF;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;IAWzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAmBzB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAuGrB;;;;;OAKG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IA+ClC,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,oBAAoB;CA0F7B"}
|
package/dist/model.js
CHANGED
|
@@ -250,19 +250,18 @@ export class Model {
|
|
|
250
250
|
return this.runtimeMorph.weights;
|
|
251
251
|
}
|
|
252
252
|
// ------- Bone helpers (public API) -------
|
|
253
|
-
rotateBones(
|
|
253
|
+
rotateBones(boneRotations, durationMs) {
|
|
254
254
|
const state = this.tweenState;
|
|
255
255
|
// Clone and normalize to avoid mutating input
|
|
256
|
-
|
|
256
|
+
Object.values(boneRotations).forEach((q) => q.normalize());
|
|
257
257
|
const now = this.tweenTimeMs;
|
|
258
258
|
const dur = durationMs && durationMs > 0 ? durationMs : 0;
|
|
259
|
-
for (
|
|
260
|
-
const name = names[i];
|
|
259
|
+
for (const [name, targetQuat] of Object.entries(boneRotations)) {
|
|
261
260
|
const idx = this.runtimeSkeleton.nameIndex[name] ?? -1;
|
|
262
261
|
if (idx < 0 || idx >= this.skeleton.bones.length)
|
|
263
262
|
continue;
|
|
264
263
|
const rotations = this.runtimeSkeleton.localRotations;
|
|
265
|
-
const targetNorm =
|
|
264
|
+
const targetNorm = targetQuat;
|
|
266
265
|
if (dur === 0) {
|
|
267
266
|
rotations[idx].set(targetNorm);
|
|
268
267
|
state.rotActive[idx] = 0;
|
|
@@ -296,7 +295,7 @@ export class Model {
|
|
|
296
295
|
}
|
|
297
296
|
// Move bones using VMD-style relative translations (relative to bind pose world position)
|
|
298
297
|
// This is the default behavior for VMD animations
|
|
299
|
-
moveBones(
|
|
298
|
+
moveBones(boneTranslations, durationMs) {
|
|
300
299
|
const state = this.tweenState;
|
|
301
300
|
const now = this.tweenTimeMs;
|
|
302
301
|
const dur = durationMs && durationMs > 0 ? durationMs : 0;
|
|
@@ -313,15 +312,13 @@ export class Model {
|
|
|
313
312
|
return bindPos;
|
|
314
313
|
}
|
|
315
314
|
};
|
|
316
|
-
for (
|
|
317
|
-
const name = names[i];
|
|
315
|
+
for (const [name, vmdRelativeTranslation] of Object.entries(boneTranslations)) {
|
|
318
316
|
const idx = this.runtimeSkeleton.nameIndex[name] ?? -1;
|
|
319
317
|
if (idx < 0 || idx >= this.skeleton.bones.length)
|
|
320
318
|
continue;
|
|
321
319
|
const bone = this.skeleton.bones[idx];
|
|
322
320
|
const translations = this.runtimeSkeleton.localTranslations;
|
|
323
321
|
const localRot = this.runtimeSkeleton.localRotations;
|
|
324
|
-
const vmdRelativeTranslation = relativeTranslations[i];
|
|
325
322
|
// VMD translation is relative to bind pose world position
|
|
326
323
|
// targetWorldPos = bindPoseWorldPos + vmdRelativeTranslation
|
|
327
324
|
const bindPoseWorldPos = computeBindPoseWorldPosition(idx);
|
|
@@ -508,6 +505,7 @@ export class Model {
|
|
|
508
505
|
*/
|
|
509
506
|
async loadVmd(vmdUrl) {
|
|
510
507
|
this.animationData = await VMDLoader.load(vmdUrl);
|
|
508
|
+
this.resetAllBones();
|
|
511
509
|
this.processFrames();
|
|
512
510
|
// Apply initial pose at time 0
|
|
513
511
|
this.animationTime = 0;
|
|
@@ -517,6 +515,22 @@ export class Model {
|
|
|
517
515
|
this.physics.reset(this.runtimeSkeleton.worldMatrices, this.skeleton.inverseBindMatrices);
|
|
518
516
|
}
|
|
519
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* Reset all bones to their default pose
|
|
520
|
+
*/
|
|
521
|
+
resetAllBones() {
|
|
522
|
+
for (let boneIdx = 0; boneIdx < this.skeleton.bones.length; boneIdx++) {
|
|
523
|
+
const localRot = this.runtimeSkeleton.localRotations[boneIdx];
|
|
524
|
+
const localTrans = this.runtimeSkeleton.localTranslations[boneIdx];
|
|
525
|
+
// Reset to default pose: identity rotation and zero translation (like initial PMX state)
|
|
526
|
+
localRot.set(Quat.identity());
|
|
527
|
+
localTrans.set(Vec3.zeros());
|
|
528
|
+
}
|
|
529
|
+
this.computeWorldMatrices();
|
|
530
|
+
if (this.physics) {
|
|
531
|
+
this.physics.reset(this.runtimeSkeleton.worldMatrices, this.skeleton.inverseBindMatrices);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
520
534
|
/**
|
|
521
535
|
* Process frames into tracks
|
|
522
536
|
*/
|