@tinypoly/gpu-renderer 0.0.5 → 0.1.1

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 (115) hide show
  1. package/ARCHITECTURE.md +59 -3
  2. package/README.md +53 -4
  3. package/dist/atmosphere.d.ts +21 -0
  4. package/dist/atmosphere.d.ts.map +1 -0
  5. package/dist/atmosphere.js +72 -0
  6. package/dist/atmosphere.js.map +1 -0
  7. package/dist/denoise.d.ts +11 -1
  8. package/dist/denoise.d.ts.map +1 -1
  9. package/dist/denoise.js +34 -6
  10. package/dist/denoise.js.map +1 -1
  11. package/dist/frameLayout.d.ts.map +1 -1
  12. package/dist/frameLayout.js +17 -0
  13. package/dist/frameLayout.js.map +1 -1
  14. package/dist/geometry.d.ts.map +1 -1
  15. package/dist/geometry.js +6 -3
  16. package/dist/geometry.js.map +1 -1
  17. package/dist/index.d.ts +4 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +3 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/lensPass.d.ts +60 -0
  22. package/dist/lensPass.d.ts.map +1 -0
  23. package/dist/lensPass.js +235 -0
  24. package/dist/lensPass.js.map +1 -0
  25. package/dist/lightTree.d.ts +50 -0
  26. package/dist/lightTree.d.ts.map +1 -0
  27. package/dist/lightTree.js +146 -0
  28. package/dist/lightTree.js.map +1 -0
  29. package/dist/lights.d.ts +12 -0
  30. package/dist/lights.d.ts.map +1 -1
  31. package/dist/lights.js +56 -1
  32. package/dist/lights.js.map +1 -1
  33. package/dist/materialLayout.d.ts +24 -0
  34. package/dist/materialLayout.d.ts.map +1 -1
  35. package/dist/materialLayout.js +36 -1
  36. package/dist/materialLayout.js.map +1 -1
  37. package/dist/pathTracePass.d.ts +6 -3
  38. package/dist/pathTracePass.d.ts.map +1 -1
  39. package/dist/pathTracePass.js +16 -10
  40. package/dist/pathTracePass.js.map +1 -1
  41. package/dist/renderer.d.ts +27 -7
  42. package/dist/renderer.d.ts.map +1 -1
  43. package/dist/renderer.js +153 -16
  44. package/dist/renderer.js.map +1 -1
  45. package/dist/sceneUpload.d.ts +6 -0
  46. package/dist/sceneUpload.d.ts.map +1 -1
  47. package/dist/sceneUpload.js +5 -0
  48. package/dist/sceneUpload.js.map +1 -1
  49. package/dist/settings.d.ts +142 -0
  50. package/dist/settings.d.ts.map +1 -0
  51. package/dist/settings.js +100 -0
  52. package/dist/settings.js.map +1 -0
  53. package/dist/subsurface.d.ts +76 -0
  54. package/dist/subsurface.d.ts.map +1 -0
  55. package/dist/subsurface.js +70 -0
  56. package/dist/subsurface.js.map +1 -0
  57. package/dist/volumeContainment.d.ts +17 -0
  58. package/dist/volumeContainment.d.ts.map +1 -0
  59. package/dist/volumeContainment.js +61 -0
  60. package/dist/volumeContainment.js.map +1 -0
  61. package/dist/wgsl/bsdf.wgsl.d.ts +1 -1
  62. package/dist/wgsl/bsdf.wgsl.d.ts.map +1 -1
  63. package/dist/wgsl/bsdf.wgsl.js +35 -3
  64. package/dist/wgsl/bsdf.wgsl.js.map +1 -1
  65. package/dist/wgsl/common.wgsl.d.ts.map +1 -1
  66. package/dist/wgsl/common.wgsl.js +4 -0
  67. package/dist/wgsl/common.wgsl.js.map +1 -1
  68. package/dist/wgsl/lens.wgsl.d.ts +17 -0
  69. package/dist/wgsl/lens.wgsl.d.ts.map +1 -0
  70. package/dist/wgsl/lens.wgsl.js +301 -0
  71. package/dist/wgsl/lens.wgsl.js.map +1 -0
  72. package/dist/wgsl/lights.wgsl.d.ts +1 -1
  73. package/dist/wgsl/lights.wgsl.d.ts.map +1 -1
  74. package/dist/wgsl/lights.wgsl.js +237 -31
  75. package/dist/wgsl/lights.wgsl.js.map +1 -1
  76. package/dist/wgsl/pathTrace.wgsl.d.ts +1 -1
  77. package/dist/wgsl/pathTrace.wgsl.d.ts.map +1 -1
  78. package/dist/wgsl/pathTrace.wgsl.js +406 -25
  79. package/dist/wgsl/pathTrace.wgsl.js.map +1 -1
  80. package/dist/wgsl/random.wgsl.d.ts +1 -1
  81. package/dist/wgsl/random.wgsl.d.ts.map +1 -1
  82. package/dist/wgsl/random.wgsl.js +28 -0
  83. package/dist/wgsl/random.wgsl.js.map +1 -1
  84. package/dist/wgsl/sampling.wgsl.d.ts +1 -1
  85. package/dist/wgsl/sampling.wgsl.d.ts.map +1 -1
  86. package/dist/wgsl/sampling.wgsl.js +25 -0
  87. package/dist/wgsl/sampling.wgsl.js.map +1 -1
  88. package/dist/wgsl/surface.wgsl.d.ts +1 -1
  89. package/dist/wgsl/surface.wgsl.d.ts.map +1 -1
  90. package/dist/wgsl/surface.wgsl.js +21 -1
  91. package/dist/wgsl/surface.wgsl.js.map +1 -1
  92. package/package.json +1 -1
  93. package/src/atmosphere.ts +95 -0
  94. package/src/denoise.ts +44 -6
  95. package/src/frameLayout.ts +17 -0
  96. package/src/geometry.ts +6 -2
  97. package/src/index.ts +13 -0
  98. package/src/lensPass.ts +299 -0
  99. package/src/lightTree.ts +218 -0
  100. package/src/lights.ts +75 -1
  101. package/src/materialLayout.ts +52 -1
  102. package/src/pathTracePass.ts +19 -10
  103. package/src/renderer.ts +206 -24
  104. package/src/sceneUpload.ts +11 -0
  105. package/src/settings.ts +240 -0
  106. package/src/subsurface.ts +153 -0
  107. package/src/volumeContainment.ts +81 -0
  108. package/src/wgsl/bsdf.wgsl.ts +35 -3
  109. package/src/wgsl/common.wgsl.ts +4 -0
  110. package/src/wgsl/lens.wgsl.ts +300 -0
  111. package/src/wgsl/lights.wgsl.ts +237 -31
  112. package/src/wgsl/pathTrace.wgsl.ts +406 -25
  113. package/src/wgsl/random.wgsl.ts +28 -0
  114. package/src/wgsl/sampling.wgsl.ts +25 -0
  115. package/src/wgsl/surface.wgsl.ts +21 -1
package/ARCHITECTURE.md CHANGED
@@ -146,6 +146,57 @@ frame traces (at the end of a pass, at most every 200 ms) and on the image `rend
146
146
  holds six vec4 per pixel for all of this, 96 bytes, and the filter six more buffers of 16 and one of 4, the last two
147
147
  the guides each tap compares, worked out once per pixel: a 2000 x 1350 image takes some 530 MB on the device.
148
148
 
149
+ **Light inside materials and volumes is a walk, compiled in only where a scene has it.** Both are media the path
150
+ crosses instead of surfaces it bounces off, and both are written into the bounce loop rather than as loops of their
151
+ own, so the one traversal call in the loop serves them.
152
+
153
+ - **Subsurface scattering** is a random walk, as in Cycles. A vertex on such a material takes the walk instead of its
154
+ surface lobes by chance, in proportion to the light each accounts for, so neither is weighted against the other; the
155
+ lobes it keeps lose that share of the diffuse layer. Inside, each colour has its own mean free path (`radius`) and the
156
+ single scattering albedo that the material's colour asks for (van de Hulst's relation, inverted); distances are drawn
157
+ for a colour picked by what the path still carries of it and weighed over all three (spectral MIS). Where the walk
158
+ reaches a surface it leaves through a white Lambert surface facing out, which takes direct light there.
159
+ - **Volumes** are homogeneous media bounded by an invisible mesh. A medium of one grey density lets the distance be
160
+ drawn after the segment is traced: the next hit is found, then a collision before it is drawn, and either way the
161
+ weight is one. A collision is a vertex whose lobe is the phase function (Henyey-Greenstein), with light sampled from
162
+ there. Shadow rays fade through every boundary they cross, and through the volume they start in; a light that casts no
163
+ shadow still fades, since the medium is not geometry. Whether the camera stands inside one is found on the CPU, by the
164
+ parity of a ray's crossings, once per frame.
165
+ - `SUBSURFACE_WALK` and `VOLUMES` are WGSL constants the pipeline is compiled with, true only for a scene with such a
166
+ material. Carrying the walk's code in every scene measured 2 to 5 percent slower on scenes that never run it (see
167
+ the next decision); folded away, a plain scene renders the same image as before, byte for byte.
168
+ - The snapshot has no field for either medium, so `serializeLive` marks the material's name while the CPU renderer
169
+ serializes it, as it already renames a shader material's type, and attaches the medium after. A snapshot built
170
+ elsewhere can carry `subsurface` or `volume` on its materials itself.
171
+
172
+ **The lens and the sensor are a pass of their own, after the radiance.** Bloom (Jimenez's 13 tap pyramid, folded
173
+ back with a tent), the aperture's rays (gathered along each ray from a quarter sized level), lateral chromatic
174
+ aberration and the white balance (a von Kries scaling in Bradford's cone space, exactly the identity at 6500 K) work on
175
+ linear light between the denoiser and the display transform, into a buffer the presentation and the image resolve read
176
+ in its place. Bloom and rays only move light, with weights that sum to one, so a flat image keeps its mean. Aerial
177
+ perspective is not part of it: it needs each sample's distance, so the kernel lays it over the camera's first surface,
178
+ as it lays Three's fog, with the extinction Koschmieder's law gives each colour and the glow of the surroundings and of
179
+ the brightest directional light scattered by the air's phase function. Lens distortion bends the camera rays, so it
180
+ needs no resampling.
181
+
182
+ **Lights are picked through a tree, by what they can deliver to the shaded point.** Picking by power alone sends a
183
+ small lamp beside a surface as few samples as its power earns against a large panel across the room, and its light
184
+ then arrives through bounce rays as fireflies. The lights that sit in the scene (emissive triangles, point, spot and
185
+ rectangular lights) lead the light buffer and are bound by a tree built on the CPU (`lightTree.ts`): each node keeps
186
+ its box, its power and a cone of the directions its lights face, and the kernel walks down choosing a child by its
187
+ importance from the point, power over squared distance times how well the cone and the receiving normal face each other,
188
+ widened by the angle the box takes (Conty Estevez and Kulla, 2018, without the splitting). The same walk, taken up from
189
+ a leaf, gives the chance a bounce ray's light was picked from the vertex it left, so the heuristic stays exact. The
190
+ directional lights and the environment follow, picked as before by the irradiance they deliver; the share between the
191
+ two groups is what the old distribution gave them. The nodes live in the texture buffer's extra words, sixteen a node,
192
+ because the kernel's eight storage bindings are taken.
193
+
194
+ **Bevel rounds edges at shading time, by one probe a sample.** As Cycles' bevel node, but stochastic: a point on a disk
195
+ of the radius around the shaded point, across an axis picked along the normal half the time and each tangent a
196
+ quarter, and a short ray along it that finds the same material there. Its normal turns the shading normal by as much
197
+ as it differs from the normal here, which keeps a normal map, and the pixel's samples average the turn into a rounded
198
+ edge. It costs a traversal a vertex on such materials, so `BEVEL` is compiled in only for a scene that has one.
199
+
149
200
  **The kernel is bound by its size, not by its arithmetic.** Measured on an Apple GPU (`scripts/bench.html`, every
150
201
  build timed in turns against the other), the nodes that hold their children's boxes made whole renders 16 to 21 percent
151
202
  faster, but only once the traversal loop tested leaves in one place: with the leaf test written out wherever a leaf
@@ -256,7 +307,7 @@ it over one pixel.
256
307
  | `SpotLight` | Cone and penumbra as Three computes them, and its projected `map` |
257
308
  | `RectAreaLight` | A real area light, sampled over its rectangle, so its penumbra is traced rather than approximated |
258
309
  | `AmbientLight`, `HemisphereLight` | See the divergence below |
259
- | Emissive geometry | Any triangle whose material emits, weighted by area and power |
310
+ | Emissive geometry | Any triangle whose material emits, picked through the light tree by what it delivers to the shaded point |
260
311
 
261
312
  `light.castShadow` gates the occlusion ray, as does `settings.shadows.enabled`. A `RectAreaLight` always occludes,
262
313
  because Three has no shadow switch for one and an area light that cast none would look broken once traced. A toon
@@ -286,7 +337,10 @@ covers every surface instead.
286
337
 
287
338
  Read: `samples`, `renderScale`, `exposure`, `toneMapping`, `vignette`, `grain`, `background`, `fog`, `depthOfField`
288
339
  (the CPU renderer's 35 mm lens, `focusDistance`, `aperture` as an f-number, `blades` for polygonal bokeh),
289
- `globalIllumination.bounces`, `globalIllumination.clamp`, `shadows.enabled`, `shadows.softness`.
340
+ `globalIllumination.bounces`, `globalIllumination.clamp`, `shadows.enabled`, `shadows.softness`, and the groups only this
341
+ renderer has: `globalIllumination.russianRoulette` and `rouletteStart`, `bloom`, `glare`, `lens`, `camera`,
342
+ `atmosphere`, `subsurface` and `volumes`. Its defaults differ from the CPU renderer's in `toneMapping` (AgX),
343
+ `globalIllumination.bounces` (12) and `globalIllumination.clamp` (10).
290
344
 
291
345
  Ignored: `tileSize`, `ambientOcclusion`, and everything else under `globalIllumination` (`enabled`, `samples`,
292
346
  `intensity`, `cache`, `cacheSpacing`, `denoise`).
@@ -322,7 +376,9 @@ Ignored: `tileSize`, `ambientOcclusion`, and everything else under `globalIllumi
322
376
  - **Transparency is stochastic.** A surface with an opacity below one lets that share of rays straight through, which is
323
377
  what makes a cutout cast a cutout shadow, and what makes the result converge rather than composite.
324
378
  - **Unlit surfaces emit.** A basic material, a shader material, a sprite: whatever colour Three would draw, the surface
325
- radiates, so it also lights its surroundings (found by bounce rays, not aimed at).
379
+ radiates, so it also lights its surroundings. An opaque `MeshBasicMaterial` of a fixed colour (normal blending, no
380
+ alpha, light or environment map) is aimed at as a light, its colour times its map and vertex colours read at the
381
+ sampled point; anything else unlit is only found by bounce rays, since what it shows is not known until it runs.
326
382
  - Global illumination is always on. There is no flag for it: tracing paths is what this renderer does.
327
383
  - **Glass refracts** where Three's transmission samples a blurred copy of the opaque scene behind it. A volume bends what
328
384
  is behind it and reflects its surroundings properly; a thin wall is exact. Neither is what Three draws.
package/README.md CHANGED
@@ -18,6 +18,7 @@ It is the GPU sibling of [@tinypoly/cpu-renderer](https://github.com/tinypoly/cp
18
18
  - Perspective and orthographic cameras, any projection Three builds; meshes, lines (`Line`, `LineSegments`, `LineLoop`), dashed lines, fat lines (`Line2`), sprites and `PointsMaterial`.
19
19
  - Your custom `ShaderMaterial` GLSL, `RawShaderMaterial` and `onBeforeCompile` hooks: fragment shaders are translated to WGSL by [naga](https://github.com/gfx-rs/wgpu/tree/trunk/naga) and run in the kernel, with real derivatives; vertex shaders run on the CPU renderer's interpreter.
20
20
  - HDR, gradient or procedural sky environments, light probes, depth of field with polygonal bokeh, fog, volumetric lights, vignette and grain, and ACES, AgX or Neutral tone mapping.
21
+ - What a photograph adds, on by default: subsurface scattering, volumes of fog and smoke, aerial perspective, a lens's bloom, aperture rays, chromatic aberration and distortion, a camera's white balance and exposure triangle.
21
22
  - Adaptive sampling: pixels whose noise is gone stop taking paths, and the work they leave goes to the dark, glossy and out of focus areas that still need it.
22
23
  - A variance-guided denoiser (the spatial filter of SVGF, with diffuse and specular light filtered apart as NVIDIA's RELAX does): each signal is separated from its albedo, filtered by an edge-avoiding wavelet that stops at normals, depths and roughness and trusts each pixel as far as its own variance says, and multiplied back, so textures stay sharp, a sharp reflection stays sharp and flat areas keep their exact mean.
23
24
  - Progressive output: the canvas refines sample by sample, and the render can be paused, resumed and cancelled.
@@ -152,20 +153,23 @@ The renderer never falls back on its own. Choosing another renderer when WebGPU
152
153
 
153
154
  ### Settings
154
155
 
155
- `RenderSettings`, grouped by feature, the CPU renderer's own. Defaults are `DEFAULT_RENDER_SETTINGS`; `mergeSettings(base, input)` applies a partial `RenderSettingsInput` the way `setSettings` does. A path tracer reads some of them differently:
156
+ `GpuRenderSettings`: the CPU renderer's `RenderSettings`, grouped by feature, with the [groups only this renderer reads](#what-a-photograph-adds) beside them in the same object, which the CPU renderer leaves alone. Defaults are `DEFAULT_GPU_RENDER_SETTINGS`, the CPU renderer's own with what a photograph has turned on; `mergeGpuSettings(base, input)` applies a partial `GpuRenderSettingsInput` the way `setSettings` does. A path tracer reads some of the shared ones differently:
156
157
 
157
158
  | Field | Default | |
158
159
  | --- | --- | --- |
159
160
  | `renderScale` | `1` | Multiplier on the image size. |
160
161
  | `samples` | `4` | **Paths per pixel**, on average: one number does the antialiasing and the global illumination in a path tracer, and a few hundred is a clean image. Above 32, a pixel that has converged stops early and the noisiest ones take up to four times as many. |
161
- | `toneMapping` | `"aces"` | `"aces"`, `"agx"`, `"neutral"` or `"linear"`. |
162
+ | `toneMapping` | `"agx"` | `"aces"`, `"agx"`, `"neutral"` or `"linear"`. AgX rolls highlights off as film does; the CPU renderer defaults to ACES. |
162
163
  | `exposure` | `1` | |
163
164
  | `background.mode` | `"environment"` | `"environment"`, `"color"` or `"transparent"`, which makes the image's alpha the coverage of every pixel. |
164
165
  | `background.color` | `"#1a1a1a"` | Used by `mode: "color"`. |
165
166
  | `shadows.enabled` | `true` | Whether Three's lights are occlusion tested. Emissive geometry always is. |
166
167
  | `shadows.softness` | `1` | Angular diameter of the lights in degrees. `0` gives hard shadows. |
167
- | `globalIllumination.bounces` | `3` | How far a path goes. Glass wants four or more. |
168
- | `globalIllumination.clamp` | `0` | Maximum luminance one indirect contribution may add, which trades a little bias for fewer fireflies. `0` disables clamping. |
168
+ | `globalIllumination.bounces` | `12` | How far a path goes: enough for light to fill a room. The roulette below keeps it affordable. |
169
+ | `globalIllumination.clamp` | `10` | Maximum luminance one indirect contribution may add, which trades a little bias for fewer fireflies, as Cycles' indirect light clamp does. `0` disables clamping. |
170
+ | `globalIllumination.russianRoulette` | `true` | Ends a path that carries little light by chance, weighting the survivors up so the mean stays exact. |
171
+ | `globalIllumination.rouletteStart` | `1` | Bounces every path takes before the roulette may end it. Past them a path carries on with the chance its own throughput gives, as in PBRT. |
172
+ | `globalIllumination.lightTree` | `true` | Picks the light to aim at by what it delivers to the shaded point (power, distance, facing) through a tree over the scene's lights, rather than by power alone: a small lamp near a surface gets the samples it needs. |
169
173
  | `depthOfField.enabled` | `false` | |
170
174
  | `depthOfField.focusDistance` | `10` | World units. |
171
175
  | `depthOfField.aperture` | `2.8` | f-number. |
@@ -176,6 +180,37 @@ The renderer never falls back on its own. Choosing another renderer when WebGPU
176
180
  | `vignette` | `0` | `0` to `1`. |
177
181
  | `grain` | `0` | `0` to `1`. |
178
182
 
183
+ #### What a photograph adds
184
+
185
+ Groups only this renderer reads, all on by default except the physical exposure, which needs a scene lit in physical units. Changing the lens, the camera's white balance or exposure, the bloom or the glare shows the finished image again without tracing it.
186
+
187
+ | Field | Default | |
188
+ | --- | --- | --- |
189
+ | `bloom.enabled` | `true` | The halo a lens and sensor scatter around bright light. Energy conserving and without a threshold: it only shows where something is far brighter than its surroundings. |
190
+ | `bloom.intensity` | `0.04` | Share of the light the halo takes, `0` to `1`. |
191
+ | `bloom.radius` | `0.65` | How far it reaches, `0` to `1`. |
192
+ | `glare.enabled` | `true` | The rays a bright light throws through the aperture's blades. Energy conserving like the bloom. |
193
+ | `glare.intensity` | `0.06` | Share of the light the rays take, `0` to `1`. |
194
+ | `glare.blades` | `6` | Blades of the aperture: an even count makes as many rays, an odd count twice as many. |
195
+ | `glare.length`, `glare.rotation` | `0.25`, `15` | How far the rays reach, as a share of the half diagonal, and the aperture's turn in degrees. |
196
+ | `lens.chromaticAberration` | `0.2` | Lateral colour fringes towards the corners, `0` to `1`. |
197
+ | `lens.distortion` | `0` | Radial distortion of the camera rays: positive is barrel, negative pincushion. |
198
+ | `camera.whiteBalance` | `6500` | Kelvin the camera takes as white; `6500` is neutral, lower cools the image. |
199
+ | `camera.physicalExposure` | `false` | Exposes from `iso`, `shutterSpeed` and `depthOfField.aperture`, with `exposure` as compensation. |
200
+ | `camera.iso`, `camera.shutterSpeed` | `100`, `1/125` | Seconds for the shutter. |
201
+ | `atmosphere.enabled` | `true` | Aerial perspective: the air fades distant surfaces towards the light it scatters, from the surroundings and the brightest directional light. Scenes in metres. |
202
+ | `atmosphere.visibility` | `20000` | Scene units at which a dark object keeps 2 percent contrast (Koschmieder): 20 km is a clear day. |
203
+ | `atmosphere.haze` | `0.6` | `0` clean air, blue (Rayleigh); `1` haze, grey and bright towards the sun (Mie). |
204
+ | `atmosphere.color` | `""` | The air's glow as `#rrggbb`; empty takes the surroundings' average. |
205
+ | `subsurface.enabled` | `true` | Materials with a [`subsurface`](#object-options) medium scatter light inside. |
206
+ | `subsurface.depth` | `2` | Bounces at which light still walks inside such a material; deeper it reflects as a diffuse surface of the same colour, which saves most of the walk's cost for what hardly shows. |
207
+ | `volumes.enabled` | `true` | Meshes with a [`volume`](#object-options) are filled with their medium; off leaves them out. |
208
+ | `bevel.enabled` | `true` | Materials with a [`bevel`](#object-options) radius round their edges at shading time. |
209
+
210
+ ```ts
211
+ renderer.setSettings({ glare: { blades: 7 }, camera: { whiteBalance: 3200 }, atmosphere: { visibility: 3000 } });
212
+ ```
213
+
179
214
  `globalIllumination.denoise` (default `true`) turns the denoiser on: on the canvas a few times a second while the frame traces, and on the image `render()` resolves with. Switching it alone filters the finished image again without tracing.
180
215
 
181
216
  ### Denoiser
@@ -189,6 +224,8 @@ A variance-guided wavelet filter, the spatial half of SVGF, with the diffuse and
189
224
  | `edge` | `2` | How large a luminance difference still counts as noise, in standard deviations of the pixel's own noise. Lower keeps more detail and removes less noise. |
190
225
  | `onlyNoisy` | `true` | Leaves the pixels that have converged as they were traced, and filters only where noise is still visible. |
191
226
  | `antiFirefly` | `true` | Before filtering, clamps a pixel brighter than every one of its eight neighbours to the brightest of them, in each signal. |
227
+ | `subsurface` | `1` | How far the diffuse filter lets go of its normal and depth tests over a material that scatters light inside, `0` to `1`: such light leaves the surface after wandering under it. |
228
+ | `mirrorRadius` | `3` | The smallest footprint a smooth reflection (roughness under 0.3) is filtered over, in pixels, by taps that see the reflected thing at the same distance, which keeps its edges. `0` leaves a mirror alone. |
192
229
 
193
230
  A denoiser trades noise for detail. What it smooths most is what its guides cannot see: the relief of a lacquer, an out of focus area. With `onlyNoisy` it leaves alone whatever has already converged, so more samples always mean less filtering.
194
231
 
@@ -227,6 +264,18 @@ The renderer reads the CPU renderer's optional settings from `userData.cpuRender
227
264
  light.userData.cpuRenderer = { volumetric: { density: 0.05 } };
228
265
  ```
229
266
 
267
+ Two more on materials, which only this renderer reads:
268
+
269
+ - **`subsurface`** (standard and physical materials): light enters the material and leaves it somewhere else, by a random walk inside it, as skin, wax, marble and milk do. `true` takes Blender's defaults. The material's colour, maps included, is what the medium reflects in all; `radius` is how far red, green and blue travel inside, as multiples of `scale` in scene units; `weight` is the share of the diffuse layer that scatters inside; `anisotropy` the phase function's.
270
+ - **`bevel`** (lit materials): a radius in scene units, over which the shading normal turns from one face to the next, as Cycles' bevel node rounds edges without changing the geometry. Sharp CG corners catch light like real, slightly rounded ones. The normal map still applies.
271
+ - **`volume`** (any material): the mesh only bounds a medium, which scatters and absorbs light in the space it encloses: fog, smoke, a beam of sunlight through dust, murky water. Its surface is invisible. `density` is per scene unit, `color` what each scattering keeps (white for fog, dark for soot), `anisotropy` how forward it scatters (about `0.7` for haze). The mesh has to be closed, with its normals out; the camera may stand inside one, and objects inside are lit through it.
272
+
273
+ ```ts
274
+ skin.userData.cpuRenderer = { subsurface: { radius: [1, 0.4, 0.25], scale: 0.01 } };
275
+ table.userData.cpuRenderer = { bevel: 0.003 };
276
+ haze.material.userData.cpuRenderer = { volume: { density: 0.05, color: "#ffffff", anisotropy: 0.6 } };
277
+ ```
278
+
230
279
  ### Helpers
231
280
 
232
281
  | Function | |
@@ -0,0 +1,21 @@
1
+ import type { PackedEnvironment } from "./environment.js";
2
+ import type { GpuRenderSettings } from "./settings.js";
3
+ import type { SerializedLight } from "./upstream.js";
4
+ /** Extinction per scene unit of red, green and blue for the atmosphere setting, or nothing when it is off. */
5
+ export declare function atmosphereExtinction(atmosphere: GpuRenderSettings["atmosphere"]): [number, number, number];
6
+ /** The brightest directional light of a scene, which lights the air: its direction towards the light and irradiance. */
7
+ export declare function brightestSun(lights: readonly SerializedLight[]): {
8
+ direction: number[];
9
+ irradiance: number[];
10
+ } | null;
11
+ /**
12
+ * The radiance of an image averaged over the whole sphere: what air scattering every direction alike sends towards the
13
+ * camera. Each row weighs by the sine of its colatitude, the share of the sphere it covers.
14
+ */
15
+ export declare function averageRadiance(environment: PackedEnvironment): [number, number, number];
16
+ /**
17
+ * A vertical gradient averaged over the sphere. Directions are spread evenly in height over a sphere, so the share of
18
+ * the top colour is the mean of h^exponent for h even in [0, 1]: one over exponent plus one.
19
+ */
20
+ export declare function gradientAverage(top: number[], bottom: number[], exponent: number): [number, number, number];
21
+ //# sourceMappingURL=atmosphere.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atmosphere.d.ts","sourceRoot":"","sources":["../src/atmosphere.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAYrD,8GAA8G;AAC9G,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,iBAAiB,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAS1G;AAED,wHAAwH;AACxH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAmBrH;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CA8BxF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAI3G"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * How much more each colour scatters than green, at 680, 550 and 440 nm. Clean air scatters as the inverse fourth
3
+ * power of the wavelength (Rayleigh), haze nearly alike (Mie, an Angstrom exponent of about 1.3).
4
+ */
5
+ const RAYLEIGH = [(550 / 680) ** 4, 1, (550 / 440) ** 4];
6
+ const MIE = [(550 / 680) ** 1.3, 1, (550 / 440) ** 1.3];
7
+ /** Koschmieder: a dark object fades to 2 percent contrast over the visibility, so green's extinction is ln 50 over it. */
8
+ const KOSCHMIEDER = Math.log(50);
9
+ /** Extinction per scene unit of red, green and blue for the atmosphere setting, or nothing when it is off. */
10
+ export function atmosphereExtinction(atmosphere) {
11
+ const visibility = Number(atmosphere.visibility);
12
+ if (!atmosphere.enabled || !(visibility > 0))
13
+ return [0, 0, 0];
14
+ const haze = Math.min(1, Math.max(0, Number(atmosphere.haze) || 0));
15
+ const scale = KOSCHMIEDER / visibility;
16
+ return [0, 1, 2].map(k => scale * (RAYLEIGH[k] + (MIE[k] - RAYLEIGH[k]) * haze));
17
+ }
18
+ /** The brightest directional light of a scene, which lights the air: its direction towards the light and irradiance. */
19
+ export function brightestSun(lights) {
20
+ let best = null;
21
+ let strongest = 0;
22
+ for (const light of lights) {
23
+ if (light.type !== "DirectionalLight" || !(light.intensity > 0))
24
+ continue;
25
+ const irradiance = light.color.map(channel => channel * light.intensity);
26
+ const strength = 0.2126 * irradiance[0] + 0.7152 * irradiance[1] + 0.0722 * irradiance[2];
27
+ const axis = [0, 1, 2].map(k => light.position[k] - light.target[k]);
28
+ const size = Math.hypot(...axis);
29
+ if (strength > strongest && size > 0) {
30
+ strongest = strength;
31
+ best = { direction: axis.map(value => value / size), irradiance };
32
+ }
33
+ }
34
+ return best;
35
+ }
36
+ const averages = new WeakMap();
37
+ /**
38
+ * The radiance of an image averaged over the whole sphere: what air scattering every direction alike sends towards the
39
+ * camera. Each row weighs by the sine of its colatitude, the share of the sphere it covers.
40
+ */
41
+ export function averageRadiance(environment) {
42
+ const known = averages.get(environment);
43
+ if (known)
44
+ return known;
45
+ const { width, height, data } = environment.texture;
46
+ const sum = [0, 0, 0];
47
+ let weight = 0;
48
+ // A byte image is stored as it was encoded; only a float one holds linear light, as an HDR image always does.
49
+ const scale = data instanceof Float32Array ? 1 : 1 / 255;
50
+ for (let y = 0; y < height; y++) {
51
+ const sine = Math.sin((y + 0.5) / height * Math.PI);
52
+ for (let x = 0; x < width; x++) {
53
+ const at = (y * width + x) * 4;
54
+ sum[0] += data[at] * scale * sine;
55
+ sum[1] += data[at + 1] * scale * sine;
56
+ sum[2] += data[at + 2] * scale * sine;
57
+ }
58
+ weight += sine * width;
59
+ }
60
+ const average = sum.map(channel => channel / Math.max(weight, 1e-12));
61
+ averages.set(environment, average);
62
+ return average;
63
+ }
64
+ /**
65
+ * A vertical gradient averaged over the sphere. Directions are spread evenly in height over a sphere, so the share of
66
+ * the top colour is the mean of h^exponent for h even in [0, 1]: one over exponent plus one.
67
+ */
68
+ export function gradientAverage(top, bottom, exponent) {
69
+ const share = 1 / (Math.max(exponent, 0) + 1);
70
+ return [0, 1, 2].map(k => bottom[k] + (top[k] - bottom[k]) * share);
71
+ }
72
+ //# sourceMappingURL=atmosphere.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atmosphere.js","sourceRoot":"","sources":["../src/atmosphere.ts"],"names":[],"mappings":"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"}
package/dist/denoise.d.ts CHANGED
@@ -13,6 +13,16 @@ export interface DenoiserSettings {
13
13
  onlyNoisy: boolean;
14
14
  /** Clamp a pixel brighter than every one of its neighbours to the brightest of them, before filtering. */
15
15
  antiFirefly: boolean;
16
+ /**
17
+ * How far the filter lets go of the normal and depth tests over a material that scatters light inside, from 0 to 1.
18
+ * Light leaves such a surface after wandering under it, so its shading hardly follows the normal at each point.
19
+ */
20
+ subsurface: number;
21
+ /**
22
+ * The smallest footprint a smooth reflection is filtered over, in pixels; 0 leaves a mirror alone. Within it, taps
23
+ * also have to agree on how far away the reflected thing is, so the edge of a reflected object stays sharp.
24
+ */
25
+ mirrorRadius: number;
16
26
  }
17
27
  export declare const DEFAULT_DENOISER: Readonly<DenoiserSettings>;
18
28
  /** The settings with `input` applied, each field kept in range. */
@@ -43,7 +53,7 @@ export interface DenoiseView {
43
53
  * The weights are normalized, which keeps every flat area at exactly its mean, and each signal is mixed with what was
44
54
  * traced by how noisy it still is, so what has converged keeps exactly its traced value.
45
55
  */
46
- export declare const DENOISE_WGSL = "\nstruct Params {\n size: vec2<u32>,\n step: u32,\n count: u32,\n edge: f32,\n strength: f32,\n onlyNoisy: u32,\n converged: f32,\n pixelScale: f32,\n orthographic: u32,\n padding: vec2<u32>,\n};\n\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read> accumulation: array<vec4<f32>>;\n@group(0) @binding(2) var<storage, read> diffuseIn: array<vec4<f32>>;\n@group(0) @binding(3) var<storage, read> specularIn: array<vec4<f32>>;\n@group(0) @binding(4) var<storage, read_write> diffuseOut: array<vec4<f32>>;\n@group(0) @binding(5) var<storage, read_write> specularOut: array<vec4<f32>>;\n// The guides each tap compares, worked out once per pixel by prepare: the normal and the depth, then the roughness, or\n// -1 where no sample has landed. The same numbers the accumulation gives, two reads a tap instead of four.\n@group(0) @binding(6) var<storage, read_write> guides: array<vec4<f32>>;\n@group(0) @binding(7) var<storage, read_write> roughnesses: array<f32>;\n\nfn luminance(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.2126, 0.7152, 0.0722));\n}\n\nfn samples(index: u32) -> f32 {\n return max(accumulation[index].w, 1.0);\n}\n\n/** Each signal's mean radiance: the diffuse one stored apart, the specular one the rest. */\nfn diffuseMean(index: u32) -> vec3<f32> {\n return accumulation[4u * params.count + index].rgb / samples(index);\n}\n\nfn specularMean(index: u32) -> vec3<f32> {\n return accumulation[index].rgb / samples(index) - diffuseMean(index);\n}\n\n/** The albedos the light is divided by, kept off zero so the division never explodes. */\nfn diffuseAlbedo(index: u32) -> vec3<f32> {\n return max(accumulation[2u * params.count + index].rgb / samples(index), vec3<f32>(0.01));\n}\n\nfn specularAlbedo(index: u32) -> vec3<f32> {\n return max(accumulation[5u * params.count + index].rgb / samples(index), vec3<f32>(0.01));\n}\n\nfn guideNormal(index: u32) -> vec3<f32> {\n let sum = accumulation[3u * params.count + index].xyz;\n let size = length(sum);\n\n return select(vec3<f32>(0.0), sum / size, size > 1e-6);\n}\n\nfn guideDepth(index: u32) -> f32 {\n return accumulation[3u * params.count + index].w / samples(index);\n}\n\nfn guideRoughness(index: u32) -> f32 {\n return accumulation[2u * params.count + index].w / samples(index);\n}\n\nfn specularDistance(index: u32) -> f32 {\n return accumulation[4u * params.count + index].w / samples(index);\n}\n\n/** The variance of a signal's mean, in the space of its demodulated light. */\nfn variance(mean: vec3<f32>, square: f32, count: f32, albedo: vec3<f32>) -> f32 {\n let m = luminance(mean);\n let a = max(luminance(albedo), 0.01);\n\n return max(square / count - m * m, 0.0) / count / (a * a);\n}\n\n/** Both signals, divided by their albedos, with the variance of their means. */\n@compute @workgroup_size(8, 8, 1)\nfn prepare(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let index = id.y * params.size.x + id.x;\n let count = accumulation[index].w;\n\n if (count <= 0.0) {\n diffuseOut[index] = vec4<f32>(0.0);\n specularOut[index] = vec4<f32>(0.0);\n guides[index] = vec4<f32>(0.0);\n roughnesses[index] = -1.0;\n\n return;\n }\n\n guides[index] = vec4<f32>(guideNormal(index), guideDepth(index));\n roughnesses[index] = guideRoughness(index);\n\n let squares = accumulation[params.count + index];\n let diffuse = diffuseMean(index);\n let specular = specularMean(index);\n\n diffuseOut[index] = vec4<f32>(diffuse / diffuseAlbedo(index), variance(diffuse, squares.z, count, diffuseAlbedo(index)));\n specularOut[index] = vec4<f32>(\n specular / specularAlbedo(index), variance(specular, squares.w, count, specularAlbedo(index)));\n}\n\nfn inside(q: vec2<i32>) -> bool {\n return q.x >= 0 && q.y >= 0 && q.x < i32(params.size.x) && q.y < i32(params.size.y);\n}\n\n/** A value brighter than every neighbour, scaled down to the brightest of them: a firefly, not a feature. */\nfn clampFirefly(value: vec4<f32>, brightest: f32) -> vec4<f32> {\n let own = luminance(value.rgb);\n\n if (own <= brightest || own <= 0.0) {\n return value;\n }\n\n return vec4<f32>(value.rgb * (brightest / own), value.w);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn antiFirefly(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let pixel = vec2<i32>(id.xy);\n let index = id.y * params.size.x + id.x;\n var diffuse = 0.0;\n var specular = 0.0;\n\n for (var dy = -1; dy <= 1; dy = dy + 1) {\n for (var dx = -1; dx <= 1; dx = dx + 1) {\n let q = pixel + vec2<i32>(dx, dy);\n\n if ((dx == 0 && dy == 0) || !inside(q)) {\n continue;\n }\n\n let other = u32(q.y) * params.size.x + u32(q.x);\n diffuse = max(diffuse, luminance(diffuseIn[other].rgb));\n specular = max(specular, luminance(specularIn[other].rgb));\n }\n }\n\n diffuseOut[index] = clampFirefly(diffuseIn[index], diffuse);\n specularOut[index] = clampFirefly(specularIn[index], specular);\n}\n\nconst KERNEL = array<f32, 5>(0.0625, 0.25, 0.375, 0.25, 0.0625);\n\n/** The variance around a pixel, blurred over 3 x 3, which steadies the luminance test on a few samples. */\nfn localVariance(pixel: vec2<i32>, specular: bool) -> f32 {\n var sum = 0.0;\n var weight = 0.0;\n\n for (var dy = -1; dy <= 1; dy = dy + 1) {\n for (var dx = -1; dx <= 1; dx = dx + 1) {\n let q = pixel + vec2<i32>(dx, dy);\n\n if (!inside(q)) {\n continue;\n }\n\n let other = u32(q.y) * params.size.x + u32(q.x);\n let w = select(0.5, 1.0, dx == 0) * select(0.5, 1.0, dy == 0);\n sum = sum + select(diffuseIn[other].w, specularIn[other].w, specular) * w;\n weight = weight + w;\n }\n }\n\n return sum / max(weight, 1e-6);\n}\n\n/**\n * How many pixels the specular lobe's footprint covers: the lobe's angle times the distance to what it reflects, seen\n * from the camera across the distance to the surface plus that.\n */\nfn specularRadius(index: u32, depth: f32) -> f32 {\n let alpha = guideRoughness(index) * guideRoughness(index);\n let reflected = specularDistance(index);\n\n if (params.orthographic != 0u) {\n return min(alpha * reflected / params.pixelScale, 64.0);\n }\n\n return min(alpha * reflected / max(depth + reflected, 1e-6) / params.pixelScale, 64.0);\n}\n\n/** One a-trous pass over both signals, its taps params.step pixels apart. */\n@compute @workgroup_size(8, 8, 1)\nfn atrous(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let pixel = vec2<i32>(id.xy);\n let index = id.y * params.size.x + id.x;\n let diffuseCenter = diffuseIn[index];\n let specularCenter = specularIn[index];\n\n if (accumulation[index].w <= 0.0) {\n diffuseOut[index] = diffuseCenter;\n specularOut[index] = specularCenter;\n\n return;\n }\n\n let guide = guides[index];\n let normal = guide.xyz;\n let depth = guide.w;\n let roughness = roughnesses[index];\n let diffuseSigma = params.edge * sqrt(max(localVariance(pixel, false), 0.0)) + 1e-6;\n let specularSigma = params.edge * sqrt(max(localVariance(pixel, true), 0.0)) + 1e-6;\n let radius = specularRadius(index, depth);\n // A smoother surface's reflection turns faster with its normal: the normal test sharpens with it.\n let specularPower = min(128.0 / max(roughness * roughness, 0.03), 4096.0);\n let step = i32(params.step);\n var diffuse = vec4<f32>(0.0);\n var specular = vec4<f32>(0.0);\n var diffuseTotal = 0.0;\n var specularTotal = 0.0;\n\n for (var dy = -2; dy <= 2; dy = dy + 1) {\n for (var dx = -2; dx <= 2; dx = dx + 1) {\n let q = pixel + vec2<i32>(dx, dy) * step;\n\n if (!inside(q)) {\n continue;\n }\n\n let other = u32(q.y) * params.size.x + u32(q.x);\n let d = diffuseIn[other];\n let s = specularIn[other];\n let base = KERNEL[dx + 2] * KERNEL[dy + 2];\n var wd = base;\n var ws = base;\n\n if (dx != 0 || dy != 0) {\n let otherRoughness = roughnesses[other];\n\n // No sample has landed there.\n if (otherRoughness < 0.0) {\n continue;\n }\n\n let otherGuide = guides[other];\n let offset = length(vec2<f32>(f32(dx * step), f32(dy * step)));\n let alignment = max(dot(normal, otherGuide.xyz), 0.0);\n let depthWeight = exp(-abs(depth - otherGuide.w) / (0.02 * depth * offset + 1e-3));\n\n wd = wd * pow(alignment, 128.0) * depthWeight\n * exp(-abs(luminance(d.rgb) - luminance(diffuseCenter.rgb)) / diffuseSigma);\n\n ws = ws * pow(alignment, specularPower) * depthWeight\n * exp(-abs(otherRoughness - roughness) * 10.0)\n * exp(-abs(luminance(s.rgb) - luminance(specularCenter.rgb)) / specularSigma)\n * select(0.0, exp(-offset * offset / (radius * radius)), radius >= 0.5);\n }\n\n diffuse = diffuse + vec4<f32>(d.rgb * wd, d.w * wd * wd);\n specular = specular + vec4<f32>(s.rgb * ws, s.w * ws * ws);\n diffuseTotal = diffuseTotal + wd;\n specularTotal = specularTotal + ws;\n }\n }\n\n diffuseOut[index] = vec4<f32>(diffuse.rgb / diffuseTotal, diffuse.w / (diffuseTotal * diffuseTotal));\n specularOut[index] = vec4<f32>(specular.rgb / specularTotal, specular.w / (specularTotal * specularTotal));\n}\n\n/** How much of the filtered signal replaces the traced one: by how noisy the signal still is, when asked. */\nfn amount(mean: vec3<f32>, square: f32, count: f32) -> f32 {\n if (params.onlyNoisy == 0u || count <= 1.0) {\n return params.strength;\n }\n\n let m = luminance(mean);\n let error = sqrt(max(square / count - m * m, 0.0) / count) / sqrt(max(m, 0.0) + 1e-3);\n\n return params.strength * smoothstep(params.converged, 4.0 * params.converged, error);\n}\n\n/** Both filtered signals, times the albedos they were divided by, each mixed with what was traced. */\n@compute @workgroup_size(8, 8, 1)\nfn finish(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let index = id.y * params.size.x + id.x;\n let count = accumulation[index].w;\n\n if (count <= 0.0) {\n diffuseOut[index] = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n\n return;\n }\n\n let squares = accumulation[params.count + index];\n let diffuse = diffuseMean(index);\n let specular = specularMean(index);\n let filteredDiffuse = diffuseIn[index].rgb * diffuseAlbedo(index);\n let filteredSpecular = specularIn[index].rgb * specularAlbedo(index);\n\n diffuseOut[index] = vec4<f32>(\n mix(diffuse, filteredDiffuse, amount(diffuse, squares.z, count))\n + mix(specular, filteredSpecular, amount(specular, squares.w, count)), 1.0);\n}\n";
56
+ export declare const DENOISE_WGSL = "\nstruct Params {\n size: vec2<u32>,\n step: u32,\n count: u32,\n edge: f32,\n strength: f32,\n onlyNoisy: u32,\n converged: f32,\n pixelScale: f32,\n orthographic: u32,\n subsurface: f32,\n mirrorRadius: f32,\n};\n\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read> accumulation: array<vec4<f32>>;\n@group(0) @binding(2) var<storage, read> diffuseIn: array<vec4<f32>>;\n@group(0) @binding(3) var<storage, read> specularIn: array<vec4<f32>>;\n@group(0) @binding(4) var<storage, read_write> diffuseOut: array<vec4<f32>>;\n@group(0) @binding(5) var<storage, read_write> specularOut: array<vec4<f32>>;\n// The guides each tap compares, worked out once per pixel by prepare: the normal and the depth, then the roughness, or\n// -1 where no sample has landed. The same numbers the accumulation gives, two reads a tap instead of four.\n@group(0) @binding(6) var<storage, read_write> guides: array<vec4<f32>>;\n@group(0) @binding(7) var<storage, read_write> roughnesses: array<f32>;\n\nfn luminance(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.2126, 0.7152, 0.0722));\n}\n\nfn samples(index: u32) -> f32 {\n return max(accumulation[index].w, 1.0);\n}\n\n/** Each signal's mean radiance: the diffuse one stored apart, the specular one the rest. */\nfn diffuseMean(index: u32) -> vec3<f32> {\n return accumulation[4u * params.count + index].rgb / samples(index);\n}\n\nfn specularMean(index: u32) -> vec3<f32> {\n return accumulation[index].rgb / samples(index) - diffuseMean(index);\n}\n\n/** The albedos the light is divided by, kept off zero so the division never explodes. */\nfn diffuseAlbedo(index: u32) -> vec3<f32> {\n return max(accumulation[2u * params.count + index].rgb / samples(index), vec3<f32>(0.01));\n}\n\nfn specularAlbedo(index: u32) -> vec3<f32> {\n return max(accumulation[5u * params.count + index].rgb / samples(index), vec3<f32>(0.01));\n}\n\nfn guideNormal(index: u32) -> vec3<f32> {\n let sum = accumulation[3u * params.count + index].xyz;\n let size = length(sum);\n\n return select(vec3<f32>(0.0), sum / size, size > 1e-6);\n}\n\nfn guideDepth(index: u32) -> f32 {\n return accumulation[3u * params.count + index].w / samples(index);\n}\n\nfn guideRoughness(index: u32) -> f32 {\n return accumulation[2u * params.count + index].w / samples(index);\n}\n\n/** How much of the first surface scatters light inside, averaged over the pixel's samples. */\nfn guideSubsurface(index: u32) -> f32 {\n return accumulation[5u * params.count + index].w / samples(index);\n}\n\nfn specularDistance(index: u32) -> f32 {\n return accumulation[4u * params.count + index].w / samples(index);\n}\n\n/** The variance of a signal's mean, in the space of its demodulated light. */\nfn variance(mean: vec3<f32>, square: f32, count: f32, albedo: vec3<f32>) -> f32 {\n let m = luminance(mean);\n let a = max(luminance(albedo), 0.01);\n\n return max(square / count - m * m, 0.0) / count / (a * a);\n}\n\n/** Both signals, divided by their albedos, with the variance of their means. */\n@compute @workgroup_size(8, 8, 1)\nfn prepare(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let index = id.y * params.size.x + id.x;\n let count = accumulation[index].w;\n\n if (count <= 0.0) {\n diffuseOut[index] = vec4<f32>(0.0);\n specularOut[index] = vec4<f32>(0.0);\n guides[index] = vec4<f32>(0.0);\n roughnesses[index] = -1.0;\n\n return;\n }\n\n guides[index] = vec4<f32>(guideNormal(index), guideDepth(index));\n roughnesses[index] = guideRoughness(index);\n\n let squares = accumulation[params.count + index];\n let diffuse = diffuseMean(index);\n let specular = specularMean(index);\n\n diffuseOut[index] = vec4<f32>(diffuse / diffuseAlbedo(index), variance(diffuse, squares.z, count, diffuseAlbedo(index)));\n specularOut[index] = vec4<f32>(\n specular / specularAlbedo(index), variance(specular, squares.w, count, specularAlbedo(index)));\n}\n\nfn inside(q: vec2<i32>) -> bool {\n return q.x >= 0 && q.y >= 0 && q.x < i32(params.size.x) && q.y < i32(params.size.y);\n}\n\n/** A value brighter than every neighbour, scaled down to the brightest of them: a firefly, not a feature. */\nfn clampFirefly(value: vec4<f32>, brightest: f32) -> vec4<f32> {\n let own = luminance(value.rgb);\n\n if (own <= brightest || own <= 0.0) {\n return value;\n }\n\n return vec4<f32>(value.rgb * (brightest / own), value.w);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn antiFirefly(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let pixel = vec2<i32>(id.xy);\n let index = id.y * params.size.x + id.x;\n var diffuse = 0.0;\n var specular = 0.0;\n\n for (var dy = -1; dy <= 1; dy = dy + 1) {\n for (var dx = -1; dx <= 1; dx = dx + 1) {\n let q = pixel + vec2<i32>(dx, dy);\n\n if ((dx == 0 && dy == 0) || !inside(q)) {\n continue;\n }\n\n let other = u32(q.y) * params.size.x + u32(q.x);\n diffuse = max(diffuse, luminance(diffuseIn[other].rgb));\n specular = max(specular, luminance(specularIn[other].rgb));\n }\n }\n\n diffuseOut[index] = clampFirefly(diffuseIn[index], diffuse);\n specularOut[index] = clampFirefly(specularIn[index], specular);\n}\n\nconst KERNEL = array<f32, 5>(0.0625, 0.25, 0.375, 0.25, 0.0625);\n\n/** The variance around a pixel, blurred over 3 x 3, which steadies the luminance test on a few samples. */\nfn localVariance(pixel: vec2<i32>, specular: bool) -> f32 {\n var sum = 0.0;\n var weight = 0.0;\n\n for (var dy = -1; dy <= 1; dy = dy + 1) {\n for (var dx = -1; dx <= 1; dx = dx + 1) {\n let q = pixel + vec2<i32>(dx, dy);\n\n if (!inside(q)) {\n continue;\n }\n\n let other = u32(q.y) * params.size.x + u32(q.x);\n let w = select(0.5, 1.0, dx == 0) * select(0.5, 1.0, dy == 0);\n sum = sum + select(diffuseIn[other].w, specularIn[other].w, specular) * w;\n weight = weight + w;\n }\n }\n\n return sum / max(weight, 1e-6);\n}\n\n/**\n * How many pixels the specular lobe's footprint covers: the lobe's angle times the distance to what it reflects, seen\n * from the camera across the distance to the surface plus that.\n */\nfn specularRadius(index: u32, depth: f32) -> f32 {\n let alpha = guideRoughness(index) * guideRoughness(index);\n let reflected = specularDistance(index);\n\n if (params.orthographic != 0u) {\n return min(alpha * reflected / params.pixelScale, 64.0);\n }\n\n return min(alpha * reflected / max(depth + reflected, 1e-6) / params.pixelScale, 64.0);\n}\n\n/** One a-trous pass over both signals, its taps params.step pixels apart. */\n@compute @workgroup_size(8, 8, 1)\nfn atrous(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let pixel = vec2<i32>(id.xy);\n let index = id.y * params.size.x + id.x;\n let diffuseCenter = diffuseIn[index];\n let specularCenter = specularIn[index];\n\n if (accumulation[index].w <= 0.0) {\n diffuseOut[index] = diffuseCenter;\n specularOut[index] = specularCenter;\n\n return;\n }\n\n let guide = guides[index];\n let normal = guide.xyz;\n let depth = guide.w;\n let roughness = roughnesses[index];\n let diffuseSigma = params.edge * sqrt(max(localVariance(pixel, false), 0.0))\n * (1.0 + guideSubsurface(index) * params.subsurface) + 1e-6;\n let specularSigma = params.edge * sqrt(max(localVariance(pixel, true), 0.0)) + 1e-6;\n // A smooth reflection is filtered over at least the mirror radius, by taps that see the reflected thing at the same\n // distance: that test keeps the edges of what it reflects, which lets the normal test relax over a curved mirror,\n // where neighbouring normals part fast and would otherwise leave the reflection unfiltered.\n let mirror = params.mirrorRadius > 0.0 && roughness < 0.3;\n let radius = select(specularRadius(index, depth), max(specularRadius(index, depth), params.mirrorRadius), mirror);\n let reflected = specularDistance(index);\n // A smoother surface's reflection turns faster with its normal: the normal test sharpens with it, short of shutting\n // out the neighbours of a curved mirror altogether once the reflected distance guards it.\n let specularPower = min(128.0 / max(roughness * roughness, 0.03), select(4096.0, 64.0, mirror));\n // Under a surface that scatters light inside, the normal and the depth say little about the light that leaves it.\n let scattering = guideSubsurface(index) * params.subsurface;\n let diffusePower = mix(128.0, 1.0, scattering);\n let depthSlack = mix(1.0, 4.0, scattering);\n let step = i32(params.step);\n var diffuse = vec4<f32>(0.0);\n var specular = vec4<f32>(0.0);\n var diffuseTotal = 0.0;\n var specularTotal = 0.0;\n\n for (var dy = -2; dy <= 2; dy = dy + 1) {\n for (var dx = -2; dx <= 2; dx = dx + 1) {\n let q = pixel + vec2<i32>(dx, dy) * step;\n\n if (!inside(q)) {\n continue;\n }\n\n let other = u32(q.y) * params.size.x + u32(q.x);\n let d = diffuseIn[other];\n let s = specularIn[other];\n let base = KERNEL[dx + 2] * KERNEL[dy + 2];\n var wd = base;\n var ws = base;\n\n if (dx != 0 || dy != 0) {\n let otherRoughness = roughnesses[other];\n\n // No sample has landed there.\n if (otherRoughness < 0.0) {\n continue;\n }\n\n let otherGuide = guides[other];\n let offset = length(vec2<f32>(f32(dx * step), f32(dy * step)));\n let alignment = max(dot(normal, otherGuide.xyz), 0.0);\n let depthWeight = exp(-abs(depth - otherGuide.w) / (0.02 * depth * offset + 1e-3));\n let diffuseDepth = exp(-abs(depth - otherGuide.w) / (0.02 * depthSlack * depth * offset + 1e-3));\n\n wd = wd * pow(alignment, diffusePower) * diffuseDepth\n * exp(-abs(luminance(d.rgb) - luminance(diffuseCenter.rgb)) / diffuseSigma);\n\n ws = ws * pow(alignment, specularPower) * depthWeight\n * exp(-abs(otherRoughness - roughness) * 10.0)\n * exp(-abs(luminance(s.rgb) - luminance(specularCenter.rgb)) / specularSigma)\n * select(0.0, exp(-offset * offset / (radius * radius)), radius >= 0.5);\n\n if (mirror) {\n ws = ws * exp(-abs(specularDistance(other) - reflected) / (0.05 * reflected + 1e-3));\n }\n }\n\n diffuse = diffuse + vec4<f32>(d.rgb * wd, d.w * wd * wd);\n specular = specular + vec4<f32>(s.rgb * ws, s.w * ws * ws);\n diffuseTotal = diffuseTotal + wd;\n specularTotal = specularTotal + ws;\n }\n }\n\n diffuseOut[index] = vec4<f32>(diffuse.rgb / diffuseTotal, diffuse.w / (diffuseTotal * diffuseTotal));\n specularOut[index] = vec4<f32>(specular.rgb / specularTotal, specular.w / (specularTotal * specularTotal));\n}\n\n/** How much of the filtered signal replaces the traced one: by how noisy the signal still is, when asked. */\nfn amount(mean: vec3<f32>, square: f32, count: f32) -> f32 {\n if (params.onlyNoisy == 0u || count <= 1.0) {\n return params.strength;\n }\n\n let m = luminance(mean);\n let error = sqrt(max(square / count - m * m, 0.0) / count) / sqrt(max(m, 0.0) + 1e-3);\n\n return params.strength * smoothstep(params.converged, 4.0 * params.converged, error);\n}\n\n/** Both filtered signals, times the albedos they were divided by, each mixed with what was traced. */\n@compute @workgroup_size(8, 8, 1)\nfn finish(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x >= params.size.x || id.y >= params.size.y) {\n return;\n }\n\n let index = id.y * params.size.x + id.x;\n let count = accumulation[index].w;\n\n if (count <= 0.0) {\n diffuseOut[index] = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n\n return;\n }\n\n let squares = accumulation[params.count + index];\n let diffuse = diffuseMean(index);\n let specular = specularMean(index);\n let filteredDiffuse = diffuseIn[index].rgb * diffuseAlbedo(index);\n let filteredSpecular = specularIn[index].rgb * specularAlbedo(index);\n\n diffuseOut[index] = vec4<f32>(\n mix(diffuse, filteredDiffuse, amount(diffuse, squares.z, count))\n + mix(specular, filteredSpecular, amount(specular, squares.w, count)), 1.0);\n}\n";
47
57
  export declare class DenoisePass {
48
58
  private readonly device;
49
59
  private readonly layout;
@@ -1 +1 @@
1
- {"version":3,"file":"denoise.d.ts","sourceRoot":"","sources":["../src/denoise.ts"],"names":[],"mappings":"AAEA,iHAAiH;AACjH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,8GAA8G;IAC9G,SAAS,EAAE,OAAO,CAAC;IACnB,0GAA0G;IAC1G,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,CAMtD,CAAC;AAEH,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,GAAE,OAAO,CAAC,gBAAgB,CAAM,GAAG,gBAAgB,CAU7G;AAED,uFAAuF;AACvF,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC,uGAAuG;AACvG,MAAM,WAAW,WAAW;IAC1B,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,onVAyTxB,CAAC;AAQF,qBAAa,WAAW;IA6BV,OAAO,CAAC,QAAQ,CAAC,MAAM;IA5BnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,gGAAgG;IAChG,OAAO,CAAC,OAAO,CAAmB;IAClC,iHAAiH;IACjH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoC;IACxD,OAAO,CAAC,MAAM,CAAK;IAEnB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IAEnB,wEAAwE;IACxE,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;gBAEH,MAAM,EAAE,SAAS;IA6B9C,OAAO,CAAC,MAAM;IAiBd,OAAO,CAAC,WAAW;IAmBnB,wDAAwD;IACxD,MAAM,CACJ,OAAO,EAAE,iBAAiB,EAC1B,YAAY,EAAE,SAAS,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,gBAAmC,EAC7C,IAAI,GAAE,WAA6D;IA6DrE,OAAO;CAOR"}
1
+ {"version":3,"file":"denoise.d.ts","sourceRoot":"","sources":["../src/denoise.ts"],"names":[],"mappings":"AAEA,iHAAiH;AACjH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,8GAA8G;IAC9G,SAAS,EAAE,OAAO,CAAC;IACnB,0GAA0G;IAC1G,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,CAQtD,CAAC;AAEH,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,GAAE,OAAO,CAAC,gBAAgB,CAAM,GAAG,gBAAgB,CAY7G;AAED,uFAAuF;AACvF,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC,uGAAuG;AACvG,MAAM,WAAW,WAAW;IAC1B,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,2iYA+UxB,CAAC;AAQF,qBAAa,WAAW;IA6BV,OAAO,CAAC,QAAQ,CAAC,MAAM;IA5BnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,gGAAgG;IAChG,OAAO,CAAC,OAAO,CAAmB;IAClC,iHAAiH;IACjH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoC;IACxD,OAAO,CAAC,MAAM,CAAK;IAEnB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IAEnB,wEAAwE;IACxE,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;gBAEH,MAAM,EAAE,SAAS;IA6B9C,OAAO,CAAC,MAAM;IAiBd,OAAO,CAAC,WAAW;IAqBnB,wDAAwD;IACxD,MAAM,CACJ,OAAO,EAAE,iBAAiB,EAC1B,YAAY,EAAE,SAAS,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,gBAAmC,EAC7C,IAAI,GAAE,WAA6D;IA6DrE,OAAO;CAOR"}
package/dist/denoise.js CHANGED
@@ -5,6 +5,8 @@ export const DEFAULT_DENOISER = Object.freeze({
5
5
  edge: 2,
6
6
  onlyNoisy: true,
7
7
  antiFirefly: true,
8
+ subsurface: 1,
9
+ mirrorRadius: 3,
8
10
  });
9
11
  /** The settings with `input` applied, each field kept in range. */
10
12
  export function mergeDenoiser(base, input = {}) {
@@ -15,6 +17,8 @@ export function mergeDenoiser(base, input = {}) {
15
17
  edge: Math.max(0.01, Number(merged.edge) || DEFAULT_DENOISER.edge),
16
18
  onlyNoisy: Boolean(merged.onlyNoisy),
17
19
  antiFirefly: Boolean(merged.antiFirefly),
20
+ subsurface: Math.min(1, Math.max(0, Number(merged.subsurface) || 0)),
21
+ mirrorRadius: Math.min(16, Math.max(0, Number(merged.mirrorRadius) || 0)),
18
22
  };
19
23
  }
20
24
  /** The error a pixel counts as converged under, the one adaptive sampling stops at. */
@@ -48,7 +52,8 @@ struct Params {
48
52
  converged: f32,
49
53
  pixelScale: f32,
50
54
  orthographic: u32,
51
- padding: vec2<u32>,
55
+ subsurface: f32,
56
+ mirrorRadius: f32,
52
57
  };
53
58
 
54
59
  @group(0) @binding(0) var<uniform> params: Params;
@@ -103,6 +108,11 @@ fn guideRoughness(index: u32) -> f32 {
103
108
  return accumulation[2u * params.count + index].w / samples(index);
104
109
  }
105
110
 
111
+ /** How much of the first surface scatters light inside, averaged over the pixel's samples. */
112
+ fn guideSubsurface(index: u32) -> f32 {
113
+ return accumulation[5u * params.count + index].w / samples(index);
114
+ }
115
+
106
116
  fn specularDistance(index: u32) -> f32 {
107
117
  return accumulation[4u * params.count + index].w / samples(index);
108
118
  }
@@ -253,11 +263,22 @@ fn atrous(@builtin(global_invocation_id) id: vec3<u32>) {
253
263
  let normal = guide.xyz;
254
264
  let depth = guide.w;
255
265
  let roughness = roughnesses[index];
256
- let diffuseSigma = params.edge * sqrt(max(localVariance(pixel, false), 0.0)) + 1e-6;
266
+ let diffuseSigma = params.edge * sqrt(max(localVariance(pixel, false), 0.0))
267
+ * (1.0 + guideSubsurface(index) * params.subsurface) + 1e-6;
257
268
  let specularSigma = params.edge * sqrt(max(localVariance(pixel, true), 0.0)) + 1e-6;
258
- let radius = specularRadius(index, depth);
259
- // A smoother surface's reflection turns faster with its normal: the normal test sharpens with it.
260
- let specularPower = min(128.0 / max(roughness * roughness, 0.03), 4096.0);
269
+ // A smooth reflection is filtered over at least the mirror radius, by taps that see the reflected thing at the same
270
+ // distance: that test keeps the edges of what it reflects, which lets the normal test relax over a curved mirror,
271
+ // where neighbouring normals part fast and would otherwise leave the reflection unfiltered.
272
+ let mirror = params.mirrorRadius > 0.0 && roughness < 0.3;
273
+ let radius = select(specularRadius(index, depth), max(specularRadius(index, depth), params.mirrorRadius), mirror);
274
+ let reflected = specularDistance(index);
275
+ // A smoother surface's reflection turns faster with its normal: the normal test sharpens with it, short of shutting
276
+ // out the neighbours of a curved mirror altogether once the reflected distance guards it.
277
+ let specularPower = min(128.0 / max(roughness * roughness, 0.03), select(4096.0, 64.0, mirror));
278
+ // Under a surface that scatters light inside, the normal and the depth say little about the light that leaves it.
279
+ let scattering = guideSubsurface(index) * params.subsurface;
280
+ let diffusePower = mix(128.0, 1.0, scattering);
281
+ let depthSlack = mix(1.0, 4.0, scattering);
261
282
  let step = i32(params.step);
262
283
  var diffuse = vec4<f32>(0.0);
263
284
  var specular = vec4<f32>(0.0);
@@ -291,14 +312,19 @@ fn atrous(@builtin(global_invocation_id) id: vec3<u32>) {
291
312
  let offset = length(vec2<f32>(f32(dx * step), f32(dy * step)));
292
313
  let alignment = max(dot(normal, otherGuide.xyz), 0.0);
293
314
  let depthWeight = exp(-abs(depth - otherGuide.w) / (0.02 * depth * offset + 1e-3));
315
+ let diffuseDepth = exp(-abs(depth - otherGuide.w) / (0.02 * depthSlack * depth * offset + 1e-3));
294
316
 
295
- wd = wd * pow(alignment, 128.0) * depthWeight
317
+ wd = wd * pow(alignment, diffusePower) * diffuseDepth
296
318
  * exp(-abs(luminance(d.rgb) - luminance(diffuseCenter.rgb)) / diffuseSigma);
297
319
 
298
320
  ws = ws * pow(alignment, specularPower) * depthWeight
299
321
  * exp(-abs(otherRoughness - roughness) * 10.0)
300
322
  * exp(-abs(luminance(s.rgb) - luminance(specularCenter.rgb)) / specularSigma)
301
323
  * select(0.0, exp(-offset * offset / (radius * radius)), radius >= 0.5);
324
+
325
+ if (mirror) {
326
+ ws = ws * exp(-abs(specularDistance(other) - reflected) / (0.05 * reflected + 1e-3));
327
+ }
302
328
  }
303
329
 
304
330
  diffuse = diffuse + vec4<f32>(d.rgb * wd, d.w * wd * wd);
@@ -431,6 +457,8 @@ export class DenoisePass {
431
457
  floats[7] = CONVERGED_ERROR;
432
458
  floats[8] = view.pixelScale;
433
459
  words[9] = view.orthographic ? 1 : 0;
460
+ floats[10] = settings.subsurface;
461
+ floats[11] = settings.mirrorRadius;
434
462
  this.device.queue.writeBuffer(this.params[k], 0, values);
435
463
  });
436
464
  }
@@ -1 +1 @@
1
- {"version":3,"file":"denoise.js","sourceRoot":"","sources":["../src/denoise.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"denoise.js","sourceRoot":"","sources":["../src/denoise.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"frameLayout.d.ts","sourceRoot":"","sources":["../src/frameLayout.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,eAAO,MAAM,YAAY,0CAwDvB,CAAC;AAEH,eAAO,MAAM,WAAW,QAAqB,CAAC"}
1
+ {"version":3,"file":"frameLayout.d.ts","sourceRoot":"","sources":["../src/frameLayout.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,eAAO,MAAM,YAAY,0CAyEvB,CAAC;AAEH,eAAO,MAAM,WAAW,QAAqB,CAAC"}
@@ -31,6 +31,11 @@ export const FRAME_LAYOUT = layoutStruct("Frame", [
31
31
  { name: "areaLightCount", type: "u32", doc: "How many leading lights are emissive triangles." },
32
32
  { name: "lightCdf", type: "u32", doc: "Where every light's cumulative probability starts in the texture buffer." },
33
33
  { name: "lightTriangles", type: "u32", doc: "Where every emissive light's triangle starts in the texture buffer." },
34
+ { name: "localLightCount", type: "u32", doc: "How many leading lights sit in the scene, which the light tree picks." },
35
+ { name: "localLightPick", type: "f32", doc: "The chance of picking one of them, the last one's cumulative probability." },
36
+ { name: "lightTree", type: "u32", doc: "Where the light tree's nodes start in the texture buffer; zero picks by power alone." },
37
+ { name: "lightList", type: "u32", doc: "Where the lights of the tree's leaves are listed in the texture buffer." },
38
+ { name: "lightLeaves", type: "u32", doc: "Where the leaf of every local light starts in the texture buffer." },
34
39
  { name: "clampIndirect", type: "f32", doc: "Maximum luminance one indirect contribution may add; zero leaves it." },
35
40
  { name: "shadowSpread", type: "f32", doc: "Tangent of half the angular diameter shadow rays spread over." },
36
41
  { name: "shadowsEnabled", type: "u32" },
@@ -55,6 +60,18 @@ export const FRAME_LAYOUT = layoutStruct("Frame", [
55
60
  { name: "volumetricData", type: "u32" },
56
61
  { name: "adaptiveMin", type: "u32", doc: "Samples a pixel takes before it may stop as converged; 0 never stops." },
57
62
  { name: "adaptiveThreshold", type: "f32", doc: "The error under which a pixel and its neighbours count as converged." },
63
+ { name: "lensDistortion", type: "f32", doc: "Radial distortion of the camera ray: positive is barrel, negative pincushion." },
64
+ { name: "rouletteThreshold", type: "f32", doc: "Throughput under which a path may be ended by chance; zero never." },
65
+ { name: "rouletteStart", type: "u32", doc: "Bounces every path takes before the roulette may end it." },
66
+ { name: "subsurfaceDepth", type: "u32", doc: "Bounces at which light still walks inside a material; deeper it reflects." },
67
+ { name: "subsurfaceEnabled", type: "u32", doc: "Whether materials that scatter light inside do; 0 renders them opaque." },
68
+ { name: "bevelEnabled", type: "u32", doc: "Whether materials with a bevel radius round their edges." },
69
+ { name: "volumesEnabled", type: "u32", doc: "Whether volumes scatter light; 0 leaves their meshes out altogether." },
70
+ { name: "cameraVolume", type: "u32", doc: "The volume material the camera stands inside, or NO_MATERIAL." },
71
+ { name: "atmosphereColor", type: "vec4f", doc: "rgb is the radiance the air scatters towards the camera, w 1 when it is on." },
72
+ { name: "atmosphereExtinction", type: "vec4f", doc: "rgb is how much of each colour the air takes per scene unit, w the haze." },
73
+ { name: "atmosphereSun", type: "vec4f", doc: "xyz is the direction towards the brightest directional light." },
74
+ { name: "atmosphereSunColor", type: "vec4f", doc: "rgb is that light's irradiance, which the air scatters." },
58
75
  { name: "clipPlane", type: "vec4f", doc: "A plane the camera ray drops surfaces behind, for planar captures; w = 0 and xyz = 0 is none." },
59
76
  ]);
60
77
  export const FRAME_WORDS = FRAME_LAYOUT.words;
@@ -1 +1 @@
1
- {"version":3,"file":"frameLayout.js","sourceRoot":"","sources":["../src/frameLayout.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frameLayout.js","sourceRoot":"","sources":["../src/frameLayout.ts"],"names":[],"mappings":"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"}