@tinypoly/gpu-renderer 0.0.4 → 0.0.5

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.
Files changed (75) hide show
  1. package/ARCHITECTURE.md +22 -7
  2. package/README.md +1 -1
  3. package/dist/bvh.d.ts +11 -6
  4. package/dist/bvh.d.ts.map +1 -1
  5. package/dist/bvh.js +64 -11
  6. package/dist/bvh.js.map +1 -1
  7. package/dist/denoise.d.ts +7 -2
  8. package/dist/denoise.d.ts.map +1 -1
  9. package/dist/denoise.js +61 -21
  10. package/dist/denoise.js.map +1 -1
  11. package/dist/dispatchScheduler.d.ts +11 -4
  12. package/dist/dispatchScheduler.d.ts.map +1 -1
  13. package/dist/dispatchScheduler.js +14 -7
  14. package/dist/dispatchScheduler.js.map +1 -1
  15. package/dist/frameLayout.d.ts.map +1 -1
  16. package/dist/frameLayout.js +3 -0
  17. package/dist/frameLayout.js.map +1 -1
  18. package/dist/lights.d.ts +9 -1
  19. package/dist/lights.d.ts.map +1 -1
  20. package/dist/lights.js +9 -0
  21. package/dist/lights.js.map +1 -1
  22. package/dist/renderer.d.ts.map +1 -1
  23. package/dist/renderer.js +80 -22
  24. package/dist/renderer.js.map +1 -1
  25. package/dist/sceneUpload.d.ts +14 -1
  26. package/dist/sceneUpload.d.ts.map +1 -1
  27. package/dist/sceneUpload.js +21 -3
  28. package/dist/sceneUpload.js.map +1 -1
  29. package/dist/texturePack.d.ts +16 -4
  30. package/dist/texturePack.d.ts.map +1 -1
  31. package/dist/texturePack.js +61 -8
  32. package/dist/texturePack.js.map +1 -1
  33. package/dist/wgsl/bvh.wgsl.d.ts +8 -2
  34. package/dist/wgsl/bvh.wgsl.d.ts.map +1 -1
  35. package/dist/wgsl/bvh.wgsl.js +167 -96
  36. package/dist/wgsl/bvh.wgsl.js.map +1 -1
  37. package/dist/wgsl/common.wgsl.d.ts.map +1 -1
  38. package/dist/wgsl/common.wgsl.js +20 -7
  39. package/dist/wgsl/common.wgsl.js.map +1 -1
  40. package/dist/wgsl/lights.wgsl.d.ts +1 -1
  41. package/dist/wgsl/lights.wgsl.d.ts.map +1 -1
  42. package/dist/wgsl/lights.wgsl.js +3 -2
  43. package/dist/wgsl/lights.wgsl.js.map +1 -1
  44. package/dist/wgsl/pathTrace.wgsl.d.ts +1 -1
  45. package/dist/wgsl/pathTrace.wgsl.d.ts.map +1 -1
  46. package/dist/wgsl/pathTrace.wgsl.js +15 -1
  47. package/dist/wgsl/pathTrace.wgsl.js.map +1 -1
  48. package/dist/wgsl/random.wgsl.d.ts +1 -1
  49. package/dist/wgsl/random.wgsl.d.ts.map +1 -1
  50. package/dist/wgsl/random.wgsl.js +9 -17
  51. package/dist/wgsl/random.wgsl.js.map +1 -1
  52. package/dist/wgsl/surface.wgsl.d.ts +1 -1
  53. package/dist/wgsl/surface.wgsl.d.ts.map +1 -1
  54. package/dist/wgsl/surface.wgsl.js +26 -3
  55. package/dist/wgsl/surface.wgsl.js.map +1 -1
  56. package/dist/wgsl/texture.wgsl.d.ts +1 -1
  57. package/dist/wgsl/texture.wgsl.d.ts.map +1 -1
  58. package/dist/wgsl/texture.wgsl.js +10 -11
  59. package/dist/wgsl/texture.wgsl.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/bvh.ts +81 -12
  62. package/src/denoise.ts +66 -21
  63. package/src/dispatchScheduler.ts +16 -7
  64. package/src/frameLayout.ts +3 -0
  65. package/src/lights.ts +19 -1
  66. package/src/renderer.ts +92 -21
  67. package/src/sceneUpload.ts +32 -4
  68. package/src/texturePack.ts +80 -13
  69. package/src/wgsl/bvh.wgsl.ts +167 -96
  70. package/src/wgsl/common.wgsl.ts +20 -7
  71. package/src/wgsl/lights.wgsl.ts +3 -2
  72. package/src/wgsl/pathTrace.wgsl.ts +15 -1
  73. package/src/wgsl/random.wgsl.ts +9 -17
  74. package/src/wgsl/surface.wgsl.ts +26 -3
  75. package/src/wgsl/texture.wgsl.ts +10 -11
@@ -330,7 +330,21 @@ fn traceRadiance(
330
330
  continue;
331
331
  }
332
332
 
333
- let surface = resolveSurface(hit.triangle, bary, direction);
333
+ let base = sampleMap(materials[m].map, hit.triangle, bary);
334
+
335
+ // A cutout lets the ray through before anything else about the surface is read: the normal map, the other maps and
336
+ // the lobes would only be thrown away. The draw and the comparison are the ones made below, so nothing changes.
337
+ if (coverageFirst(m)) {
338
+ let opacity = coverageOf(m, materialAlphaFrom(m, hit.triangle, bary, base));
339
+
340
+ if (opacity < 1.0 && coverage.x >= opacity) {
341
+ origin = point + direction * RAY_EPSILON;
342
+ limit = select(1e30, limit - hit.distance, straight);
343
+ continue;
344
+ }
345
+ }
346
+
347
+ let surface = resolveSurfaceFrom(hit.triangle, bary, direction, base);
334
348
 
335
349
  // Blending other than normal: the surface adds its light to, or filters, whatever is behind it, and the path goes on.
336
350
  if (surface.blending == BLEND_ADDITIVE || surface.blending == BLEND_MULTIPLY || surface.blending == BLEND_SUBTRACTIVE) {
@@ -46,24 +46,16 @@ fn nestedScramble(value: u32, seed: u32) -> u32 {
46
46
  return reverseBits(laineKarras(reverseBits(value), seed));
47
47
  }
48
48
 
49
- /** The first two Sobol dimensions, as fixed point fractions. */
49
+ /**
50
+ * The first two Sobol dimensions, as fixed point fractions. The second is the index times Pascal's triangle mod 2,
51
+ * which is linear in the bits of the index, so it is read one byte at a time from the tables texturePack.ts writes
52
+ * instead of folded in one bit at a time: four reads where the scrambled index made it thirty two steps.
53
+ */
50
54
  fn sobol2(index: u32) -> vec2<u32> {
51
- var second = 0u;
52
- var direction = 0x80000000u;
53
- var bits = index;
54
-
55
- loop {
56
- if (bits == 0u) {
57
- break;
58
- }
59
-
60
- if ((bits & 1u) != 0u) {
61
- second = second ^ direction;
62
- }
63
-
64
- bits = bits >> 1u;
65
- direction = direction ^ (direction >> 1u);
66
- }
55
+ let second = textures[SOBOL_TABLE + (index & 0xffu)]
56
+ ^ textures[SOBOL_TABLE + 256u + ((index >> 8u) & 0xffu)]
57
+ ^ textures[SOBOL_TABLE + 512u + ((index >> 16u) & 0xffu)]
58
+ ^ textures[SOBOL_TABLE + 768u + (index >> 24u)];
67
59
 
68
60
  return vec2<u32>(reverseBits(index), second);
69
61
  }
@@ -173,8 +173,12 @@ fn onWireframe(triangle: u32, point: vec3<f32>) -> bool {
173
173
 
174
174
  /** Three's diffuseColor.a: opacity, the colour map's alpha, the alpha map's green and the vertex alpha. */
175
175
  fn materialAlpha(m: u32, triangle: u32, bary: vec2<f32>) -> f32 {
176
- var alpha = materials[m].color.w * sampleMap(materials[m].map, triangle, bary).a
177
- * sampleMap(materials[m].alphaMap, triangle, bary).g;
176
+ return materialAlphaFrom(m, triangle, bary, sampleMap(materials[m].map, triangle, bary));
177
+ }
178
+
179
+ /** The same, from the colour map's texel at this point. Multiplied in the order resolveSurface multiplies it. */
180
+ fn materialAlphaFrom(m: u32, triangle: u32, bary: vec2<f32>, base: vec4<f32>) -> f32 {
181
+ var alpha = materials[m].color.w * base.a * sampleMap(materials[m].alphaMap, triangle, bary).g;
178
182
 
179
183
  if ((materials[m].flags & MATERIAL_VERTEX_COLORS) != 0u) {
180
184
  alpha = alpha * triangleColor(triangle, bary).a;
@@ -554,12 +558,31 @@ fn toonRamp(gradientMap: u32, cosine: f32) -> f32 {
554
558
  return sampleTextureRaw(gradientMap, vec2<f32>(coordinate, 0.0)).r;
555
559
  }
556
560
 
561
+ /**
562
+ * Whether a material's coverage can be told from its maps alone, before the rest of the surface is read: no shader that
563
+ * might rewrite the alpha or discard, normal blending, and something that makes it partial at all.
564
+ */
565
+ fn coverageFirst(m: u32) -> bool {
566
+ let flags = materials[m].flags;
567
+ let blending = materials[m].blending;
568
+
569
+ return materials[m].program == NO_PROGRAM
570
+ && (blending == BLEND_NORMAL || blending == BLEND_NONE)
571
+ && (materials[m].alphaTest > 0.0 || (flags & (MATERIAL_ALPHA_HASH | MATERIAL_TRANSPARENT)) != 0u);
572
+ }
573
+
557
574
  /** Everything the lobes need about one point of one triangle. */
558
575
  fn resolveSurface(triangle: u32, bary: vec2<f32>, direction: vec3<f32>) -> Surface {
559
576
  let m = materialIndexOf(triangle);
577
+
578
+ return resolveSurfaceFrom(triangle, bary, direction, sampleMap(materials[m].map, triangle, bary));
579
+ }
580
+
581
+ /** The same, from the colour map's texel at this point, for a caller that already read it. */
582
+ fn resolveSurfaceFrom(triangle: u32, bary: vec2<f32>, direction: vec3<f32>, base: vec4<f32>) -> Surface {
583
+ let m = materialIndexOf(triangle);
560
584
  let flags = materials[m].flags;
561
585
  let kind = materials[m].kind;
562
- let base = sampleMap(materials[m].map, triangle, bary);
563
586
  let facing = interpolatedNormal(m, triangle, bary, direction);
564
587
  let view = -direction;
565
588
  var surface: Surface;
@@ -33,10 +33,6 @@ fn wrapIndex(index: i32, size: i32, mode: u32) -> i32 {
33
33
  return clamp(index, 0, size - 1);
34
34
  }
35
35
 
36
- fn srgbChannelToLinear(value: f32) -> f32 {
37
- return select(pow((value + 0.055) / 1.055, 2.4), value / 12.92, value <= 0.04045);
38
- }
39
-
40
36
  /** One texel, in linear light. Alpha is never encoded, as in Three. */
41
37
  fn readTexel(info: TextureInfo, x: i32, y: i32) -> vec4<f32> {
42
38
  let index = u32(y) * info.size.x + u32(x);
@@ -52,18 +48,21 @@ fn readTexel(info: TextureInfo, x: i32, y: i32) -> vec4<f32> {
52
48
  }
53
49
 
54
50
  let word = textures[info.offset + index];
55
- let raw = vec4<f32>(
56
- f32(word & 0xffu),
57
- f32((word >> 8u) & 0xffu),
58
- f32((word >> 16u) & 0xffu),
59
- f32((word >> 24u) & 0xffu)) / 255.0;
60
51
 
52
+ // The decode is a table of the 256 codes rather than a power per channel and per texel: the same values, read.
61
53
  if ((info.flags & TEXTURE_SRGB) != 0u) {
62
54
  return vec4<f32>(
63
- srgbChannelToLinear(raw.r), srgbChannelToLinear(raw.g), srgbChannelToLinear(raw.b), raw.a);
55
+ bitcast<f32>(textures[SRGB_TABLE + (word & 0xffu)]),
56
+ bitcast<f32>(textures[SRGB_TABLE + ((word >> 8u) & 0xffu)]),
57
+ bitcast<f32>(textures[SRGB_TABLE + ((word >> 16u) & 0xffu)]),
58
+ f32((word >> 24u) & 0xffu) / 255.0);
64
59
  }
65
60
 
66
- return raw;
61
+ return vec4<f32>(
62
+ f32(word & 0xffu),
63
+ f32((word >> 8u) & 0xffu),
64
+ f32((word >> 16u) & 0xffu),
65
+ f32((word >> 24u) & 0xffu)) / 255.0;
67
66
  }
68
67
 
69
68
  /** One texture of the table, sampled with its own transform, wrap modes and filter. */