reze-engine 0.1.10 → 0.1.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/README.md +13 -8
- package/dist/engine.d.ts +3 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +72 -12
- package/package.json +2 -2
- package/src/engine.ts +75 -12
package/README.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
A lightweight engine built with WebGPU and TypeScript for real-time 3D anime character MMD model rendering.
|
|
4
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
|
+
|
|
5
18
|
## Usage
|
|
6
19
|
|
|
7
20
|
```typescript
|
|
@@ -13,14 +26,6 @@ export default function Home() {
|
|
|
13
26
|
const [stats, setStats] = useState<EngineStats>({
|
|
14
27
|
fps: 0,
|
|
15
28
|
frameTime: 0,
|
|
16
|
-
memoryUsed: 0,
|
|
17
|
-
drawCalls: 0,
|
|
18
|
-
vertices: 0,
|
|
19
|
-
triangles: 0,
|
|
20
|
-
materials: 0,
|
|
21
|
-
textures: 0,
|
|
22
|
-
textureMemory: 0,
|
|
23
|
-
bufferMemory: 0,
|
|
24
29
|
gpuMemory: 0,
|
|
25
30
|
})
|
|
26
31
|
const [progress, setProgress] = useState(0)
|
package/dist/engine.d.ts
CHANGED
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAKnC,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,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;IACtC,MAAM,EAAG,MAAM,CAAA;IACtB,OAAO,CAAC,mBAAmB,CAAY;IACvC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,kBAAkB,CAAY;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,WAAW,CAAC,CAAW;IAC/B,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,mBAAmB,CAAoB;IAC/C,OAAO,CAAC,2BAA2B,CAAoB;IACvD,OAAO,CAAC,oBAAoB,CAAoB;IAChD,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,WAAW,CAAoB;IACvC,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,eAAe,CAAC,CAAW;IACnC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAChC,OAAO,CAAC,oBAAoB,CAA0B;IAEtD,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;IAE3B,cAAc,EAAE,MAAM,CAAM;IAC5B,cAAc,EAAE,MAAM,CAAO;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAKnC,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,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;IACtC,MAAM,EAAG,MAAM,CAAA;IACtB,OAAO,CAAC,mBAAmB,CAAY;IACvC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,kBAAkB,CAAY;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,WAAW,CAAC,CAAW;IAC/B,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,mBAAmB,CAAoB;IAC/C,OAAO,CAAC,2BAA2B,CAAoB;IACvD,OAAO,CAAC,oBAAoB,CAAoB;IAChD,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,WAAW,CAAoB;IACvC,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,eAAe,CAAC,CAAW;IACnC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAChC,OAAO,CAAC,oBAAoB,CAA0B;IAEtD,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;IAE3B,cAAc,EAAE,MAAM,CAAM;IAC5B,cAAc,EAAE,MAAM,CAAO;IAEpC,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,YAAY,CAAuD;IAE3E,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,CAIZ;IACD,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,kBAAkB,CAA4B;gBAE1C,MAAM,EAAE,iBAAiB;IAKxB,IAAI;IA+BjB,OAAO,CAAC,eAAe;IAg1BvB,OAAO,CAAC,+BAA+B;IAyCvC,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,oBAAoB;IAgP5B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,YAAY;IAiGpB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,aAAa;IAgBd,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,GAAE,MAAY,GAAG,OAAO;IAmBxE,UAAU,CAAC,SAAS,EAAE,MAAM;IAI5B,QAAQ,IAAI,WAAW;IAIvB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI;IAgBnC,cAAc;IAQd,OAAO;IAUD,SAAS,CAAC,IAAI,EAAE,MAAM;IAW5B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM;YAK5D,iBAAiB;IA+F/B,OAAO,CAAC,wBAAwB,CAKxB;IACR,OAAO,CAAC,QAAQ,CAA+F;IAC/G,OAAO,CAAC,iBAAiB,CACrB;IACJ,OAAO,CAAC,oBAAoB,CAKpB;IACR,OAAO,CAAC,6BAA6B,CAK7B;IACR,OAAO,CAAC,+BAA+B,CAK/B;IACR,OAAO,CAAC,eAAe,CAA+F;IACtH,OAAO,CAAC,gBAAgB,CACpB;IACJ,OAAO,CAAC,oCAAoC,CAKpC;YAGM,cAAc;YA4Rd,qBAAqB;IAkD5B,MAAM;IA0Hb,OAAO,CAAC,UAAU;IA8IlB,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,eAAe;IA8BvB,OAAO,CAAC,mBAAmB;IAgC3B,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,WAAW;CAuEpB"}
|
package/dist/engine.js
CHANGED
|
@@ -12,6 +12,10 @@ export class Engine {
|
|
|
12
12
|
// Bloom settings
|
|
13
13
|
this.bloomThreshold = 0.3;
|
|
14
14
|
this.bloomIntensity = 0.13;
|
|
15
|
+
// Rim light settings
|
|
16
|
+
this.rimLightIntensity = 0.35;
|
|
17
|
+
this.rimLightPower = 2.0;
|
|
18
|
+
this.rimLightColor = [1.0, 1.0, 1.0];
|
|
15
19
|
this.currentModel = null;
|
|
16
20
|
this.modelDir = "";
|
|
17
21
|
this.physics = null;
|
|
@@ -102,9 +106,11 @@ export class Engine {
|
|
|
102
106
|
|
|
103
107
|
struct MaterialUniforms {
|
|
104
108
|
alpha: f32,
|
|
109
|
+
rimIntensity: f32,
|
|
110
|
+
rimPower: f32,
|
|
105
111
|
_padding1: f32,
|
|
112
|
+
rimColor: vec3f,
|
|
106
113
|
_padding2: f32,
|
|
107
|
-
_padding3: f32,
|
|
108
114
|
};
|
|
109
115
|
|
|
110
116
|
struct VertexOutput {
|
|
@@ -175,7 +181,13 @@ export class Engine {
|
|
|
175
181
|
lightAccum += toonFactor * radiance * nDotL;
|
|
176
182
|
}
|
|
177
183
|
|
|
178
|
-
|
|
184
|
+
// Rim light calculation
|
|
185
|
+
let viewDir = normalize(camera.viewPos - input.worldPos);
|
|
186
|
+
var rimFactor = 1.0 - max(dot(n, viewDir), 0.0);
|
|
187
|
+
rimFactor = pow(rimFactor, material.rimPower);
|
|
188
|
+
let rimLight = material.rimColor * material.rimIntensity * rimFactor;
|
|
189
|
+
|
|
190
|
+
let color = albedo * lightAccum + rimLight;
|
|
179
191
|
let finalAlpha = material.alpha;
|
|
180
192
|
if (finalAlpha < 0.001) {
|
|
181
193
|
discard;
|
|
@@ -215,8 +227,10 @@ export class Engine {
|
|
|
215
227
|
struct MaterialUniforms {
|
|
216
228
|
alpha: f32,
|
|
217
229
|
alphaMultiplier: f32, // New: multiplier for alpha (0.5 for over-eyes, 1.0 for over-non-eyes)
|
|
230
|
+
rimIntensity: f32,
|
|
231
|
+
rimPower: f32,
|
|
232
|
+
rimColor: vec3f,
|
|
218
233
|
_padding1: f32,
|
|
219
|
-
_padding2: f32,
|
|
220
234
|
};
|
|
221
235
|
|
|
222
236
|
struct VertexOutput {
|
|
@@ -286,7 +300,13 @@ export class Engine {
|
|
|
286
300
|
lightAccum += toonFactor * radiance * nDotL;
|
|
287
301
|
}
|
|
288
302
|
|
|
289
|
-
|
|
303
|
+
// Rim light calculation
|
|
304
|
+
let viewDir = normalize(camera.viewPos - input.worldPos);
|
|
305
|
+
var rimFactor = 1.0 - max(dot(n, viewDir), 0.0);
|
|
306
|
+
rimFactor = pow(rimFactor, material.rimPower);
|
|
307
|
+
let rimLight = material.rimColor * material.rimIntensity * rimFactor;
|
|
308
|
+
|
|
309
|
+
let color = albedo * lightAccum + rimLight;
|
|
290
310
|
let finalAlpha = material.alpha * material.alphaMultiplier;
|
|
291
311
|
if (finalAlpha < 0.001) {
|
|
292
312
|
discard;
|
|
@@ -1501,11 +1521,16 @@ export class Engine {
|
|
|
1501
1521
|
const EPSILON = 0.001;
|
|
1502
1522
|
const isTransparent = materialAlpha < 1.0 - EPSILON;
|
|
1503
1523
|
// Create material uniform data - for hair materials, we'll create two versions
|
|
1504
|
-
|
|
1524
|
+
// MaterialUniforms struct: alpha, rimIntensity, rimPower, _padding1, rimColor (vec3), _padding2
|
|
1525
|
+
const materialUniformData = new Float32Array(8);
|
|
1505
1526
|
materialUniformData[0] = materialAlpha;
|
|
1506
|
-
materialUniformData[1] =
|
|
1507
|
-
materialUniformData[2] =
|
|
1508
|
-
materialUniformData[3] = 0.0;
|
|
1527
|
+
materialUniformData[1] = this.rimLightIntensity;
|
|
1528
|
+
materialUniformData[2] = this.rimLightPower;
|
|
1529
|
+
materialUniformData[3] = 0.0; // _padding1
|
|
1530
|
+
materialUniformData[4] = this.rimLightColor[0]; // rimColor.r
|
|
1531
|
+
materialUniformData[5] = this.rimLightColor[1]; // rimColor.g
|
|
1532
|
+
materialUniformData[6] = this.rimLightColor[2]; // rimColor.b
|
|
1533
|
+
materialUniformData[7] = 0.0; // _padding2
|
|
1509
1534
|
const materialUniformBuffer = this.device.createBuffer({
|
|
1510
1535
|
label: `material uniform: ${mat.name}`,
|
|
1511
1536
|
size: materialUniformData.byteLength,
|
|
@@ -1538,11 +1563,16 @@ export class Engine {
|
|
|
1538
1563
|
}
|
|
1539
1564
|
else if (mat.isHair) {
|
|
1540
1565
|
// For hair materials, create two bind groups: one for over-eyes (alphaMultiplier = 0.5) and one for over-non-eyes (alphaMultiplier = 1.0)
|
|
1541
|
-
|
|
1566
|
+
// Hair MaterialUniforms struct: alpha, alphaMultiplier, rimIntensity, rimPower, rimColor (vec3), _padding1
|
|
1567
|
+
const materialUniformDataOverEyes = new Float32Array(8);
|
|
1542
1568
|
materialUniformDataOverEyes[0] = materialAlpha;
|
|
1543
1569
|
materialUniformDataOverEyes[1] = 0.5; // alphaMultiplier: 0.5 for over-eyes
|
|
1544
|
-
materialUniformDataOverEyes[2] =
|
|
1545
|
-
materialUniformDataOverEyes[3] =
|
|
1570
|
+
materialUniformDataOverEyes[2] = this.rimLightIntensity;
|
|
1571
|
+
materialUniformDataOverEyes[3] = this.rimLightPower;
|
|
1572
|
+
materialUniformDataOverEyes[4] = this.rimLightColor[0]; // rimColor.r
|
|
1573
|
+
materialUniformDataOverEyes[5] = this.rimLightColor[1]; // rimColor.g
|
|
1574
|
+
materialUniformDataOverEyes[6] = this.rimLightColor[2]; // rimColor.b
|
|
1575
|
+
materialUniformDataOverEyes[7] = 0.0; // _padding1
|
|
1546
1576
|
const materialUniformBufferOverEyes = this.device.createBuffer({
|
|
1547
1577
|
label: `material uniform (over eyes): ${mat.name}`,
|
|
1548
1578
|
size: materialUniformDataOverEyes.byteLength,
|
|
@@ -1569,10 +1599,40 @@ export class Engine {
|
|
|
1569
1599
|
bindGroup: bindGroupOverEyes,
|
|
1570
1600
|
isTransparent,
|
|
1571
1601
|
});
|
|
1602
|
+
// Create material uniform for hair over non-eyes (alphaMultiplier = 1.0)
|
|
1603
|
+
const materialUniformDataOverNonEyes = new Float32Array(8);
|
|
1604
|
+
materialUniformDataOverNonEyes[0] = materialAlpha;
|
|
1605
|
+
materialUniformDataOverNonEyes[1] = 1.0; // alphaMultiplier: 1.0 for over-non-eyes
|
|
1606
|
+
materialUniformDataOverNonEyes[2] = this.rimLightIntensity;
|
|
1607
|
+
materialUniformDataOverNonEyes[3] = this.rimLightPower;
|
|
1608
|
+
materialUniformDataOverNonEyes[4] = this.rimLightColor[0]; // rimColor.r
|
|
1609
|
+
materialUniformDataOverNonEyes[5] = this.rimLightColor[1]; // rimColor.g
|
|
1610
|
+
materialUniformDataOverNonEyes[6] = this.rimLightColor[2]; // rimColor.b
|
|
1611
|
+
materialUniformDataOverNonEyes[7] = 0.0; // _padding1
|
|
1612
|
+
const materialUniformBufferOverNonEyes = this.device.createBuffer({
|
|
1613
|
+
label: `material uniform (over non-eyes): ${mat.name}`,
|
|
1614
|
+
size: materialUniformDataOverNonEyes.byteLength,
|
|
1615
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1616
|
+
});
|
|
1617
|
+
this.device.queue.writeBuffer(materialUniformBufferOverNonEyes, 0, materialUniformDataOverNonEyes);
|
|
1618
|
+
const bindGroupOverNonEyes = this.device.createBindGroup({
|
|
1619
|
+
label: `material bind group (over non-eyes): ${mat.name}`,
|
|
1620
|
+
layout: this.hairBindGroupLayout,
|
|
1621
|
+
entries: [
|
|
1622
|
+
{ binding: 0, resource: { buffer: this.cameraUniformBuffer } },
|
|
1623
|
+
{ binding: 1, resource: { buffer: this.lightUniformBuffer } },
|
|
1624
|
+
{ binding: 2, resource: diffuseTexture.createView() },
|
|
1625
|
+
{ binding: 3, resource: this.textureSampler },
|
|
1626
|
+
{ binding: 4, resource: { buffer: this.skinMatrixBuffer } },
|
|
1627
|
+
{ binding: 5, resource: toonTexture.createView() },
|
|
1628
|
+
{ binding: 6, resource: this.textureSampler },
|
|
1629
|
+
{ binding: 7, resource: { buffer: materialUniformBufferOverNonEyes } },
|
|
1630
|
+
],
|
|
1631
|
+
});
|
|
1572
1632
|
this.hairDrawsOverNonEyes.push({
|
|
1573
1633
|
count: matCount,
|
|
1574
1634
|
firstIndex: runningFirstIndex,
|
|
1575
|
-
bindGroup,
|
|
1635
|
+
bindGroup: bindGroupOverNonEyes,
|
|
1576
1636
|
isTransparent,
|
|
1577
1637
|
});
|
|
1578
1638
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reze-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "A WebGPU-based MMD model renderer",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/
|
|
10
|
+
"url": "https://github.com/AmyangXYZ/reze-engine"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
package/src/engine.ts
CHANGED
|
@@ -63,6 +63,10 @@ export class Engine {
|
|
|
63
63
|
// Bloom settings
|
|
64
64
|
public bloomThreshold: number = 0.3
|
|
65
65
|
public bloomIntensity: number = 0.13
|
|
66
|
+
// Rim light settings
|
|
67
|
+
private rimLightIntensity: number = 0.35
|
|
68
|
+
private rimLightPower: number = 2.0
|
|
69
|
+
private rimLightColor: [number, number, number] = [1.0, 1.0, 1.0]
|
|
66
70
|
private currentModel: Model | null = null
|
|
67
71
|
private modelDir: string = ""
|
|
68
72
|
private physics: Physics | null = null
|
|
@@ -155,9 +159,11 @@ export class Engine {
|
|
|
155
159
|
|
|
156
160
|
struct MaterialUniforms {
|
|
157
161
|
alpha: f32,
|
|
162
|
+
rimIntensity: f32,
|
|
163
|
+
rimPower: f32,
|
|
158
164
|
_padding1: f32,
|
|
165
|
+
rimColor: vec3f,
|
|
159
166
|
_padding2: f32,
|
|
160
|
-
_padding3: f32,
|
|
161
167
|
};
|
|
162
168
|
|
|
163
169
|
struct VertexOutput {
|
|
@@ -228,7 +234,13 @@ export class Engine {
|
|
|
228
234
|
lightAccum += toonFactor * radiance * nDotL;
|
|
229
235
|
}
|
|
230
236
|
|
|
231
|
-
|
|
237
|
+
// Rim light calculation
|
|
238
|
+
let viewDir = normalize(camera.viewPos - input.worldPos);
|
|
239
|
+
var rimFactor = 1.0 - max(dot(n, viewDir), 0.0);
|
|
240
|
+
rimFactor = pow(rimFactor, material.rimPower);
|
|
241
|
+
let rimLight = material.rimColor * material.rimIntensity * rimFactor;
|
|
242
|
+
|
|
243
|
+
let color = albedo * lightAccum + rimLight;
|
|
232
244
|
let finalAlpha = material.alpha;
|
|
233
245
|
if (finalAlpha < 0.001) {
|
|
234
246
|
discard;
|
|
@@ -269,8 +281,10 @@ export class Engine {
|
|
|
269
281
|
struct MaterialUniforms {
|
|
270
282
|
alpha: f32,
|
|
271
283
|
alphaMultiplier: f32, // New: multiplier for alpha (0.5 for over-eyes, 1.0 for over-non-eyes)
|
|
284
|
+
rimIntensity: f32,
|
|
285
|
+
rimPower: f32,
|
|
286
|
+
rimColor: vec3f,
|
|
272
287
|
_padding1: f32,
|
|
273
|
-
_padding2: f32,
|
|
274
288
|
};
|
|
275
289
|
|
|
276
290
|
struct VertexOutput {
|
|
@@ -340,7 +354,13 @@ export class Engine {
|
|
|
340
354
|
lightAccum += toonFactor * radiance * nDotL;
|
|
341
355
|
}
|
|
342
356
|
|
|
343
|
-
|
|
357
|
+
// Rim light calculation
|
|
358
|
+
let viewDir = normalize(camera.viewPos - input.worldPos);
|
|
359
|
+
var rimFactor = 1.0 - max(dot(n, viewDir), 0.0);
|
|
360
|
+
rimFactor = pow(rimFactor, material.rimPower);
|
|
361
|
+
let rimLight = material.rimColor * material.rimIntensity * rimFactor;
|
|
362
|
+
|
|
363
|
+
let color = albedo * lightAccum + rimLight;
|
|
344
364
|
let finalAlpha = material.alpha * material.alphaMultiplier;
|
|
345
365
|
if (finalAlpha < 0.001) {
|
|
346
366
|
discard;
|
|
@@ -1698,11 +1718,16 @@ export class Engine {
|
|
|
1698
1718
|
const isTransparent = materialAlpha < 1.0 - EPSILON
|
|
1699
1719
|
|
|
1700
1720
|
// Create material uniform data - for hair materials, we'll create two versions
|
|
1701
|
-
|
|
1721
|
+
// MaterialUniforms struct: alpha, rimIntensity, rimPower, _padding1, rimColor (vec3), _padding2
|
|
1722
|
+
const materialUniformData = new Float32Array(8)
|
|
1702
1723
|
materialUniformData[0] = materialAlpha
|
|
1703
|
-
materialUniformData[1] =
|
|
1704
|
-
materialUniformData[2] =
|
|
1705
|
-
materialUniformData[3] = 0.0
|
|
1724
|
+
materialUniformData[1] = this.rimLightIntensity
|
|
1725
|
+
materialUniformData[2] = this.rimLightPower
|
|
1726
|
+
materialUniformData[3] = 0.0 // _padding1
|
|
1727
|
+
materialUniformData[4] = this.rimLightColor[0] // rimColor.r
|
|
1728
|
+
materialUniformData[5] = this.rimLightColor[1] // rimColor.g
|
|
1729
|
+
materialUniformData[6] = this.rimLightColor[2] // rimColor.b
|
|
1730
|
+
materialUniformData[7] = 0.0 // _padding2
|
|
1706
1731
|
|
|
1707
1732
|
const materialUniformBuffer = this.device.createBuffer({
|
|
1708
1733
|
label: `material uniform: ${mat.name}`,
|
|
@@ -1737,11 +1762,16 @@ export class Engine {
|
|
|
1737
1762
|
})
|
|
1738
1763
|
} else if (mat.isHair) {
|
|
1739
1764
|
// For hair materials, create two bind groups: one for over-eyes (alphaMultiplier = 0.5) and one for over-non-eyes (alphaMultiplier = 1.0)
|
|
1740
|
-
|
|
1765
|
+
// Hair MaterialUniforms struct: alpha, alphaMultiplier, rimIntensity, rimPower, rimColor (vec3), _padding1
|
|
1766
|
+
const materialUniformDataOverEyes = new Float32Array(8)
|
|
1741
1767
|
materialUniformDataOverEyes[0] = materialAlpha
|
|
1742
1768
|
materialUniformDataOverEyes[1] = 0.5 // alphaMultiplier: 0.5 for over-eyes
|
|
1743
|
-
materialUniformDataOverEyes[2] =
|
|
1744
|
-
materialUniformDataOverEyes[3] =
|
|
1769
|
+
materialUniformDataOverEyes[2] = this.rimLightIntensity
|
|
1770
|
+
materialUniformDataOverEyes[3] = this.rimLightPower
|
|
1771
|
+
materialUniformDataOverEyes[4] = this.rimLightColor[0] // rimColor.r
|
|
1772
|
+
materialUniformDataOverEyes[5] = this.rimLightColor[1] // rimColor.g
|
|
1773
|
+
materialUniformDataOverEyes[6] = this.rimLightColor[2] // rimColor.b
|
|
1774
|
+
materialUniformDataOverEyes[7] = 0.0 // _padding1
|
|
1745
1775
|
|
|
1746
1776
|
const materialUniformBufferOverEyes = this.device.createBuffer({
|
|
1747
1777
|
label: `material uniform (over eyes): ${mat.name}`,
|
|
@@ -1772,10 +1802,43 @@ export class Engine {
|
|
|
1772
1802
|
isTransparent,
|
|
1773
1803
|
})
|
|
1774
1804
|
|
|
1805
|
+
// Create material uniform for hair over non-eyes (alphaMultiplier = 1.0)
|
|
1806
|
+
const materialUniformDataOverNonEyes = new Float32Array(8)
|
|
1807
|
+
materialUniformDataOverNonEyes[0] = materialAlpha
|
|
1808
|
+
materialUniformDataOverNonEyes[1] = 1.0 // alphaMultiplier: 1.0 for over-non-eyes
|
|
1809
|
+
materialUniformDataOverNonEyes[2] = this.rimLightIntensity
|
|
1810
|
+
materialUniformDataOverNonEyes[3] = this.rimLightPower
|
|
1811
|
+
materialUniformDataOverNonEyes[4] = this.rimLightColor[0] // rimColor.r
|
|
1812
|
+
materialUniformDataOverNonEyes[5] = this.rimLightColor[1] // rimColor.g
|
|
1813
|
+
materialUniformDataOverNonEyes[6] = this.rimLightColor[2] // rimColor.b
|
|
1814
|
+
materialUniformDataOverNonEyes[7] = 0.0 // _padding1
|
|
1815
|
+
|
|
1816
|
+
const materialUniformBufferOverNonEyes = this.device.createBuffer({
|
|
1817
|
+
label: `material uniform (over non-eyes): ${mat.name}`,
|
|
1818
|
+
size: materialUniformDataOverNonEyes.byteLength,
|
|
1819
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1820
|
+
})
|
|
1821
|
+
this.device.queue.writeBuffer(materialUniformBufferOverNonEyes, 0, materialUniformDataOverNonEyes)
|
|
1822
|
+
|
|
1823
|
+
const bindGroupOverNonEyes = this.device.createBindGroup({
|
|
1824
|
+
label: `material bind group (over non-eyes): ${mat.name}`,
|
|
1825
|
+
layout: this.hairBindGroupLayout,
|
|
1826
|
+
entries: [
|
|
1827
|
+
{ binding: 0, resource: { buffer: this.cameraUniformBuffer } },
|
|
1828
|
+
{ binding: 1, resource: { buffer: this.lightUniformBuffer } },
|
|
1829
|
+
{ binding: 2, resource: diffuseTexture.createView() },
|
|
1830
|
+
{ binding: 3, resource: this.textureSampler },
|
|
1831
|
+
{ binding: 4, resource: { buffer: this.skinMatrixBuffer! } },
|
|
1832
|
+
{ binding: 5, resource: toonTexture.createView() },
|
|
1833
|
+
{ binding: 6, resource: this.textureSampler },
|
|
1834
|
+
{ binding: 7, resource: { buffer: materialUniformBufferOverNonEyes } },
|
|
1835
|
+
],
|
|
1836
|
+
})
|
|
1837
|
+
|
|
1775
1838
|
this.hairDrawsOverNonEyes.push({
|
|
1776
1839
|
count: matCount,
|
|
1777
1840
|
firstIndex: runningFirstIndex,
|
|
1778
|
-
bindGroup,
|
|
1841
|
+
bindGroup: bindGroupOverNonEyes,
|
|
1779
1842
|
isTransparent,
|
|
1780
1843
|
})
|
|
1781
1844
|
} else if (isTransparent) {
|