reze-engine 0.6.5 → 0.6.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-solver.d.ts +2 -1
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +31 -14
- package/dist/model.d.ts +6 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +125 -8
- package/dist/runtime-bone.d.ts +49 -0
- package/dist/runtime-bone.d.ts.map +1 -0
- package/dist/runtime-bone.js +121 -0
- package/package.json +1 -1
- package/src/ik-solver.ts +37 -14
- package/src/model.ts +149 -16
- package/dist/bezier-interpolate.d.ts +0 -15
- package/dist/bezier-interpolate.d.ts.map +0 -1
- package/dist/bezier-interpolate.js +0 -40
- package/dist/engine_ts.d.ts +0 -143
- package/dist/engine_ts.d.ts.map +0 -1
- package/dist/engine_ts.js +0 -1575
- package/dist/ik.d.ts +0 -32
- package/dist/ik.d.ts.map +0 -1
- package/dist/ik.js +0 -337
- package/dist/player.d.ts +0 -64
- package/dist/player.d.ts.map +0 -1
- package/dist/player.js +0 -220
- package/dist/pool-scene.d.ts +0 -52
- package/dist/pool-scene.d.ts.map +0 -1
- package/dist/pool-scene.js +0 -1122
- package/dist/pool.d.ts +0 -38
- package/dist/pool.d.ts.map +0 -1
- package/dist/pool.js +0 -422
- package/dist/rzm-converter.d.ts +0 -12
- package/dist/rzm-converter.d.ts.map +0 -1
- package/dist/rzm-converter.js +0 -40
- package/dist/rzm-loader.d.ts +0 -24
- package/dist/rzm-loader.d.ts.map +0 -1
- package/dist/rzm-loader.js +0 -488
- package/dist/rzm-writer.d.ts +0 -27
- package/dist/rzm-writer.d.ts.map +0 -1
- package/dist/rzm-writer.js +0 -701
package/dist/ik-solver.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Mat4, Quat, Vec3 } from "./math";
|
|
7
7
|
import { Bone, IKSolver, IKChainInfo } from "./model";
|
|
8
|
+
export type UpdateWorldMatrixFn = (boneIndex: number, applyIK: boolean) => void;
|
|
8
9
|
/**
|
|
9
10
|
* Solve IK chains for a model
|
|
10
11
|
*/
|
|
@@ -14,7 +15,7 @@ export declare class IKSolverSystem {
|
|
|
14
15
|
/**
|
|
15
16
|
* Solve all IK chains
|
|
16
17
|
*/
|
|
17
|
-
static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Quat[], localTranslations: Vec3[], worldMatrices: Mat4[], ikChainInfo: IKChainInfo[]): void;
|
|
18
|
+
static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Quat[], localTranslations: Vec3[], worldMatrices: Mat4[], ikChainInfo: IKChainInfo[], updateWorldMatrix?: UpdateWorldMatrixFn): void;
|
|
18
19
|
private static solveIK;
|
|
19
20
|
private static solveChain;
|
|
20
21
|
private static limitAngle;
|
package/dist/ik-solver.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,EAAE,IAAI,EAAU,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,EAAE,IAAI,EAAU,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG7D,MAAM,MAAM,mBAAmB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;AAoE/E;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAS;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAuB;IAExD;;OAEG;WACW,KAAK,CACjB,SAAS,EAAE,QAAQ,EAAE,EACrB,KAAK,EAAE,IAAI,EAAE,EACb,cAAc,EAAE,IAAI,EAAE,EACtB,iBAAiB,EAAE,IAAI,EAAE,EACzB,aAAa,EAAE,IAAI,EAAE,EACrB,WAAW,EAAE,WAAW,EAAE,EAC1B,iBAAiB,CAAC,EAAE,mBAAmB,GACtC,IAAI;IAMP,OAAO,CAAC,MAAM,CAAC,OAAO;IAoFtB,OAAO,CAAC,MAAM,CAAC,UAAU;IAqGzB,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB,OAAO,CAAC,MAAM,CAAC,WAAW;IAM1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAKlC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAmCjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAQ/B,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAqBvC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAc3C,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAoCjC"}
|
package/dist/ik-solver.js
CHANGED
|
@@ -74,12 +74,12 @@ export class IKSolverSystem {
|
|
|
74
74
|
/**
|
|
75
75
|
* Solve all IK chains
|
|
76
76
|
*/
|
|
77
|
-
static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
|
|
77
|
+
static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix) {
|
|
78
78
|
for (const solver of ikSolvers) {
|
|
79
|
-
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
|
|
79
|
+
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
static solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
|
|
82
|
+
static solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix) {
|
|
83
83
|
if (solver.links.length === 0)
|
|
84
84
|
return;
|
|
85
85
|
const ikBoneIndex = solver.ikBoneIndex;
|
|
@@ -99,10 +99,18 @@ export class IKSolverSystem {
|
|
|
99
99
|
chains.push(new IKChain(link.boneIndex, link));
|
|
100
100
|
}
|
|
101
101
|
// Update chain bones and target bone world matrices (initial state, no IK yet)
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (updateWorldMatrix) {
|
|
103
|
+
for (let i = chains.length - 1; i >= 0; i--) {
|
|
104
|
+
updateWorldMatrix(chains[i].boneIndex, false);
|
|
105
|
+
}
|
|
106
|
+
updateWorldMatrix(targetBoneIndex, false);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
for (let i = chains.length - 1; i >= 0; i--) {
|
|
110
|
+
this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
111
|
+
}
|
|
112
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
104
113
|
}
|
|
105
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
106
114
|
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
107
115
|
return;
|
|
108
116
|
// Solve iteratively
|
|
@@ -112,7 +120,7 @@ export class IKSolverSystem {
|
|
|
112
120
|
for (let chainIndex = 0; chainIndex < chains.length; chainIndex++) {
|
|
113
121
|
const chain = chains[chainIndex];
|
|
114
122
|
if (chain.solveAxis !== InternalSolveAxis.Fixed) {
|
|
115
|
-
this.solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, i < halfIteration);
|
|
123
|
+
this.solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, i < halfIteration, updateWorldMatrix);
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
126
|
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
@@ -128,7 +136,7 @@ export class IKSolverSystem {
|
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
138
|
}
|
|
131
|
-
static solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, useAxis) {
|
|
139
|
+
static solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, useAxis, updateWorldMatrix) {
|
|
132
140
|
const chainBoneIndex = chain.boneIndex;
|
|
133
141
|
const chainPosition = this.getWorldTranslation(chainBoneIndex, worldMatrices);
|
|
134
142
|
const ikPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
@@ -191,13 +199,22 @@ export class IKSolverSystem {
|
|
|
191
199
|
chainInfo.ikRotation = chainInfo.ikRotation.multiply(localRot.clone().conjugate().normalize());
|
|
192
200
|
}
|
|
193
201
|
}
|
|
194
|
-
// Update world matrices for affected bones (using
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
// Update world matrices for affected bones (using callback - handles append correctly)
|
|
203
|
+
if (updateWorldMatrix) {
|
|
204
|
+
for (let i = chainIndex; i >= 0; i--) {
|
|
205
|
+
const link = solver.links[i];
|
|
206
|
+
updateWorldMatrix(link.boneIndex, true); // applyIK = true
|
|
207
|
+
}
|
|
208
|
+
updateWorldMatrix(targetBoneIndex, false);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
for (let i = chainIndex; i >= 0; i--) {
|
|
212
|
+
const link = solver.links[i];
|
|
213
|
+
this.updateWorldMatrix(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
|
|
214
|
+
}
|
|
215
|
+
this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
216
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
198
217
|
}
|
|
199
|
-
this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
200
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
201
218
|
}
|
|
202
219
|
static limitAngle(angle, min, max, useAxis) {
|
|
203
220
|
if (angle < min) {
|
package/dist/model.d.ts
CHANGED
|
@@ -146,6 +146,10 @@ export declare class Model {
|
|
|
146
146
|
/**
|
|
147
147
|
* Convert VMD-style relative translation (relative to bind pose world position) to local translation
|
|
148
148
|
* This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
|
|
149
|
+
* @param boneIdx - Bone index
|
|
150
|
+
* @param vmdRelativeTranslation - VMD relative translation
|
|
151
|
+
* @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
|
|
152
|
+
* Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
|
|
149
153
|
*/
|
|
150
154
|
private convertVMDTranslationToLocal;
|
|
151
155
|
getBoneWorldMatrices(): Float32Array;
|
|
@@ -208,6 +212,8 @@ export declare class Model {
|
|
|
208
212
|
*/
|
|
209
213
|
update(deltaTime: number): boolean;
|
|
210
214
|
private solveIKChains;
|
|
215
|
+
private ikComputedSet;
|
|
216
|
+
private computeSingleBoneWorldMatrix;
|
|
211
217
|
private computeWorldMatrices;
|
|
212
218
|
}
|
|
213
219
|
//# sourceMappingURL=model.d.ts.map
|
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,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;IAGtC,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,cAAc,CAAO;gBAG3B,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;IAoD5E
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
package/dist/model.js
CHANGED
|
@@ -31,6 +31,8 @@ export class Model {
|
|
|
31
31
|
// IK and Physics enable flags
|
|
32
32
|
this.ikEnabled = true;
|
|
33
33
|
this.physicsEnabled = true;
|
|
34
|
+
// Cached set to track which bones are being computed in current IK pass (to avoid infinite recursion)
|
|
35
|
+
this.ikComputedSet = new Set();
|
|
34
36
|
// Store base vertex data (original positions before morphing)
|
|
35
37
|
this.baseVertexData = new Float32Array(vertexData);
|
|
36
38
|
this.vertexData = vertexData;
|
|
@@ -346,8 +348,12 @@ export class Model {
|
|
|
346
348
|
/**
|
|
347
349
|
* Convert VMD-style relative translation (relative to bind pose world position) to local translation
|
|
348
350
|
* This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
|
|
351
|
+
* @param boneIdx - Bone index
|
|
352
|
+
* @param vmdRelativeTranslation - VMD relative translation
|
|
353
|
+
* @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
|
|
354
|
+
* Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
|
|
349
355
|
*/
|
|
350
|
-
convertVMDTranslationToLocal(boneIdx, vmdRelativeTranslation) {
|
|
356
|
+
convertVMDTranslationToLocal(boneIdx, vmdRelativeTranslation, rotation) {
|
|
351
357
|
const skeleton = this.skeleton;
|
|
352
358
|
const bones = skeleton.bones;
|
|
353
359
|
const localRot = this.runtimeSkeleton.localRotations;
|
|
@@ -383,7 +389,9 @@ export class Model {
|
|
|
383
389
|
// Subtract bindTranslation to get position after bind translation
|
|
384
390
|
const afterBindTranslation = parentSpacePos.subtract(new Vec3(bone.bindTranslation[0], bone.bindTranslation[1], bone.bindTranslation[2]));
|
|
385
391
|
// Apply inverse rotation to get local translation
|
|
386
|
-
|
|
392
|
+
// Use provided rotation (animation rotation) or fall back to current localRotation
|
|
393
|
+
// Using animation rotation prevents conflicts when IK modifies the rotation
|
|
394
|
+
const localRotation = rotation ?? localRot[boneIdx];
|
|
387
395
|
// Clone to avoid mutating, then conjugate and normalize
|
|
388
396
|
const invRotation = localRotation.clone().conjugate().normalize();
|
|
389
397
|
const rotationMat = Mat4.fromQuat(invRotation.x, invRotation.y, invRotation.z, invRotation.w);
|
|
@@ -714,9 +722,12 @@ export class Model {
|
|
|
714
722
|
const localTrans = this.runtimeSkeleton.localTranslations[boneIdx];
|
|
715
723
|
if (!frameB) {
|
|
716
724
|
// No interpolation needed - direct assignment
|
|
717
|
-
|
|
718
|
-
//
|
|
719
|
-
const
|
|
725
|
+
// Use animation frame's rotation for translation conversion to ensure consistency
|
|
726
|
+
// This prevents conflicts when IK later modifies the rotation
|
|
727
|
+
const frameRotation = frameA.rotation;
|
|
728
|
+
localRot.set(frameRotation);
|
|
729
|
+
// Convert VMD relative translation to local translation using animation rotation
|
|
730
|
+
const localTranslation = this.convertVMDTranslationToLocal(boneIdx, frameA.translation, frameRotation);
|
|
720
731
|
localTrans.set(localTranslation);
|
|
721
732
|
}
|
|
722
733
|
else {
|
|
@@ -737,8 +748,10 @@ export class Model {
|
|
|
737
748
|
const tzWeight = getWeight(32);
|
|
738
749
|
// Interpolate VMD relative translations (relative to bind pose world position)
|
|
739
750
|
const interpolatedVMDTranslation = new Vec3(frameA.translation.x + (frameB.translation.x - frameA.translation.x) * txWeight, frameA.translation.y + (frameB.translation.y - frameA.translation.y) * tyWeight, frameA.translation.z + (frameB.translation.z - frameA.translation.z) * tzWeight);
|
|
740
|
-
// Convert interpolated VMD translation to local translation
|
|
741
|
-
|
|
751
|
+
// Convert interpolated VMD translation to local translation using animation rotation
|
|
752
|
+
// This ensures translation is computed for the animation rotation, not the runtime rotation
|
|
753
|
+
// that will be modified by IK, preventing conflicts
|
|
754
|
+
const localTranslation = this.convertVMDTranslationToLocal(boneIdx, interpolatedVMDTranslation, rotation);
|
|
742
755
|
// Direct property writes to avoid object allocation
|
|
743
756
|
localRot.set(rotation);
|
|
744
757
|
localTrans.set(localTranslation);
|
|
@@ -821,7 +834,111 @@ export class Model {
|
|
|
821
834
|
const ikChainInfo = this.runtimeSkeleton.ikChainInfo;
|
|
822
835
|
if (!ikChainInfo)
|
|
823
836
|
return;
|
|
824
|
-
|
|
837
|
+
// Solve each IK solver sequentially, ensuring consistent state between solvers
|
|
838
|
+
for (const solver of ikSolvers) {
|
|
839
|
+
// Recompute ALL world matrices before each solver starts
|
|
840
|
+
// This ensures each solver sees the effects of previous solvers on localRotations
|
|
841
|
+
this.computeWorldMatrices();
|
|
842
|
+
// Clear computed set for this solver's pass
|
|
843
|
+
this.ikComputedSet.clear();
|
|
844
|
+
// Solve this IK chain
|
|
845
|
+
// Pass callback that uses model's world matrix computation (handles append correctly)
|
|
846
|
+
IKSolverSystem.solve([solver], // Solve one at a time
|
|
847
|
+
this.skeleton.bones, this.runtimeSkeleton.localRotations, this.runtimeSkeleton.localTranslations, this.runtimeSkeleton.worldMatrices, ikChainInfo, (boneIndex, applyIK) => {
|
|
848
|
+
// Clear computed set for each bone update to allow recomputation in same iteration
|
|
849
|
+
this.ikComputedSet.delete(boneIndex);
|
|
850
|
+
this.computeSingleBoneWorldMatrix(boneIndex, applyIK);
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
// Add this new method to compute a single bone's world matrix
|
|
855
|
+
// Recursively ensures parents are computed first to avoid using stale parent matrices
|
|
856
|
+
computeSingleBoneWorldMatrix(boneIndex, applyIK) {
|
|
857
|
+
const bones = this.skeleton.bones;
|
|
858
|
+
const localRot = this.runtimeSkeleton.localRotations;
|
|
859
|
+
const localTrans = this.runtimeSkeleton.localTranslations;
|
|
860
|
+
const worldMats = this.runtimeSkeleton.worldMatrices;
|
|
861
|
+
const ikChainInfo = this.runtimeSkeleton.ikChainInfo;
|
|
862
|
+
const b = bones[boneIndex];
|
|
863
|
+
// Prevent infinite recursion: if this bone is already being computed in this call chain, skip
|
|
864
|
+
if (this.ikComputedSet.has(boneIndex)) {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
// Mark this bone as being computed to prevent infinite recursion
|
|
868
|
+
this.ikComputedSet.add(boneIndex);
|
|
869
|
+
// Recursively compute parent first if it exists (ensures parent matrix is up-to-date)
|
|
870
|
+
if (b.parentIndex >= 0) {
|
|
871
|
+
this.computeSingleBoneWorldMatrix(b.parentIndex, applyIK);
|
|
872
|
+
}
|
|
873
|
+
// Get base rotation
|
|
874
|
+
let boneRot = localRot[boneIndex];
|
|
875
|
+
// Apply IK rotation if requested
|
|
876
|
+
if (applyIK && ikChainInfo) {
|
|
877
|
+
const chainInfo = ikChainInfo[boneIndex];
|
|
878
|
+
if (chainInfo?.ikRotation) {
|
|
879
|
+
boneRot = chainInfo.ikRotation.multiply(boneRot).normalize();
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
let rotateM = Mat4.fromQuat(boneRot.x, boneRot.y, boneRot.z, boneRot.w);
|
|
883
|
+
let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0;
|
|
884
|
+
// Handle append transformations (same logic as computeWorldMatrices)
|
|
885
|
+
const appendParentIdx = b.appendParentIndex;
|
|
886
|
+
const hasAppend = b.appendRotate &&
|
|
887
|
+
appendParentIdx !== undefined &&
|
|
888
|
+
appendParentIdx >= 0 &&
|
|
889
|
+
appendParentIdx < bones.length;
|
|
890
|
+
if (hasAppend) {
|
|
891
|
+
const ratio = b.appendRatio === undefined ? 1 : Math.max(-1, Math.min(1, b.appendRatio));
|
|
892
|
+
const hasRatio = Math.abs(ratio) > 1e-6;
|
|
893
|
+
if (hasRatio) {
|
|
894
|
+
if (b.appendRotate) {
|
|
895
|
+
// Get append parent's rotation
|
|
896
|
+
// During IK solving, use only base local rotation (not IK rotations) to avoid
|
|
897
|
+
// conflicts with IK rotations that are still being computed incrementally
|
|
898
|
+
// IK rotations will be applied to localRotations after IK solving completes
|
|
899
|
+
if (appendParentIdx >= 0) {
|
|
900
|
+
// Compute append parent's world matrix for dependency order, but use base rotation for append
|
|
901
|
+
this.computeSingleBoneWorldMatrix(appendParentIdx, applyIK);
|
|
902
|
+
}
|
|
903
|
+
// Use append parent's base local rotation only (IK rotations are applied after solving)
|
|
904
|
+
let appendRot = localRot[appendParentIdx];
|
|
905
|
+
let ax = appendRot.x, ay = appendRot.y, az = appendRot.z;
|
|
906
|
+
const aw = appendRot.w;
|
|
907
|
+
const absRatio = ratio < 0 ? -ratio : ratio;
|
|
908
|
+
if (ratio < 0) {
|
|
909
|
+
ax = -ax;
|
|
910
|
+
ay = -ay;
|
|
911
|
+
az = -az;
|
|
912
|
+
}
|
|
913
|
+
const appendQuat = new Quat(ax, ay, az, aw);
|
|
914
|
+
const result = Quat.slerp(Quat.identity(), appendQuat, absRatio);
|
|
915
|
+
rotateM = Mat4.fromQuat(result.x, result.y, result.z, result.w).multiply(rotateM);
|
|
916
|
+
}
|
|
917
|
+
if (b.appendMove) {
|
|
918
|
+
const appendTrans = localTrans[appendParentIdx];
|
|
919
|
+
addLocalTx = appendTrans.x * ratio;
|
|
920
|
+
addLocalTy = appendTrans.y * ratio;
|
|
921
|
+
addLocalTz = appendTrans.z * ratio;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
const boneTrans = localTrans[boneIndex];
|
|
926
|
+
const localTx = boneTrans.x + addLocalTx;
|
|
927
|
+
const localTy = boneTrans.y + addLocalTy;
|
|
928
|
+
const localTz = boneTrans.z + addLocalTz;
|
|
929
|
+
this.cachedIdentityMat1
|
|
930
|
+
.setIdentity()
|
|
931
|
+
.translateInPlace(b.bindTranslation[0], b.bindTranslation[1], b.bindTranslation[2]);
|
|
932
|
+
this.cachedIdentityMat2.setIdentity().translateInPlace(localTx, localTy, localTz);
|
|
933
|
+
const localM = this.cachedIdentityMat1.multiply(rotateM).multiply(this.cachedIdentityMat2);
|
|
934
|
+
const worldMat = worldMats[boneIndex];
|
|
935
|
+
if (b.parentIndex >= 0) {
|
|
936
|
+
const parentMat = worldMats[b.parentIndex];
|
|
937
|
+
Mat4.multiplyArrays(parentMat.values, 0, localM.values, 0, worldMat.values, 0);
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
worldMat.values.set(localM.values);
|
|
941
|
+
}
|
|
825
942
|
}
|
|
826
943
|
computeWorldMatrices() {
|
|
827
944
|
const bones = this.skeleton.bones;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Quat, Vec3, Mat4 } from "./math";
|
|
2
|
+
import type { Bone } from "./model";
|
|
3
|
+
/**
|
|
4
|
+
* Runtime bone state - encapsulates bone pose and world matrix
|
|
5
|
+
* Similar to babylon-mmd's IMmdRuntimeBone approach
|
|
6
|
+
*/
|
|
7
|
+
export declare class RuntimeBone {
|
|
8
|
+
localRotation: Quat;
|
|
9
|
+
localTranslation: Vec3;
|
|
10
|
+
worldMatrix: Mat4;
|
|
11
|
+
readonly bone: Bone;
|
|
12
|
+
readonly index: number;
|
|
13
|
+
ikRotation?: Quat;
|
|
14
|
+
constructor(bone: Bone, index: number);
|
|
15
|
+
/**
|
|
16
|
+
* Set local rotation
|
|
17
|
+
*/
|
|
18
|
+
setRotation(rotation: Quat): void;
|
|
19
|
+
/**
|
|
20
|
+
* Set local translation
|
|
21
|
+
*/
|
|
22
|
+
setTranslation(translation: Vec3): void;
|
|
23
|
+
/**
|
|
24
|
+
* Get world position from world matrix
|
|
25
|
+
*/
|
|
26
|
+
getWorldPosition(): Vec3;
|
|
27
|
+
/**
|
|
28
|
+
* Update world matrix based on local rotation, translation, and parent's world matrix
|
|
29
|
+
* Handles append rotations and translations
|
|
30
|
+
*
|
|
31
|
+
* @param parentWorldMatrix Parent's world matrix (null if root bone)
|
|
32
|
+
* @param allBones Array of all runtime bones (for append parent lookup)
|
|
33
|
+
* @param applyIK Whether to apply IK rotation (default: true). Set to false when computing initial world matrices before IK solving.
|
|
34
|
+
*/
|
|
35
|
+
updateWorldMatrix(parentWorldMatrix: Mat4 | null, allBones: RuntimeBone[], applyIK?: boolean): void;
|
|
36
|
+
/**
|
|
37
|
+
* Reset IK rotation to identity
|
|
38
|
+
*/
|
|
39
|
+
resetIKRotation(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Set IK rotation delta (accumulated during IK solving)
|
|
42
|
+
*/
|
|
43
|
+
setIKRotation(ikRotation: Quat): void;
|
|
44
|
+
/**
|
|
45
|
+
* Apply IK rotation to local rotation and clear IK rotation
|
|
46
|
+
*/
|
|
47
|
+
applyIKRotation(): void;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=runtime-bone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-bone.d.ts","sourceRoot":"","sources":["../src/runtime-bone.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAEnC;;;GAGG;AACH,qBAAa,WAAW;IACf,aAAa,EAAE,IAAI,CAAA;IACnB,gBAAgB,EAAE,IAAI,CAAA;IACtB,WAAW,EAAE,IAAI,CAAA;IACxB,SAAgB,IAAI,EAAE,IAAI,CAAA;IAC1B,SAAgB,KAAK,EAAE,MAAM,CAAA;IAGtB,UAAU,CAAC,EAAE,IAAI,CAAA;gBAEZ,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM;IAQrC;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IAIjC;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI;IAIvC;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAKxB;;;;;;;OAOG;IACH,iBAAiB,CAAC,iBAAiB,EAAE,IAAI,GAAG,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,GAAE,OAAc,GAAG,IAAI;IA2EzG;;OAEG;IACH,eAAe,IAAI,IAAI;IAIvB;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI;IAIrC;;OAEG;IACH,eAAe,IAAI,IAAI;CAMxB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Quat, Vec3, Mat4 } from "./math";
|
|
2
|
+
/**
|
|
3
|
+
* Runtime bone state - encapsulates bone pose and world matrix
|
|
4
|
+
* Similar to babylon-mmd's IMmdRuntimeBone approach
|
|
5
|
+
*/
|
|
6
|
+
export class RuntimeBone {
|
|
7
|
+
constructor(bone, index) {
|
|
8
|
+
this.bone = bone;
|
|
9
|
+
this.index = index;
|
|
10
|
+
this.localRotation = Quat.identity();
|
|
11
|
+
this.localTranslation = new Vec3(0, 0, 0);
|
|
12
|
+
this.worldMatrix = Mat4.identity();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Set local rotation
|
|
16
|
+
*/
|
|
17
|
+
setRotation(rotation) {
|
|
18
|
+
this.localRotation.set(rotation);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Set local translation
|
|
22
|
+
*/
|
|
23
|
+
setTranslation(translation) {
|
|
24
|
+
this.localTranslation.set(translation);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get world position from world matrix
|
|
28
|
+
*/
|
|
29
|
+
getWorldPosition() {
|
|
30
|
+
const m = this.worldMatrix.values;
|
|
31
|
+
return new Vec3(m[12], m[13], m[14]);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Update world matrix based on local rotation, translation, and parent's world matrix
|
|
35
|
+
* Handles append rotations and translations
|
|
36
|
+
*
|
|
37
|
+
* @param parentWorldMatrix Parent's world matrix (null if root bone)
|
|
38
|
+
* @param allBones Array of all runtime bones (for append parent lookup)
|
|
39
|
+
* @param applyIK Whether to apply IK rotation (default: true). Set to false when computing initial world matrices before IK solving.
|
|
40
|
+
*/
|
|
41
|
+
updateWorldMatrix(parentWorldMatrix, allBones, applyIK = true) {
|
|
42
|
+
// Start with local rotation
|
|
43
|
+
let finalRot = this.localRotation;
|
|
44
|
+
// Apply IK rotation if present and applyIK is true
|
|
45
|
+
if (applyIK && this.ikRotation) {
|
|
46
|
+
finalRot = this.ikRotation.multiply(finalRot).normalize();
|
|
47
|
+
}
|
|
48
|
+
// Build rotation matrix
|
|
49
|
+
let rotateM = Mat4.fromQuat(finalRot.x, finalRot.y, finalRot.z, finalRot.w);
|
|
50
|
+
let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0;
|
|
51
|
+
// Handle append rotation and translation
|
|
52
|
+
const appendParentIdx = this.bone.appendParentIndex;
|
|
53
|
+
const hasAppend = this.bone.appendRotate && appendParentIdx !== undefined && appendParentIdx >= 0 && appendParentIdx < allBones.length;
|
|
54
|
+
if (hasAppend) {
|
|
55
|
+
const ratio = this.bone.appendRatio === undefined ? 1 : Math.max(-1, Math.min(1, this.bone.appendRatio));
|
|
56
|
+
const hasRatio = Math.abs(ratio) > 1e-6;
|
|
57
|
+
if (hasRatio) {
|
|
58
|
+
if (this.bone.appendRotate) {
|
|
59
|
+
const appendParent = allBones[appendParentIdx];
|
|
60
|
+
const appendRot = appendParent.localRotation;
|
|
61
|
+
let ax = appendRot.x;
|
|
62
|
+
let ay = appendRot.y;
|
|
63
|
+
let az = appendRot.z;
|
|
64
|
+
const aw = appendRot.w;
|
|
65
|
+
const absRatio = ratio < 0 ? -ratio : ratio;
|
|
66
|
+
if (ratio < 0) {
|
|
67
|
+
ax = -ax;
|
|
68
|
+
ay = -ay;
|
|
69
|
+
az = -az;
|
|
70
|
+
}
|
|
71
|
+
const appendQuat = new Quat(ax, ay, az, aw);
|
|
72
|
+
const result = Quat.slerp(Quat.identity(), appendQuat, absRatio);
|
|
73
|
+
rotateM = Mat4.fromQuat(result.x, result.y, result.z, result.w).multiply(rotateM);
|
|
74
|
+
}
|
|
75
|
+
if (this.bone.appendMove) {
|
|
76
|
+
const appendParent = allBones[appendParentIdx];
|
|
77
|
+
const appendTrans = appendParent.localTranslation;
|
|
78
|
+
const appendRatio = this.bone.appendRatio ?? 1;
|
|
79
|
+
addLocalTx = appendTrans.x * appendRatio;
|
|
80
|
+
addLocalTy = appendTrans.y * appendRatio;
|
|
81
|
+
addLocalTz = appendTrans.z * appendRatio;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Build local matrix: bind translation, then rotation, then local translation + append translation
|
|
86
|
+
const localTx = this.localTranslation.x + addLocalTx;
|
|
87
|
+
const localTy = this.localTranslation.y + addLocalTy;
|
|
88
|
+
const localTz = this.localTranslation.z + addLocalTz;
|
|
89
|
+
const bindMat = Mat4.identity().translateInPlace(this.bone.bindTranslation[0], this.bone.bindTranslation[1], this.bone.bindTranslation[2]);
|
|
90
|
+
const transMat = Mat4.identity().translateInPlace(localTx, localTy, localTz);
|
|
91
|
+
const localM = bindMat.multiply(rotateM).multiply(transMat);
|
|
92
|
+
// Compute world matrix
|
|
93
|
+
if (parentWorldMatrix) {
|
|
94
|
+
this.worldMatrix = parentWorldMatrix.multiply(localM);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.worldMatrix = localM;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reset IK rotation to identity
|
|
102
|
+
*/
|
|
103
|
+
resetIKRotation() {
|
|
104
|
+
this.ikRotation = undefined;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Set IK rotation delta (accumulated during IK solving)
|
|
108
|
+
*/
|
|
109
|
+
setIKRotation(ikRotation) {
|
|
110
|
+
this.ikRotation = ikRotation;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Apply IK rotation to local rotation and clear IK rotation
|
|
114
|
+
*/
|
|
115
|
+
applyIKRotation() {
|
|
116
|
+
if (this.ikRotation) {
|
|
117
|
+
this.localRotation = this.ikRotation.multiply(this.localRotation).normalize();
|
|
118
|
+
this.ikRotation = undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
package/package.json
CHANGED
package/src/ik-solver.ts
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
import { Mat4, Quat, Vec3 } from "./math"
|
|
8
8
|
import { Bone, IKLink, IKSolver, IKChainInfo } from "./model"
|
|
9
9
|
|
|
10
|
+
// Callback type for updating world matrix (provided by model to handle append transformations)
|
|
11
|
+
export type UpdateWorldMatrixFn = (boneIndex: number, applyIK: boolean) => void
|
|
12
|
+
|
|
10
13
|
const enum InternalEulerRotationOrder {
|
|
11
14
|
YXZ = 0,
|
|
12
15
|
ZYX = 1,
|
|
@@ -89,10 +92,11 @@ export class IKSolverSystem {
|
|
|
89
92
|
localRotations: Quat[],
|
|
90
93
|
localTranslations: Vec3[],
|
|
91
94
|
worldMatrices: Mat4[],
|
|
92
|
-
ikChainInfo: IKChainInfo[]
|
|
95
|
+
ikChainInfo: IKChainInfo[],
|
|
96
|
+
updateWorldMatrix?: UpdateWorldMatrixFn
|
|
93
97
|
): void {
|
|
94
98
|
for (const solver of ikSolvers) {
|
|
95
|
-
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo)
|
|
99
|
+
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix)
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
|
|
@@ -102,7 +106,8 @@ export class IKSolverSystem {
|
|
|
102
106
|
localRotations: Quat[],
|
|
103
107
|
localTranslations: Vec3[],
|
|
104
108
|
worldMatrices: Mat4[],
|
|
105
|
-
ikChainInfo: IKChainInfo[]
|
|
109
|
+
ikChainInfo: IKChainInfo[],
|
|
110
|
+
updateWorldMatrix?: UpdateWorldMatrixFn
|
|
106
111
|
): void {
|
|
107
112
|
if (solver.links.length === 0) return
|
|
108
113
|
|
|
@@ -126,10 +131,17 @@ export class IKSolverSystem {
|
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
// Update chain bones and target bone world matrices (initial state, no IK yet)
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
if (updateWorldMatrix) {
|
|
135
|
+
for (let i = chains.length - 1; i >= 0; i--) {
|
|
136
|
+
updateWorldMatrix(chains[i].boneIndex, false)
|
|
137
|
+
}
|
|
138
|
+
updateWorldMatrix(targetBoneIndex, false)
|
|
139
|
+
} else {
|
|
140
|
+
for (let i = chains.length - 1; i >= 0; i--) {
|
|
141
|
+
this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
142
|
+
}
|
|
143
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
131
144
|
}
|
|
132
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
133
145
|
|
|
134
146
|
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON) return
|
|
135
147
|
|
|
@@ -152,7 +164,8 @@ export class IKSolverSystem {
|
|
|
152
164
|
localTranslations,
|
|
153
165
|
worldMatrices,
|
|
154
166
|
ikChainInfo,
|
|
155
|
-
i < halfIteration
|
|
167
|
+
i < halfIteration,
|
|
168
|
+
updateWorldMatrix
|
|
156
169
|
)
|
|
157
170
|
}
|
|
158
171
|
}
|
|
@@ -182,7 +195,8 @@ export class IKSolverSystem {
|
|
|
182
195
|
localTranslations: Vec3[],
|
|
183
196
|
worldMatrices: Mat4[],
|
|
184
197
|
ikChainInfo: IKChainInfo[],
|
|
185
|
-
useAxis: boolean
|
|
198
|
+
useAxis: boolean,
|
|
199
|
+
updateWorldMatrix?: UpdateWorldMatrixFn
|
|
186
200
|
): void {
|
|
187
201
|
const chainBoneIndex = chain.boneIndex
|
|
188
202
|
const chainPosition = this.getWorldTranslation(chainBoneIndex, worldMatrices)
|
|
@@ -254,13 +268,21 @@ export class IKSolverSystem {
|
|
|
254
268
|
}
|
|
255
269
|
}
|
|
256
270
|
|
|
257
|
-
// Update world matrices for affected bones (using
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
271
|
+
// Update world matrices for affected bones (using callback - handles append correctly)
|
|
272
|
+
if (updateWorldMatrix) {
|
|
273
|
+
for (let i = chainIndex; i >= 0; i--) {
|
|
274
|
+
const link = solver.links[i]
|
|
275
|
+
updateWorldMatrix(link.boneIndex, true) // applyIK = true
|
|
276
|
+
}
|
|
277
|
+
updateWorldMatrix(targetBoneIndex, false)
|
|
278
|
+
} else {
|
|
279
|
+
for (let i = chainIndex; i >= 0; i--) {
|
|
280
|
+
const link = solver.links[i]
|
|
281
|
+
this.updateWorldMatrix(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo)
|
|
282
|
+
}
|
|
283
|
+
this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
284
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
261
285
|
}
|
|
262
|
-
this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
263
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
264
286
|
}
|
|
265
287
|
|
|
266
288
|
private static limitAngle(angle: number, min: number, max: number, useAxis: boolean): number {
|
|
@@ -410,3 +432,4 @@ export class IKSolverSystem {
|
|
|
410
432
|
}
|
|
411
433
|
}
|
|
412
434
|
}
|
|
435
|
+
|