@tinypoly/gpu-renderer 0.2.5 → 0.3.0

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 (101) hide show
  1. package/ARCHITECTURE.md +48 -10
  2. package/README.md +2 -0
  3. package/dist/accumulator.d.ts.map +1 -1
  4. package/dist/accumulator.js +1 -0
  5. package/dist/accumulator.js.map +1 -1
  6. package/dist/denoise.js +2 -2
  7. package/dist/denoise.js.map +1 -1
  8. package/dist/device.d.ts.map +1 -1
  9. package/dist/device.js +9 -0
  10. package/dist/device.js.map +1 -1
  11. package/dist/frameLayout.d.ts.map +1 -1
  12. package/dist/frameLayout.js +5 -0
  13. package/dist/frameLayout.js.map +1 -1
  14. package/dist/geometry.d.ts +48 -8
  15. package/dist/geometry.d.ts.map +1 -1
  16. package/dist/geometry.js +409 -134
  17. package/dist/geometry.js.map +1 -1
  18. package/dist/grass.d.ts.map +1 -1
  19. package/dist/grass.js +2 -1
  20. package/dist/grass.js.map +1 -1
  21. package/dist/imageResolve.js +2 -2
  22. package/dist/imageResolve.js.map +1 -1
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/instancing.d.ts +100 -0
  28. package/dist/instancing.d.ts.map +1 -0
  29. package/dist/instancing.js +286 -0
  30. package/dist/instancing.js.map +1 -0
  31. package/dist/lights.d.ts.map +1 -1
  32. package/dist/lights.js +8 -5
  33. package/dist/lights.js.map +1 -1
  34. package/dist/memoryProbe.d.ts +76 -0
  35. package/dist/memoryProbe.d.ts.map +1 -0
  36. package/dist/memoryProbe.js +197 -0
  37. package/dist/memoryProbe.js.map +1 -0
  38. package/dist/oidnPass.d.ts +6 -0
  39. package/dist/oidnPass.d.ts.map +1 -1
  40. package/dist/oidnPass.js +18 -1
  41. package/dist/oidnPass.js.map +1 -1
  42. package/dist/pathTracePass.d.ts +15 -2
  43. package/dist/pathTracePass.d.ts.map +1 -1
  44. package/dist/pathTracePass.js +38 -16
  45. package/dist/pathTracePass.js.map +1 -1
  46. package/dist/renderer.d.ts +13 -0
  47. package/dist/renderer.d.ts.map +1 -1
  48. package/dist/renderer.js +248 -41
  49. package/dist/renderer.js.map +1 -1
  50. package/dist/sceneUpload.d.ts +26 -8
  51. package/dist/sceneUpload.d.ts.map +1 -1
  52. package/dist/sceneUpload.js +97 -27
  53. package/dist/sceneUpload.js.map +1 -1
  54. package/dist/shaderModule.d.ts.map +1 -1
  55. package/dist/shaderModule.js +2 -1
  56. package/dist/shaderModule.js.map +1 -1
  57. package/dist/skyBake.d.ts.map +1 -1
  58. package/dist/skyBake.js +5 -3
  59. package/dist/skyBake.js.map +1 -1
  60. package/dist/texturePack.d.ts +43 -3
  61. package/dist/texturePack.d.ts.map +1 -1
  62. package/dist/texturePack.js +209 -37
  63. package/dist/texturePack.js.map +1 -1
  64. package/dist/wgsl/bvh.wgsl.d.ts +5 -1
  65. package/dist/wgsl/bvh.wgsl.d.ts.map +1 -1
  66. package/dist/wgsl/bvh.wgsl.js +105 -15
  67. package/dist/wgsl/bvh.wgsl.js.map +1 -1
  68. package/dist/wgsl/common.wgsl.d.ts.map +1 -1
  69. package/dist/wgsl/common.wgsl.js +92 -11
  70. package/dist/wgsl/common.wgsl.js.map +1 -1
  71. package/dist/wgsl/surface.wgsl.d.ts +1 -1
  72. package/dist/wgsl/surface.wgsl.d.ts.map +1 -1
  73. package/dist/wgsl/surface.wgsl.js +24 -14
  74. package/dist/wgsl/surface.wgsl.js.map +1 -1
  75. package/dist/wgsl/texture.wgsl.d.ts +1 -1
  76. package/dist/wgsl/texture.wgsl.d.ts.map +1 -1
  77. package/dist/wgsl/texture.wgsl.js +11 -0
  78. package/dist/wgsl/texture.wgsl.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/accumulator.ts +1 -0
  81. package/src/denoise.ts +2 -2
  82. package/src/device.ts +12 -0
  83. package/src/frameLayout.ts +5 -0
  84. package/src/geometry.ts +527 -133
  85. package/src/grass.ts +2 -1
  86. package/src/imageResolve.ts +2 -2
  87. package/src/index.ts +1 -0
  88. package/src/instancing.ts +415 -0
  89. package/src/lights.ts +9 -5
  90. package/src/memoryProbe.ts +275 -0
  91. package/src/oidnPass.ts +21 -1
  92. package/src/pathTracePass.ts +42 -18
  93. package/src/renderer.ts +308 -47
  94. package/src/sceneUpload.ts +139 -36
  95. package/src/shaderModule.ts +2 -1
  96. package/src/skyBake.ts +5 -3
  97. package/src/texturePack.ts +274 -43
  98. package/src/wgsl/bvh.wgsl.ts +105 -15
  99. package/src/wgsl/common.wgsl.ts +92 -11
  100. package/src/wgsl/surface.wgsl.ts +24 -14
  101. package/src/wgsl/texture.wgsl.ts +11 -0
@@ -137,13 +137,16 @@ const TEXTURE_TABLE: u32 = ${TEXTURE_TABLE}u;
137
137
  // A WebGPU device only has to offer eight storage buffers per stage, so arrays of the same kind share one binding and
138
138
  // the uniform says where the second one starts. See sceneUpload.ts, which joins them.
139
139
  @group(0) @binding(0) var<uniform> frame: Frame;
140
- // Nine coordinates per triangle, in the hierarchy's leaf order: see leafOf in bvh.wgsl.ts.
140
+ // Nine coordinates per stored triangle, in the hierarchy's leaf order: see leafOf in bvh.wgsl.ts. A prototype's are
141
+ // in object space.
141
142
  @group(0) @binding(1) var<storage, read> positions: array<f32>;
142
- // Normals, then the UV sets from frame.uvOffset, vertex colours from frame.colorOffset and shader varyings from
143
- // frame.varyingOffset.
143
+ // Per vertex: the UV sets from frame.uvOffset and vertex colours from frame.colorOffset; then shader varyings, per
144
+ // corner, from frame.varyingOffset.
144
145
  @group(0) @binding(2) var<storage, read> attributes: array<f32>;
145
- // One material index per triangle, then the hierarchy's triangle order from frame.orderOffset on (the triangle at each
146
- // position of the leaf order), then from frame.leafOffset on the other way (the position of each triangle).
146
+ // One material index per triangle a hit can name, then the hierarchy's triangle order from frame.orderOffset on (the
147
+ // stored triangle at each position of the leaf order), then from frame.leafOffset on the other way (the position of
148
+ // each stored triangle), the instance of every instanced triangle from frame.instanceOffset, the three vertices of each
149
+ // stored triangle from frame.cornerOffset and every vertex's folded normal from frame.normalOffset.
147
150
  @group(0) @binding(3) var<storage, read> indices: array<u32>;
148
151
  @group(0) @binding(4) var<storage, read> materials: array<Material>;
149
152
  @group(0) @binding(5) var<storage, read> nodes: array<BvhNode>;
@@ -163,24 +166,102 @@ fn orderedTriangle(at: u32) -> u32 {
163
166
  return indices[frame.orderOffset + at];
164
167
  }
165
168
 
166
- /** One word of a UV set: three vertices of four components, two per set. */
167
- fn attributeUv(triangle: u32, corner: u32, channel: u32) -> vec2<f32> {
168
- let at = frame.uvOffset + triangle * 12u + corner * 4u + channel * 2u;
169
+ /** What a triangle of the scene's own belongs to: no instance. */
170
+ const NO_INSTANCE: u32 = 0xffffffffu;
171
+
172
+ /** The instance a triangle a hit named belongs to, or NO_INSTANCE for one of the scene's own. */
173
+ fn instanceOf(triangle: u32) -> u32 {
174
+ if (!INSTANCES || triangle < frame.sceneTriangles) {
175
+ return NO_INSTANCE;
176
+ }
177
+
178
+ return indices[frame.instanceOffset + triangle - frame.sceneTriangles];
179
+ }
180
+
181
+ /** One word of an instance's record: see INSTANCE_WORDS in instancing.ts. */
182
+ fn instanceWord(instance: u32, word: u32) -> u32 {
183
+ return textures[frame.instanceData + instance * 28u + word];
184
+ }
185
+
186
+ /** A row of an instance's transforms: 0 to 2 take object space to world, 3 to 5 back. */
187
+ fn instanceRow(instance: u32, row: u32) -> vec4<f32> {
188
+ let at = frame.instanceData + instance * 28u + row * 4u;
189
+
190
+ return vec4<f32>(bitcast<f32>(textures[at]), bitcast<f32>(textures[at + 1u]), bitcast<f32>(textures[at + 2u]),
191
+ bitcast<f32>(textures[at + 3u]));
192
+ }
193
+
194
+ /** Where a named triangle is stored: itself, or for an instance's, the prototype's triangle it repeats. */
195
+ fn storedTriangle(triangle: u32, instance: u32) -> u32 {
196
+ if (instance == NO_INSTANCE) {
197
+ return triangle;
198
+ }
199
+
200
+ return instanceWord(instance, 25u) + triangle - instanceWord(instance, 26u);
201
+ }
202
+
203
+ /** A point of an instance's prototype, in world space. */
204
+ fn instancePoint(instance: u32, p: vec3<f32>) -> vec3<f32> {
205
+ let q = vec4<f32>(p, 1.0);
206
+
207
+ return vec3<f32>(dot(instanceRow(instance, 0u), q), dot(instanceRow(instance, 1u), q), dot(instanceRow(instance, 2u), q));
208
+ }
209
+
210
+ /** A world space point (w 1) or direction (w 0), in an instance's object space. */
211
+ fn instanceToObject(instance: u32, v: vec3<f32>, w: f32) -> vec3<f32> {
212
+ let q = vec4<f32>(v, w);
213
+
214
+ return vec3<f32>(dot(instanceRow(instance, 3u), q), dot(instanceRow(instance, 4u), q), dot(instanceRow(instance, 5u), q));
215
+ }
216
+
217
+ /** An object space normal in world space, by the inverse transpose; not normalized. */
218
+ fn instanceNormal(instance: u32, n: vec3<f32>) -> vec3<f32> {
219
+ return n.x * instanceRow(instance, 3u).xyz + n.y * instanceRow(instance, 4u).xyz + n.z * instanceRow(instance, 5u).xyz;
220
+ }
221
+
222
+ /** The three vertices of a triangle a hit named. */
223
+ fn triangleCorners(triangle: u32) -> vec3<u32> {
224
+ let at = frame.cornerOffset + storedTriangle(triangle, instanceOf(triangle)) * 3u;
225
+
226
+ return vec3<u32>(indices[at], indices[at + 1u], indices[at + 2u]);
227
+ }
228
+
229
+ /** One UV set of a vertex: four components, two per set. */
230
+ fn vertexUv(vertex: u32, channel: u32) -> vec2<f32> {
231
+ let at = frame.uvOffset + vertex * 4u + channel * 2u;
169
232
 
170
233
  return vec2<f32>(attributes[at], attributes[at + 1u]);
171
234
  }
172
235
 
173
- /** A corner's vertex colour, or white when the scene has none. */
174
- fn attributeColor(triangle: u32, corner: u32) -> vec4<f32> {
236
+ /** A vertex's colour, or white when the scene has none. */
237
+ fn vertexColor(vertex: u32) -> vec4<f32> {
175
238
  if (frame.hasColors == 0u) {
176
239
  return vec4<f32>(1.0);
177
240
  }
178
241
 
179
- let at = frame.colorOffset + triangle * 12u + corner * 4u;
242
+ let at = frame.colorOffset + vertex * 4u;
180
243
 
181
244
  return vec4<f32>(attributes[at], attributes[at + 1u], attributes[at + 2u], attributes[at + 3u]);
182
245
  }
183
246
 
247
+ /** A normal folded onto an octahedron in two signed 16 bit halves, as sceneUpload.ts folds it; zero for NO_NORMAL. */
248
+ fn vertexNormal(vertex: u32) -> vec3<f32> {
249
+ let code = indices[frame.normalOffset + vertex];
250
+
251
+ if (code == 0x80008000u) {
252
+ return vec3<f32>(0.0);
253
+ }
254
+
255
+ let e = unpack2x16snorm(code);
256
+ var n = vec3<f32>(e.x, e.y, 1.0 - abs(e.x) - abs(e.y));
257
+ let t = max(-n.z, 0.0);
258
+
259
+ n.x = n.x + select(t, -t, n.x >= 0.0);
260
+ n.y = n.y + select(t, -t, n.y >= 0.0);
261
+
262
+ return normalize(n);
263
+ }
264
+
184
265
  fn extraFloat(at: u32) -> f32 {
185
266
  return bitcast<f32>(textures[at]);
186
267
  }
@@ -82,15 +82,19 @@ fn trianglePointAt(triangle: u32, bary: vec2<f32>) -> vec3<f32> {
82
82
  }
83
83
 
84
84
  fn triangleUv(triangle: u32, bary: vec2<f32>, channel: u32) -> vec2<f32> {
85
- return attributeUv(triangle, 0u, channel) * (1.0 - bary.x - bary.y)
86
- + attributeUv(triangle, 1u, channel) * bary.x
87
- + attributeUv(triangle, 2u, channel) * bary.y;
85
+ let corners = triangleCorners(triangle);
86
+
87
+ return vertexUv(corners.x, channel) * (1.0 - bary.x - bary.y)
88
+ + vertexUv(corners.y, channel) * bary.x
89
+ + vertexUv(corners.z, channel) * bary.y;
88
90
  }
89
91
 
90
92
  fn triangleColor(triangle: u32, bary: vec2<f32>) -> vec4<f32> {
91
- return attributeColor(triangle, 0u) * (1.0 - bary.x - bary.y)
92
- + attributeColor(triangle, 1u) * bary.x
93
- + attributeColor(triangle, 2u) * bary.y;
93
+ let corners = triangleCorners(triangle);
94
+
95
+ return vertexColor(corners.x) * (1.0 - bary.x - bary.y)
96
+ + vertexColor(corners.y) * bary.x
97
+ + vertexColor(corners.z) * bary.y;
94
98
  }
95
99
 
96
100
  /** A map slot, sampled through the UV set the texture asks for. Missing maps read as one, so a multiply is always safe. */
@@ -362,9 +366,10 @@ fn tangentFrame(triangle: u32, channel: u32, normal: vec3<f32>) -> TangentFrame
362
366
  let p0 = triangleVertex(triangle, 0u);
363
367
  let edge1 = triangleVertex(triangle, 1u) - p0;
364
368
  let edge2 = triangleVertex(triangle, 2u) - p0;
365
- let uv0 = attributeUv(triangle, 0u, channel);
366
- let delta1 = attributeUv(triangle, 1u, channel) - uv0;
367
- let delta2 = attributeUv(triangle, 2u, channel) - uv0;
369
+ let corners = triangleCorners(triangle);
370
+ let uv0 = vertexUv(corners.x, channel);
371
+ let delta1 = vertexUv(corners.y, channel) - uv0;
372
+ let delta2 = vertexUv(corners.z, channel) - uv0;
368
373
  let determinant = delta1.x * delta2.y - delta2.x * delta1.y;
369
374
 
370
375
  // A triangle with no UV area has no tangent frame to offer.
@@ -460,12 +465,17 @@ fn mappedNormal(m: u32, triangle: u32, bary: vec2<f32>, normal: vec3<f32>) -> ve
460
465
 
461
466
  /** The interpolated vertex normal as the mesh authored it, pointing out of a closed volume. */
462
467
  fn authoredNormal(triangle: u32, bary: vec2<f32>) -> vec3<f32> {
463
- let base = triangle * 9u;
464
- let n0 = vec3<f32>(attributes[base], attributes[base + 1u], attributes[base + 2u]);
465
- let n1 = vec3<f32>(attributes[base + 3u], attributes[base + 4u], attributes[base + 5u]);
466
- let n2 = vec3<f32>(attributes[base + 6u], attributes[base + 7u], attributes[base + 8u]);
468
+ let instance = instanceOf(triangle);
469
+ let at = frame.cornerOffset + storedTriangle(triangle, instance) * 3u;
470
+ let n = vertexNormal(indices[at]) * (1.0 - bary.x - bary.y)
471
+ + vertexNormal(indices[at + 1u]) * bary.x
472
+ + vertexNormal(indices[at + 2u]) * bary.y;
473
+
474
+ if (instance != NO_INSTANCE) {
475
+ return normalize(instanceNormal(instance, n));
476
+ }
467
477
 
468
- return normalize(n0 * (1.0 - bary.x - bary.y) + n1 * bary.x + n2 * bary.y);
478
+ return normalize(n);
469
479
  }
470
480
 
471
481
  /** The interpolated vertex normal, or the face's for flat shading, turned to face the ray. */
@@ -12,6 +12,7 @@ const TEXTURE_FLOAT: u32 = 1u;
12
12
  const TEXTURE_SRGB: u32 = 2u;
13
13
  const TEXTURE_NEAREST: u32 = 4u;
14
14
  const TEXTURE_FLIP_Y: u32 = 8u;
15
+ const TEXTURE_SINGLE: u32 = 32u;
15
16
 
16
17
  // Three's own wrap constants. Anything else clamps, as it does in the CPU renderer.
17
18
  const WRAP_REPEAT: u32 = 1000u;
@@ -47,6 +48,16 @@ fn readTexel(info: TextureInfo, x: i32, y: i32) -> vec4<f32> {
47
48
  bitcast<f32>(textures[at + 3u]));
48
49
  }
49
50
 
51
+ // The only channel the scene reads, four texels to a word, handed back in every channel: alpha as it is, the colour
52
+ // decoded where the texture is sRGB, as a full texel's would be.
53
+ if ((info.flags & TEXTURE_SINGLE) != 0u) {
54
+ let code = (textures[info.offset + (index >> 2u)] >> ((index & 3u) * 8u)) & 0xffu;
55
+ let raw = f32(code) / 255.0;
56
+ let colour = select(raw, bitcast<f32>(textures[SRGB_TABLE + code]), (info.flags & TEXTURE_SRGB) != 0u);
57
+
58
+ return vec4<f32>(colour, colour, colour, raw);
59
+ }
60
+
50
61
  let word = textures[info.offset + index];
51
62
 
52
63
  // The decode is a table of the 256 codes rather than a power per channel and per texel: the same values, read.