@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.
- package/README.md +3 -0
- package/dist/assets/bvh.worker.js +1 -1
- package/dist/mutracer.umd.js +8949 -7915
- package/docs/api.md +42 -21
- package/docs/caustics.md +80 -0
- package/docs/materials.md +5 -4
- package/docs/progressive-rendering.md +50 -9
- package/docs/technical/continuous-spectrum.md +93 -0
- package/docs/updates.md +3 -1
- package/docs/viewer-checklist.md +65 -0
- package/docs/viewer.md +7 -5
- package/lib/Display.js +1 -1
- package/lib/Display.js.map +1 -1
- package/lib/Engine.d.ts +2 -0
- package/lib/Engine.js +47 -12
- package/lib/Engine.js.map +1 -1
- package/lib/Render.d.ts +61 -13
- package/lib/Render.js +169 -19
- package/lib/Render.js.map +1 -1
- package/lib/RenderLoop.d.ts +7 -3
- package/lib/RenderLoop.js +68 -44
- package/lib/RenderLoop.js.map +1 -1
- package/lib/main.d.ts +1 -1
- package/lib/main.js.map +1 -1
- package/lib/oidn.d.ts +1 -1
- package/lib/oidnBundledWeights.cdn.d.ts +2 -2
- package/lib/renderer/GPUTraceQueue.d.ts +2 -1
- package/lib/renderer/GPUTraceQueue.js +3 -1
- package/lib/renderer/GPUTraceQueue.js.map +1 -1
- package/lib/renderer/RenderingPipeline.d.ts +4 -0
- package/lib/renderer/RenderingPipeline.js.map +1 -1
- package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
- package/lib/renderer/WGPUCausticLightPass.js +217 -0
- package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
- package/lib/renderer/WGPUEnvMapDistribution.js +18 -18
- package/lib/renderer/WGPUFullQuadPass.js +3 -3
- package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
- package/lib/renderer/WGPUPhotonMap.js +191 -0
- package/lib/renderer/WGPUPhotonMap.js.map +1 -0
- package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
- package/lib/renderer/WGPURayTraceOutput.js +122 -28
- package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
- package/lib/renderer/WGPURayTracePass.d.ts +48 -17
- package/lib/renderer/WGPURayTracePass.js +538 -340
- package/lib/renderer/WGPURayTracePass.js.map +1 -1
- package/lib/renderer/WGPURenderingPipeline.js +83 -47
- package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLFullQuadPass.d.ts +2 -1
- package/lib/renderer/WebGLFullQuadPass.js +4 -0
- package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
- package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
- package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
- package/lib/renderer/WebGLRayTracePass.d.ts +6 -1
- package/lib/renderer/WebGLRayTracePass.js +43 -6
- package/lib/renderer/WebGLRayTracePass.js.map +1 -1
- package/lib/renderer/WebGLRenderingPipeline.js +10 -14
- package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLSkyBaker.js +60 -60
- package/lib/renderer/accumulationTarget.d.ts +2 -1
- package/lib/renderer/accumulationTarget.js.map +1 -1
- package/lib/renderer/causticDiagnostics.d.ts +31 -0
- package/lib/renderer/causticDiagnostics.js +5 -0
- package/lib/renderer/causticDiagnostics.js.map +1 -0
- package/lib/renderer/causticEmission.d.ts +10 -0
- package/lib/renderer/causticEmission.js +40 -0
- package/lib/renderer/causticEmission.js.map +1 -0
- package/lib/renderer/causticUniform.d.ts +12 -0
- package/lib/renderer/causticUniform.js +22 -0
- package/lib/renderer/causticUniform.js.map +1 -0
- package/lib/renderer/caustics.d.ts +16 -0
- package/lib/renderer/caustics.js +93 -0
- package/lib/renderer/caustics.js.map +1 -0
- package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
- package/lib/renderer/glsl/aovReflectance.glsl.js +53 -53
- package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
- package/lib/renderer/glsl/aovTrace.frag.js +33 -33
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -9
- package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
- package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -73
- package/lib/renderer/glsl/chunks/intersect.glsl.js +426 -428
- package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +156 -153
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +771 -771
- package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
- package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +68 -63
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js +94 -76
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +140 -117
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +14 -14
- package/lib/renderer/glsl/chunks/sampling.glsl.js +89 -92
- package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
- package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
- package/lib/renderer/glsl/depthQuery.frag.js +2 -2
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
- package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
- package/lib/renderer/glsl/rayTrace.frag.js +260 -237
- package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/shadowCatcher.frag.js +26 -26
- package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
- package/lib/renderer/glsl/webglPipeline.frag.js +59 -59
- package/lib/renderer/lightSampling.d.ts +3 -2
- package/lib/renderer/lightSampling.js +14 -8
- package/lib/renderer/lightSampling.js.map +1 -1
- package/lib/renderer/progressiveScheduler.js +4 -3
- package/lib/renderer/progressiveScheduler.js.map +1 -1
- package/lib/renderer/renderPipeline.d.ts +1 -0
- package/lib/renderer/renderPipeline.js.map +1 -1
- package/lib/renderer/researchTransport.d.ts +31 -0
- package/lib/renderer/researchTransport.js +5 -0
- package/lib/renderer/researchTransport.js.map +1 -0
- package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
- package/lib/renderer/sceneLayoutSchema.js +2 -2
- package/lib/renderer/sceneLayoutSchema.js.map +1 -1
- package/lib/renderer/scratchSampling.js +6 -6
- package/lib/renderer/spectrum.d.ts +21 -0
- package/lib/renderer/spectrum.js +154 -0
- package/lib/renderer/spectrum.js.map +1 -0
- package/lib/renderer/webglLightSampling.d.ts +39 -0
- package/lib/renderer/webglLightSampling.js +15 -0
- package/lib/renderer/webglLightSampling.js.map +1 -0
- package/lib/renderer/wgpuBindlessSource.js +3 -3
- package/lib/renderer/wgpuShaderSource.d.ts +7 -0
- package/lib/renderer/wgpuShaderSource.js +2 -0
- package/lib/renderer/wgpuShaderSource.js.map +1 -1
- package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
- package/lib/renderer/wgsl/aovReflectance.wgsl.js +55 -55
- package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
- package/lib/renderer/wgsl/aovResolve.wgsl.js +2 -2
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js +1 -1
- package/lib/renderer/wgsl/aovTrace.wgsl.js +33 -33
- package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
- package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
- package/lib/renderer/wgsl/causticLight.compute.js +537 -0
- package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
- package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
- package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
- package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
- package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
- package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
- package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js +37 -37
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +598 -592
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +14 -14
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +75 -73
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +794 -794
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +139 -139
- package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +2 -1
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +35 -25
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +142 -138
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +204 -187
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +11 -11
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js +89 -93
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
- package/lib/renderer/wgsl/compose.frag.wgsl.js +98 -98
- package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
- package/lib/renderer/wgsl/depthQuery.wgsl.js +2 -2
- package/lib/renderer/wgsl/jnlm.compute.js +74 -74
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +25 -25
- package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
- package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
- package/lib/renderer/wgsl/photonMap.compute.js +352 -0
- package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
- package/lib/renderer/wgsl/proceduralSky.compute.js +64 -64
- package/lib/renderer/wgsl/rayTrace.compute.d.ts +9 -1
- package/lib/renderer/wgsl/rayTrace.compute.js +448 -522
- package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
- package/lib/scene/MaterialState.d.ts +2 -2
- package/lib/scene/MaterialState.js +2 -2
- package/lib/scene/MaterialState.js.map +1 -1
- package/lib/settings/render.d.ts +11 -0
- package/lib/settings/render.js +1 -0
- package/lib/settings/render.js.map +1 -1
- package/lib/util/fromTHREE.js +2 -2
- package/lib/util/fromTHREE.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/llms.txt +2 -1
- 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
|
-
|
|
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
|
|
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) ->
|
|
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
|
|
38
|
-
let
|
|
39
|
-
((pixel +
|
|
40
|
-
((size - vec2u(1u)) /
|
|
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
|
|
43
|
-
if (normalBuffer[
|
|
44
|
-
idx =
|
|
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:
|
|
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
|
|
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,
|
|
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(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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
|
|
128
|
-
private
|
|
129
|
-
private
|
|
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
|
|
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
|
-
|
|
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):
|
|
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[];
|