reze-engine 0.2.9 → 0.2.11

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 CHANGED
@@ -1,8 +1,10 @@
1
- import { Quat } from "./math";
1
+ import { Quat, Vec3 } from "./math";
2
2
  export type EngineOptions = {
3
3
  ambient?: number;
4
4
  bloomIntensity?: number;
5
5
  rimLightIntensity?: number;
6
+ cameraDistance?: number;
7
+ cameraTarget?: Vec3;
6
8
  };
7
9
  export interface EngineStats {
8
10
  fps: number;
@@ -17,6 +19,8 @@ export declare class Engine {
17
19
  private camera;
18
20
  private cameraUniformBuffer;
19
21
  private cameraMatrixData;
22
+ private cameraDistance;
23
+ private cameraTarget;
20
24
  private lightUniformBuffer;
21
25
  private lightData;
22
26
  private lightCount;
@@ -94,6 +98,8 @@ export declare class Engine {
94
98
  private animationFrames;
95
99
  private animationTimeouts;
96
100
  private gpuMemoryMB;
101
+ private hasAnimation;
102
+ private playingAnimation;
97
103
  constructor(canvas: HTMLCanvasElement, options?: EngineOptions);
98
104
  init(): Promise<void>;
99
105
  private createPipelines;
@@ -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
@@ -6,6 +6,8 @@ import { VMDLoader } from "./vmd-loader";
6
6
  export class Engine {
7
7
  constructor(canvas, options) {
8
8
  this.cameraMatrixData = new Float32Array(36);
9
+ this.cameraDistance = 26.6;
10
+ this.cameraTarget = new Vec3(0, 12.5, 0);
9
11
  this.lightData = new Float32Array(64);
10
12
  this.lightCount = 0;
11
13
  this.resizeObserver = null;
@@ -51,11 +53,15 @@ export class Engine {
51
53
  this.animationFrames = [];
52
54
  this.animationTimeouts = [];
53
55
  this.gpuMemoryMB = 0;
56
+ this.hasAnimation = false; // Set to true when loadAnimation is called
57
+ this.playingAnimation = false; // Set to true when playAnimation is called
54
58
  this.canvas = canvas;
55
59
  if (options) {
56
60
  this.ambient = options.ambient ?? 1.0;
57
61
  this.bloomIntensity = options.bloomIntensity ?? 0.12;
58
62
  this.rimLightIntensity = options.rimLightIntensity ?? 0.45;
63
+ this.cameraDistance = options.cameraDistance ?? 26.6;
64
+ this.cameraTarget = options.cameraTarget ?? new Vec3(0, 12.5, 0);
59
65
  }
60
66
  }
61
67
  // Step 1: Get WebGPU device and context
@@ -1219,7 +1225,7 @@ export class Engine {
1219
1225
  size: 40 * 4,
1220
1226
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
1221
1227
  });
1222
- this.camera = new Camera(Math.PI, Math.PI / 2.5, 26.6, new Vec3(0, 12.5, 0));
1228
+ this.camera = new Camera(Math.PI, Math.PI / 2.5, this.cameraDistance, this.cameraTarget);
1223
1229
  this.camera.aspect = this.canvas.width / this.canvas.height;
1224
1230
  this.camera.attachControl(this.canvas);
1225
1231
  }
@@ -1260,11 +1266,13 @@ export class Engine {
1260
1266
  async loadAnimation(url) {
1261
1267
  const frames = await VMDLoader.load(url);
1262
1268
  this.animationFrames = frames;
1269
+ this.hasAnimation = true;
1263
1270
  }
1264
1271
  playAnimation() {
1265
1272
  if (this.animationFrames.length === 0)
1266
1273
  return;
1267
1274
  this.stopAnimation();
1275
+ this.playingAnimation = true;
1268
1276
  const allBoneKeyFrames = [];
1269
1277
  for (const keyFrame of this.animationFrames) {
1270
1278
  for (const boneFrame of keyFrame.boneFrames) {
@@ -1314,9 +1322,9 @@ export class Engine {
1314
1322
  const identityQuats = new Array(bonesToReset.length).fill(identityQuat);
1315
1323
  this.rotateBones(bonesToReset, identityQuats, 0);
1316
1324
  }
1317
- this.currentModel.evaluatePose();
1318
1325
  // Reset physics immediately and upload matrices to prevent A-pose flash
1319
1326
  if (this.physics) {
1327
+ this.currentModel.evaluatePose();
1320
1328
  const worldMats = this.currentModel.getBoneWorldMatrices();
1321
1329
  this.physics.reset(worldMats, this.currentModel.getBoneInverseBindMatrices());
1322
1330
  // Upload matrices immediately so next frame shows correct pose
@@ -1358,6 +1366,7 @@ export class Engine {
1358
1366
  clearTimeout(timeoutId);
1359
1367
  }
1360
1368
  this.animationTimeouts = [];
1369
+ this.playingAnimation = false;
1361
1370
  }
1362
1371
  getStats() {
1363
1372
  return { ...this.stats };
@@ -1762,6 +1771,13 @@ export class Engine {
1762
1771
  // Use single encoder for both compute and render (reduces sync points)
1763
1772
  const encoder = this.device.createCommandEncoder();
1764
1773
  this.updateModelPose(deltaTime, encoder);
1774
+ // Hide model if animation is loaded but not playing yet (prevents A-pose flash)
1775
+ // Still update physics and poses, just don't render visually
1776
+ if (this.hasAnimation && !this.playingAnimation) {
1777
+ // Submit encoder to ensure matrices are uploaded and physics initializes
1778
+ this.device.queue.submit([encoder.finish()]);
1779
+ return;
1780
+ }
1765
1781
  const pass = encoder.beginRenderPass(this.renderPassDescriptor);
1766
1782
  pass.setVertexBuffer(0, this.vertexBuffer);
1767
1783
  pass.setVertexBuffer(1, this.jointsBuffer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "A WebGPU-based MMD model renderer",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/engine.ts CHANGED
@@ -9,6 +9,8 @@ export type EngineOptions = {
9
9
  ambient?: number
10
10
  bloomIntensity?: number
11
11
  rimLightIntensity?: number
12
+ cameraDistance?: number
13
+ cameraTarget?: Vec3
12
14
  }
13
15
 
14
16
  export interface EngineStats {
@@ -38,6 +40,8 @@ export class Engine {
38
40
  private camera!: Camera
39
41
  private cameraUniformBuffer!: GPUBuffer
40
42
  private cameraMatrixData = new Float32Array(36)
43
+ private cameraDistance: number = 26.6
44
+ private cameraTarget: Vec3 = new Vec3(0, 12.5, 0)
41
45
  private lightUniformBuffer!: GPUBuffer
42
46
  private lightData = new Float32Array(64)
43
47
  private lightCount = 0
@@ -133,6 +137,8 @@ export class Engine {
133
137
  private animationFrames: VMDKeyFrame[] = []
134
138
  private animationTimeouts: number[] = []
135
139
  private gpuMemoryMB: number = 0
140
+ private hasAnimation = false // Set to true when loadAnimation is called
141
+ private playingAnimation = false // Set to true when playAnimation is called
136
142
 
137
143
  constructor(canvas: HTMLCanvasElement, options?: EngineOptions) {
138
144
  this.canvas = canvas
@@ -140,6 +146,8 @@ export class Engine {
140
146
  this.ambient = options.ambient ?? 1.0
141
147
  this.bloomIntensity = options.bloomIntensity ?? 0.12
142
148
  this.rimLightIntensity = options.rimLightIntensity ?? 0.45
149
+ this.cameraDistance = options.cameraDistance ?? 26.6
150
+ this.cameraTarget = options.cameraTarget ?? new Vec3(0, 12.5, 0)
143
151
  }
144
152
  }
145
153
 
@@ -1360,7 +1368,7 @@ export class Engine {
1360
1368
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
1361
1369
  })
1362
1370
 
1363
- this.camera = new Camera(Math.PI, Math.PI / 2.5, 26.6, new Vec3(0, 12.5, 0))
1371
+ this.camera = new Camera(Math.PI, Math.PI / 2.5, this.cameraDistance, this.cameraTarget)
1364
1372
 
1365
1373
  this.camera.aspect = this.canvas.width / this.canvas.height
1366
1374
  this.camera.attachControl(this.canvas)
@@ -1409,12 +1417,14 @@ export class Engine {
1409
1417
  public async loadAnimation(url: string) {
1410
1418
  const frames = await VMDLoader.load(url)
1411
1419
  this.animationFrames = frames
1420
+ this.hasAnimation = true
1412
1421
  }
1413
1422
 
1414
1423
  public playAnimation() {
1415
1424
  if (this.animationFrames.length === 0) return
1416
1425
 
1417
1426
  this.stopAnimation()
1427
+ this.playingAnimation = true
1418
1428
 
1419
1429
  const allBoneKeyFrames: BoneKeyFrame[] = []
1420
1430
  for (const keyFrame of this.animationFrames) {
@@ -1472,10 +1482,10 @@ export class Engine {
1472
1482
  this.rotateBones(bonesToReset, identityQuats, 0)
1473
1483
  }
1474
1484
 
1475
- this.currentModel.evaluatePose()
1476
-
1477
1485
  // Reset physics immediately and upload matrices to prevent A-pose flash
1478
1486
  if (this.physics) {
1487
+ this.currentModel.evaluatePose()
1488
+
1479
1489
  const worldMats = this.currentModel.getBoneWorldMatrices()
1480
1490
  this.physics.reset(worldMats, this.currentModel.getBoneInverseBindMatrices())
1481
1491
 
@@ -1526,6 +1536,7 @@ export class Engine {
1526
1536
  clearTimeout(timeoutId)
1527
1537
  }
1528
1538
  this.animationTimeouts = []
1539
+ this.playingAnimation = false
1529
1540
  }
1530
1541
 
1531
1542
  public getStats(): EngineStats {
@@ -2001,6 +2012,14 @@ export class Engine {
2001
2012
 
2002
2013
  this.updateModelPose(deltaTime, encoder)
2003
2014
 
2015
+ // Hide model if animation is loaded but not playing yet (prevents A-pose flash)
2016
+ // Still update physics and poses, just don't render visually
2017
+ if (this.hasAnimation && !this.playingAnimation) {
2018
+ // Submit encoder to ensure matrices are uploaded and physics initializes
2019
+ this.device.queue.submit([encoder.finish()])
2020
+ return
2021
+ }
2022
+
2004
2023
  const pass = encoder.beginRenderPass(this.renderPassDescriptor)
2005
2024
 
2006
2025
  pass.setVertexBuffer(0, this.vertexBuffer)