reze-engine 0.1.16 → 0.2.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 CHANGED
@@ -1,104 +1,104 @@
1
- # Reze Engine
2
-
3
- A lightweight engine built with WebGPU and TypeScript for real-time 3D anime character MMD model rendering.
4
-
5
- ## Features
6
-
7
- - Physics
8
- - Alpha blending
9
- - Post alpha eye rendering
10
- - Rim lighting
11
- - Bloom
12
- - Outlines
13
- - Toon shading with directional lights
14
- - MSAA 4x anti-aliasing
15
- - GPU-accelerated skinning
16
- - Bone rotation api
17
-
18
- ## Usage
19
-
20
- ```typescript
21
- export default function Home() {
22
- const canvasRef = useRef<HTMLCanvasElement>(null)
23
- const engineRef = useRef<Engine | null>(null)
24
- const [engineError, setEngineError] = useState<string | null>(null)
25
- const [loading, setLoading] = useState(true)
26
- const [stats, setStats] = useState<EngineStats>({
27
- fps: 0,
28
- frameTime: 0,
29
- gpuMemory: 0,
30
- })
31
- const [progress, setProgress] = useState(0)
32
-
33
- const initEngine = useCallback(async () => {
34
- if (canvasRef.current) {
35
- // Initialize engine
36
- try {
37
- const engine = new Engine(canvasRef.current)
38
- engineRef.current = engine
39
- await engine.init()
40
- await engine.loadModel("/models/塞尔凯特/塞尔凯特.pmx")
41
- setLoading(false)
42
-
43
- engine.runRenderLoop(() => {
44
- setStats(engine.getStats())
45
- })
46
- } catch (error) {
47
- setEngineError(error instanceof Error ? error.message : "Unknown error")
48
- }
49
- }
50
- }, [])
51
-
52
- useEffect(() => {
53
- void (async () => {
54
- initEngine()
55
- })()
56
-
57
- // Cleanup on unmount
58
- return () => {
59
- if (engineRef.current) {
60
- engineRef.current.dispose()
61
- }
62
- }
63
- }, [initEngine])
64
-
65
- useEffect(() => {
66
- if (loading) {
67
- const interval = setInterval(() => {
68
- setProgress((prev) => {
69
- if (prev >= 100) {
70
- return 0
71
- }
72
- return prev + 1
73
- })
74
- }, 50)
75
-
76
- return () => clearInterval(interval)
77
- }
78
- }, [loading])
79
-
80
- return (
81
- <div
82
- className="fixed inset-0 w-full h-full overflow-hidden touch-none"
83
- style={{
84
- background:
85
- "radial-gradient(ellipse at center, rgba(35, 35, 45, 0.8) 0%, rgba(35, 35, 45, 0.8) 8%, rgba(8, 8, 12, 0.95) 65%, rgba(0, 0, 0, 1) 100%)",
86
- }}
87
- >
88
- <Header stats={stats} />
89
-
90
- {engineError && (
91
- <div className="absolute inset-0 w-full h-full flex items-center justify-center text-white p-6">
92
- Engine Error: {engineError}
93
- </div>
94
- )}
95
- {loading && !engineError && (
96
- <div className="absolute inset-0 max-w-xs mx-auto w-full h-full flex items-center justify-center text-white p-6">
97
- <Progress value={progress} className="rounded-none" />
98
- </div>
99
- )}
100
- <canvas ref={canvasRef} className="absolute inset-0 w-full h-full touch-none z-1" />
101
- </div>
102
- )
103
- }
104
- ```
1
+ # Reze Engine
2
+
3
+ A lightweight engine built with WebGPU and TypeScript for real-time 3D anime character MMD model rendering.
4
+
5
+ ## Features
6
+
7
+ - Physics
8
+ - Alpha blending
9
+ - Post alpha eye rendering
10
+ - Rim lighting
11
+ - Bloom
12
+ - Outlines
13
+ - Toon shading with directional lights
14
+ - MSAA 4x anti-aliasing
15
+ - GPU-accelerated skinning
16
+ - Bone rotation api
17
+
18
+ ## Usage
19
+
20
+ ```typescript
21
+ export default function Home() {
22
+ const canvasRef = useRef<HTMLCanvasElement>(null)
23
+ const engineRef = useRef<Engine | null>(null)
24
+ const [engineError, setEngineError] = useState<string | null>(null)
25
+ const [loading, setLoading] = useState(true)
26
+ const [stats, setStats] = useState<EngineStats>({
27
+ fps: 0,
28
+ frameTime: 0,
29
+ gpuMemory: 0,
30
+ })
31
+ const [progress, setProgress] = useState(0)
32
+
33
+ const initEngine = useCallback(async () => {
34
+ if (canvasRef.current) {
35
+ // Initialize engine
36
+ try {
37
+ const engine = new Engine(canvasRef.current)
38
+ engineRef.current = engine
39
+ await engine.init()
40
+ await engine.loadModel("/models/塞尔凯特/塞尔凯特.pmx")
41
+ setLoading(false)
42
+
43
+ engine.runRenderLoop(() => {
44
+ setStats(engine.getStats())
45
+ })
46
+ } catch (error) {
47
+ setEngineError(error instanceof Error ? error.message : "Unknown error")
48
+ }
49
+ }
50
+ }, [])
51
+
52
+ useEffect(() => {
53
+ void (async () => {
54
+ initEngine()
55
+ })()
56
+
57
+ // Cleanup on unmount
58
+ return () => {
59
+ if (engineRef.current) {
60
+ engineRef.current.dispose()
61
+ }
62
+ }
63
+ }, [initEngine])
64
+
65
+ useEffect(() => {
66
+ if (loading) {
67
+ const interval = setInterval(() => {
68
+ setProgress((prev) => {
69
+ if (prev >= 100) {
70
+ return 0
71
+ }
72
+ return prev + 1
73
+ })
74
+ }, 50)
75
+
76
+ return () => clearInterval(interval)
77
+ }
78
+ }, [loading])
79
+
80
+ return (
81
+ <div
82
+ className="fixed inset-0 w-full h-full overflow-hidden touch-none"
83
+ style={{
84
+ background:
85
+ "radial-gradient(ellipse at center, rgba(35, 35, 45, 0.8) 0%, rgba(35, 35, 45, 0.8) 8%, rgba(8, 8, 12, 0.95) 65%, rgba(0, 0, 0, 1) 100%)",
86
+ }}
87
+ >
88
+ <Header stats={stats} />
89
+
90
+ {engineError && (
91
+ <div className="absolute inset-0 w-full h-full flex items-center justify-center text-white p-6">
92
+ Engine Error: {engineError}
93
+ </div>
94
+ )}
95
+ {loading && !engineError && (
96
+ <div className="absolute inset-0 max-w-xs mx-auto w-full h-full flex items-center justify-center text-white p-6">
97
+ <Progress value={progress} className="rounded-none" />
98
+ </div>
99
+ )}
100
+ <canvas ref={canvasRef} className="absolute inset-0 w-full h-full touch-none z-1" />
101
+ </div>
102
+ )
103
+ }
104
+ ```
package/dist/engine.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Camera } from "./camera";
2
- import { Quat, Vec3 } from "./math";
2
+ import { Quat } from "./math";
3
3
  export interface EngineStats {
4
4
  fps: number;
5
5
  frameTime: number;
@@ -77,6 +77,8 @@ export declare class Engine {
77
77
  private stats;
78
78
  private animationFrameId;
79
79
  private renderLoopCallback;
80
+ private animationFrames;
81
+ private animationTimeouts;
80
82
  constructor(canvas: HTMLCanvasElement);
81
83
  init(): Promise<void>;
82
84
  private createPipelines;
@@ -88,8 +90,11 @@ export declare class Engine {
88
90
  private handleResize;
89
91
  private setupCamera;
90
92
  private setupLighting;
91
- addLight(direction: Vec3, color: Vec3, intensity?: number): boolean;
92
- setAmbient(intensity: number): void;
93
+ private addLight;
94
+ private setAmbient;
95
+ loadAnimation(url: string): Promise<void>;
96
+ playAnimation(): void;
97
+ stopAnimation(): void;
93
98
  getStats(): EngineStats;
94
99
  runRenderLoop(callback?: () => void): void;
95
100
  stopRenderLoop(): void;
@@ -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
@@ -1,7 +1,8 @@
1
1
  import { Camera } from "./camera";
2
- import { Vec3 } from "./math";
2
+ import { Quat, Vec3 } from "./math";
3
3
  import { PmxLoader } from "./pmx-loader";
4
4
  import { Physics } from "./physics";
5
+ import { VMDLoader } from "./vmd-loader";
5
6
  export class Engine {
6
7
  constructor(canvas) {
7
8
  this.cameraMatrixData = new Float32Array(36);
@@ -11,9 +12,9 @@ export class Engine {
11
12
  this.sampleCount = 4; // MSAA 4x
12
13
  // Bloom settings
13
14
  this.bloomThreshold = 0.3;
14
- this.bloomIntensity = 0.1;
15
+ this.bloomIntensity = 0.12;
15
16
  // Rim light settings
16
- this.rimLightIntensity = 0.35;
17
+ this.rimLightIntensity = 0.45;
17
18
  this.rimLightPower = 2.0;
18
19
  this.rimLightColor = [1.0, 1.0, 1.0];
19
20
  this.currentModel = null;
@@ -34,6 +35,8 @@ export class Engine {
34
35
  };
35
36
  this.animationFrameId = null;
36
37
  this.renderLoopCallback = null;
38
+ this.animationFrames = [];
39
+ this.animationTimeouts = [];
37
40
  this.opaqueNonEyeNonHairDraws = [];
38
41
  this.eyeDraws = [];
39
42
  this.hairDrawsOverEyes = [];
@@ -1232,10 +1235,10 @@ export class Engine {
1232
1235
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
1233
1236
  });
1234
1237
  this.lightCount = 0;
1235
- this.setAmbient(0.96);
1236
- this.addLight(new Vec3(-0.5, -0.8, 0.5).normalize(), new Vec3(1.0, 0.95, 0.9), 0.12);
1237
- this.addLight(new Vec3(0.7, -0.5, 0.3).normalize(), new Vec3(0.8, 0.85, 1.0), 0.1);
1238
- this.addLight(new Vec3(0.3, -0.5, -1.0).normalize(), new Vec3(0.9, 0.9, 1.0), 0.08);
1238
+ this.setAmbient(1);
1239
+ this.addLight(new Vec3(-0.5, -0.8, 0.5).normalize(), new Vec3(1.0, 0.95, 0.9), 0.02);
1240
+ this.addLight(new Vec3(0.7, -0.5, 0.3).normalize(), new Vec3(0.8, 0.85, 1.0), 0.015);
1241
+ this.addLight(new Vec3(0.3, -0.5, -1.0).normalize(), new Vec3(0.9, 0.9, 1.0), 0.01);
1239
1242
  this.device.queue.writeBuffer(this.lightUniformBuffer, 0, this.lightData);
1240
1243
  }
1241
1244
  addLight(direction, color, intensity = 1.0) {
@@ -1258,6 +1261,107 @@ export class Engine {
1258
1261
  setAmbient(intensity) {
1259
1262
  this.lightData[0] = intensity;
1260
1263
  }
1264
+ async loadAnimation(url) {
1265
+ const frames = await VMDLoader.load(url);
1266
+ this.animationFrames = frames;
1267
+ console.log(this.animationFrames);
1268
+ }
1269
+ playAnimation() {
1270
+ if (this.animationFrames.length === 0)
1271
+ return;
1272
+ this.stopAnimation();
1273
+ const allBoneKeyFrames = [];
1274
+ for (const keyFrame of this.animationFrames) {
1275
+ for (const boneFrame of keyFrame.boneFrames) {
1276
+ allBoneKeyFrames.push({
1277
+ boneName: boneFrame.boneName,
1278
+ time: keyFrame.time,
1279
+ rotation: boneFrame.rotation,
1280
+ });
1281
+ }
1282
+ }
1283
+ const boneKeyFramesByBone = new Map();
1284
+ for (const boneKeyFrame of allBoneKeyFrames) {
1285
+ if (!boneKeyFramesByBone.has(boneKeyFrame.boneName)) {
1286
+ boneKeyFramesByBone.set(boneKeyFrame.boneName, []);
1287
+ }
1288
+ boneKeyFramesByBone.get(boneKeyFrame.boneName).push(boneKeyFrame);
1289
+ }
1290
+ for (const keyFrames of boneKeyFramesByBone.values()) {
1291
+ keyFrames.sort((a, b) => a.time - b.time);
1292
+ }
1293
+ const time0Rotations = [];
1294
+ const bonesWithTime0 = new Set();
1295
+ for (const [boneName, keyFrames] of boneKeyFramesByBone.entries()) {
1296
+ if (keyFrames.length > 0 && keyFrames[0].time === 0) {
1297
+ time0Rotations.push({
1298
+ boneName: boneName,
1299
+ rotation: keyFrames[0].rotation,
1300
+ });
1301
+ bonesWithTime0.add(boneName);
1302
+ }
1303
+ }
1304
+ if (this.currentModel) {
1305
+ if (time0Rotations.length > 0) {
1306
+ const boneNames = time0Rotations.map((r) => r.boneName);
1307
+ const rotations = time0Rotations.map((r) => r.rotation);
1308
+ this.rotateBones(boneNames, rotations, 0);
1309
+ }
1310
+ const skeleton = this.currentModel.getSkeleton();
1311
+ const bonesToReset = [];
1312
+ for (const bone of skeleton.bones) {
1313
+ if (!bonesWithTime0.has(bone.name)) {
1314
+ bonesToReset.push(bone.name);
1315
+ }
1316
+ }
1317
+ if (bonesToReset.length > 0) {
1318
+ const identityQuat = new Quat(0, 0, 0, 1);
1319
+ const identityQuats = new Array(bonesToReset.length).fill(identityQuat);
1320
+ this.rotateBones(bonesToReset, identityQuats, 0);
1321
+ }
1322
+ this.currentModel.evaluatePose();
1323
+ // Reset physics immediately and upload matrices to prevent A-pose flash
1324
+ if (this.physics) {
1325
+ const worldMats = this.currentModel.getBoneWorldMatrices();
1326
+ this.physics.reset(worldMats, this.currentModel.getBoneInverseBindMatrices());
1327
+ // Upload matrices immediately so next frame shows correct pose
1328
+ this.device.queue.writeBuffer(this.worldMatrixBuffer, 0, worldMats.buffer, worldMats.byteOffset, worldMats.byteLength);
1329
+ this.computeSkinMatrices();
1330
+ }
1331
+ }
1332
+ for (const [_, keyFrames] of boneKeyFramesByBone.entries()) {
1333
+ for (let i = 0; i < keyFrames.length; i++) {
1334
+ const boneKeyFrame = keyFrames[i];
1335
+ const previousBoneKeyFrame = i > 0 ? keyFrames[i - 1] : null;
1336
+ if (boneKeyFrame.time === 0)
1337
+ continue;
1338
+ let durationMs = 0;
1339
+ if (i === 0) {
1340
+ durationMs = boneKeyFrame.time * 1000;
1341
+ }
1342
+ else if (previousBoneKeyFrame) {
1343
+ durationMs = (boneKeyFrame.time - previousBoneKeyFrame.time) * 1000;
1344
+ }
1345
+ const scheduleTime = i > 0 && previousBoneKeyFrame ? previousBoneKeyFrame.time : 0;
1346
+ const delayMs = scheduleTime * 1000;
1347
+ if (delayMs <= 0) {
1348
+ this.rotateBones([boneKeyFrame.boneName], [boneKeyFrame.rotation], durationMs);
1349
+ }
1350
+ else {
1351
+ const timeoutId = window.setTimeout(() => {
1352
+ this.rotateBones([boneKeyFrame.boneName], [boneKeyFrame.rotation], durationMs);
1353
+ }, delayMs);
1354
+ this.animationTimeouts.push(timeoutId);
1355
+ }
1356
+ }
1357
+ }
1358
+ }
1359
+ stopAnimation() {
1360
+ for (const timeoutId of this.animationTimeouts) {
1361
+ clearTimeout(timeoutId);
1362
+ }
1363
+ this.animationTimeouts = [];
1364
+ }
1261
1365
  getStats() {
1262
1366
  return { ...this.stats };
1263
1367
  }
@@ -1281,6 +1385,7 @@ export class Engine {
1281
1385
  }
1282
1386
  dispose() {
1283
1387
  this.stopRenderLoop();
1388
+ this.stopAnimation();
1284
1389
  if (this.camera)
1285
1390
  this.camera.detachControl();
1286
1391
  if (this.resizeObserver) {
@@ -1899,19 +2004,13 @@ export class Engine {
1899
2004
  colorAttachment.view = this.sceneRenderTextureView;
1900
2005
  }
1901
2006
  }
1902
- // Update model pose and physics
1903
2007
  updateModelPose(deltaTime) {
1904
- // Step 1: Animation evaluation (computes matrices to CPU memory, no upload yet)
1905
2008
  this.currentModel.evaluatePose();
1906
- // Step 2: Get world matrices (still in CPU memory)
1907
2009
  const worldMats = this.currentModel.getBoneWorldMatrices();
1908
- // Step 3: Physics modifies matrices in-place
1909
2010
  if (this.physics) {
1910
2011
  this.physics.step(deltaTime, worldMats, this.currentModel.getBoneInverseBindMatrices());
1911
2012
  }
1912
- // Step 4: Upload ONCE with final result (animation + physics)
1913
2013
  this.device.queue.writeBuffer(this.worldMatrixBuffer, 0, worldMats.buffer, worldMats.byteOffset, worldMats.byteLength);
1914
- // Step 5: GPU skinning
1915
2014
  this.computeSkinMatrices();
1916
2015
  }
1917
2016
  // Compute skin matrices on GPU
package/dist/physics.d.ts CHANGED
@@ -72,6 +72,7 @@ export declare class Physics {
72
72
  private createAmmoRigidbodies;
73
73
  private createAmmoJoints;
74
74
  private normalizeAngle;
75
+ reset(boneWorldMatrices: Float32Array, boneInverseBindMatrices: Float32Array): void;
75
76
  step(dt: number, boneWorldMatrices: Float32Array, boneInverseBindMatrices: Float32Array): void;
76
77
  private computeBodyOffsets;
77
78
  private positionBodiesFromBones;
@@ -1 +1 @@
1
- {"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../src/physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAIzC,oBAAY,cAAc;IACxB,MAAM,IAAI;IACV,GAAG,IAAI;IACP,OAAO,IAAI;CACZ;AAED,oBAAY,aAAa;IACvB,MAAM,IAAI;IACV,OAAO,IAAI;IACX,SAAS,IAAI;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,cAAc,CAAA;IACrB,IAAI,EAAE,IAAI,CAAA;IACV,aAAa,EAAE,IAAI,CAAA;IACnB,aAAa,EAAE,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,aAAa,CAAA;IACnB,uBAAuB,EAAE,IAAI,CAAA;IAC7B,gBAAgB,CAAC,EAAE,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,IAAI,CAAA;IACd,QAAQ,EAAE,IAAI,CAAA;IACd,WAAW,EAAE,IAAI,CAAA;IACjB,WAAW,EAAE,IAAI,CAAA;IACjB,WAAW,EAAE,IAAI,CAAA;IACjB,WAAW,EAAE,IAAI,CAAA;IACjB,cAAc,EAAE,IAAI,CAAA;IACpB,cAAc,EAAE,IAAI,CAAA;CACrB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,IAAI,CAA4B;IAExC,OAAO,CAAC,aAAa,CAAY;IAEjC,OAAO,CAAC,eAAe,CAAY;IAEnC,OAAO,CAAC,eAAe,CAAY;IACnC,OAAO,CAAC,sBAAsB,CAAQ;IACtC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,oCAAoC,CAAO;IAEnD,OAAO,CAAC,UAAU,CAAY;gBAElB,WAAW,EAAE,SAAS,EAAE,EAAE,MAAM,GAAE,KAAK,EAAO;YAM5C,QAAQ;IAatB,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI;IAU/B,UAAU,IAAI,IAAI;IAIlB,cAAc,IAAI,SAAS,EAAE;IAI7B,SAAS,IAAI,KAAK,EAAE;IAIpB,sBAAsB,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC;IA6CnE,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,qBAAqB;IA+F7B,OAAO,CAAC,gBAAgB;IA0KxB,OAAO,CAAC,cAAc;IActB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,uBAAuB,EAAE,YAAY,GAAG,IAAI;IAsC9F,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,uBAAuB;IAkD/B,OAAO,CAAC,aAAa;IAwDrB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,2BAA2B;CAqCpC"}
1
+ {"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../src/physics.ts"],"names":[],"mappings":"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"}
package/dist/physics.js CHANGED
@@ -329,6 +329,64 @@ export class Physics {
329
329
  }
330
330
  return angle;
331
331
  }
332
+ // Reset physics state (reposition bodies, clear velocities)
333
+ // Following babylon-mmd pattern: initialize all rigid body positions from current bone poses
334
+ // Call this when starting a new animation to prevent physics instability from sudden pose changes
335
+ reset(boneWorldMatrices, boneInverseBindMatrices) {
336
+ if (!this.ammoInitialized || !this.ammo || !this.dynamicsWorld) {
337
+ return;
338
+ }
339
+ const boneCount = boneWorldMatrices.length / 16;
340
+ const Ammo = this.ammo;
341
+ // Ensure body offsets are computed
342
+ if (!this.rigidbodiesInitialized) {
343
+ this.computeBodyOffsets(boneInverseBindMatrices, boneCount);
344
+ this.rigidbodiesInitialized = true;
345
+ }
346
+ // Reposition ALL rigid bodies from current bone poses (like babylon-mmd initialize)
347
+ // This ensures all bodies are correctly positioned before physics starts
348
+ for (let i = 0; i < this.rigidbodies.length; i++) {
349
+ const rb = this.rigidbodies[i];
350
+ const ammoBody = this.ammoRigidbodies[i];
351
+ if (!ammoBody || rb.boneIndex < 0 || rb.boneIndex >= boneCount)
352
+ continue;
353
+ const boneIdx = rb.boneIndex;
354
+ const worldMatIdx = boneIdx * 16;
355
+ // Get bone world matrix
356
+ const boneWorldMat = new Mat4(boneWorldMatrices.subarray(worldMatIdx, worldMatIdx + 16));
357
+ // Compute body world matrix: bodyWorld = boneWorld × bodyOffsetMatrix
358
+ // (like babylon-mmd: bodyWorldMatrix = bodyOffsetMatrix.multiplyToRef(bodyWorldMatrix))
359
+ const bodyOffsetMatrix = rb.bodyOffsetMatrix || rb.bodyOffsetMatrixInverse.inverse();
360
+ const bodyWorldMatrix = boneWorldMat.multiply(bodyOffsetMatrix);
361
+ const worldPos = bodyWorldMatrix.getPosition();
362
+ const worldRot = bodyWorldMatrix.toQuat();
363
+ // Set transform matrix
364
+ const transform = new Ammo.btTransform();
365
+ const pos = new Ammo.btVector3(worldPos.x, worldPos.y, worldPos.z);
366
+ const quat = new Ammo.btQuaternion(worldRot.x, worldRot.y, worldRot.z, worldRot.w);
367
+ transform.setOrigin(pos);
368
+ transform.setRotation(quat);
369
+ ammoBody.setWorldTransform(transform);
370
+ ammoBody.getMotionState().setWorldTransform(transform);
371
+ // Clear velocities for all rigidbodies
372
+ if (!this.zeroVector) {
373
+ this.zeroVector = new Ammo.btVector3(0, 0, 0);
374
+ }
375
+ ammoBody.setLinearVelocity(this.zeroVector);
376
+ ammoBody.setAngularVelocity(this.zeroVector);
377
+ // Explicitly activate dynamic rigidbodies after reset (wake them up)
378
+ // This is critical for dress pieces and other dynamic bodies to prevent teleporting
379
+ if (rb.type === RigidbodyType.Dynamic) {
380
+ ammoBody.activate(true); // Wake up the body
381
+ }
382
+ Ammo.destroy(pos);
383
+ Ammo.destroy(quat);
384
+ }
385
+ // Step simulation once to stabilize (like babylon-mmd)
386
+ if (this.dynamicsWorld.stepSimulation) {
387
+ this.dynamicsWorld.stepSimulation(0, 0, 0);
388
+ }
389
+ }
332
390
  // Syncs bones to rigidbodies, simulates dynamics, solves constraints
333
391
  // Modifies boneWorldMatrices in-place for dynamic rigidbodies that drive bones
334
392
  step(dt, boneWorldMatrices, boneInverseBindMatrices) {
@@ -0,0 +1,25 @@
1
+ import { Quat } from "./math";
2
+ export interface BoneFrame {
3
+ boneName: string;
4
+ frame: number;
5
+ rotation: Quat;
6
+ }
7
+ export interface VMDKeyFrame {
8
+ time: number;
9
+ boneFrames: BoneFrame[];
10
+ }
11
+ export declare class VMDLoader {
12
+ private view;
13
+ private offset;
14
+ private decoder;
15
+ private constructor();
16
+ static load(url: string): Promise<VMDKeyFrame[]>;
17
+ static loadFromBuffer(buffer: ArrayBuffer): VMDKeyFrame[];
18
+ private parse;
19
+ private readBoneFrame;
20
+ private getUint32;
21
+ private getFloat32;
22
+ private getString;
23
+ private skip;
24
+ }
25
+ //# sourceMappingURL=vmd-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vmd-loader.d.ts","sourceRoot":"","sources":["../src/vmd-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,IAAI,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,SAAS,EAAE,CAAA;CACxB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAa;IAE5B,OAAO;WAWM,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,EAAE;IAKzD,OAAO,CAAC,KAAK;IA8Db,OAAO,CAAC,aAAa;IA+CrB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,IAAI;CAMb"}