reze-engine 0.2.15 → 0.2.17
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 +1 -5
- package/dist/engine.d.ts +0 -8
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +9 -154
- package/package.json +1 -1
- package/src/engine.ts +10 -162
package/README.md
CHANGED
|
@@ -26,11 +26,7 @@ export default function Scene() {
|
|
|
26
26
|
const initEngine = useCallback(async () => {
|
|
27
27
|
if (canvasRef.current) {
|
|
28
28
|
try {
|
|
29
|
-
const engine = new Engine(canvasRef.current
|
|
30
|
-
ambient: 1.0,
|
|
31
|
-
rimLightIntensity: 0.1,
|
|
32
|
-
bloomIntensity: 0.1,
|
|
33
|
-
})
|
|
29
|
+
const engine = new Engine(canvasRef.current)
|
|
34
30
|
engineRef.current = engine
|
|
35
31
|
await engine.init()
|
|
36
32
|
await engine.loadModel("/models/塞尔凯特/塞尔凯特.pmx")
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Quat, Vec3 } from "./math";
|
|
2
2
|
export type EngineOptions = {
|
|
3
|
-
ambient?: number;
|
|
4
3
|
ambientColor?: Vec3;
|
|
5
4
|
bloomIntensity?: number;
|
|
6
5
|
rimLightIntensity?: number;
|
|
@@ -10,7 +9,6 @@ export type EngineOptions = {
|
|
|
10
9
|
export interface EngineStats {
|
|
11
10
|
fps: number;
|
|
12
11
|
frameTime: number;
|
|
13
|
-
gpuMemory: number;
|
|
14
12
|
}
|
|
15
13
|
export declare class Engine {
|
|
16
14
|
private canvas;
|
|
@@ -24,7 +22,6 @@ export declare class Engine {
|
|
|
24
22
|
private cameraTarget;
|
|
25
23
|
private lightUniformBuffer;
|
|
26
24
|
private lightData;
|
|
27
|
-
private lightCount;
|
|
28
25
|
private vertexBuffer;
|
|
29
26
|
private indexBuffer?;
|
|
30
27
|
private resizeObserver;
|
|
@@ -52,7 +49,6 @@ export declare class Engine {
|
|
|
52
49
|
private readonly STENCIL_EYE_VALUE;
|
|
53
50
|
private readonly COMPUTE_WORKGROUP_SIZE;
|
|
54
51
|
private readonly BLOOM_DOWNSCALE_FACTOR;
|
|
55
|
-
private ambient;
|
|
56
52
|
private ambientColor;
|
|
57
53
|
private sceneRenderTexture;
|
|
58
54
|
private sceneRenderTextureView;
|
|
@@ -99,7 +95,6 @@ export declare class Engine {
|
|
|
99
95
|
private renderLoopCallback;
|
|
100
96
|
private animationFrames;
|
|
101
97
|
private animationTimeouts;
|
|
102
|
-
private gpuMemoryMB;
|
|
103
98
|
private hasAnimation;
|
|
104
99
|
private playingAnimation;
|
|
105
100
|
private breathingTimeout;
|
|
@@ -115,8 +110,6 @@ export declare class Engine {
|
|
|
115
110
|
private handleResize;
|
|
116
111
|
private setupCamera;
|
|
117
112
|
private setupLighting;
|
|
118
|
-
private addLight;
|
|
119
|
-
private setAmbient;
|
|
120
113
|
private setAmbientColor;
|
|
121
114
|
loadAnimation(url: string): Promise<void>;
|
|
122
115
|
playAnimation(options?: {
|
|
@@ -143,6 +136,5 @@ export declare class Engine {
|
|
|
143
136
|
private computeSkinMatrices;
|
|
144
137
|
private drawOutlines;
|
|
145
138
|
private updateStats;
|
|
146
|
-
private calculateGpuMemory;
|
|
147
139
|
}
|
|
148
140
|
//# sourceMappingURL=engine.d.ts.map
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAMnC,MAAM,MAAM,aAAa,GAAG;IAC1B,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAMnC,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,CAAC,EAAE,IAAI,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,IAAI,CAAA;CACpB,CAAA;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;CAClB;AAeD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,kBAAkB,CAAmB;IAC7C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,mBAAmB,CAAY;IACvC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,cAAc,CAAe;IACrC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,kBAAkB,CAAY;IACtC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,WAAW,CAAC,CAAW;IAC/B,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,YAAY,CAAa;IAEjC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,oBAAoB,CAAoB;IAChD,OAAO,CAAC,uBAAuB,CAAoB;IACnD,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,mBAAmB,CAAoB;IAC/C,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,gBAAgB,CAAC,CAAW;IACpC,OAAO,CAAC,iBAAiB,CAAC,CAAW;IACrC,OAAO,CAAC,uBAAuB,CAAC,CAAW;IAC3C,OAAO,CAAC,yBAAyB,CAAC,CAAoB;IACtD,OAAO,CAAC,0BAA0B,CAAC,CAAc;IACjD,OAAO,CAAC,eAAe,CAAC,CAAW;IACnC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAChC,OAAO,CAAC,oBAAoB,CAA0B;IAEtD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAI;IACtC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAK;IAC5C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAI;IAE3C,OAAO,CAAC,YAAY,CAAgC;IAEpD,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,sBAAsB,CAAiB;IAC/C,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,iBAAiB,CAAa;IAEtC,OAAO,CAAC,oBAAoB,CAAoB;IAChD,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,oBAAoB,CAAoB;IAEhD,OAAO,CAAC,oBAAoB,CAAY;IACxC,OAAO,CAAC,mBAAmB,CAAY;IACvC,OAAO,CAAC,oBAAoB,CAAY;IACxC,OAAO,CAAC,oBAAoB,CAAY;IACxC,OAAO,CAAC,aAAa,CAAa;IAElC,OAAO,CAAC,qBAAqB,CAAC,CAAc;IAC5C,OAAO,CAAC,mBAAmB,CAAC,CAAc;IAC1C,OAAO,CAAC,mBAAmB,CAAC,CAAc;IAC1C,OAAO,CAAC,qBAAqB,CAAC,CAAc;IAE5C,OAAO,CAAC,cAAc,CAAe;IACrC,OAAO,CAAC,cAAc,CAAe;IAErC,OAAO,CAAC,iBAAiB,CAAe;IAExC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,YAAY,CAAgC;IAEpD,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,oBAAoB,CAAiB;IAC7C,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,kBAAkB,CAAiB;IAC3C,OAAO,CAAC,eAAe,CAAiB;IACxC,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,uBAAuB,CAAiB;IAEhD,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,qBAAqB,CAAI;IACjC,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,KAAK,CAGZ;IACD,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,kBAAkB,CAA4B;IAEtD,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,sBAAsB,CAA+B;gBAEjD,MAAM,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,aAAa;IAYjD,IAAI;IA8BjB,OAAO,CAAC,eAAe;IAwrBvB,OAAO,CAAC,+BAA+B;IAwCvC,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,oBAAoB;IA4O5B,OAAO,CAAC,UAAU;IA+DlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,YAAY;IA8EpB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,eAAe;IAQV,aAAa,CAAC,GAAG,EAAE,MAAM;IAM/B,aAAa,CAAC,OAAO,CAAC,EAAE;QAC7B,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/C,cAAc,CAAC,EAAE,MAAM,CAAA;KACxB;IAqKM,aAAa;IAQpB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,cAAc;IAuDf,QAAQ,IAAI,WAAW;IAIvB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI;IAgBnC,cAAc;IAQd,OAAO;IAYD,SAAS,CAAC,IAAI,EAAE,MAAM;IAY5B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM;YAK5D,iBAAiB;YA0GjB,cAAc;YA6Pd,qBAAqB;IAmC5B,MAAM;IAmIb,OAAO,CAAC,UAAU;IAmGlB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,WAAW;CAqBpB"}
|
package/dist/engine.js
CHANGED
|
@@ -8,8 +8,7 @@ export class Engine {
|
|
|
8
8
|
this.cameraMatrixData = new Float32Array(36);
|
|
9
9
|
this.cameraDistance = 26.6;
|
|
10
10
|
this.cameraTarget = new Vec3(0, 12.5, 0);
|
|
11
|
-
this.lightData = new Float32Array(
|
|
12
|
-
this.lightCount = 0;
|
|
11
|
+
this.lightData = new Float32Array(4);
|
|
13
12
|
this.resizeObserver = null;
|
|
14
13
|
this.sampleCount = 4;
|
|
15
14
|
// Constants
|
|
@@ -17,10 +16,9 @@ export class Engine {
|
|
|
17
16
|
this.COMPUTE_WORKGROUP_SIZE = 64;
|
|
18
17
|
this.BLOOM_DOWNSCALE_FACTOR = 2;
|
|
19
18
|
// Ambient light settings
|
|
20
|
-
this.ambient = 1.0;
|
|
21
19
|
this.ambientColor = new Vec3(1.0, 1.0, 1.0);
|
|
22
20
|
// Bloom settings
|
|
23
|
-
this.bloomThreshold = 0.
|
|
21
|
+
this.bloomThreshold = 0.01;
|
|
24
22
|
this.bloomIntensity = 0.12;
|
|
25
23
|
// Rim light settings
|
|
26
24
|
this.rimLightIntensity = 0.45;
|
|
@@ -47,20 +45,17 @@ export class Engine {
|
|
|
47
45
|
this.stats = {
|
|
48
46
|
fps: 0,
|
|
49
47
|
frameTime: 0,
|
|
50
|
-
gpuMemory: 0,
|
|
51
48
|
};
|
|
52
49
|
this.animationFrameId = null;
|
|
53
50
|
this.renderLoopCallback = null;
|
|
54
51
|
this.animationFrames = [];
|
|
55
52
|
this.animationTimeouts = [];
|
|
56
|
-
this.gpuMemoryMB = 0;
|
|
57
53
|
this.hasAnimation = false; // Set to true when loadAnimation is called
|
|
58
54
|
this.playingAnimation = false; // Set to true when playAnimation is called
|
|
59
55
|
this.breathingTimeout = null;
|
|
60
56
|
this.breathingBaseRotations = new Map();
|
|
61
57
|
this.canvas = canvas;
|
|
62
58
|
if (options) {
|
|
63
|
-
this.ambient = options.ambient ?? 1.0;
|
|
64
59
|
this.ambientColor = options.ambientColor ?? new Vec3(1.0, 1.0, 1.0);
|
|
65
60
|
this.bloomIntensity = options.bloomIntensity ?? 0.12;
|
|
66
61
|
this.rimLightIntensity = options.rimLightIntensity ?? 0.45;
|
|
@@ -111,20 +106,8 @@ export class Engine {
|
|
|
111
106
|
_padding: f32,
|
|
112
107
|
};
|
|
113
108
|
|
|
114
|
-
struct Light {
|
|
115
|
-
direction: vec3f,
|
|
116
|
-
_padding1: f32,
|
|
117
|
-
color: vec3f,
|
|
118
|
-
intensity: f32,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
109
|
struct LightUniforms {
|
|
122
|
-
ambient: f32,
|
|
123
110
|
ambientColor: vec3f,
|
|
124
|
-
lightCount: f32,
|
|
125
|
-
_padding1: f32,
|
|
126
|
-
_padding2: f32,
|
|
127
|
-
lights: array<Light, 4>,
|
|
128
111
|
};
|
|
129
112
|
|
|
130
113
|
struct MaterialUniforms {
|
|
@@ -198,16 +181,7 @@ export class Engine {
|
|
|
198
181
|
let n = normalize(input.normal);
|
|
199
182
|
let albedo = textureSample(diffuseTexture, diffuseSampler, input.uv).rgb;
|
|
200
183
|
|
|
201
|
-
|
|
202
|
-
let numLights = u32(light.lightCount);
|
|
203
|
-
for (var i = 0u; i < numLights; i++) {
|
|
204
|
-
let l = -light.lights[i].direction;
|
|
205
|
-
let nDotL = max(dot(n, l), 0.0);
|
|
206
|
-
let toonUV = vec2f(nDotL, 0.5);
|
|
207
|
-
let toonFactor = textureSample(toonTexture, toonSampler, toonUV).rgb;
|
|
208
|
-
let radiance = light.lights[i].color * light.lights[i].intensity;
|
|
209
|
-
lightAccum += toonFactor * radiance * nDotL;
|
|
210
|
-
}
|
|
184
|
+
let lightAccum = light.ambientColor;
|
|
211
185
|
|
|
212
186
|
// Rim light calculation
|
|
213
187
|
let viewDir = normalize(camera.viewPos - input.worldPos);
|
|
@@ -1238,46 +1212,18 @@ export class Engine {
|
|
|
1238
1212
|
setupLighting() {
|
|
1239
1213
|
this.lightUniformBuffer = this.device.createBuffer({
|
|
1240
1214
|
label: "light uniforms",
|
|
1241
|
-
size:
|
|
1215
|
+
size: 4 * 4, // 4 floats: ambientColor vec3f (3) + padding (1)
|
|
1242
1216
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1243
1217
|
});
|
|
1244
|
-
this.lightCount = 0;
|
|
1245
|
-
this.setAmbient(this.ambient);
|
|
1246
1218
|
this.setAmbientColor(this.ambientColor);
|
|
1247
|
-
this.addLight(new Vec3(-0.5, -0.8, 0.5).normalize(), new Vec3(1.0, 0.95, 0.9), 0.02);
|
|
1248
|
-
this.addLight(new Vec3(0.7, -0.5, 0.3).normalize(), new Vec3(0.8, 0.85, 1.0), 0.015);
|
|
1249
|
-
this.addLight(new Vec3(0.3, -0.5, -1.0).normalize(), new Vec3(0.9, 0.9, 1.0), 0.01);
|
|
1250
1219
|
this.device.queue.writeBuffer(this.lightUniformBuffer, 0, this.lightData);
|
|
1251
1220
|
}
|
|
1252
|
-
addLight(direction, color, intensity = 1.0) {
|
|
1253
|
-
if (this.lightCount >= 4)
|
|
1254
|
-
return false;
|
|
1255
|
-
const normalized = direction.normalize();
|
|
1256
|
-
const baseIndex = 12 + this.lightCount * 8;
|
|
1257
|
-
this.lightData[baseIndex] = normalized.x;
|
|
1258
|
-
this.lightData[baseIndex + 1] = normalized.y;
|
|
1259
|
-
this.lightData[baseIndex + 2] = normalized.z;
|
|
1260
|
-
this.lightData[baseIndex + 3] = 0;
|
|
1261
|
-
this.lightData[baseIndex + 4] = color.x;
|
|
1262
|
-
this.lightData[baseIndex + 5] = color.y;
|
|
1263
|
-
this.lightData[baseIndex + 6] = color.z;
|
|
1264
|
-
this.lightData[baseIndex + 7] = intensity;
|
|
1265
|
-
this.lightCount++;
|
|
1266
|
-
// lightCount: f32 at offset 28 (index 7)
|
|
1267
|
-
// Layout: ambient (0), padding (1-3), ambientColor (4-6, padding 7), lightCount (8), _padding1 (9), _padding2 (10), lights start at 12
|
|
1268
|
-
this.lightData[8] = this.lightCount;
|
|
1269
|
-
return true;
|
|
1270
|
-
}
|
|
1271
|
-
setAmbient(intensity) {
|
|
1272
|
-
// ambient: f32 at offset 0 (index 0)
|
|
1273
|
-
this.lightData[0] = intensity;
|
|
1274
|
-
}
|
|
1275
1221
|
setAmbientColor(color) {
|
|
1276
|
-
|
|
1277
|
-
this.lightData[
|
|
1278
|
-
this.lightData[
|
|
1279
|
-
|
|
1280
|
-
this.lightData[
|
|
1222
|
+
// Layout: ambientColor (0-2), padding (3)
|
|
1223
|
+
this.lightData[0] = color.x;
|
|
1224
|
+
this.lightData[1] = color.y;
|
|
1225
|
+
this.lightData[2] = color.z;
|
|
1226
|
+
this.lightData[3] = 0.0; // Padding for vec3f alignment
|
|
1281
1227
|
}
|
|
1282
1228
|
async loadAnimation(url) {
|
|
1283
1229
|
const frames = await VMDLoader.load(url);
|
|
@@ -1520,14 +1466,6 @@ export class Engine {
|
|
|
1520
1466
|
const dir = pathParts.join("/") + "/";
|
|
1521
1467
|
this.modelDir = dir;
|
|
1522
1468
|
const model = await PmxLoader.load(path);
|
|
1523
|
-
// console.log({
|
|
1524
|
-
// vertices: Array.from(model.getVertices()),
|
|
1525
|
-
// indices: Array.from(model.getIndices()),
|
|
1526
|
-
// materials: model.getMaterials(),
|
|
1527
|
-
// textures: model.getTextures(),
|
|
1528
|
-
// bones: model.getSkeleton().bones,
|
|
1529
|
-
// skinning: { joints: Array.from(model.getSkinning().joints), weights: Array.from(model.getSkinning().weights) },
|
|
1530
|
-
// })
|
|
1531
1469
|
this.physics = new Physics(model.getRigidbodies(), model.getJoints());
|
|
1532
1470
|
await this.setupModelBuffers(model);
|
|
1533
1471
|
}
|
|
@@ -1841,7 +1779,6 @@ export class Engine {
|
|
|
1841
1779
|
}
|
|
1842
1780
|
currentIndexOffset += indexCount;
|
|
1843
1781
|
}
|
|
1844
|
-
this.gpuMemoryMB = this.calculateGpuMemory();
|
|
1845
1782
|
}
|
|
1846
1783
|
async createTextureFromPath(path) {
|
|
1847
1784
|
const cached = this.textureCache.get(path);
|
|
@@ -2147,87 +2084,5 @@ export class Engine {
|
|
|
2147
2084
|
this.framesSinceLastUpdate = 0;
|
|
2148
2085
|
this.lastFpsUpdate = now;
|
|
2149
2086
|
}
|
|
2150
|
-
this.stats.gpuMemory = this.gpuMemoryMB;
|
|
2151
|
-
}
|
|
2152
|
-
calculateGpuMemory() {
|
|
2153
|
-
let textureMemoryBytes = 0;
|
|
2154
|
-
for (const texture of this.textureCache.values()) {
|
|
2155
|
-
textureMemoryBytes += texture.width * texture.height * 4;
|
|
2156
|
-
}
|
|
2157
|
-
let bufferMemoryBytes = 0;
|
|
2158
|
-
if (this.vertexBuffer) {
|
|
2159
|
-
const vertices = this.currentModel?.getVertices();
|
|
2160
|
-
if (vertices)
|
|
2161
|
-
bufferMemoryBytes += vertices.byteLength;
|
|
2162
|
-
}
|
|
2163
|
-
if (this.indexBuffer) {
|
|
2164
|
-
const indices = this.currentModel?.getIndices();
|
|
2165
|
-
if (indices)
|
|
2166
|
-
bufferMemoryBytes += indices.byteLength;
|
|
2167
|
-
}
|
|
2168
|
-
if (this.jointsBuffer) {
|
|
2169
|
-
const skinning = this.currentModel?.getSkinning();
|
|
2170
|
-
if (skinning)
|
|
2171
|
-
bufferMemoryBytes += skinning.joints.byteLength;
|
|
2172
|
-
}
|
|
2173
|
-
if (this.weightsBuffer) {
|
|
2174
|
-
const skinning = this.currentModel?.getSkinning();
|
|
2175
|
-
if (skinning)
|
|
2176
|
-
bufferMemoryBytes += skinning.weights.byteLength;
|
|
2177
|
-
}
|
|
2178
|
-
if (this.skinMatrixBuffer) {
|
|
2179
|
-
const skeleton = this.currentModel?.getSkeleton();
|
|
2180
|
-
if (skeleton)
|
|
2181
|
-
bufferMemoryBytes += Math.max(256, skeleton.bones.length * 16 * 4);
|
|
2182
|
-
}
|
|
2183
|
-
if (this.worldMatrixBuffer) {
|
|
2184
|
-
const skeleton = this.currentModel?.getSkeleton();
|
|
2185
|
-
if (skeleton)
|
|
2186
|
-
bufferMemoryBytes += Math.max(256, skeleton.bones.length * 16 * 4);
|
|
2187
|
-
}
|
|
2188
|
-
if (this.inverseBindMatrixBuffer) {
|
|
2189
|
-
const skeleton = this.currentModel?.getSkeleton();
|
|
2190
|
-
if (skeleton)
|
|
2191
|
-
bufferMemoryBytes += Math.max(256, skeleton.bones.length * 16 * 4);
|
|
2192
|
-
}
|
|
2193
|
-
bufferMemoryBytes += 40 * 4;
|
|
2194
|
-
bufferMemoryBytes += 64 * 4;
|
|
2195
|
-
bufferMemoryBytes += 32;
|
|
2196
|
-
bufferMemoryBytes += 32;
|
|
2197
|
-
bufferMemoryBytes += 32;
|
|
2198
|
-
bufferMemoryBytes += 32;
|
|
2199
|
-
if (this.fullscreenQuadBuffer) {
|
|
2200
|
-
bufferMemoryBytes += 24 * 4;
|
|
2201
|
-
}
|
|
2202
|
-
const totalMaterialDraws = this.opaqueDraws.length +
|
|
2203
|
-
this.eyeDraws.length +
|
|
2204
|
-
this.hairDrawsOverEyes.length +
|
|
2205
|
-
this.hairDrawsOverNonEyes.length +
|
|
2206
|
-
this.transparentDraws.length;
|
|
2207
|
-
bufferMemoryBytes += totalMaterialDraws * 32;
|
|
2208
|
-
const totalOutlineDraws = this.opaqueOutlineDraws.length +
|
|
2209
|
-
this.eyeOutlineDraws.length +
|
|
2210
|
-
this.hairOutlineDraws.length +
|
|
2211
|
-
this.transparentOutlineDraws.length;
|
|
2212
|
-
bufferMemoryBytes += totalOutlineDraws * 32;
|
|
2213
|
-
let renderTargetMemoryBytes = 0;
|
|
2214
|
-
if (this.multisampleTexture) {
|
|
2215
|
-
const width = this.canvas.width;
|
|
2216
|
-
const height = this.canvas.height;
|
|
2217
|
-
renderTargetMemoryBytes += width * height * 4 * this.sampleCount;
|
|
2218
|
-
renderTargetMemoryBytes += width * height * 4;
|
|
2219
|
-
}
|
|
2220
|
-
if (this.sceneRenderTexture) {
|
|
2221
|
-
const width = this.canvas.width;
|
|
2222
|
-
const height = this.canvas.height;
|
|
2223
|
-
renderTargetMemoryBytes += width * height * 4;
|
|
2224
|
-
}
|
|
2225
|
-
if (this.bloomExtractTexture) {
|
|
2226
|
-
const width = Math.floor(this.canvas.width / this.BLOOM_DOWNSCALE_FACTOR);
|
|
2227
|
-
const height = Math.floor(this.canvas.height / this.BLOOM_DOWNSCALE_FACTOR);
|
|
2228
|
-
renderTargetMemoryBytes += width * height * 4 * 3;
|
|
2229
|
-
}
|
|
2230
|
-
const totalGPUMemoryBytes = textureMemoryBytes + bufferMemoryBytes + renderTargetMemoryBytes;
|
|
2231
|
-
return Math.round((totalGPUMemoryBytes / 1024 / 1024) * 100) / 100;
|
|
2232
2087
|
}
|
|
2233
2088
|
}
|
package/package.json
CHANGED
package/src/engine.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { Physics } from "./physics"
|
|
|
6
6
|
import { VMDKeyFrame, VMDLoader } from "./vmd-loader"
|
|
7
7
|
|
|
8
8
|
export type EngineOptions = {
|
|
9
|
-
ambient?: number
|
|
10
9
|
ambientColor?: Vec3
|
|
11
10
|
bloomIntensity?: number
|
|
12
11
|
rimLightIntensity?: number
|
|
@@ -17,7 +16,6 @@ export type EngineOptions = {
|
|
|
17
16
|
export interface EngineStats {
|
|
18
17
|
fps: number
|
|
19
18
|
frameTime: number // ms
|
|
20
|
-
gpuMemory: number // MB (estimated total GPU memory)
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
interface DrawCall {
|
|
@@ -44,8 +42,7 @@ export class Engine {
|
|
|
44
42
|
private cameraDistance: number = 26.6
|
|
45
43
|
private cameraTarget: Vec3 = new Vec3(0, 12.5, 0)
|
|
46
44
|
private lightUniformBuffer!: GPUBuffer
|
|
47
|
-
private lightData = new Float32Array(
|
|
48
|
-
private lightCount = 0
|
|
45
|
+
private lightData = new Float32Array(4)
|
|
49
46
|
private vertexBuffer!: GPUBuffer
|
|
50
47
|
private indexBuffer?: GPUBuffer
|
|
51
48
|
private resizeObserver: ResizeObserver | null = null
|
|
@@ -77,7 +74,6 @@ export class Engine {
|
|
|
77
74
|
private readonly COMPUTE_WORKGROUP_SIZE = 64
|
|
78
75
|
private readonly BLOOM_DOWNSCALE_FACTOR = 2
|
|
79
76
|
// Ambient light settings
|
|
80
|
-
private ambient: number = 1.0
|
|
81
77
|
private ambientColor: Vec3 = new Vec3(1.0, 1.0, 1.0)
|
|
82
78
|
// Bloom post-processing textures
|
|
83
79
|
private sceneRenderTexture!: GPUTexture
|
|
@@ -101,7 +97,7 @@ export class Engine {
|
|
|
101
97
|
private bloomBlurVBindGroup?: GPUBindGroup
|
|
102
98
|
private bloomComposeBindGroup?: GPUBindGroup
|
|
103
99
|
// Bloom settings
|
|
104
|
-
private bloomThreshold: number = 0.
|
|
100
|
+
private bloomThreshold: number = 0.01
|
|
105
101
|
private bloomIntensity: number = 0.12
|
|
106
102
|
// Rim light settings
|
|
107
103
|
private rimLightIntensity: number = 0.45
|
|
@@ -131,14 +127,12 @@ export class Engine {
|
|
|
131
127
|
private stats: EngineStats = {
|
|
132
128
|
fps: 0,
|
|
133
129
|
frameTime: 0,
|
|
134
|
-
gpuMemory: 0,
|
|
135
130
|
}
|
|
136
131
|
private animationFrameId: number | null = null
|
|
137
132
|
private renderLoopCallback: (() => void) | null = null
|
|
138
133
|
|
|
139
134
|
private animationFrames: VMDKeyFrame[] = []
|
|
140
135
|
private animationTimeouts: number[] = []
|
|
141
|
-
private gpuMemoryMB: number = 0
|
|
142
136
|
private hasAnimation = false // Set to true when loadAnimation is called
|
|
143
137
|
private playingAnimation = false // Set to true when playAnimation is called
|
|
144
138
|
private breathingTimeout: number | null = null
|
|
@@ -147,7 +141,6 @@ export class Engine {
|
|
|
147
141
|
constructor(canvas: HTMLCanvasElement, options?: EngineOptions) {
|
|
148
142
|
this.canvas = canvas
|
|
149
143
|
if (options) {
|
|
150
|
-
this.ambient = options.ambient ?? 1.0
|
|
151
144
|
this.ambientColor = options.ambientColor ?? new Vec3(1.0, 1.0, 1.0)
|
|
152
145
|
this.bloomIntensity = options.bloomIntensity ?? 0.12
|
|
153
146
|
this.rimLightIntensity = options.rimLightIntensity ?? 0.45
|
|
@@ -205,20 +198,8 @@ export class Engine {
|
|
|
205
198
|
_padding: f32,
|
|
206
199
|
};
|
|
207
200
|
|
|
208
|
-
struct Light {
|
|
209
|
-
direction: vec3f,
|
|
210
|
-
_padding1: f32,
|
|
211
|
-
color: vec3f,
|
|
212
|
-
intensity: f32,
|
|
213
|
-
};
|
|
214
|
-
|
|
215
201
|
struct LightUniforms {
|
|
216
|
-
ambient: f32,
|
|
217
202
|
ambientColor: vec3f,
|
|
218
|
-
lightCount: f32,
|
|
219
|
-
_padding1: f32,
|
|
220
|
-
_padding2: f32,
|
|
221
|
-
lights: array<Light, 4>,
|
|
222
203
|
};
|
|
223
204
|
|
|
224
205
|
struct MaterialUniforms {
|
|
@@ -292,16 +273,7 @@ export class Engine {
|
|
|
292
273
|
let n = normalize(input.normal);
|
|
293
274
|
let albedo = textureSample(diffuseTexture, diffuseSampler, input.uv).rgb;
|
|
294
275
|
|
|
295
|
-
|
|
296
|
-
let numLights = u32(light.lightCount);
|
|
297
|
-
for (var i = 0u; i < numLights; i++) {
|
|
298
|
-
let l = -light.lights[i].direction;
|
|
299
|
-
let nDotL = max(dot(n, l), 0.0);
|
|
300
|
-
let toonUV = vec2f(nDotL, 0.5);
|
|
301
|
-
let toonFactor = textureSample(toonTexture, toonSampler, toonUV).rgb;
|
|
302
|
-
let radiance = light.lights[i].color * light.lights[i].intensity;
|
|
303
|
-
lightAccum += toonFactor * radiance * nDotL;
|
|
304
|
-
}
|
|
276
|
+
let lightAccum = light.ambientColor;
|
|
305
277
|
|
|
306
278
|
// Rim light calculation
|
|
307
279
|
let viewDir = normalize(camera.viewPos - input.worldPos);
|
|
@@ -1384,53 +1356,21 @@ export class Engine {
|
|
|
1384
1356
|
private setupLighting() {
|
|
1385
1357
|
this.lightUniformBuffer = this.device.createBuffer({
|
|
1386
1358
|
label: "light uniforms",
|
|
1387
|
-
size:
|
|
1359
|
+
size: 4 * 4, // 4 floats: ambientColor vec3f (3) + padding (1)
|
|
1388
1360
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1389
1361
|
})
|
|
1390
1362
|
|
|
1391
|
-
this.lightCount = 0
|
|
1392
|
-
|
|
1393
|
-
this.setAmbient(this.ambient)
|
|
1394
1363
|
this.setAmbientColor(this.ambientColor)
|
|
1395
1364
|
|
|
1396
|
-
this.addLight(new Vec3(-0.5, -0.8, 0.5).normalize(), new Vec3(1.0, 0.95, 0.9), 0.02)
|
|
1397
|
-
this.addLight(new Vec3(0.7, -0.5, 0.3).normalize(), new Vec3(0.8, 0.85, 1.0), 0.015)
|
|
1398
|
-
this.addLight(new Vec3(0.3, -0.5, -1.0).normalize(), new Vec3(0.9, 0.9, 1.0), 0.01)
|
|
1399
1365
|
this.device.queue.writeBuffer(this.lightUniformBuffer, 0, this.lightData)
|
|
1400
1366
|
}
|
|
1401
1367
|
|
|
1402
|
-
private addLight(direction: Vec3, color: Vec3, intensity: number = 1.0): boolean {
|
|
1403
|
-
if (this.lightCount >= 4) return false
|
|
1404
|
-
|
|
1405
|
-
const normalized = direction.normalize()
|
|
1406
|
-
const baseIndex = 12 + this.lightCount * 8
|
|
1407
|
-
this.lightData[baseIndex] = normalized.x
|
|
1408
|
-
this.lightData[baseIndex + 1] = normalized.y
|
|
1409
|
-
this.lightData[baseIndex + 2] = normalized.z
|
|
1410
|
-
this.lightData[baseIndex + 3] = 0
|
|
1411
|
-
this.lightData[baseIndex + 4] = color.x
|
|
1412
|
-
this.lightData[baseIndex + 5] = color.y
|
|
1413
|
-
this.lightData[baseIndex + 6] = color.z
|
|
1414
|
-
this.lightData[baseIndex + 7] = intensity
|
|
1415
|
-
|
|
1416
|
-
this.lightCount++
|
|
1417
|
-
// lightCount: f32 at offset 28 (index 7)
|
|
1418
|
-
// Layout: ambient (0), padding (1-3), ambientColor (4-6, padding 7), lightCount (8), _padding1 (9), _padding2 (10), lights start at 12
|
|
1419
|
-
this.lightData[8] = this.lightCount
|
|
1420
|
-
return true
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
private setAmbient(intensity: number) {
|
|
1424
|
-
// ambient: f32 at offset 0 (index 0)
|
|
1425
|
-
this.lightData[0] = intensity
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
1368
|
private setAmbientColor(color: Vec3) {
|
|
1429
|
-
|
|
1430
|
-
this.lightData[
|
|
1431
|
-
this.lightData[
|
|
1432
|
-
|
|
1433
|
-
this.lightData[
|
|
1369
|
+
// Layout: ambientColor (0-2), padding (3)
|
|
1370
|
+
this.lightData[0] = color.x
|
|
1371
|
+
this.lightData[1] = color.y
|
|
1372
|
+
this.lightData[2] = color.z
|
|
1373
|
+
this.lightData[3] = 0.0 // Padding for vec3f alignment
|
|
1434
1374
|
}
|
|
1435
1375
|
|
|
1436
1376
|
public async loadAnimation(url: string) {
|
|
@@ -1725,14 +1665,7 @@ export class Engine {
|
|
|
1725
1665
|
this.modelDir = dir
|
|
1726
1666
|
|
|
1727
1667
|
const model = await PmxLoader.load(path)
|
|
1728
|
-
|
|
1729
|
-
// vertices: Array.from(model.getVertices()),
|
|
1730
|
-
// indices: Array.from(model.getIndices()),
|
|
1731
|
-
// materials: model.getMaterials(),
|
|
1732
|
-
// textures: model.getTextures(),
|
|
1733
|
-
// bones: model.getSkeleton().bones,
|
|
1734
|
-
// skinning: { joints: Array.from(model.getSkinning().joints), weights: Array.from(model.getSkinning().weights) },
|
|
1735
|
-
// })
|
|
1668
|
+
|
|
1736
1669
|
this.physics = new Physics(model.getRigidbodies(), model.getJoints())
|
|
1737
1670
|
await this.setupModelBuffers(model)
|
|
1738
1671
|
}
|
|
@@ -2099,8 +2032,6 @@ export class Engine {
|
|
|
2099
2032
|
|
|
2100
2033
|
currentIndexOffset += indexCount
|
|
2101
2034
|
}
|
|
2102
|
-
|
|
2103
|
-
this.gpuMemoryMB = this.calculateGpuMemory()
|
|
2104
2035
|
}
|
|
2105
2036
|
|
|
2106
2037
|
private async createTextureFromPath(path: string): Promise<GPUTexture | null> {
|
|
@@ -2457,88 +2388,5 @@ export class Engine {
|
|
|
2457
2388
|
this.framesSinceLastUpdate = 0
|
|
2458
2389
|
this.lastFpsUpdate = now
|
|
2459
2390
|
}
|
|
2460
|
-
|
|
2461
|
-
this.stats.gpuMemory = this.gpuMemoryMB
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2464
|
-
private calculateGpuMemory(): number {
|
|
2465
|
-
let textureMemoryBytes = 0
|
|
2466
|
-
for (const texture of this.textureCache.values()) {
|
|
2467
|
-
textureMemoryBytes += texture.width * texture.height * 4
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
let bufferMemoryBytes = 0
|
|
2471
|
-
if (this.vertexBuffer) {
|
|
2472
|
-
const vertices = this.currentModel?.getVertices()
|
|
2473
|
-
if (vertices) bufferMemoryBytes += vertices.byteLength
|
|
2474
|
-
}
|
|
2475
|
-
if (this.indexBuffer) {
|
|
2476
|
-
const indices = this.currentModel?.getIndices()
|
|
2477
|
-
if (indices) bufferMemoryBytes += indices.byteLength
|
|
2478
|
-
}
|
|
2479
|
-
if (this.jointsBuffer) {
|
|
2480
|
-
const skinning = this.currentModel?.getSkinning()
|
|
2481
|
-
if (skinning) bufferMemoryBytes += skinning.joints.byteLength
|
|
2482
|
-
}
|
|
2483
|
-
if (this.weightsBuffer) {
|
|
2484
|
-
const skinning = this.currentModel?.getSkinning()
|
|
2485
|
-
if (skinning) bufferMemoryBytes += skinning.weights.byteLength
|
|
2486
|
-
}
|
|
2487
|
-
if (this.skinMatrixBuffer) {
|
|
2488
|
-
const skeleton = this.currentModel?.getSkeleton()
|
|
2489
|
-
if (skeleton) bufferMemoryBytes += Math.max(256, skeleton.bones.length * 16 * 4)
|
|
2490
|
-
}
|
|
2491
|
-
if (this.worldMatrixBuffer) {
|
|
2492
|
-
const skeleton = this.currentModel?.getSkeleton()
|
|
2493
|
-
if (skeleton) bufferMemoryBytes += Math.max(256, skeleton.bones.length * 16 * 4)
|
|
2494
|
-
}
|
|
2495
|
-
if (this.inverseBindMatrixBuffer) {
|
|
2496
|
-
const skeleton = this.currentModel?.getSkeleton()
|
|
2497
|
-
if (skeleton) bufferMemoryBytes += Math.max(256, skeleton.bones.length * 16 * 4)
|
|
2498
|
-
}
|
|
2499
|
-
bufferMemoryBytes += 40 * 4
|
|
2500
|
-
bufferMemoryBytes += 64 * 4
|
|
2501
|
-
bufferMemoryBytes += 32
|
|
2502
|
-
bufferMemoryBytes += 32
|
|
2503
|
-
bufferMemoryBytes += 32
|
|
2504
|
-
bufferMemoryBytes += 32
|
|
2505
|
-
if (this.fullscreenQuadBuffer) {
|
|
2506
|
-
bufferMemoryBytes += 24 * 4
|
|
2507
|
-
}
|
|
2508
|
-
const totalMaterialDraws =
|
|
2509
|
-
this.opaqueDraws.length +
|
|
2510
|
-
this.eyeDraws.length +
|
|
2511
|
-
this.hairDrawsOverEyes.length +
|
|
2512
|
-
this.hairDrawsOverNonEyes.length +
|
|
2513
|
-
this.transparentDraws.length
|
|
2514
|
-
bufferMemoryBytes += totalMaterialDraws * 32
|
|
2515
|
-
|
|
2516
|
-
const totalOutlineDraws =
|
|
2517
|
-
this.opaqueOutlineDraws.length +
|
|
2518
|
-
this.eyeOutlineDraws.length +
|
|
2519
|
-
this.hairOutlineDraws.length +
|
|
2520
|
-
this.transparentOutlineDraws.length
|
|
2521
|
-
bufferMemoryBytes += totalOutlineDraws * 32
|
|
2522
|
-
|
|
2523
|
-
let renderTargetMemoryBytes = 0
|
|
2524
|
-
if (this.multisampleTexture) {
|
|
2525
|
-
const width = this.canvas.width
|
|
2526
|
-
const height = this.canvas.height
|
|
2527
|
-
renderTargetMemoryBytes += width * height * 4 * this.sampleCount
|
|
2528
|
-
renderTargetMemoryBytes += width * height * 4
|
|
2529
|
-
}
|
|
2530
|
-
if (this.sceneRenderTexture) {
|
|
2531
|
-
const width = this.canvas.width
|
|
2532
|
-
const height = this.canvas.height
|
|
2533
|
-
renderTargetMemoryBytes += width * height * 4
|
|
2534
|
-
}
|
|
2535
|
-
if (this.bloomExtractTexture) {
|
|
2536
|
-
const width = Math.floor(this.canvas.width / this.BLOOM_DOWNSCALE_FACTOR)
|
|
2537
|
-
const height = Math.floor(this.canvas.height / this.BLOOM_DOWNSCALE_FACTOR)
|
|
2538
|
-
renderTargetMemoryBytes += width * height * 4 * 3
|
|
2539
|
-
}
|
|
2540
|
-
|
|
2541
|
-
const totalGPUMemoryBytes = textureMemoryBytes + bufferMemoryBytes + renderTargetMemoryBytes
|
|
2542
|
-
return Math.round((totalGPUMemoryBytes / 1024 / 1024) * 100) / 100
|
|
2543
2391
|
}
|
|
2544
2392
|
}
|