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 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
@@ -54,6 +54,9 @@ export declare class Engine {
54
54
  private linearSampler;
55
55
  bloomThreshold: number;
56
56
  bloomIntensity: number;
57
+ private rimLightIntensity;
58
+ private rimLightPower;
59
+ private rimLightColor;
57
60
  private currentModel;
58
61
  private modelDir;
59
62
  private physics;
@@ -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;IACpC,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;IAg0BvB,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;YAiPd,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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
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
- let color = albedo * lightAccum;
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
- let color = albedo * lightAccum;
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
- const materialUniformData = new Float32Array(4);
1524
+ // MaterialUniforms struct: alpha, rimIntensity, rimPower, _padding1, rimColor (vec3), _padding2
1525
+ const materialUniformData = new Float32Array(8);
1505
1526
  materialUniformData[0] = materialAlpha;
1506
- materialUniformData[1] = 1.0; // alphaMultiplier: 1.0 for normal rendering
1507
- materialUniformData[2] = 0.0;
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
- const materialUniformDataOverEyes = new Float32Array(4);
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] = 0.0;
1545
- materialUniformDataOverEyes[3] = 0.0;
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.10",
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/reze-engine/reze-engine"
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
- let color = albedo * lightAccum;
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
- let color = albedo * lightAccum;
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
- const materialUniformData = new Float32Array(4)
1721
+ // MaterialUniforms struct: alpha, rimIntensity, rimPower, _padding1, rimColor (vec3), _padding2
1722
+ const materialUniformData = new Float32Array(8)
1702
1723
  materialUniformData[0] = materialAlpha
1703
- materialUniformData[1] = 1.0 // alphaMultiplier: 1.0 for normal rendering
1704
- materialUniformData[2] = 0.0
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
- const materialUniformDataOverEyes = new Float32Array(4)
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] = 0.0
1744
- materialUniformDataOverEyes[3] = 0.0
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) {