reze-engine 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -45
- package/dist/animation.d.ts +0 -27
- package/dist/animation.d.ts.map +1 -1
- package/dist/animation.js +3 -17
- package/dist/camera.d.ts.map +1 -1
- package/dist/camera.js +2 -2
- package/dist/engine.d.ts +49 -52
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +613 -614
- package/dist/ik-solver.d.ts +0 -11
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +1 -11
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/math.d.ts +1 -0
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +24 -0
- package/dist/model.d.ts +10 -50
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +60 -93
- package/dist/pmx-loader.js +1 -1
- package/package.json +1 -1
- package/src/animation.ts +3 -37
- package/src/camera.ts +2 -2
- package/src/engine.ts +646 -750
- package/src/ik-solver.ts +1 -11
- package/src/index.ts +3 -4
- package/src/math.ts +27 -0
- package/src/model.ts +68 -99
- package/src/pmx-loader.ts +1 -1
package/dist/ik-solver.d.ts
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IK Solver implementation
|
|
3
|
-
* Based on reference from babylon-mmd and Saba MMD library
|
|
4
|
-
* https://github.com/benikabocha/saba/blob/master/src/Saba/Model/MMD/MMDIkSolver.cpp
|
|
5
|
-
*/
|
|
6
1
|
import { Mat4, Quat, Vec3 } from "./math";
|
|
7
2
|
import { Bone, IKSolver, IKChainInfo } from "./model";
|
|
8
3
|
export type UpdateWorldMatrixFn = (boneIndex: number, applyIK: boolean) => void;
|
|
9
|
-
/**
|
|
10
|
-
* Solve IK chains for a model
|
|
11
|
-
*/
|
|
12
4
|
export declare class IKSolverSystem {
|
|
13
5
|
private static readonly EPSILON;
|
|
14
6
|
private static readonly THRESHOLD;
|
|
15
|
-
/**
|
|
16
|
-
* Solve all IK chains
|
|
17
|
-
*/
|
|
18
7
|
static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Quat[], localTranslations: Vec3[], worldMatrices: Mat4[], ikChainInfo: IKChainInfo[], updateWorldMatrix?: UpdateWorldMatrixFn): void;
|
|
19
8
|
private static solveIK;
|
|
20
9
|
private static solveChain;
|
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":"
|
|
1
|
+
{"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAEA,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,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAS;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAuB;WAE1C,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
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* IK Solver implementation
|
|
3
|
-
* Based on reference from babylon-mmd and Saba MMD library
|
|
4
|
-
* https://github.com/benikabocha/saba/blob/master/src/Saba/Model/MMD/MMDIkSolver.cpp
|
|
5
|
-
*/
|
|
1
|
+
// IK solver (MMD-style; see Saba MMDIkSolver.cpp)
|
|
6
2
|
import { Mat4, Quat, Vec3 } from "./math";
|
|
7
3
|
var InternalEulerRotationOrder;
|
|
8
4
|
(function (InternalEulerRotationOrder) {
|
|
@@ -67,13 +63,7 @@ class IKChain {
|
|
|
67
63
|
}
|
|
68
64
|
}
|
|
69
65
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Solve IK chains for a model
|
|
72
|
-
*/
|
|
73
66
|
export class IKSolverSystem {
|
|
74
|
-
/**
|
|
75
|
-
* Solve all IK chains
|
|
76
|
-
*/
|
|
77
67
|
static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix) {
|
|
78
68
|
for (const solver of ikSolvers) {
|
|
79
69
|
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { Engine, type EngineStats } from "./engine";
|
|
2
|
+
export { Model } from "./model";
|
|
2
3
|
export { Vec3, Quat, Mat4 } from "./math";
|
|
3
|
-
export type { AnimationData, BoneKeyframe, MorphKeyframe, BoneInterpolation, ControlPoint } from "./animation";
|
|
4
|
-
export { bezierInterpolate, interpolateControlPoints, rawInterpolationToBoneInterpolation, LINEAR_INTERPOLATION } from "./animation";
|
|
5
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/math.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ export declare class Mat4 {
|
|
|
39
39
|
static identity(): Mat4;
|
|
40
40
|
static perspective(fov: number, aspect: number, near: number, far: number): Mat4;
|
|
41
41
|
static lookAt(eye: Vec3, target: Vec3, up: Vec3): Mat4;
|
|
42
|
+
static orthographicLh(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4;
|
|
42
43
|
multiply(other: Mat4): Mat4;
|
|
43
44
|
static multiplyArrays(a: Float32Array, aOffset: number, b: Float32Array, bOffset: number, out: Float32Array, outOffset: number): void;
|
|
44
45
|
clone(): Mat4;
|
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,MAAM,CAAC,KAAK,IAAI,IAAI;IAIpB,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAItB,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAI3B,MAAM,IAAI,MAAM;IAKhB,SAAS,IAAI,IAAI;IAejB,KAAK,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAQxB,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM;IAIxB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK3B,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;CAMvB;AAED,qBAAa,IAAI;IACf,CAAC,EAAE,MAAM,CAAA;IACT,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,EAAE,CAAC,EAAE,MAAM;IAOtD,MAAM,CAAC,QAAQ,IAAI,IAAI;IAIvB,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAItB,KAAK,IAAI,IAAI;IAIb,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAY3B,SAAS,IAAI,IAAI;IAOjB,MAAM,IAAI,MAAM;IAKhB,SAAS,IAAI,IAAI;IAkBjB,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAiBrD,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAK3C,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI;IAStB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAoC/C,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CAejE;AAED,qBAAa,IAAI;IACf,MAAM,EAAE,YAAY,CAAA;gBAER,MAAM,EAAE,YAAY;IAIhC,MAAM,CAAC,QAAQ,IAAI,IAAI;IAMvB,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IA4BhF,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"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"}
|
package/dist/math.js
CHANGED
|
@@ -234,6 +234,30 @@ export class Mat4 {
|
|
|
234
234
|
1,
|
|
235
235
|
]));
|
|
236
236
|
}
|
|
237
|
+
// LH ortho, NDC depth 0=near 1=far
|
|
238
|
+
static orthographicLh(left, right, bottom, top, near, far) {
|
|
239
|
+
const rl = 1 / (right - left);
|
|
240
|
+
const tb = 1 / (top - bottom);
|
|
241
|
+
const fn = 1 / (far - near);
|
|
242
|
+
return new Mat4(new Float32Array([
|
|
243
|
+
2 * rl,
|
|
244
|
+
0,
|
|
245
|
+
0,
|
|
246
|
+
0,
|
|
247
|
+
0,
|
|
248
|
+
2 * tb,
|
|
249
|
+
0,
|
|
250
|
+
0,
|
|
251
|
+
0,
|
|
252
|
+
0,
|
|
253
|
+
fn,
|
|
254
|
+
0,
|
|
255
|
+
-(right + left) * rl,
|
|
256
|
+
-(top + bottom) * tb,
|
|
257
|
+
-near * fn,
|
|
258
|
+
1,
|
|
259
|
+
]));
|
|
260
|
+
}
|
|
237
261
|
multiply(other) {
|
|
238
262
|
// Column-major multiplication (matches WGSL/GLSL convention):
|
|
239
263
|
// result = a * b
|
package/dist/model.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Mat4, Quat, Vec3 } from "./math";
|
|
2
2
|
import { Rigidbody, Joint } from "./physics";
|
|
3
|
-
import { AnimationData } from "./animation";
|
|
4
3
|
export interface Texture {
|
|
5
4
|
path: string;
|
|
6
5
|
name: string;
|
|
@@ -95,6 +94,12 @@ export interface MorphRuntime {
|
|
|
95
94
|
weights: Float32Array;
|
|
96
95
|
}
|
|
97
96
|
export declare class Model {
|
|
97
|
+
private static _nextId;
|
|
98
|
+
private static nextDefaultName;
|
|
99
|
+
static loadPmx(path: string, name?: string): Promise<Model>;
|
|
100
|
+
private _name;
|
|
101
|
+
get name(): string;
|
|
102
|
+
setName(value: string): void;
|
|
98
103
|
private vertexData;
|
|
99
104
|
private baseVertexData;
|
|
100
105
|
private vertexCount;
|
|
@@ -115,7 +120,6 @@ export declare class Model {
|
|
|
115
120
|
private tweenState;
|
|
116
121
|
private tweenTimeMs;
|
|
117
122
|
private _hasAnimation;
|
|
118
|
-
private _animationData;
|
|
119
123
|
private boneTracks;
|
|
120
124
|
private morphTracks;
|
|
121
125
|
private animationDuration;
|
|
@@ -124,7 +128,6 @@ export declare class Model {
|
|
|
124
128
|
private animationTime;
|
|
125
129
|
private boneTrackIndices;
|
|
126
130
|
private morphTrackIndices;
|
|
127
|
-
private physics;
|
|
128
131
|
private ikEnabled;
|
|
129
132
|
private physicsEnabled;
|
|
130
133
|
constructor(vertexData: Float32Array<ArrayBuffer>, indexData: Uint32Array<ArrayBuffer>, textures: Texture[], materials: Material[], skeleton: Skeleton, skinning: Skinning, morphing: Morphing, rigidbodies?: Rigidbody[], joints?: Joint[]);
|
|
@@ -138,6 +141,7 @@ export declare class Model {
|
|
|
138
141
|
getMaterials(): Material[];
|
|
139
142
|
getIndices(): Uint32Array<ArrayBuffer>;
|
|
140
143
|
getSkeleton(): Skeleton;
|
|
144
|
+
getBoneWorldPosition(boneName: string): Vec3 | null;
|
|
141
145
|
getSkinning(): Skinning;
|
|
142
146
|
getRigidbodies(): Rigidbody[];
|
|
143
147
|
getJoints(): Joint[];
|
|
@@ -145,79 +149,35 @@ export declare class Model {
|
|
|
145
149
|
getMorphWeights(): Float32Array;
|
|
146
150
|
rotateBones(boneRotations: Record<string, Quat>, durationMs?: number): void;
|
|
147
151
|
moveBones(boneTranslations: Record<string, Vec3>, durationMs?: number): void;
|
|
148
|
-
/**
|
|
149
|
-
* Convert VMD-style relative translation (relative to bind pose world position) to local translation
|
|
150
|
-
* This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
|
|
151
|
-
* @param boneIdx - Bone index
|
|
152
|
-
* @param vmdRelativeTranslation - VMD relative translation
|
|
153
|
-
* @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
|
|
154
|
-
* Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
|
|
155
|
-
*/
|
|
156
152
|
private convertVMDTranslationToLocal;
|
|
153
|
+
getWorldMatrices(): Mat4[];
|
|
157
154
|
getBoneWorldMatrices(): Float32Array;
|
|
158
155
|
getBoneInverseBindMatrices(): Float32Array;
|
|
159
156
|
getSkinMatrices(): Float32Array;
|
|
160
157
|
setMorphWeight(name: string, weight: number, durationMs?: number): void;
|
|
161
158
|
private applyMorphs;
|
|
162
|
-
/**
|
|
163
|
-
* Load VMD animation file
|
|
164
|
-
*/
|
|
165
159
|
loadVmd(vmdUrl: string): Promise<void>;
|
|
166
|
-
/**
|
|
167
|
-
* Load animation from structured keyframe data.
|
|
168
|
-
* This is the primary way to set animation data — loadVmd delegates to this.
|
|
169
|
-
*/
|
|
170
|
-
loadAnimationData(data: AnimationData): void;
|
|
171
|
-
/**
|
|
172
|
-
* Reset all bones to their default pose
|
|
173
|
-
*/
|
|
174
160
|
resetAllBones(): void;
|
|
175
161
|
resetAllMorphs(): void;
|
|
176
|
-
/**
|
|
177
|
-
* Enable or disable IK solving
|
|
178
|
-
*/
|
|
179
162
|
setIKEnabled(enabled: boolean): void;
|
|
180
|
-
/**
|
|
181
|
-
* Enable or disable physics simulation
|
|
182
|
-
*/
|
|
183
163
|
setPhysicsEnabled(enabled: boolean): void;
|
|
164
|
+
getPhysicsEnabled(): boolean;
|
|
184
165
|
playAnimation(): void;
|
|
185
166
|
pauseAnimation(): void;
|
|
186
167
|
stopAnimation(): void;
|
|
187
168
|
seekAnimation(time: number): void;
|
|
188
|
-
/**
|
|
189
|
-
* Get current animation progress
|
|
190
|
-
*/
|
|
191
|
-
getAnimationData(): AnimationData | null;
|
|
192
169
|
getAnimationProgress(): {
|
|
193
170
|
current: number;
|
|
194
171
|
duration: number;
|
|
195
172
|
percentage: number;
|
|
196
173
|
};
|
|
197
|
-
/**
|
|
198
|
-
* Binary search upper bound helper (static to avoid recreation)
|
|
199
|
-
*/
|
|
200
174
|
private static upperBound;
|
|
201
|
-
/**
|
|
202
|
-
* Find keyframe index with caching optimization
|
|
203
|
-
* Uses cached index as starting point for faster lookup when time is close
|
|
204
|
-
*/
|
|
205
175
|
private findKeyframeIndex;
|
|
206
|
-
/**
|
|
207
|
-
* Get pose at specific time (internal helper)
|
|
208
|
-
* Optimized for per-frame performance
|
|
209
|
-
*/
|
|
210
176
|
private getPoseAtTime;
|
|
211
|
-
/**
|
|
212
|
-
* Updates the model pose by recomputing all matrices.
|
|
213
|
-
* If animation is playing, applies animation pose first.
|
|
214
|
-
* deltaTime: Time elapsed since last update in seconds
|
|
215
|
-
* Returns true if vertices were modified (morphs changed)
|
|
216
|
-
*/
|
|
217
177
|
update(deltaTime: number): boolean;
|
|
218
178
|
private solveIKChains;
|
|
219
179
|
private ikComputedSet;
|
|
220
180
|
private computeSingleBoneWorldMatrix;
|
|
221
|
-
|
|
181
|
+
computeWorldMatrices(): void;
|
|
222
182
|
}
|
|
223
183
|
//# 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,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
package/dist/model.js
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { Mat4, Quat, Vec3 } from "./math";
|
|
2
|
-
import {
|
|
2
|
+
import { Engine } from "./engine";
|
|
3
|
+
import { PmxLoader } from "./pmx-loader";
|
|
3
4
|
import { IKSolverSystem } from "./ik-solver";
|
|
4
5
|
import { VMDLoader } from "./vmd-loader";
|
|
5
6
|
import { interpolateControlPoints, rawInterpolationToBoneInterpolation } from "./animation";
|
|
6
7
|
const VMD_FPS = 30;
|
|
7
8
|
const VERTEX_STRIDE = 8;
|
|
8
9
|
export class Model {
|
|
10
|
+
static nextDefaultName() {
|
|
11
|
+
return "model_" + Model._nextId++;
|
|
12
|
+
}
|
|
13
|
+
static async loadPmx(path, name) {
|
|
14
|
+
const model = await PmxLoader.load(path);
|
|
15
|
+
model.setName(name ?? Model.nextDefaultName());
|
|
16
|
+
await Engine.getInstance().registerModel(model, path);
|
|
17
|
+
return model;
|
|
18
|
+
}
|
|
19
|
+
get name() {
|
|
20
|
+
return this._name;
|
|
21
|
+
}
|
|
22
|
+
setName(value) {
|
|
23
|
+
this._name = value;
|
|
24
|
+
}
|
|
9
25
|
constructor(vertexData, indexData, textures, materials, skeleton, skinning, morphing, rigidbodies = [], joints = []) {
|
|
26
|
+
this._name = "";
|
|
10
27
|
this.textures = [];
|
|
11
28
|
this.materials = [];
|
|
12
29
|
// Physics data from PMX
|
|
@@ -19,7 +36,6 @@ export class Model {
|
|
|
19
36
|
this.tweenTimeMs = 0; // Time tracking for tweens (milliseconds)
|
|
20
37
|
// Animation runtime
|
|
21
38
|
this._hasAnimation = false;
|
|
22
|
-
this._animationData = null;
|
|
23
39
|
this.boneTracks = new Map();
|
|
24
40
|
this.morphTracks = new Map();
|
|
25
41
|
this.animationDuration = 0;
|
|
@@ -29,8 +45,6 @@ export class Model {
|
|
|
29
45
|
// Cached keyframe indices for faster lookup (per track)
|
|
30
46
|
this.boneTrackIndices = new Map();
|
|
31
47
|
this.morphTrackIndices = new Map();
|
|
32
|
-
// Physics runtime
|
|
33
|
-
this.physics = null;
|
|
34
48
|
// IK and Physics enable flags
|
|
35
49
|
this.ikEnabled = true;
|
|
36
50
|
this.physicsEnabled = true;
|
|
@@ -55,10 +69,6 @@ export class Model {
|
|
|
55
69
|
this.initializeRuntimeMorph();
|
|
56
70
|
this.initializeTweenBuffers();
|
|
57
71
|
this.applyMorphs();
|
|
58
|
-
// Initialize physics if rigidbodies exist
|
|
59
|
-
if (rigidbodies.length > 0) {
|
|
60
|
-
this.physics = new Physics(rigidbodies, joints);
|
|
61
|
-
}
|
|
62
72
|
}
|
|
63
73
|
initializeRuntimeSkeleton() {
|
|
64
74
|
const boneCount = this.skeleton.bones.length;
|
|
@@ -242,6 +252,13 @@ export class Model {
|
|
|
242
252
|
getSkeleton() {
|
|
243
253
|
return this.skeleton;
|
|
244
254
|
}
|
|
255
|
+
// World bone origin (world matrix col3); unknown name → null
|
|
256
|
+
getBoneWorldPosition(boneName) {
|
|
257
|
+
const idx = this.runtimeSkeleton.nameIndex[boneName];
|
|
258
|
+
if (idx === undefined || idx < 0)
|
|
259
|
+
return null;
|
|
260
|
+
return this.runtimeSkeleton.worldMatrices[idx].getPosition();
|
|
261
|
+
}
|
|
245
262
|
getSkinning() {
|
|
246
263
|
return this.skinning;
|
|
247
264
|
}
|
|
@@ -348,14 +365,7 @@ export class Model {
|
|
|
348
365
|
state.transActive[idx] = 1;
|
|
349
366
|
}
|
|
350
367
|
}
|
|
351
|
-
|
|
352
|
-
* Convert VMD-style relative translation (relative to bind pose world position) to local translation
|
|
353
|
-
* This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
|
|
354
|
-
* @param boneIdx - Bone index
|
|
355
|
-
* @param vmdRelativeTranslation - VMD relative translation
|
|
356
|
-
* @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
|
|
357
|
-
* Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
|
|
358
|
-
*/
|
|
368
|
+
// VMD translation (world delta from bind pose) → bone local space; optional rotation for animation vs IK
|
|
359
369
|
convertVMDTranslationToLocal(boneIdx, vmdRelativeTranslation, rotation) {
|
|
360
370
|
const skeleton = this.skeleton;
|
|
361
371
|
const bones = skeleton.bones;
|
|
@@ -402,6 +412,9 @@ export class Model {
|
|
|
402
412
|
const localTranslation = new Vec3(rm[0] * afterBindTranslation.x + rm[4] * afterBindTranslation.y + rm[8] * afterBindTranslation.z, rm[1] * afterBindTranslation.x + rm[5] * afterBindTranslation.y + rm[9] * afterBindTranslation.z, rm[2] * afterBindTranslation.x + rm[6] * afterBindTranslation.y + rm[10] * afterBindTranslation.z);
|
|
403
413
|
return localTranslation;
|
|
404
414
|
}
|
|
415
|
+
getWorldMatrices() {
|
|
416
|
+
return this.runtimeSkeleton.worldMatrices;
|
|
417
|
+
}
|
|
405
418
|
getBoneWorldMatrices() {
|
|
406
419
|
// Convert Mat4[] to Float32Array for WebGPU compatibility
|
|
407
420
|
const boneCount = this.skeleton.bones.length;
|
|
@@ -444,6 +457,12 @@ export class Model {
|
|
|
444
457
|
this.runtimeMorph.weights[idx] = clampedWeight;
|
|
445
458
|
this.tweenState.morphActive[idx] = 0;
|
|
446
459
|
this.applyMorphs();
|
|
460
|
+
try {
|
|
461
|
+
Engine.getInstance().markVertexBufferDirty(this);
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
/* not registered yet */
|
|
465
|
+
}
|
|
447
466
|
return;
|
|
448
467
|
}
|
|
449
468
|
// Animated change
|
|
@@ -524,47 +543,27 @@ export class Model {
|
|
|
524
543
|
}
|
|
525
544
|
}
|
|
526
545
|
}
|
|
527
|
-
/**
|
|
528
|
-
* Load VMD animation file
|
|
529
|
-
*/
|
|
530
546
|
async loadVmd(vmdUrl) {
|
|
531
547
|
const vmdKeyFrames = await VMDLoader.load(vmdUrl);
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
548
|
+
this.resetAllBones();
|
|
549
|
+
this.resetAllMorphs();
|
|
550
|
+
// Build bone tracks: Map<boneName, Array<{boneName, frame, rotation, translation, interpolation, time}>>
|
|
551
|
+
const boneTracksByBone = {};
|
|
535
552
|
for (const keyFrame of vmdKeyFrames) {
|
|
536
553
|
for (const bf of keyFrame.boneFrames) {
|
|
537
|
-
if (!
|
|
538
|
-
|
|
539
|
-
|
|
554
|
+
if (!boneTracksByBone[bf.boneName])
|
|
555
|
+
boneTracksByBone[bf.boneName] = [];
|
|
556
|
+
boneTracksByBone[bf.boneName].push({
|
|
540
557
|
frame: bf.frame,
|
|
541
558
|
rotation: bf.rotation,
|
|
542
559
|
translation: bf.translation,
|
|
543
560
|
interpolation: rawInterpolationToBoneInterpolation(bf.interpolation),
|
|
544
561
|
});
|
|
545
562
|
}
|
|
546
|
-
for (const mf of keyFrame.morphFrames) {
|
|
547
|
-
if (!morphTracks[mf.morphName])
|
|
548
|
-
morphTracks[mf.morphName] = [];
|
|
549
|
-
morphTracks[mf.morphName].push({
|
|
550
|
-
frame: mf.frame,
|
|
551
|
-
weight: mf.weight,
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
563
|
}
|
|
555
|
-
this.loadAnimationData({ boneTracks, morphTracks });
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* Load animation from structured keyframe data.
|
|
559
|
-
* This is the primary way to set animation data — loadVmd delegates to this.
|
|
560
|
-
*/
|
|
561
|
-
loadAnimationData(data) {
|
|
562
|
-
this._animationData = data;
|
|
563
|
-
this.resetAllBones();
|
|
564
|
-
this.resetAllMorphs();
|
|
565
564
|
this.boneTracks = new Map();
|
|
566
|
-
for (const name in
|
|
567
|
-
const keyframes =
|
|
565
|
+
for (const name in boneTracksByBone) {
|
|
566
|
+
const keyframes = boneTracksByBone[name];
|
|
568
567
|
const sorted = [...keyframes].sort((a, b) => a.frame - b.frame);
|
|
569
568
|
this.boneTracks.set(name, sorted.map((kf) => ({
|
|
570
569
|
boneName: name,
|
|
@@ -575,9 +574,18 @@ export class Model {
|
|
|
575
574
|
time: kf.frame / VMD_FPS,
|
|
576
575
|
})));
|
|
577
576
|
}
|
|
577
|
+
// Build morph tracks: Map<morphName, Array<{morphName, frame, weight, time}>>
|
|
578
|
+
const morphTracksByMorph = {};
|
|
579
|
+
for (const keyFrame of vmdKeyFrames) {
|
|
580
|
+
for (const mf of keyFrame.morphFrames) {
|
|
581
|
+
if (!morphTracksByMorph[mf.morphName])
|
|
582
|
+
morphTracksByMorph[mf.morphName] = [];
|
|
583
|
+
morphTracksByMorph[mf.morphName].push({ frame: mf.frame, weight: mf.weight });
|
|
584
|
+
}
|
|
585
|
+
}
|
|
578
586
|
this.morphTracks = new Map();
|
|
579
|
-
for (const name in
|
|
580
|
-
const keyframes =
|
|
587
|
+
for (const name in morphTracksByMorph) {
|
|
588
|
+
const keyframes = morphTracksByMorph[name];
|
|
581
589
|
const sorted = [...keyframes].sort((a, b) => a.frame - b.frame);
|
|
582
590
|
this.morphTracks.set(name, sorted.map((kf) => ({
|
|
583
591
|
morphName: name,
|
|
@@ -602,14 +610,7 @@ export class Model {
|
|
|
602
610
|
this._hasAnimation = true;
|
|
603
611
|
this.animationTime = 0;
|
|
604
612
|
this.getPoseAtTime(0);
|
|
605
|
-
if (this.physics) {
|
|
606
|
-
this.computeWorldMatrices();
|
|
607
|
-
this.physics.reset(this.runtimeSkeleton.worldMatrices, this.skeleton.inverseBindMatrices);
|
|
608
|
-
}
|
|
609
613
|
}
|
|
610
|
-
/**
|
|
611
|
-
* Reset all bones to their default pose
|
|
612
|
-
*/
|
|
613
614
|
resetAllBones() {
|
|
614
615
|
for (let boneIdx = 0; boneIdx < this.skeleton.bones.length; boneIdx++) {
|
|
615
616
|
const localRot = this.runtimeSkeleton.localRotations[boneIdx];
|
|
@@ -619,9 +620,6 @@ export class Model {
|
|
|
619
620
|
localTrans.set(Vec3.zeros());
|
|
620
621
|
}
|
|
621
622
|
this.computeWorldMatrices();
|
|
622
|
-
if (this.physics) {
|
|
623
|
-
this.physics.reset(this.runtimeSkeleton.worldMatrices, this.skeleton.inverseBindMatrices);
|
|
624
|
-
}
|
|
625
623
|
}
|
|
626
624
|
resetAllMorphs() {
|
|
627
625
|
for (let morphIdx = 0; morphIdx < this.morphing.morphs.length; morphIdx++) {
|
|
@@ -631,27 +629,20 @@ export class Model {
|
|
|
631
629
|
this.morphsDirty = true;
|
|
632
630
|
this.applyMorphs();
|
|
633
631
|
}
|
|
634
|
-
/**
|
|
635
|
-
* Enable or disable IK solving
|
|
636
|
-
*/
|
|
637
632
|
setIKEnabled(enabled) {
|
|
638
633
|
this.ikEnabled = enabled;
|
|
639
634
|
}
|
|
640
|
-
/**
|
|
641
|
-
* Enable or disable physics simulation
|
|
642
|
-
*/
|
|
643
635
|
setPhysicsEnabled(enabled) {
|
|
644
636
|
this.physicsEnabled = enabled;
|
|
645
637
|
}
|
|
638
|
+
getPhysicsEnabled() {
|
|
639
|
+
return this.physicsEnabled;
|
|
640
|
+
}
|
|
646
641
|
playAnimation() {
|
|
647
642
|
if (!this._hasAnimation)
|
|
648
643
|
return;
|
|
649
644
|
this.isPaused = false;
|
|
650
645
|
this.isPlaying = true;
|
|
651
|
-
if (this.physics && this.animationTime === 0) {
|
|
652
|
-
this.computeWorldMatrices();
|
|
653
|
-
this.physics.reset(this.runtimeSkeleton.worldMatrices, this.skeleton.inverseBindMatrices);
|
|
654
|
-
}
|
|
655
646
|
}
|
|
656
647
|
pauseAnimation() {
|
|
657
648
|
if (!this.isPlaying || this.isPaused)
|
|
@@ -669,12 +660,6 @@ export class Model {
|
|
|
669
660
|
const clampedTime = Math.max(0, Math.min(time, this.animationDuration));
|
|
670
661
|
this.animationTime = clampedTime;
|
|
671
662
|
}
|
|
672
|
-
/**
|
|
673
|
-
* Get current animation progress
|
|
674
|
-
*/
|
|
675
|
-
getAnimationData() {
|
|
676
|
-
return this._animationData;
|
|
677
|
-
}
|
|
678
663
|
getAnimationProgress() {
|
|
679
664
|
const duration = this.animationDuration;
|
|
680
665
|
const percentage = duration > 0 ? (this.animationTime / duration) * 100 : 0;
|
|
@@ -684,9 +669,6 @@ export class Model {
|
|
|
684
669
|
percentage,
|
|
685
670
|
};
|
|
686
671
|
}
|
|
687
|
-
/**
|
|
688
|
-
* Binary search upper bound helper (static to avoid recreation)
|
|
689
|
-
*/
|
|
690
672
|
static upperBound(time, keyFrames, startIdx = 0) {
|
|
691
673
|
let left = startIdx, right = keyFrames.length;
|
|
692
674
|
while (left < right) {
|
|
@@ -698,10 +680,6 @@ export class Model {
|
|
|
698
680
|
}
|
|
699
681
|
return left;
|
|
700
682
|
}
|
|
701
|
-
/**
|
|
702
|
-
* Find keyframe index with caching optimization
|
|
703
|
-
* Uses cached index as starting point for faster lookup when time is close
|
|
704
|
-
*/
|
|
705
683
|
findKeyframeIndex(time, keyFrames, cachedIdx) {
|
|
706
684
|
if (keyFrames.length === 0)
|
|
707
685
|
return -1;
|
|
@@ -718,10 +696,6 @@ export class Model {
|
|
|
718
696
|
const idx = Model.upperBound(time, keyFrames, 0) - 1;
|
|
719
697
|
return idx;
|
|
720
698
|
}
|
|
721
|
-
/**
|
|
722
|
-
* Get pose at specific time (internal helper)
|
|
723
|
-
* Optimized for per-frame performance
|
|
724
|
-
*/
|
|
725
699
|
getPoseAtTime(time) {
|
|
726
700
|
if (!this._hasAnimation)
|
|
727
701
|
return;
|
|
@@ -787,12 +761,7 @@ export class Model {
|
|
|
787
761
|
this.morphsDirty = true; // Mark as dirty when animation sets morph weights
|
|
788
762
|
}
|
|
789
763
|
}
|
|
790
|
-
|
|
791
|
-
* Updates the model pose by recomputing all matrices.
|
|
792
|
-
* If animation is playing, applies animation pose first.
|
|
793
|
-
* deltaTime: Time elapsed since last update in seconds
|
|
794
|
-
* Returns true if vertices were modified (morphs changed)
|
|
795
|
-
*/
|
|
764
|
+
// Returns true when morphs changed (vertex buffer may need upload)
|
|
796
765
|
update(deltaTime) {
|
|
797
766
|
// Update tween time (in milliseconds)
|
|
798
767
|
this.tweenTimeMs += deltaTime * 1000;
|
|
@@ -827,9 +796,6 @@ export class Model {
|
|
|
827
796
|
// Recompute world matrices with final IK rotations applied to localRotations
|
|
828
797
|
this.computeWorldMatrices();
|
|
829
798
|
}
|
|
830
|
-
if (this.physicsEnabled && this.physics) {
|
|
831
|
-
this.physics.step(deltaTime, this.runtimeSkeleton.worldMatrices, this.skeleton.inverseBindMatrices);
|
|
832
|
-
}
|
|
833
799
|
return verticesChanged;
|
|
834
800
|
}
|
|
835
801
|
solveIKChains() {
|
|
@@ -1026,3 +992,4 @@ export class Model {
|
|
|
1026
992
|
computeWorld(i);
|
|
1027
993
|
}
|
|
1028
994
|
}
|
|
995
|
+
Model._nextId = 0;
|
package/dist/pmx-loader.js
CHANGED
|
@@ -218,7 +218,7 @@ export class PmxLoader {
|
|
|
218
218
|
this.getFloat32(),
|
|
219
219
|
];
|
|
220
220
|
// edgeSize float
|
|
221
|
-
const edgeSize = this.getFloat32();
|
|
221
|
+
const edgeSize = this.getFloat32() * 2; // double the size for better visibility
|
|
222
222
|
const textureIndex = this.getNonVertexIndex(this.textureIndexSize);
|
|
223
223
|
const sphereTextureIndex = this.getNonVertexIndex(this.textureIndexSize);
|
|
224
224
|
const sphereTextureMode = this.getUint8();
|