@meimu/mutracer 0.2.0 → 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 (211) hide show
  1. package/README.md +3 -0
  2. package/dist/assets/bvh.worker.js +1 -1
  3. package/dist/mutracer.umd.js +8949 -7915
  4. package/docs/api.md +42 -21
  5. package/docs/caustics.md +80 -0
  6. package/docs/materials.md +5 -4
  7. package/docs/progressive-rendering.md +50 -9
  8. package/docs/technical/continuous-spectrum.md +93 -0
  9. package/docs/updates.md +3 -1
  10. package/docs/viewer-checklist.md +65 -0
  11. package/docs/viewer.md +7 -5
  12. package/lib/Display.js +1 -1
  13. package/lib/Display.js.map +1 -1
  14. package/lib/Engine.d.ts +2 -0
  15. package/lib/Engine.js +47 -12
  16. package/lib/Engine.js.map +1 -1
  17. package/lib/Render.d.ts +61 -13
  18. package/lib/Render.js +169 -19
  19. package/lib/Render.js.map +1 -1
  20. package/lib/RenderLoop.d.ts +7 -3
  21. package/lib/RenderLoop.js +68 -44
  22. package/lib/RenderLoop.js.map +1 -1
  23. package/lib/main.d.ts +1 -1
  24. package/lib/main.js.map +1 -1
  25. package/lib/oidn.d.ts +1 -1
  26. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  27. package/lib/renderer/GPUTraceQueue.d.ts +2 -1
  28. package/lib/renderer/GPUTraceQueue.js +3 -1
  29. package/lib/renderer/GPUTraceQueue.js.map +1 -1
  30. package/lib/renderer/RenderingPipeline.d.ts +4 -0
  31. package/lib/renderer/RenderingPipeline.js.map +1 -1
  32. package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
  33. package/lib/renderer/WGPUCausticLightPass.js +217 -0
  34. package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
  35. package/lib/renderer/WGPUEnvMapDistribution.js +18 -18
  36. package/lib/renderer/WGPUFullQuadPass.js +3 -3
  37. package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
  38. package/lib/renderer/WGPUPhotonMap.js +191 -0
  39. package/lib/renderer/WGPUPhotonMap.js.map +1 -0
  40. package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
  41. package/lib/renderer/WGPURayTraceOutput.js +122 -28
  42. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  43. package/lib/renderer/WGPURayTracePass.d.ts +48 -17
  44. package/lib/renderer/WGPURayTracePass.js +538 -340
  45. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  46. package/lib/renderer/WGPURenderingPipeline.js +83 -47
  47. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  48. package/lib/renderer/WebGLFullQuadPass.d.ts +2 -1
  49. package/lib/renderer/WebGLFullQuadPass.js +4 -0
  50. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  51. package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
  52. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  53. package/lib/renderer/WebGLRayTracePass.d.ts +6 -1
  54. package/lib/renderer/WebGLRayTracePass.js +43 -6
  55. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  56. package/lib/renderer/WebGLRenderingPipeline.js +10 -14
  57. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  58. package/lib/renderer/WebGLSkyBaker.js +60 -60
  59. package/lib/renderer/accumulationTarget.d.ts +2 -1
  60. package/lib/renderer/accumulationTarget.js.map +1 -1
  61. package/lib/renderer/causticDiagnostics.d.ts +31 -0
  62. package/lib/renderer/causticDiagnostics.js +5 -0
  63. package/lib/renderer/causticDiagnostics.js.map +1 -0
  64. package/lib/renderer/causticEmission.d.ts +10 -0
  65. package/lib/renderer/causticEmission.js +40 -0
  66. package/lib/renderer/causticEmission.js.map +1 -0
  67. package/lib/renderer/causticUniform.d.ts +12 -0
  68. package/lib/renderer/causticUniform.js +22 -0
  69. package/lib/renderer/causticUniform.js.map +1 -0
  70. package/lib/renderer/caustics.d.ts +16 -0
  71. package/lib/renderer/caustics.js +93 -0
  72. package/lib/renderer/caustics.js.map +1 -0
  73. package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
  74. package/lib/renderer/glsl/aovReflectance.glsl.js +53 -53
  75. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
  76. package/lib/renderer/glsl/aovTrace.frag.js +33 -33
  77. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -9
  78. package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
  79. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
  80. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
  81. package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -73
  82. package/lib/renderer/glsl/chunks/intersect.glsl.js +426 -428
  83. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  84. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
  85. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +156 -153
  86. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  87. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +771 -771
  88. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  89. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  90. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
  91. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +68 -63
  92. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  93. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +94 -76
  94. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  95. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
  96. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +140 -117
  97. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  98. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +14 -14
  99. package/lib/renderer/glsl/chunks/sampling.glsl.js +89 -92
  100. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
  101. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  102. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  103. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  104. package/lib/renderer/glsl/depthQuery.frag.js +2 -2
  105. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
  106. package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
  107. package/lib/renderer/glsl/rayTrace.frag.js +260 -237
  108. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  109. package/lib/renderer/glsl/shadowCatcher.frag.js +26 -26
  110. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  111. package/lib/renderer/glsl/webglPipeline.frag.js +59 -59
  112. package/lib/renderer/lightSampling.d.ts +3 -2
  113. package/lib/renderer/lightSampling.js +14 -8
  114. package/lib/renderer/lightSampling.js.map +1 -1
  115. package/lib/renderer/progressiveScheduler.js +4 -3
  116. package/lib/renderer/progressiveScheduler.js.map +1 -1
  117. package/lib/renderer/renderPipeline.d.ts +1 -0
  118. package/lib/renderer/renderPipeline.js.map +1 -1
  119. package/lib/renderer/researchTransport.d.ts +31 -0
  120. package/lib/renderer/researchTransport.js +5 -0
  121. package/lib/renderer/researchTransport.js.map +1 -0
  122. package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
  123. package/lib/renderer/sceneLayoutSchema.js +2 -2
  124. package/lib/renderer/sceneLayoutSchema.js.map +1 -1
  125. package/lib/renderer/scratchSampling.js +6 -6
  126. package/lib/renderer/spectrum.d.ts +21 -0
  127. package/lib/renderer/spectrum.js +154 -0
  128. package/lib/renderer/spectrum.js.map +1 -0
  129. package/lib/renderer/webglLightSampling.d.ts +39 -0
  130. package/lib/renderer/webglLightSampling.js +15 -0
  131. package/lib/renderer/webglLightSampling.js.map +1 -0
  132. package/lib/renderer/wgpuBindlessSource.js +3 -3
  133. package/lib/renderer/wgpuShaderSource.d.ts +7 -0
  134. package/lib/renderer/wgpuShaderSource.js +2 -0
  135. package/lib/renderer/wgpuShaderSource.js.map +1 -1
  136. package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
  137. package/lib/renderer/wgsl/aovReflectance.wgsl.js +55 -55
  138. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
  139. package/lib/renderer/wgsl/aovResolve.wgsl.js +2 -2
  140. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +1 -1
  141. package/lib/renderer/wgsl/aovTrace.wgsl.js +33 -33
  142. package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
  143. package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
  144. package/lib/renderer/wgsl/causticLight.compute.js +537 -0
  145. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
  146. package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
  147. package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
  148. package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
  149. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
  150. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
  151. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
  152. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
  153. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
  154. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
  155. package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
  156. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
  157. package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
  158. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  159. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +37 -37
  160. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +598 -592
  161. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  162. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +14 -14
  163. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
  164. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +75 -73
  165. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  166. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +794 -794
  167. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +139 -139
  168. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  169. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +2 -1
  170. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +35 -25
  171. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  172. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  173. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +142 -138
  174. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  175. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  176. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +204 -187
  177. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  178. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  179. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +11 -11
  180. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  181. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
  182. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +89 -93
  183. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
  184. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  185. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  186. package/lib/renderer/wgsl/compose.frag.wgsl.js +98 -98
  187. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  188. package/lib/renderer/wgsl/depthQuery.wgsl.js +2 -2
  189. package/lib/renderer/wgsl/jnlm.compute.js +74 -74
  190. package/lib/renderer/wgsl/offlineAdaptive.compute.js +25 -25
  191. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
  192. package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
  193. package/lib/renderer/wgsl/photonMap.compute.js +352 -0
  194. package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
  195. package/lib/renderer/wgsl/proceduralSky.compute.js +64 -64
  196. package/lib/renderer/wgsl/rayTrace.compute.d.ts +9 -1
  197. package/lib/renderer/wgsl/rayTrace.compute.js +448 -522
  198. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  199. package/lib/scene/MaterialState.d.ts +2 -2
  200. package/lib/scene/MaterialState.js +2 -2
  201. package/lib/scene/MaterialState.js.map +1 -1
  202. package/lib/settings/render.d.ts +11 -0
  203. package/lib/settings/render.js +1 -0
  204. package/lib/settings/render.js.map +1 -1
  205. package/lib/util/fromTHREE.js +2 -2
  206. package/lib/util/fromTHREE.js.map +1 -1
  207. package/lib/version.d.ts +1 -1
  208. package/lib/version.js +1 -1
  209. package/lib/version.js.map +1 -1
  210. package/llms.txt +2 -1
  211. package/package.json +3 -3
@@ -1,7 +1,9 @@
1
- export declare function createNormalizeRayTraceOutputWGSL(layers?: boolean, catcher?: boolean): string;
1
+ export declare function createNormalizeRayTraceOutputWGSL(layers?: boolean, catcher?: boolean, caustics?: boolean): string;
2
2
  type RayTraceOutput = 'color' | 'normal' | 'albedo' | 'shadowCatcher' | 'foreground' | 'catcherBackground';
3
3
  type RayTraceBuffers = {
4
4
  color: GPUBuffer;
5
+ caustic?: GPUBuffer;
6
+ wideHdr?: boolean;
5
7
  normal: GPUBuffer;
6
8
  albedo: GPUBuffer;
7
9
  shadowCatcher: GPUBuffer;
@@ -23,6 +25,12 @@ export declare class WGPURayTraceOutputPass {
23
25
  private _width;
24
26
  private _height;
25
27
  private _hasCatcher;
28
+ private _hasCaustics;
29
+ private _hasWideHdr;
30
+ private _maskPipeline?;
31
+ private _wideColor?;
32
+ private _wideForeground?;
33
+ private _causticPipeline?;
26
34
  private _needsUpdatePipeline;
27
35
  constructor(device: GPUDevice, zeroTexture?: GPUTexture | undefined);
28
36
  private readonly _retainedOutputs;
@@ -37,8 +45,12 @@ export declare class WGPURayTraceOutputPass {
37
45
  setSampleTileGrid(columns: number, rows: number): void;
38
46
  createPass(encoder: GPUCommandEncoder, inputBuffers: RayTraceBuffers, separateCatcher?: boolean): void;
39
47
  private _createOutputPass;
48
+ private _resolveMask;
49
+ private _addCaustics;
40
50
  private _destroyTextures;
41
51
  getMemoryBytes(): number;
42
52
  dispose(): void;
43
53
  }
54
+ export declare const causticCompositeWGSL = "\n@group(0)@binding(0)var base:texture_2d<f32>;\n@group(0)@binding(1)var<storage,read>caustics:array<vec4f>;\n@fragment fn main(@builtin(position)position:vec4f)->@location(0)vec4f{\n let pixel=vec2u(position.xy);let size=textureDimensions(base);\n let c=textureLoad(base,vec2i(pixel),0);let photon=caustics[pixel.x+(size.y-pixel.y-1u)*size.x];\n return vec4f(c.rgb+photon.rgb/max(photon.a,1.0),c.a);\n}\n";
55
+ export declare const shadowMaskResolveWGSL: string;
44
56
  export {};
@@ -3,7 +3,7 @@ import { getTargetShaderCache } from './WGPUShaderCache.js';
3
3
  import { textureBytes } from './gpuMemory.js';
4
4
  import shadowCatcherAccumulationWGSL from './wgsl/chunks/shadowCatcherAccumulation.wgsl.js';
5
5
  import { fullScreenQuadVertexShaderWGSL } from './WGPUFullQuadPass.js';
6
- export function createNormalizeRayTraceOutputWGSL(layers = false, catcher = true) {
6
+ export function createNormalizeRayTraceOutputWGSL(layers = false, catcher = true, caustics = false) {
7
7
  return /* wgsl */ `
8
8
  ${hdrResolveWGSL}
9
9
  @group(0) @binding(0) var<storage, read> colorBuffer: array<vec4f>;
@@ -12,20 +12,21 @@ ${hdrResolveWGSL}
12
12
  ${shadowCatcherAccumulationWGSL}
13
13
  @group(0) @binding(3) var<storage, read> shadowCatcherBuffer: array<ShadowCatcherAccumulation>;
14
14
 
15
- @group(1) @binding(0) var<uniform> sampleCount: f32;
15
+ ${caustics ? /* wgsl */ `@group(0) @binding(4) var<storage, read> causticBuffer: array<vec4f>;
16
+ ` : ''}@group(1) @binding(0) var<uniform> sampleCount: f32;
16
17
  @group(1) @binding(1) var<uniform> sampleTileGrid: vec2u;
17
18
 
18
19
  override outputWidth: f32;
19
20
  override outputHeight: f32;
20
21
 
21
- struct qa {
22
+ struct pV {
22
23
  ${layers ? `@location(0) foreground: vec4f,
23
24
  @location(1) catcherBackground: vec4f` : `@location(0) color: vec4f,
24
25
  @location(1) normal: vec4f,
25
26
  @location(2) albedo: vec4f${catcher ? ',\n @location(3) shadowCatcher: vec4f' : ''}`}
26
27
  }
27
28
  @fragment
28
- fn main(@builtin(position) coord: vec4f) -> qa {
29
+ fn main(@builtin(position) coord: vec4f) -> pV {
29
30
  let size = vec2u(u32(outputWidth), u32(outputHeight));
30
31
  let pixel = vec2u(u32(coord.x), size.y - u32(coord.y) - 1u);
31
32
  var idx = pixel.x + pixel.y * size.x;
@@ -34,17 +35,17 @@ var idx = pixel.x + pixel.y * size.x;
34
35
 
35
36
 
36
37
  if (sampleCount < 1.0 && normalBuffer[idx].a <= 0.0) {
37
- let wU = max(sampleTileGrid, vec2u(1u));
38
- let wq = min(
39
- ((pixel + wU / 2u) / wU) * wU,
40
- ((size - vec2u(1u)) / wU) * wU
38
+ let grid = max(sampleTileGrid, vec2u(1u));
39
+ let nearest = min(
40
+ ((pixel + grid / 2u) / grid) * grid,
41
+ ((size - vec2u(1u)) / grid) * grid
41
42
  );
42
- let tW = wq.x + wq.y * size.x;
43
- if (normalBuffer[tW].a > 0.0) {
44
- idx = tW;
43
+ let tZ = nearest.x + nearest.y * size.x;
44
+ if (normalBuffer[tZ].a > 0.0) {
45
+ idx = tZ;
45
46
  }
46
47
  }
47
- var output: qa;
48
+ var output: pV;
48
49
  if (normalBuffer[idx].a <= 0.0) {
49
50
  ${layers ? `output.foreground = vec4f(0.0);
50
51
  output.catcherBackground = vec4f(0.0);` : `output.color = vec4f(0.0);
@@ -64,22 +65,22 @@ let hit = albedo.a;
64
65
  let total = max(normal.a, 1.0);
65
66
  ${layers ? `
66
67
  let shadow = shadowCatcherBuffer[idx];
67
- let jo = max(hit - shadow.mask.b, 0.0);
68
+ let iT = max(hit - shadow.mask.b, 0.0);
68
69
 
69
70
 
70
71
  output.foreground = vec4f(
71
72
  (color.rgb - shadow.background.rgb)
72
- / select(total, jo, jo > 0.0),
73
+ / select(total, iT, iT > 0.0),
73
74
  clamp((color.a - shadow.mask.g) / total, 0.0, 1.0)
74
75
  );
75
76
  output.catcherBackground = shadow.background / total;
76
77
  ` : `output.color = vec4f(
77
78
 
78
79
 
79
- vec3f(fK(color.r,normal.a,hit,1.0,true),
80
- fK(color.g,normal.a,hit,1.0,true),
81
- fK(color.b,normal.a,hit,1.0,true)),
82
- fK(color.a,normal.a,hit,1.0,false)
80
+ vec3f(fo(color.r,normal.a,hit,1.0,true),
81
+ fo(color.g,normal.a,hit,1.0,true),
82
+ fo(color.b,normal.a,hit,1.0,true)),
83
+ fo(color.a,normal.a,hit,1.0,false)
83
84
  );
84
85
 
85
86
  output.normal = vec4f(0.0);
@@ -95,7 +96,9 @@ ${catcher ? `let shadow = shadowCatcherBuffer[idx];
95
96
  output.shadowCatcher = vec4f(shadow.mask.rgb / total,
96
97
  shadow.mask.r / total * select(0.0, shadow.moments.z / shadow.moments.w, shadow.moments.w > 0.0));` : ''}
97
98
  `}
98
- return output;
99
+ ${caustics ? /* wgsl */ ` let causticColor=causticBuffer[idx].rgb/max(causticBuffer[idx].a,1.0);
100
+ ${layers ? 'output.foreground = vec4f(output.foreground.rgb+causticColor,output.foreground.a);' : 'output.color = vec4f(output.color.rgb+causticColor,output.color.a);'}
101
+ ` : ''} return output;
99
102
  }
100
103
  `;
101
104
  }
@@ -115,6 +118,12 @@ export class WGPURayTraceOutputPass {
115
118
  _width = 1;
116
119
  _height = 1;
117
120
  _hasCatcher = false;
121
+ _hasCaustics = false;
122
+ _hasWideHdr = false;
123
+ _maskPipeline;
124
+ _wideColor;
125
+ _wideForeground;
126
+ _causticPipeline;
118
127
  _needsUpdatePipeline = true;
119
128
  constructor(device, zeroTexture) {
120
129
  this.zeroTexture = zeroTexture;
@@ -145,6 +154,10 @@ export class WGPURayTraceOutputPass {
145
154
  }
146
155
  }
147
156
  getOutput(label) {
157
+ if (this._hasCaustics && label === 'color' && this._wideColor)
158
+ return this._wideColor;
159
+ if (this._hasCaustics && label === 'foreground' && this._wideForeground)
160
+ return this._wideForeground;
148
161
  return this[`_${label}Texture`] ?? this.zeroTexture;
149
162
  }
150
163
  _createTextures() {
@@ -163,7 +176,7 @@ export class WGPURayTraceOutputPass {
163
176
  this._colorTexture = device.createTexture({
164
177
  ...textureDescriptor,
165
178
  label: 'Ray Trace Color',
166
- format: 'rgba16float',
179
+ format: this._hasWideHdr ? 'rgba32float' : 'rgba16float',
167
180
  usage: GPUTextureUsage.RENDER_ATTACHMENT |
168
181
  GPUTextureUsage.TEXTURE_BINDING |
169
182
  GPUTextureUsage.COPY_SRC
@@ -177,11 +190,17 @@ export class WGPURayTraceOutputPass {
177
190
  ...textureDescriptor,
178
191
  label: 'Ray Trace Albedo'
179
192
  });
193
+ this._wideColor = this._wideForeground = undefined;
194
+ if (this._hasCaustics) {
195
+ this._wideColor = device.createTexture({ ...textureDescriptor, label: 'Caustic HDR color', format: 'rgba32float' });
196
+ if (this._hasCatcher)
197
+ this._wideForeground = device.createTexture({ ...textureDescriptor, label: 'Caustic HDR foreground', format: 'rgba32float' });
198
+ }
180
199
  if (this._hasCatcher) {
181
200
  this._foregroundTexture = device.createTexture({
182
201
  ...textureDescriptor,
183
202
  label: 'Ray Trace Foreground',
184
- format: 'rgba16float'
203
+ format: this._hasWideHdr ? 'rgba32float' : 'rgba16float'
185
204
  });
186
205
  this._catcherBackgroundTexture = device.createTexture({
187
206
  ...textureDescriptor,
@@ -235,12 +254,12 @@ export class WGPURayTraceOutputPass {
235
254
  },
236
255
  fragment: {
237
256
  module: getTargetShaderCache(device).createShaderModule({
238
- code: createNormalizeRayTraceOutputWGSL(false, this._hasCatcher)
257
+ code: createNormalizeRayTraceOutputWGSL(false, this._hasCatcher && !this._hasWideHdr, false)
239
258
  }),
240
259
  entryPoint: 'main',
241
260
  targets: [
242
261
  {
243
- format: 'rgba16float'
262
+ format: this._hasWideHdr ? 'rgba32float' : 'rgba16float'
244
263
  },
245
264
  {
246
265
  format: 'rgba8unorm'
@@ -248,7 +267,7 @@ export class WGPURayTraceOutputPass {
248
267
  {
249
268
  format: 'rgba8unorm'
250
269
  },
251
- ...(this._hasCatcher ? [{ format: 'rgba16float' }] : [])
270
+ ...(this._hasCatcher && !this._hasWideHdr ? [{ format: 'rgba16float' }] : [])
252
271
  ],
253
272
  constants: {
254
273
  outputWidth: this._width,
@@ -265,9 +284,9 @@ export class WGPURayTraceOutputPass {
265
284
  entryPoint: 'main'
266
285
  },
267
286
  fragment: {
268
- module: getTargetShaderCache(device).createShaderModule({ code: createNormalizeRayTraceOutputWGSL(true) }),
287
+ module: getTargetShaderCache(device).createShaderModule({ code: createNormalizeRayTraceOutputWGSL(true, true, false) }),
269
288
  entryPoint: 'main',
270
- targets: [{ format: 'rgba16float' }, { format: 'rgba16float' }],
289
+ targets: [{ format: this._hasWideHdr ? 'rgba32float' : 'rgba16float' }, { format: 'rgba16float' }],
271
290
  constants: { outputWidth: this._width, outputHeight: this._height }
272
291
  }
273
292
  });
@@ -279,6 +298,7 @@ export class WGPURayTraceOutputPass {
279
298
  !this._colorTexture) {
280
299
  this._width = width;
281
300
  this._height = height;
301
+ this._maskPipeline = undefined;
282
302
  this._createTextures();
283
303
  this._needsUpdatePipeline = true;
284
304
  }
@@ -290,6 +310,16 @@ export class WGPURayTraceOutputPass {
290
310
  this._device.queue.writeBuffer(this._uniformsBuffers.sampleTileGrid, 0, new Uint32Array([columns, rows]));
291
311
  }
292
312
  createPass(encoder, inputBuffers, separateCatcher = false) {
313
+ if (this._hasWideHdr !== !!inputBuffers.wideHdr) {
314
+ this._hasWideHdr = !!inputBuffers.wideHdr;
315
+ this._createTextures();
316
+ this._needsUpdatePipeline = true;
317
+ }
318
+ if (this._hasCaustics !== !!inputBuffers.caustic) {
319
+ this._hasCaustics = !!inputBuffers.caustic;
320
+ this._createTextures();
321
+ this._needsUpdatePipeline = true;
322
+ }
293
323
  if (this._hasCatcher !== separateCatcher) {
294
324
  this._hasCatcher = separateCatcher;
295
325
  this._createTextures();
@@ -299,12 +329,19 @@ export class WGPURayTraceOutputPass {
299
329
  this._createOutputPass(encoder, inputBuffers, false);
300
330
  if (separateCatcher)
301
331
  this._createOutputPass(encoder, inputBuffers, true);
332
+ if (this._hasWideHdr && separateCatcher)
333
+ this._resolveMask(encoder, inputBuffers);
334
+ if (inputBuffers.caustic) {
335
+ this._addCaustics(encoder, this._colorTexture, this._wideColor, inputBuffers.caustic);
336
+ if (separateCatcher)
337
+ this._addCaustics(encoder, this._foregroundTexture, this._wideForeground, inputBuffers.caustic);
338
+ }
302
339
  }
303
340
  _createOutputPass(encoder, inputBuffers, layers) {
304
341
  const pipeline = layers ? this._layersPipeline : this._pipeline;
305
342
  const textures = layers
306
343
  ? [this._foregroundTexture, this._catcherBackgroundTexture]
307
- : [this._colorTexture, this._normalTexture, this._albedoTexture, ...(this._hasCatcher ? [this._shadowCatcherTexture] : [])];
344
+ : [this._colorTexture, this._normalTexture, this._albedoTexture, ...(this._hasCatcher && !this._hasWideHdr ? [this._shadowCatcherTexture] : [])];
308
345
  const pass = encoder.beginRenderPass({
309
346
  colorAttachments: textures.map((texture) => ({
310
347
  view: texture.createView(),
@@ -328,7 +365,7 @@ export class WGPURayTraceOutputPass {
328
365
  buffer,
329
366
  ...(idx === 3 ? { offset: inputBuffers.shadowCatcherOffset ?? 0 } : {})
330
367
  }
331
- })).filter(entry => entry.binding < 3 || this._hasCatcher || layers)
368
+ })).filter(entry => entry.binding < 3 || (this._hasCatcher && !this._hasWideHdr) || layers).concat([])
332
369
  }));
333
370
  pass.setBindGroup(1, layers ? this._device.createBindGroup({
334
371
  layout: pipeline.getBindGroupLayout(1),
@@ -339,6 +376,31 @@ export class WGPURayTraceOutputPass {
339
376
  pass.draw(6, 1, 0, 0);
340
377
  pass.end();
341
378
  }
379
+ _resolveMask(encoder, input) {
380
+ const device = this._device;
381
+ this._maskPipeline ??= device.createRenderPipeline({ label: 'Wide HDR catcher mask', layout: 'auto',
382
+ vertex: { module: device.createShaderModule({ code: fullScreenQuadVertexShaderWGSL }), entryPoint: 'main' },
383
+ fragment: { module: device.createShaderModule({ code: shadowMaskResolveWGSL }), entryPoint: 'main', constants: { IMAGE_WIDTH: this._width, IMAGE_HEIGHT: this._height }, targets: [{ format: 'rgba16float' }] } });
384
+ const pass = encoder.beginRenderPass({ label: 'Wide HDR catcher mask', colorAttachments: [{ view: this._shadowCatcherTexture.createView(), loadOp: 'clear', storeOp: 'store' }] });
385
+ pass.setPipeline(this._maskPipeline);
386
+ pass.setBindGroup(0, device.createBindGroup({ layout: this._maskPipeline.getBindGroupLayout(0), entries: [
387
+ { binding: 0, resource: { buffer: input.normal } }, { binding: 1, resource: { buffer: input.shadowCatcher } },
388
+ { binding: 2, resource: { buffer: this._uniformsBuffers.sampleTileGrid } }, { binding: 3, resource: { buffer: this._uniformsBuffers.sampleCount } }
389
+ ] }));
390
+ pass.draw(6);
391
+ pass.end();
392
+ }
393
+ _addCaustics(encoder, base, target, caustics) {
394
+ const device = this._device;
395
+ this._causticPipeline ??= device.createRenderPipeline({ label: 'Caustic HDR resolve', layout: 'auto',
396
+ vertex: { module: device.createShaderModule({ code: fullScreenQuadVertexShaderWGSL }), entryPoint: 'main' },
397
+ fragment: { module: device.createShaderModule({ code: causticCompositeWGSL }), entryPoint: 'main', targets: [{ format: 'rgba32float' }] } });
398
+ const pass = encoder.beginRenderPass({ label: 'Caustic HDR resolve', colorAttachments: [{ view: target.createView(), loadOp: 'clear', storeOp: 'store' }] });
399
+ pass.setPipeline(this._causticPipeline);
400
+ pass.setBindGroup(0, device.createBindGroup({ layout: this._causticPipeline.getBindGroupLayout(0), entries: [{ binding: 0, resource: base.createView() }, { binding: 1, resource: { buffer: caustics } }] }));
401
+ pass.draw(6);
402
+ pass.end();
403
+ }
342
404
  _destroyTextures() {
343
405
  if (!this._colorTexture)
344
406
  return;
@@ -348,6 +410,7 @@ export class WGPURayTraceOutputPass {
348
410
  // far has completed; destroying them synchronously can make Dawn validate
349
411
  // the pending submit against an already-destroyed texture.
350
412
  const textures = [
413
+ this._wideColor, this._wideForeground,
351
414
  this._colorTexture,
352
415
  this._normalTexture,
353
416
  this._albedoTexture,
@@ -376,4 +439,35 @@ export class WGPURayTraceOutputPass {
376
439
  });
377
440
  }
378
441
  }
442
+ // A separate color attachment preserves float32 caustics within the baseline
443
+ // 32-byte MRT budget, including when the catcher needs its fourth attachment.
444
+ export const causticCompositeWGSL = /* wgsl */ `
445
+ @group(0)@binding(0)var base:texture_2d<f32>;
446
+ @group(0)@binding(1)var<storage,read>caustics:array<vec4f>;
447
+ @fragment fn main(@builtin(position)position:vec4f)->@location(0)vec4f{
448
+ let pixel=vec2u(position.xy);let size=textureDimensions(base);
449
+ let c=textureLoad(base,vec2i(pixel),0);let photon=caustics[pixel.x+(size.y-pixel.y-1u)*size.x];
450
+ return vec4f(c.rgb+photon.rgb/max(photon.a,1.0),c.a);
451
+ }
452
+ `;
453
+ export const shadowMaskResolveWGSL = /* wgsl */ `
454
+ ${shadowCatcherAccumulationWGSL}
455
+ override IMAGE_WIDTH:u32;override IMAGE_HEIGHT:u32;
456
+ @group(0)@binding(0)var<storage,read>normal:array<vec4f>;
457
+ @group(0)@binding(1)var<storage,read>shadow:array<ShadowCatcherAccumulation>;
458
+ @group(0)@binding(2)var<uniform>grid:vec2u;
459
+ @group(0)@binding(3)var<uniform>samples:f32;
460
+ @fragment fn main(@builtin(position)position:vec4f)->@location(0)vec4f{
461
+
462
+ let size=vec2u(IMAGE_WIDTH,IMAGE_HEIGHT);
463
+ let pixel=vec2u(u32(position.x),size.y-u32(position.y)-1u);var index=pixel.x+pixel.y*size.x;
464
+ if(samples<1.0&&normal[index].a<=0.0){
465
+ let tile=max(grid,vec2u(1u));let nearest=min(((pixel+tile/2u)/tile)*tile,((size-vec2u(1u))/tile)*tile);
466
+ let candidate=nearest.x+nearest.y*size.x;if(normal[candidate].a>0.0){index=candidate;}
467
+ }
468
+ if(normal[index].a<=0.0){return vec4f(0.0);}
469
+ let s=shadow[index];let total=max(normal[index].a,1.0);
470
+ return vec4f(s.mask.rgb/total,s.mask.r/total*select(0.0,s.moments.z/s.moments.w,s.moments.w>0.0));
471
+ }
472
+ `;
379
473
  //# sourceMappingURL=WGPURayTraceOutput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WGPURayTraceOutput.js","sourceRoot":"","sources":["../../src/renderer/WGPURayTraceOutput.ts"],"names":[],"mappings":"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","sourcesContent":["import {hdrResolveWGSL} from './wgsl/compose.frag.wgsl.js';\nimport { getTargetShaderCache } from './WGPUShaderCache.js';\nimport { textureBytes } from './gpuMemory.js';\nimport shadowCatcherAccumulationWGSL from './wgsl/chunks/shadowCatcherAccumulation.wgsl.js';\nimport { fullScreenQuadVertexShaderWGSL } from './WGPUFullQuadPass.js';\n\nexport function createNormalizeRayTraceOutputWGSL(layers = false, catcher = true) {\n return /* wgsl */ `\n${hdrResolveWGSL}\n@group(0) @binding(0) var<storage, read> colorBuffer: array<vec4f>;\n@group(0) @binding(1) var<storage, read> normalBuffer: array<vec4f>;\n@group(0) @binding(2) var<storage, read> albedoBuffer: array<vec4f>;\n${shadowCatcherAccumulationWGSL}\n@group(0) @binding(3) var<storage, read> shadowCatcherBuffer: array<ShadowCatcherAccumulation>;\n\n@group(1) @binding(0) var<uniform> sampleCount: f32;\n@group(1) @binding(1) var<uniform> sampleTileGrid: vec2u;\n\noverride outputWidth: f32;\noverride outputHeight: f32;\n\nstruct FSOutput {\n ${layers ? `@location(0) foreground: vec4f,\n @location(1) catcherBackground: vec4f` : `@location(0) color: vec4f,\n @location(1) normal: vec4f,\n @location(2) albedo: vec4f${catcher ? ',\\n @location(3) shadowCatcher: vec4f' : ''}`}\n}\n@fragment\nfn main(@builtin(position) coord: vec4f) -> FSOutput {\n let size = vec2u(u32(outputWidth), u32(outputHeight));\n let pixel = vec2u(u32(coord.x), size.y - u32(coord.y) - 1u);\n var idx = pixel.x + pixel.y * size.x;\n // Tiles are interleaved pixel grids, not contiguous rectangles. The first\n // tile samples (0, 0) of every grid cell across the current camera image.\n // Reconstruct only pixels not yet sampled, until the first sweep completes;\n // never write these display estimates back into the accumulated ray buffers.\n if (sampleCount < 1.0 && normalBuffer[idx].a <= 0.0) {\n let grid = max(sampleTileGrid, vec2u(1u));\n let nearest = min(\n ((pixel + grid / 2u) / grid) * grid,\n ((size - vec2u(1u)) / grid) * grid\n );\n let nearestIdx = nearest.x + nearest.y * size.x;\n if (normalBuffer[nearestIdx].a > 0.0) {\n idx = nearestIdx;\n }\n }\n var output: FSOutput;\n if (normalBuffer[idx].a <= 0.0) {\n ${layers ? `output.foreground = vec4f(0.0);\n output.catcherBackground = vec4f(0.0);` : `output.color = vec4f(0.0);\n output.normal = vec4f(0.0);\n output.albedo = vec4f(0.0);\n ${catcher ? 'output.shadowCatcher = vec4f(0.0);' : ''}`}\n return output;\n }\n let color = colorBuffer[idx];\n let normal = normalBuffer[idx];\n let albedo = albedoBuffer[idx];\n let hit = albedo.a;\n // The CPU count covers completed sweeps and is still zero during the first\n // interleaved sample. Use the actual per-pixel count, including for misses.\n // Empty pixels must remain finite: NaN alpha can poison float HDR output\n // even when its canvas uses opaque compositing.\n let total = max(normal.a, 1.0);\n ${layers ? `\n let shadow = shadowCatcherBuffer[idx];\n let foregroundHit = max(hit - shadow.mask.b, 0.0);\n // Separated background includes flat primary misses as well as catcher\n // samples. Neither belongs in the hit-normalized geometry color/alpha.\n output.foreground = vec4f(\n (color.rgb - shadow.background.rgb)\n / select(total, foregroundHit, foregroundHit > 0.0),\n clamp((color.a - shadow.mask.g) / total, 0.0, 1.0)\n );\n output.catcherBackground = shadow.background / total;\n ` : `output.color = vec4f(\n // average the color by hit count.\n // So the antialised edge color will be correct when having transparent background\n vec3f(hdr_resolve_component(color.r,normal.a,hit,1.0,true),\n hdr_resolve_component(color.g,normal.a,hit,1.0,true),\n hdr_resolve_component(color.b,normal.a,hit,1.0,true)),\n hdr_resolve_component(color.a,normal.a,hit,1.0,false)\n );\n\n output.normal = vec4f(0.0);\n // Normalize to 0 - 1\n if (dot(normal.rgb, normal.rgb) > 0.1) {\n output.normal = vec4f(normal.rgb / total * 0.5 + 0.5, 1.0);\n }\n output.albedo = vec4f(albedo.rgb / total, clamp(hit / total, 0.0, 1.0));\n ${catcher ? `let shadow = shadowCatcherBuffer[idx];\n // Opacity is the ratio of the summed occluded and total light sample\n // counts; a per-sample ratio average would keep its low-sample bias. Alpha\n // carries it scaled by coverage, as composition expects.\n output.shadowCatcher = vec4f(shadow.mask.rgb / total,\n shadow.mask.r / total * select(0.0, shadow.moments.z / shadow.moments.w, shadow.moments.w > 0.0));` : ''}\n `}\n return output;\n}\n`;\n}\n\ntype RayTraceOutput = 'color' | 'normal' | 'albedo' | 'shadowCatcher'\n | 'foreground' | 'catcherBackground';\ntype RayTraceBuffers = {\n color: GPUBuffer;\n normal: GPUBuffer;\n albedo: GPUBuffer;\n shadowCatcher: GPUBuffer;\n shadowCatcherOffset?: number;\n};\n\nexport class WGPURayTraceOutputPass {\n private _device: GPUDevice;\n\n private _pipeline!: GPURenderPipeline;\n private _layersPipeline!: GPURenderPipeline;\n private _foregroundTexture!: GPUTexture;\n private _catcherBackgroundTexture!: GPUTexture;\n private _colorTexture!: GPUTexture;\n private _normalTexture!: GPUTexture;\n private _albedoTexture!: GPUTexture;\n private _shadowCatcherTexture!: GPUTexture;\n private _uniformBindGroup!: GPUBindGroup;\n\n private _uniformsBuffers;\n\n private _width = 1;\n private _height = 1;\n\n private _hasCatcher = false;\n private _needsUpdatePipeline = true;\n\n constructor(device: GPUDevice, private readonly zeroTexture?: GPUTexture) {\n this._device = device;\n this._uniformsBuffers = {\n sampleCount: device.createBuffer({\n size: 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n }),\n sampleTileGrid: device.createBuffer({\n size: 8,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n })\n };\n }\n\n private readonly _retainedOutputs = new Set<GPUTexture>();\n retainOutput(texture: GPUTexture) {\n const owned = ['color', 'normal', 'albedo', 'shadowCatcher', 'foreground', 'catcherBackground'] as const;\n if (owned.some(label => this.getOutput(label) === texture)) this._retainedOutputs.add(texture);\n }\n releaseOutput(texture: GPUTexture) {\n if (!this._retainedOutputs.delete(texture)) return;\n const owned = ['color', 'normal', 'albedo', 'shadowCatcher', 'foreground', 'catcherBackground'] as const;\n if (!owned.some(label => this.getOutput(label) === texture)) {\n void this._device.queue.onSubmittedWorkDone().catch(() => undefined).then(() => texture.destroy());\n }\n }\n\n getOutput(label: RayTraceOutput): GPUTexture {\n\n return this[`_${label}Texture`] ?? this.zeroTexture!;\n }\n\n private _createTextures() {\n const { _device: device, _width: width, _height: height } = this;\n const textureDescriptor: GPUTextureDescriptor = {\n size: {\n width,\n height,\n depthOrArrayLayers: 1\n },\n format: 'rgba8unorm',\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_SRC\n };\n this._destroyTextures();\n this._colorTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Color',\n format: 'rgba16float',\n usage:\n GPUTextureUsage.RENDER_ATTACHMENT |\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_SRC\n });\n this._normalTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Normal',\n usage: textureDescriptor.usage | GPUTextureUsage.COPY_SRC\n });\n this._albedoTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Albedo'\n });\n if (this._hasCatcher) {\n this._foregroundTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Foreground',\n format: 'rgba16float'\n });\n this._catcherBackgroundTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Catcher Background',\n format: 'rgba16float'\n });\n this._shadowCatcherTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Shadow Catcher',\n format: 'rgba16float'\n });\n } else {\n this._foregroundTexture = this._catcherBackgroundTexture = this._shadowCatcherTexture = undefined!;\n }\n }\n\n private _updateBindGroups() {\n const device = this._device;\n this._uniformBindGroup = device.createBindGroup({\n layout: this._pipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: this._uniformsBuffers.sampleCount\n }\n },\n {\n binding: 1,\n resource: {\n buffer: this._uniformsBuffers.sampleTileGrid\n }\n }\n ]\n });\n }\n\n private _updatePipeline() {\n if (!this._needsUpdatePipeline) {\n return;\n }\n this._needsUpdatePipeline = false;\n const device = this._device;\n\n this._pipeline = getTargetShaderCache(device).createRenderPipeline({\n label: 'rayTraceOutput',\n layout: 'auto',\n vertex: {\n module: getTargetShaderCache(device).createShaderModule({\n code: fullScreenQuadVertexShaderWGSL\n }),\n entryPoint: 'main'\n },\n fragment: {\n module: getTargetShaderCache(device).createShaderModule({\n code: createNormalizeRayTraceOutputWGSL(false, this._hasCatcher)\n }),\n entryPoint: 'main',\n targets: [\n {\n format: 'rgba16float'\n },\n {\n format: 'rgba8unorm'\n },\n {\n format: 'rgba8unorm'\n },\n ...(this._hasCatcher ? [{format: 'rgba16float' as const}] : [])\n ],\n constants: {\n outputWidth: this._width,\n outputHeight: this._height\n }\n }\n });\n\n if (this._hasCatcher) this._layersPipeline = getTargetShaderCache(device).createRenderPipeline({\n label: 'rayTraceLayers',\n layout: 'auto',\n vertex: {\n module: getTargetShaderCache(device).createShaderModule({ code: fullScreenQuadVertexShaderWGSL }),\n entryPoint: 'main'\n },\n fragment: {\n module: getTargetShaderCache(device).createShaderModule({ code: createNormalizeRayTraceOutputWGSL(true) }),\n entryPoint: 'main',\n targets: [{ format: 'rgba16float' }, { format: 'rgba16float' }],\n constants: { outputWidth: this._width, outputHeight: this._height }\n }\n });\n this._updateBindGroups();\n }\n\n setSize(width: number, height: number) {\n if (\n this._width !== width ||\n this._height !== height ||\n !this._colorTexture\n ) {\n this._width = width;\n this._height = height;\n this._createTextures();\n this._needsUpdatePipeline = true;\n }\n }\n\n setSampleCount(sampleCount: number) {\n this._device.queue.writeBuffer(\n this._uniformsBuffers.sampleCount,\n 0,\n new Float32Array([sampleCount])\n );\n }\n\n setSampleTileGrid(columns: number, rows: number) {\n this._device.queue.writeBuffer(\n this._uniformsBuffers.sampleTileGrid,\n 0,\n new Uint32Array([columns, rows])\n );\n }\n\n createPass(\n encoder: GPUCommandEncoder,\n inputBuffers: RayTraceBuffers,\n separateCatcher = false\n ) {\n if (this._hasCatcher !== separateCatcher) {\n this._hasCatcher = separateCatcher; this._createTextures(); this._needsUpdatePipeline = true;\n }\n this._updatePipeline();\n this._createOutputPass(encoder, inputBuffers, false);\n if (separateCatcher) this._createOutputPass(encoder, inputBuffers, true);\n }\n\n private _createOutputPass(\n encoder: GPUCommandEncoder,\n inputBuffers: RayTraceBuffers,\n layers: boolean\n ) {\n const pipeline = layers ? this._layersPipeline : this._pipeline;\n const textures = layers\n ? [this._foregroundTexture, this._catcherBackgroundTexture]\n : [this._colorTexture, this._normalTexture, this._albedoTexture, ...(this._hasCatcher ? [this._shadowCatcherTexture] : [])];\n const pass = encoder.beginRenderPass({\n colorAttachments: textures.map((texture) => ({\n view: texture.createView(),\n loadValue: { r: 0, g: 0, b: 0, a: 0 },\n storeOp: 'store',\n loadOp: 'clear'\n }))\n });\n pass.setPipeline(pipeline);\n\n pass.setBindGroup(\n 0,\n this._device.createBindGroup({\n label: 'rayTraceOutput',\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n inputBuffers.color,\n inputBuffers.normal,\n inputBuffers.albedo,\n inputBuffers.shadowCatcher\n ].map((buffer, idx) => ({\n binding: idx,\n resource: {\n buffer,\n ...(idx === 3 ? { offset: inputBuffers.shadowCatcherOffset ?? 0 } : {})\n }\n })).filter(entry => entry.binding < 3 || this._hasCatcher || layers)\n })\n );\n pass.setBindGroup(1, layers ? this._device.createBindGroup({\n layout: pipeline.getBindGroupLayout(1),\n entries: Object.values(this._uniformsBuffers).map((buffer, binding) => ({\n binding, resource: { buffer }\n }))\n }) : this._uniformBindGroup);\n\n pass.draw(6, 1, 0, 0);\n pass.end();\n\n }\n\n private _destroyTextures() {\n if (!this._colorTexture) return;\n\n // These textures are also OIDN inputs. A resolution or preview-mode\n // change can replace them immediately after a denoising command buffer\n // was submitted. Keep the old resources alive until all work submitted so\n // far has completed; destroying them synchronously can make Dawn validate\n // the pending submit against an already-destroyed texture.\n const textures = [\n this._colorTexture,\n this._normalTexture,\n this._albedoTexture,\n this._shadowCatcherTexture,\n this._foregroundTexture,\n this._catcherBackgroundTexture\n ].filter((texture): texture is GPUTexture => !!texture && !this._retainedOutputs.has(texture));\n void this._device.queue\n .onSubmittedWorkDone()\n .catch(() => undefined)\n .then(() => textures.forEach((texture) => texture.destroy()));\n }\n\n getMemoryBytes() {\n const textures = ['color', 'normal', 'albedo', 'shadowCatcher', 'foreground', 'catcherBackground'] as const;\n return Object.values(this._uniformsBuffers).reduce((sum, buffer) => sum + buffer.size, 0)\n + Array.from(new Set([...textures.map(label => this[`_${label}Texture`]), ...this._retainedOutputs]))\n .reduce((sum, texture) => sum + textureBytes(texture), 0);\n }\n\n dispose() {\n const retained = Array.from(this._retainedOutputs);\n void this._device.queue.onSubmittedWorkDone().catch(() => undefined).then(() => retained.forEach(texture => texture.destroy()));\n this._destroyTextures();\n this._retainedOutputs.clear();\n Object.keys(this._uniformsBuffers).forEach((key) => {\n (this._uniformsBuffers as any)[key].destroy();\n });\n }\n}\n"]}
1
+ {"version":3,"file":"WGPURayTraceOutput.js","sourceRoot":"","sources":["../../src/renderer/WGPURayTraceOutput.ts"],"names":[],"mappings":"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","sourcesContent":["import {hdrResolveWGSL} from './wgsl/compose.frag.wgsl.js';\nimport { getTargetShaderCache } from './WGPUShaderCache.js';\nimport { textureBytes } from './gpuMemory.js';\nimport shadowCatcherAccumulationWGSL from './wgsl/chunks/shadowCatcherAccumulation.wgsl.js';\nimport { fullScreenQuadVertexShaderWGSL } from './WGPUFullQuadPass.js';\n\nexport function createNormalizeRayTraceOutputWGSL(layers = false, catcher = true, caustics = false) {\n return /* wgsl */ `\n${hdrResolveWGSL}\n@group(0) @binding(0) var<storage, read> colorBuffer: array<vec4f>;\n@group(0) @binding(1) var<storage, read> normalBuffer: array<vec4f>;\n@group(0) @binding(2) var<storage, read> albedoBuffer: array<vec4f>;\n${shadowCatcherAccumulationWGSL}\n@group(0) @binding(3) var<storage, read> shadowCatcherBuffer: array<ShadowCatcherAccumulation>;\n\n${caustics ? /* wgsl */ `@group(0) @binding(4) var<storage, read> causticBuffer: array<vec4f>;\n` : ''}@group(1) @binding(0) var<uniform> sampleCount: f32;\n@group(1) @binding(1) var<uniform> sampleTileGrid: vec2u;\n\noverride outputWidth: f32;\noverride outputHeight: f32;\n\nstruct FSOutput {\n ${layers ? `@location(0) foreground: vec4f,\n @location(1) catcherBackground: vec4f` : `@location(0) color: vec4f,\n @location(1) normal: vec4f,\n @location(2) albedo: vec4f${catcher ? ',\\n @location(3) shadowCatcher: vec4f' : ''}`}\n}\n@fragment\nfn main(@builtin(position) coord: vec4f) -> FSOutput {\n let size = vec2u(u32(outputWidth), u32(outputHeight));\n let pixel = vec2u(u32(coord.x), size.y - u32(coord.y) - 1u);\n var idx = pixel.x + pixel.y * size.x;\n // Tiles are interleaved pixel grids, not contiguous rectangles. The first\n // tile samples (0, 0) of every grid cell across the current camera image.\n // Reconstruct only pixels not yet sampled, until the first sweep completes;\n // never write these display estimates back into the accumulated ray buffers.\n if (sampleCount < 1.0 && normalBuffer[idx].a <= 0.0) {\n let grid = max(sampleTileGrid, vec2u(1u));\n let nearest = min(\n ((pixel + grid / 2u) / grid) * grid,\n ((size - vec2u(1u)) / grid) * grid\n );\n let nearestIdx = nearest.x + nearest.y * size.x;\n if (normalBuffer[nearestIdx].a > 0.0) {\n idx = nearestIdx;\n }\n }\n var output: FSOutput;\n if (normalBuffer[idx].a <= 0.0) {\n ${layers ? `output.foreground = vec4f(0.0);\n output.catcherBackground = vec4f(0.0);` : `output.color = vec4f(0.0);\n output.normal = vec4f(0.0);\n output.albedo = vec4f(0.0);\n ${catcher ? 'output.shadowCatcher = vec4f(0.0);' : ''}`}\n return output;\n }\n let color = colorBuffer[idx];\n let normal = normalBuffer[idx];\n let albedo = albedoBuffer[idx];\n let hit = albedo.a;\n // The CPU count covers completed sweeps and is still zero during the first\n // interleaved sample. Use the actual per-pixel count, including for misses.\n // Empty pixels must remain finite: NaN alpha can poison float HDR output\n // even when its canvas uses opaque compositing.\n let total = max(normal.a, 1.0);\n ${layers ? `\n let shadow = shadowCatcherBuffer[idx];\n let foregroundHit = max(hit - shadow.mask.b, 0.0);\n // Separated background includes flat primary misses as well as catcher\n // samples. Neither belongs in the hit-normalized geometry color/alpha.\n output.foreground = vec4f(\n (color.rgb - shadow.background.rgb)\n / select(total, foregroundHit, foregroundHit > 0.0),\n clamp((color.a - shadow.mask.g) / total, 0.0, 1.0)\n );\n output.catcherBackground = shadow.background / total;\n ` : `output.color = vec4f(\n // average the color by hit count.\n // So the antialised edge color will be correct when having transparent background\n vec3f(hdr_resolve_component(color.r,normal.a,hit,1.0,true),\n hdr_resolve_component(color.g,normal.a,hit,1.0,true),\n hdr_resolve_component(color.b,normal.a,hit,1.0,true)),\n hdr_resolve_component(color.a,normal.a,hit,1.0,false)\n );\n\n output.normal = vec4f(0.0);\n // Normalize to 0 - 1\n if (dot(normal.rgb, normal.rgb) > 0.1) {\n output.normal = vec4f(normal.rgb / total * 0.5 + 0.5, 1.0);\n }\n output.albedo = vec4f(albedo.rgb / total, clamp(hit / total, 0.0, 1.0));\n ${catcher ? `let shadow = shadowCatcherBuffer[idx];\n // Opacity is the ratio of the summed occluded and total light sample\n // counts; a per-sample ratio average would keep its low-sample bias. Alpha\n // carries it scaled by coverage, as composition expects.\n output.shadowCatcher = vec4f(shadow.mask.rgb / total,\n shadow.mask.r / total * select(0.0, shadow.moments.z / shadow.moments.w, shadow.moments.w > 0.0));` : ''}\n `}\n${caustics ? /* wgsl */ ` let causticColor=causticBuffer[idx].rgb/max(causticBuffer[idx].a,1.0);\n ${layers ? 'output.foreground = vec4f(output.foreground.rgb+causticColor,output.foreground.a);' : 'output.color = vec4f(output.color.rgb+causticColor,output.color.a);'}\n` : ''} return output;\n}\n`;\n}\n\ntype RayTraceOutput = 'color' | 'normal' | 'albedo' | 'shadowCatcher'\n | 'foreground' | 'catcherBackground';\ntype RayTraceBuffers = {\n color: GPUBuffer;\n caustic?: GPUBuffer;\n wideHdr?:boolean;\n normal: GPUBuffer;\n albedo: GPUBuffer;\n shadowCatcher: GPUBuffer;\n shadowCatcherOffset?: number;\n};\n\nexport class WGPURayTraceOutputPass {\n private _device: GPUDevice;\n\n private _pipeline!: GPURenderPipeline;\n private _layersPipeline!: GPURenderPipeline;\n private _foregroundTexture!: GPUTexture;\n private _catcherBackgroundTexture!: GPUTexture;\n private _colorTexture!: GPUTexture;\n private _normalTexture!: GPUTexture;\n private _albedoTexture!: GPUTexture;\n private _shadowCatcherTexture!: GPUTexture;\n private _uniformBindGroup!: GPUBindGroup;\n\n private _uniformsBuffers;\n\n private _width = 1;\n private _height = 1;\n\n private _hasCatcher = false;\n private _hasCaustics = false;\n private _hasWideHdr=false;\n private _maskPipeline?:GPURenderPipeline;\n private _wideColor?:GPUTexture;\n private _wideForeground?:GPUTexture;\n private _causticPipeline?:GPURenderPipeline;\n private _needsUpdatePipeline = true;\n\n constructor(device: GPUDevice, private readonly zeroTexture?: GPUTexture) {\n this._device = device;\n this._uniformsBuffers = {\n sampleCount: device.createBuffer({\n size: 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n }),\n sampleTileGrid: device.createBuffer({\n size: 8,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n })\n };\n }\n\n private readonly _retainedOutputs = new Set<GPUTexture>();\n retainOutput(texture: GPUTexture) {\n const owned = ['color', 'normal', 'albedo', 'shadowCatcher', 'foreground', 'catcherBackground'] as const;\n if (owned.some(label => this.getOutput(label) === texture)) this._retainedOutputs.add(texture);\n }\n releaseOutput(texture: GPUTexture) {\n if (!this._retainedOutputs.delete(texture)) return;\n const owned = ['color', 'normal', 'albedo', 'shadowCatcher', 'foreground', 'catcherBackground'] as const;\n if (!owned.some(label => this.getOutput(label) === texture)) {\n void this._device.queue.onSubmittedWorkDone().catch(() => undefined).then(() => texture.destroy());\n }\n }\n\n getOutput(label: RayTraceOutput): GPUTexture {\n\n if(this._hasCaustics&&label==='color'&&this._wideColor)return this._wideColor;\n if(this._hasCaustics&&label==='foreground'&&this._wideForeground)return this._wideForeground;\n return this[`_${label}Texture`] ?? this.zeroTexture!;\n }\n\n private _createTextures() {\n const { _device: device, _width: width, _height: height } = this;\n const textureDescriptor: GPUTextureDescriptor = {\n size: {\n width,\n height,\n depthOrArrayLayers: 1\n },\n format: 'rgba8unorm',\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_SRC\n };\n this._destroyTextures();\n this._colorTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Color',\n format: this._hasWideHdr?'rgba32float':'rgba16float',\n usage:\n GPUTextureUsage.RENDER_ATTACHMENT |\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_SRC\n });\n this._normalTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Normal',\n usage: textureDescriptor.usage | GPUTextureUsage.COPY_SRC\n });\n this._albedoTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Albedo'\n });\n this._wideColor=this._wideForeground=undefined;\n if(this._hasCaustics){\n this._wideColor=device.createTexture({...textureDescriptor,label:'Caustic HDR color',format:'rgba32float'});\n if(this._hasCatcher)this._wideForeground=device.createTexture({...textureDescriptor,label:'Caustic HDR foreground',format:'rgba32float'});\n }\n if (this._hasCatcher) {\n this._foregroundTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Foreground',\n format: this._hasWideHdr?'rgba32float':'rgba16float'\n });\n this._catcherBackgroundTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Catcher Background',\n format: 'rgba16float'\n });\n this._shadowCatcherTexture = device.createTexture({\n ...textureDescriptor,\n label: 'Ray Trace Shadow Catcher',\n format: 'rgba16float'\n });\n } else {\n this._foregroundTexture = this._catcherBackgroundTexture = this._shadowCatcherTexture = undefined!;\n }\n }\n\n private _updateBindGroups() {\n const device = this._device;\n this._uniformBindGroup = device.createBindGroup({\n layout: this._pipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: this._uniformsBuffers.sampleCount\n }\n },\n {\n binding: 1,\n resource: {\n buffer: this._uniformsBuffers.sampleTileGrid\n }\n }\n ]\n });\n }\n\n private _updatePipeline() {\n if (!this._needsUpdatePipeline) {\n return;\n }\n this._needsUpdatePipeline = false;\n const device = this._device;\n\n this._pipeline = getTargetShaderCache(device).createRenderPipeline({\n label: 'rayTraceOutput',\n layout: 'auto',\n vertex: {\n module: getTargetShaderCache(device).createShaderModule({\n code: fullScreenQuadVertexShaderWGSL\n }),\n entryPoint: 'main'\n },\n fragment: {\n module: getTargetShaderCache(device).createShaderModule({\n code: createNormalizeRayTraceOutputWGSL(false, this._hasCatcher&&!this._hasWideHdr, false)\n }),\n entryPoint: 'main',\n targets: [\n {\n format: this._hasWideHdr?'rgba32float':'rgba16float'\n },\n {\n format: 'rgba8unorm'\n },\n {\n format: 'rgba8unorm'\n },\n ...(this._hasCatcher&&!this._hasWideHdr ? [{format: 'rgba16float' as const}] : [])\n ],\n constants: {\n outputWidth: this._width,\n outputHeight: this._height\n }\n }\n });\n\n if (this._hasCatcher) this._layersPipeline = getTargetShaderCache(device).createRenderPipeline({\n label: 'rayTraceLayers',\n layout: 'auto',\n vertex: {\n module: getTargetShaderCache(device).createShaderModule({ code: fullScreenQuadVertexShaderWGSL }),\n entryPoint: 'main'\n },\n fragment: {\n module: getTargetShaderCache(device).createShaderModule({ code: createNormalizeRayTraceOutputWGSL(true, true, false) }),\n entryPoint: 'main',\n targets: [{ format: this._hasWideHdr?'rgba32float':'rgba16float' }, { format: 'rgba16float' }],\n constants: { outputWidth: this._width, outputHeight: this._height }\n }\n });\n this._updateBindGroups();\n }\n\n setSize(width: number, height: number) {\n if (\n this._width !== width ||\n this._height !== height ||\n !this._colorTexture\n ) {\n this._width = width;\n this._height = height;this._maskPipeline=undefined;\n this._createTextures();\n this._needsUpdatePipeline = true;\n }\n }\n\n setSampleCount(sampleCount: number) {\n this._device.queue.writeBuffer(\n this._uniformsBuffers.sampleCount,\n 0,\n new Float32Array([sampleCount])\n );\n }\n\n setSampleTileGrid(columns: number, rows: number) {\n this._device.queue.writeBuffer(\n this._uniformsBuffers.sampleTileGrid,\n 0,\n new Uint32Array([columns, rows])\n );\n }\n\n createPass(\n encoder: GPUCommandEncoder,\n inputBuffers: RayTraceBuffers,\n separateCatcher = false\n ) {\n if(this._hasWideHdr!==!!inputBuffers.wideHdr){this._hasWideHdr=!!inputBuffers.wideHdr;this._createTextures();this._needsUpdatePipeline=true;}\n if (this._hasCaustics !== !!inputBuffers.caustic) {\n this._hasCaustics=!!inputBuffers.caustic;this._createTextures();this._needsUpdatePipeline=true;\n }\n if (this._hasCatcher !== separateCatcher) {\n this._hasCatcher = separateCatcher; this._createTextures(); this._needsUpdatePipeline = true;\n }\n this._updatePipeline();\n this._createOutputPass(encoder, inputBuffers, false);\n if (separateCatcher) this._createOutputPass(encoder, inputBuffers, true);\n if(this._hasWideHdr&&separateCatcher)this._resolveMask(encoder,inputBuffers);\n if(inputBuffers.caustic){\n this._addCaustics(encoder,this._colorTexture,this._wideColor!,inputBuffers.caustic);\n if(separateCatcher)this._addCaustics(encoder,this._foregroundTexture,this._wideForeground!,inputBuffers.caustic);\n }\n }\n\n private _createOutputPass(\n encoder: GPUCommandEncoder,\n inputBuffers: RayTraceBuffers,\n layers: boolean\n ) {\n const pipeline = layers ? this._layersPipeline : this._pipeline;\n const textures = layers\n ? [this._foregroundTexture, this._catcherBackgroundTexture]\n : [this._colorTexture, this._normalTexture, this._albedoTexture, ...(this._hasCatcher&&!this._hasWideHdr ? [this._shadowCatcherTexture] : [])];\n const pass = encoder.beginRenderPass({\n colorAttachments: textures.map((texture) => ({\n view: texture.createView(),\n loadValue: { r: 0, g: 0, b: 0, a: 0 },\n storeOp: 'store',\n loadOp: 'clear'\n }))\n });\n pass.setPipeline(pipeline);\n\n pass.setBindGroup(\n 0,\n this._device.createBindGroup({\n label: 'rayTraceOutput',\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n inputBuffers.color,\n inputBuffers.normal,\n inputBuffers.albedo,\n inputBuffers.shadowCatcher\n ].map((buffer, idx) => ({\n binding: idx,\n resource: {\n buffer,\n ...(idx === 3 ? { offset: inputBuffers.shadowCatcherOffset ?? 0 } : {})\n }\n })).filter(entry => entry.binding < 3 || (this._hasCatcher&&!this._hasWideHdr) || layers).concat(\n []\n )\n })\n );\n pass.setBindGroup(1, layers ? this._device.createBindGroup({\n layout: pipeline.getBindGroupLayout(1),\n entries: Object.values(this._uniformsBuffers).map((buffer, binding) => ({\n binding, resource: { buffer }\n }))\n }) : this._uniformBindGroup);\n\n pass.draw(6, 1, 0, 0);\n pass.end();\n\n }\n\n private _resolveMask(encoder:GPUCommandEncoder,input:RayTraceBuffers){\n const device=this._device;\n this._maskPipeline??=device.createRenderPipeline({label:'Wide HDR catcher mask',layout:'auto',\n vertex:{module:device.createShaderModule({code:fullScreenQuadVertexShaderWGSL}),entryPoint:'main'},\n fragment:{module:device.createShaderModule({code:shadowMaskResolveWGSL}),entryPoint:'main',constants:{IMAGE_WIDTH:this._width,IMAGE_HEIGHT:this._height},targets:[{format:'rgba16float'}]}});\n const pass=encoder.beginRenderPass({label:'Wide HDR catcher mask',colorAttachments:[{view:this._shadowCatcherTexture.createView(),loadOp:'clear',storeOp:'store'}]});\n pass.setPipeline(this._maskPipeline);pass.setBindGroup(0,device.createBindGroup({layout:this._maskPipeline.getBindGroupLayout(0),entries:[\n {binding:0,resource:{buffer:input.normal}},{binding:1,resource:{buffer:input.shadowCatcher}},\n {binding:2,resource:{buffer:this._uniformsBuffers.sampleTileGrid}},{binding:3,resource:{buffer:this._uniformsBuffers.sampleCount}}]}));\n pass.draw(6);pass.end();\n }\n\n private _addCaustics(encoder:GPUCommandEncoder,base:GPUTexture,target:GPUTexture,caustics:GPUBuffer){\n const device=this._device;\n this._causticPipeline??=device.createRenderPipeline({label:'Caustic HDR resolve',layout:'auto',\n vertex:{module:device.createShaderModule({code:fullScreenQuadVertexShaderWGSL}),entryPoint:'main'},\n fragment:{module:device.createShaderModule({code:causticCompositeWGSL}),entryPoint:'main',targets:[{format:'rgba32float'}]}});\n const pass=encoder.beginRenderPass({label:'Caustic HDR resolve',colorAttachments:[{view:target.createView(),loadOp:'clear',storeOp:'store'}]});\n pass.setPipeline(this._causticPipeline);pass.setBindGroup(0,device.createBindGroup({layout:this._causticPipeline.getBindGroupLayout(0),entries:[{binding:0,resource:base.createView()},{binding:1,resource:{buffer:caustics}}]}));\n pass.draw(6);pass.end();\n }\n\n private _destroyTextures() {\n if (!this._colorTexture) return;\n\n // These textures are also OIDN inputs. A resolution or preview-mode\n // change can replace them immediately after a denoising command buffer\n // was submitted. Keep the old resources alive until all work submitted so\n // far has completed; destroying them synchronously can make Dawn validate\n // the pending submit against an already-destroyed texture.\n const textures = [\n this._wideColor,this._wideForeground,\n this._colorTexture,\n this._normalTexture,\n this._albedoTexture,\n this._shadowCatcherTexture,\n this._foregroundTexture,\n this._catcherBackgroundTexture\n ].filter((texture): texture is GPUTexture => !!texture && !this._retainedOutputs.has(texture));\n void this._device.queue\n .onSubmittedWorkDone()\n .catch(() => undefined)\n .then(() => textures.forEach((texture) => texture.destroy()));\n }\n\n getMemoryBytes() {\n const textures = ['color', 'normal', 'albedo', 'shadowCatcher', 'foreground', 'catcherBackground'] as const;\n return Object.values(this._uniformsBuffers).reduce((sum, buffer) => sum + buffer.size, 0)\n + Array.from(new Set([...textures.map(label => this[`_${label}Texture`]), ...this._retainedOutputs]))\n .reduce((sum, texture) => sum + textureBytes(texture), 0);\n }\n\n dispose() {\n const retained = Array.from(this._retainedOutputs);\n void this._device.queue.onSubmittedWorkDone().catch(() => undefined).then(() => retained.forEach(texture => texture.destroy()));\n this._destroyTextures();\n this._retainedOutputs.clear();\n Object.keys(this._uniformsBuffers).forEach((key) => {\n (this._uniformsBuffers as any)[key].destroy();\n });\n }\n}\n\n// A separate color attachment preserves float32 caustics within the baseline\n// 32-byte MRT budget, including when the catcher needs its fourth attachment.\nexport const causticCompositeWGSL=/* wgsl */ `\n@group(0)@binding(0)var base:texture_2d<f32>;\n@group(0)@binding(1)var<storage,read>caustics:array<vec4f>;\n@fragment fn main(@builtin(position)position:vec4f)->@location(0)vec4f{\n let pixel=vec2u(position.xy);let size=textureDimensions(base);\n let c=textureLoad(base,vec2i(pixel),0);let photon=caustics[pixel.x+(size.y-pixel.y-1u)*size.x];\n return vec4f(c.rgb+photon.rgb/max(photon.a,1.0),c.a);\n}\n`;\n\nexport const shadowMaskResolveWGSL=/* wgsl */ `\n${shadowCatcherAccumulationWGSL}\noverride IMAGE_WIDTH:u32;override IMAGE_HEIGHT:u32;\n@group(0)@binding(0)var<storage,read>normal:array<vec4f>;\n@group(0)@binding(1)var<storage,read>shadow:array<ShadowCatcherAccumulation>;\n@group(0)@binding(2)var<uniform>grid:vec2u;\n@group(0)@binding(3)var<uniform>samples:f32;\n@fragment fn main(@builtin(position)position:vec4f)->@location(0)vec4f{\n // Image dimensions are supplied by the actual attachment through a uniform.\n let size=vec2u(IMAGE_WIDTH,IMAGE_HEIGHT);\n let pixel=vec2u(u32(position.x),size.y-u32(position.y)-1u);var index=pixel.x+pixel.y*size.x;\n if(samples<1.0&&normal[index].a<=0.0){\n let tile=max(grid,vec2u(1u));let nearest=min(((pixel+tile/2u)/tile)*tile,((size-vec2u(1u))/tile)*tile);\n let candidate=nearest.x+nearest.y*size.x;if(normal[candidate].a>0.0){index=candidate;}\n }\n if(normal[index].a<=0.0){return vec4f(0.0);}\n let s=shadow[index];let total=max(normal[index].a,1.0);\n return vec4f(s.mask.rgb/total,s.mask.r/total*select(0.0,s.moments.z/s.moments.w,s.moments.w>0.0));\n}\n`;\n"]}
@@ -39,6 +39,16 @@ declare class WGPURayTracePass {
39
39
  private _width;
40
40
  private _height;
41
41
  private _meshes;
42
+ private _causticKey;
43
+ private _photonMapping;
44
+ private _photonMap?;
45
+ private _causticLight?;
46
+ private _causticSettings?;
47
+ private _causticPerspective;
48
+ private _causticCameraScale;
49
+ private _causticBounds;
50
+ private _transport?;
51
+ private _lightTracing;
42
52
  private _sceneEnvironment;
43
53
  private _rectLightTextures;
44
54
  private _analyticLights;
@@ -111,22 +121,25 @@ declare class WGPURayTracePass {
111
121
  private _skyBaker?;
112
122
  private _backgroundImageSource;
113
123
  private _backgroundTex?;
114
- private _rayTracePipelineLayout?;
115
124
  private _rayTraceBindGroups?;
125
+ private _photonEmissionGroups?;
116
126
  private _blasLayoutMask;
117
- private _compiledBlasLayoutMask;
118
- private _compiledAnisotropyDirections;
119
- private _compiledCoatNormals;
120
- private _compiledHasAlpha;
121
- private _compiledSceneHasAlpha;
122
127
  private _alphaBlendStrategy;
123
128
  private _constants;
124
129
  private _retainedShaderCapabilities?;
125
130
  private _retainedShaderStructure?;
126
131
  private _shaderCapabilities;
127
- private _prevPipelineConstants;
128
- private _prevDefinesCode;
129
- private _prevPipelineInputs?;
132
+ private _targetTransport;
133
+ private _traceVariants;
134
+ private _queuedCompiles;
135
+ private _activeCompiles;
136
+ private _traceModules;
137
+ private _requestedVariant?;
138
+ private _activeVariant?;
139
+ private _activeInputs?;
140
+ private _awaitingRetirement?;
141
+ private _resourceError;
142
+ private _aovPipelinesFailed;
130
143
  private _hasTransmission;
131
144
  private _hasShadowCatcher;
132
145
  private _hasDisplacement;
@@ -140,24 +153,23 @@ declare class WGPURayTracePass {
140
153
  private _apertureRadius;
141
154
  private _focusDistance;
142
155
  private _needsUpdateBindGroups;
143
- private _computeShaderModule?;
156
+ private _needsPhotonTargetBindGroups;
157
+ private _needsUpdateOutputBindGroup;
144
158
  private _aovPipelines;
145
159
  private _depthCompute?;
146
160
  private _depthTracePipeline?;
147
161
  private _depthPipeline?;
148
162
  private _shaderCache;
149
163
  private _debugBVHBuffer?;
150
- private _isCompilingShader;
151
- private _shaderCompilationDiagnostics?;
152
- private _pipelineError;
153
164
  private _bakePipelineConstants;
154
- private _failedPipelineSignature?;
155
165
  constructor(device: GPUDevice, _textureSelection?: MaterialTextureSelection);
156
166
  getOutputBuffer(): {
157
- color: GPUBuffer;
158
167
  normal: GPUBuffer;
159
168
  albedo: GPUBuffer;
160
169
  shadowCatcher: GPUBuffer;
170
+ caustic?: GPUBuffer | undefined;
171
+ wideHdr?: boolean | undefined;
172
+ color: GPUBuffer;
161
173
  };
162
174
  private _ensureAdaptiveSamplingTexture;
163
175
  /**
@@ -169,16 +181,33 @@ declare class WGPURayTracePass {
169
181
  private _createPipelineLayout;
170
182
  private _updateGPUBuffer;
171
183
  private _uniformBuffer;
172
- updatePipeline(): Promise<void>;
184
+ private _preparePhotonTarget;
185
+ /**
186
+ * Prepares the pipeline for the settings currently written to this pass.
187
+ * Everything except compilation runs synchronously, and compilation only
188
+ * writes to its own variant. Renders with different settings can therefore
189
+ * interleave without invalidating each other. Returns a promise while the
190
+ * requested state waits on the GPU; undefined means nothing is outstanding.
191
+ */
192
+ updatePipeline(): Promise<void> | undefined;
193
+ /** Runs only for a ready variant, without yielding, so tracing can start in this call. */
194
+ private _installTraceVariant;
195
+ /** Snapshots everything compilation needs. The task must not read mutable pass state afterwards. */
196
+ private _startTraceVariant;
197
+ /** Runs the most recently requested variants first: a dragged slider's last value is the one in use. */
198
+ private _pumpCompiles;
199
+ private _requestQueuedCompile;
173
200
  private _prepareAovPipelines;
174
201
  prepareAovs(kinds: readonly AovKind[]): boolean;
175
202
  renderAovs(state: WGPUAov, camera: Camera, samples: number, cap: number, kinds: readonly AovKind[]): boolean;
176
203
  readDepthSamples(area: DepthSampleArea, aspect?: number): Promise<Float32Array | undefined>;
204
+ /** Whether the latest request waits on GPU work that will settle on its own. */
177
205
  isCompilingShader(): boolean;
178
206
  isPipelineReady(): boolean;
207
+ /** Failure of the latest request. A failed variant does not affect other renders. */
179
208
  getPipelineError(): unknown;
180
209
  private _updateBindGroups;
181
- createPass(encoder: GPUCommandEncoder, clear: boolean, tiles: [number, number], timing?: WGPURayTraceTimingCapture): void;
210
+ createPass(encoder: GPUCommandEncoder, clear: boolean, tiles: [number, number], timing?: WGPURayTraceTimingCapture): number;
182
211
  getDebugBVHData(): Promise<{
183
212
  buffer: ArrayBuffer;
184
213
  }>;
@@ -242,7 +271,9 @@ declare class WGPURayTracePass {
242
271
  bevel: boolean;
243
272
  dispersionWavelengths: 1 | 3;
244
273
  directLightCandidates: number;
274
+ caustics?: import('../Render.js').CausticSettings;
245
275
  }): void;
276
+ private _setCaustics;
246
277
  private _setEnvMap;
247
278
  setMeshes(meshes: Mesh[], update?: {
248
279
  transforms?: readonly Mesh[];