@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
|
@@ -7,7 +7,7 @@ function guideBinding(guides, binding, name) {
|
|
|
7
7
|
: `@group(0) @binding(${binding}) var<storage, read> ${name}: array<vec4f>;`;
|
|
8
8
|
}
|
|
9
9
|
function loadGuide(guides, name, position) {
|
|
10
|
-
return guides === 'textures' ? `textureLoad(${name}, ${position}, 0)` : `${name}[
|
|
10
|
+
return guides === 'textures' ? `textureLoad(${name}, ${position}, 0)` : `${name}[gf(${position})]`;
|
|
11
11
|
}
|
|
12
12
|
// Shared uniform packing also fixes sensitivity and dilation for native callers.
|
|
13
13
|
export function packJNLMParameters(width, height, strength, pass) {
|
|
@@ -43,9 +43,9 @@ ${shadowCatcherAccumulationWGSL}
|
|
|
43
43
|
fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
44
44
|
let size = params.size;
|
|
45
45
|
if (id.x >= size.x || id.y >= size.y) { return; }
|
|
46
|
-
let
|
|
47
|
-
let n = normalBuffer[
|
|
48
|
-
let moments = accumulation[
|
|
46
|
+
let qw = id.x + (size.y - 1u - id.y) * size.x;
|
|
47
|
+
let n = normalBuffer[qw].a;
|
|
48
|
+
let moments = accumulation[qw].moments;
|
|
49
49
|
let mean = moments.x / max(n, 1.0);
|
|
50
50
|
|
|
51
51
|
var variance = -1.0;
|
|
@@ -69,28 +69,28 @@ fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
|
69
69
|
let size = params.size;
|
|
70
70
|
if (id.x >= size.x || id.y >= size.y) { return; }
|
|
71
71
|
let center = rawGuide[id.x + id.y * size.x];
|
|
72
|
-
var
|
|
73
|
-
var
|
|
74
|
-
var
|
|
75
|
-
var
|
|
72
|
+
var lM = 0.0;
|
|
73
|
+
var je = 0.0;
|
|
74
|
+
var nM = 0.0;
|
|
75
|
+
var iV = 0.0;
|
|
76
76
|
for (var dy = -1; dy <= 1; dy++) {
|
|
77
77
|
for (var dx = -1; dx <= 1; dx++) {
|
|
78
78
|
let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);
|
|
79
79
|
let value = rawGuide[u32(q.x) + u32(q.y) * size.x];
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
nM += value.x;
|
|
81
|
+
iV += value.x * value.x;
|
|
82
82
|
if (value.y >= 0.0) {
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
lM += value.y;
|
|
84
|
+
je += 1.0;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
var variance: f32;
|
|
89
89
|
if (center.y >= 0.0) {
|
|
90
|
-
variance =
|
|
90
|
+
variance = lM / je;
|
|
91
91
|
} else {
|
|
92
|
-
let
|
|
93
|
-
variance = max(
|
|
92
|
+
let lL = nM / 9.0;
|
|
93
|
+
variance = max(iV / 9.0 - lL * lL, 0.0) * 9.0 / 8.0;
|
|
94
94
|
}
|
|
95
95
|
guide[id.x + id.y * size.x] = vec2f(center.x, variance);
|
|
96
96
|
}
|
|
@@ -114,11 +114,11 @@ fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
|
114
114
|
if (id.x >= params.size.x || id.y >= params.size.y) { return; }
|
|
115
115
|
outColor[id.x + id.y * params.size.x] = textureLoad(colorTex, vec2i(id.xy), 0);
|
|
116
116
|
${guides === 'buffers' ? ` let index = id.x + id.y * params.size.x;
|
|
117
|
-
let
|
|
118
|
-
let n = normalAccumulation[
|
|
117
|
+
let qw = id.x + (params.size.y - 1u - id.y) * params.size.x;
|
|
118
|
+
let n = normalAccumulation[qw];
|
|
119
119
|
let samples = max(n.a, 1.0);
|
|
120
120
|
normal[index] = vec4f(n.rgb / samples * 0.5 + 0.5, select(0.0, 1.0, dot(n.rgb, n.rgb) > 0.1));
|
|
121
|
-
shadow[index] = shadowAccumulation[
|
|
121
|
+
shadow[index] = shadowAccumulation[qw].mask / samples;
|
|
122
122
|
albedo[index] = textureLoad(albedoTex, vec2i(id.xy), 0);` : ''}
|
|
123
123
|
}
|
|
124
124
|
`;
|
|
@@ -155,23 +155,23 @@ const INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};
|
|
|
155
155
|
|
|
156
156
|
const CENTER_WEIGHT_MIN = 0.01;
|
|
157
157
|
|
|
158
|
-
fn
|
|
158
|
+
fn gf(p: vec2i) -> u32 {
|
|
159
159
|
let q = clamp(p, vec2i(0), vec2i(params.size) - 1);
|
|
160
160
|
return u32(q.x) + u32(q.y) * params.size.x;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
fn
|
|
163
|
+
fn lP(q: vec2i, bo: vec4f, gO: vec3f) -> f32 {
|
|
164
164
|
let albedo = ${loadGuide(guides, 'albedoTex', 'q')};
|
|
165
165
|
|
|
166
166
|
|
|
167
|
-
let
|
|
168
|
-
let
|
|
169
|
-
let
|
|
170
|
-
let
|
|
167
|
+
let pY = max((albedo.rgb + bo.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
168
|
+
let lu = (albedo.rgb - bo.rgb) / pY;
|
|
169
|
+
let iQ = albedo.a - bo.a;
|
|
170
|
+
let lG = ${loadGuide(guides, 'normalTex', 'q')}.rgb - gO;
|
|
171
171
|
return max(
|
|
172
|
-
dot(
|
|
173
|
-
+
|
|
174
|
-
dot(
|
|
172
|
+
dot(lu, lu) * INV_ALBEDO_BANDWIDTH2
|
|
173
|
+
+ iQ * iQ * INV_COVERAGE_BANDWIDTH2,
|
|
174
|
+
dot(lG, lG) * INV_NORMAL_BANDWIDTH2
|
|
175
175
|
);
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -185,37 +185,37 @@ let size = vec2i(params.size);
|
|
|
185
185
|
let p = vec2i(id.xy);
|
|
186
186
|
if (p.x >= size.x || p.y >= size.y) { return; }
|
|
187
187
|
let step = i32(params.dilation);
|
|
188
|
-
let
|
|
189
|
-
let
|
|
190
|
-
let
|
|
191
|
-
let index =
|
|
188
|
+
let bo = ${loadGuide(guides, 'albedoTex', 'p')};
|
|
189
|
+
let fC = ${loadGuide(guides, 'normalTex', 'p')};
|
|
190
|
+
let gO = fC.rgb;
|
|
191
|
+
let index = gf(p);
|
|
192
192
|
|
|
193
193
|
|
|
194
|
-
if (
|
|
194
|
+
if (fC.a <= 0.0 && ${loadGuide(guides, 'shadowCatcherTex', 'p')}.r <= 0.0) {
|
|
195
195
|
outColor[index] = color[index];
|
|
196
196
|
outGuide[index] = guide[index];
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
var
|
|
200
|
+
var lA: array<vec2f, PATCH_SIZE>;
|
|
201
201
|
var k = 0;
|
|
202
202
|
for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
|
|
203
203
|
for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
|
|
204
|
-
|
|
204
|
+
lA[k] = guide[gf(p + vec2i(dx, dy) * step)];
|
|
205
205
|
k++;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
let k2 = params.colorSensitivity * params.colorSensitivity;
|
|
209
209
|
|
|
210
210
|
var sum = vec4f(0.0);
|
|
211
|
-
let
|
|
212
|
-
var
|
|
213
|
-
var
|
|
214
|
-
var
|
|
215
|
-
var
|
|
216
|
-
var
|
|
217
|
-
var
|
|
218
|
-
var
|
|
211
|
+
let gR = max(bo.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
212
|
+
var mQ = vec3f(0.0);
|
|
213
|
+
var gv = vec3f(0.0);
|
|
214
|
+
var hm = vec3f(0.0);
|
|
215
|
+
var qf = 0.0;
|
|
216
|
+
var gx = 0.0;
|
|
217
|
+
var oE = 0.0;
|
|
218
|
+
var kX = 0.0;
|
|
219
219
|
for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {
|
|
220
220
|
for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {
|
|
221
221
|
let q = p + vec2i(sx, sy) * step;
|
|
@@ -224,63 +224,63 @@ if (
|
|
|
224
224
|
q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y
|
|
225
225
|
) { continue; }
|
|
226
226
|
|
|
227
|
-
let features =
|
|
227
|
+
let features = lP(q, bo, gO);
|
|
228
228
|
if (features > 16.0) { continue; }
|
|
229
229
|
|
|
230
|
-
var
|
|
230
|
+
var fW = 0.0;
|
|
231
231
|
k = 0;
|
|
232
232
|
for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
|
|
233
233
|
for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
|
|
234
|
-
let a =
|
|
235
|
-
let b = guide[
|
|
236
|
-
let
|
|
237
|
-
|
|
234
|
+
let a = lA[k];
|
|
235
|
+
let b = guide[gf(q + vec2i(dx, dy) * step)];
|
|
236
|
+
let rV = a.x - b.x;
|
|
237
|
+
fW += (rV * rV
|
|
238
238
|
- VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))
|
|
239
239
|
/ (1e-10 + k2 * (a.y + b.y));
|
|
240
240
|
k++;
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
|
-
|
|
243
|
+
fW /= f32(PATCH_SIZE);
|
|
244
244
|
|
|
245
|
-
let weight = exp(-max(max(
|
|
246
|
-
let index =
|
|
245
|
+
let weight = exp(-max(max(fW, 0.0), features));
|
|
246
|
+
let index = gf(q);
|
|
247
247
|
let c = color[index];
|
|
248
248
|
let g = guide[index];
|
|
249
249
|
|
|
250
|
-
let a = (${loadGuide(guides, 'albedoTex', 'q')}.rgb -
|
|
250
|
+
let a = (${loadGuide(guides, 'albedoTex', 'q')}.rgb - bo.rgb) / gR;
|
|
251
251
|
let value = premultiplied(c);
|
|
252
252
|
sum += value * weight;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
253
|
+
mQ += a * weight;
|
|
254
|
+
gv += a * a * weight;
|
|
255
|
+
hm += a * value.rgb * weight;
|
|
256
|
+
qf += g.x * weight;
|
|
257
|
+
gx += g.y * weight * weight;
|
|
258
|
+
oE += weight;
|
|
259
|
+
kX = max(kX, weight);
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
|
|
264
264
|
|
|
265
265
|
let center = color[index];
|
|
266
|
-
let
|
|
267
|
-
let
|
|
268
|
-
let totalWeight =
|
|
269
|
-
let
|
|
270
|
-
let mean = (sum +
|
|
266
|
+
let lw = guide[index];
|
|
267
|
+
let dE = max(kX, CENTER_WEIGHT_MIN);
|
|
268
|
+
let totalWeight = oE + dE;
|
|
269
|
+
let vs = premultiplied(center);
|
|
270
|
+
let mean = (sum + vs * dE) / totalWeight;
|
|
271
271
|
|
|
272
272
|
|
|
273
|
-
let
|
|
274
|
-
let
|
|
275
|
-
let
|
|
273
|
+
let er = mQ / totalWeight;
|
|
274
|
+
let lQ = max(gv / totalWeight - er * er, vec3f(0.0));
|
|
275
|
+
let rq = hm / totalWeight - er * mean.rgb;
|
|
276
276
|
|
|
277
277
|
|
|
278
278
|
|
|
279
|
-
let
|
|
280
|
-
let
|
|
281
|
-
let
|
|
282
|
-
let
|
|
283
|
-
let filtered = vec4f(max(
|
|
279
|
+
let rD = bo.rgb + er * gR;
|
|
280
|
+
let pd = mean.rgb * gR / max(rD, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
281
|
+
let xI = clamp(rq / (lQ + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), pd);
|
|
282
|
+
let sz = mean.rgb - xI * er;
|
|
283
|
+
let filtered = vec4f(max(sz, vec3f(0.0)), max(mean.a, 0.0));
|
|
284
284
|
let rgb = select(
|
|
285
285
|
center.rgb,
|
|
286
286
|
filtered.rgb / max(filtered.a, 1e-6),
|
|
@@ -288,8 +288,8 @@ filtered.a > 1e-6
|
|
|
288
288
|
);
|
|
289
289
|
outColor[index] = vec4f(rgb, filtered.a);
|
|
290
290
|
outGuide[index] = vec2f(
|
|
291
|
-
(
|
|
292
|
-
(
|
|
291
|
+
(qf + lw.x * dE) / totalWeight,
|
|
292
|
+
(gx + lw.y * dE * dE)
|
|
293
293
|
/ (totalWeight * totalWeight)
|
|
294
294
|
);
|
|
295
295
|
}
|
|
@@ -27,8 +27,8 @@ _padding: f32,
|
|
|
27
27
|
const LUMINANCE = vec3f(0.2126, 0.7152, 0.0722);
|
|
28
28
|
|
|
29
29
|
@compute @workgroup_size(64)
|
|
30
|
-
fn main(@builtin(global_invocation_id)
|
|
31
|
-
let tile =
|
|
30
|
+
fn main(@builtin(global_invocation_id) eA: vec3u) {
|
|
31
|
+
let tile = eA.x;
|
|
32
32
|
let tileCount = params.columns * params.rows;
|
|
33
33
|
if (tile >= tileCount) {
|
|
34
34
|
return;
|
|
@@ -36,16 +36,16 @@ return;
|
|
|
36
36
|
|
|
37
37
|
let tileX = tile % params.columns;
|
|
38
38
|
let tileY = tile / params.columns;
|
|
39
|
-
let
|
|
40
|
-
let
|
|
41
|
-
let
|
|
42
|
-
let
|
|
43
|
-
var
|
|
44
|
-
var
|
|
39
|
+
let ws = tileX * params.tileSize;
|
|
40
|
+
let wt = tileY * params.tileSize;
|
|
41
|
+
let yF = min(ws + params.tileSize, params.width);
|
|
42
|
+
let yG = min(wt + params.tileSize, params.height);
|
|
43
|
+
var nM = 0.0;
|
|
44
|
+
var jh = 0.0;
|
|
45
45
|
var count = 0u;
|
|
46
46
|
|
|
47
|
-
for (var y =
|
|
48
|
-
for (var x =
|
|
47
|
+
for (var y = wt; y < yG; y++) {
|
|
48
|
+
for (var x = ws; x < yF; x++) {
|
|
49
49
|
let pixel = y * params.width + x;
|
|
50
50
|
let offset = pixel * 4u;
|
|
51
51
|
let samples = pilotMoments[offset + 3u];
|
|
@@ -60,28 +60,28 @@ pilotColor[offset + 2u]
|
|
|
60
60
|
),
|
|
61
61
|
LUMINANCE
|
|
62
62
|
) / samples;
|
|
63
|
-
let
|
|
64
|
-
let
|
|
65
|
-
var variance =
|
|
63
|
+
let vj = pilotMoments[offset] / samples;
|
|
64
|
+
let qb = max(vj - mean * mean, 0.0);
|
|
65
|
+
var variance = qb;
|
|
66
66
|
if (samples > 1.0) {
|
|
67
|
-
variance =
|
|
67
|
+
variance = qb * samples / (samples - 1.0);
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
nM += mean;
|
|
70
|
+
jh = max(jh, variance);
|
|
71
71
|
count += 1u;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
let mean =
|
|
76
|
-
var
|
|
75
|
+
let mean = nM / f32(max(count, 1u));
|
|
76
|
+
var pK = 0.0;
|
|
77
77
|
if (params.hasPrevious != 0u) {
|
|
78
|
-
|
|
78
|
+
pK = previousVariance[tile];
|
|
79
79
|
}
|
|
80
|
-
let tu = max(
|
|
81
|
-
let
|
|
80
|
+
let tu = max(jh, pK);
|
|
81
|
+
let uH = params.absoluteError + params.relativeError * abs(mean);
|
|
82
82
|
let required = ceil(
|
|
83
83
|
params.confidence * params.confidence * tu /
|
|
84
|
-
max(
|
|
84
|
+
max(uH * uH, 1e-16)
|
|
85
85
|
);
|
|
86
86
|
let targetSamples = u32(min(
|
|
87
87
|
f32(params.maxSamples),
|
|
@@ -91,11 +91,11 @@ max(f32(params.minSamples), required)
|
|
|
91
91
|
tileMeans[tile] = mean;
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
tileVariances[tile] =
|
|
94
|
+
tileVariances[tile] = jh;
|
|
95
95
|
tileTargets[tile] = targetSamples;
|
|
96
96
|
|
|
97
|
-
for (var y =
|
|
98
|
-
for (var x =
|
|
97
|
+
for (var y = wt; y < yG; y++) {
|
|
98
|
+
for (var x = ws; x < yF; x++) {
|
|
99
99
|
textureStore(
|
|
100
100
|
targetTexture,
|
|
101
101
|
vec2i(i32(x), i32(y)),
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// OIDN's LDR auxiliary networks use sRGB albedo and normals in [0,1].
|
|
2
2
|
export const oidnAuxiliaryDefine = /* wgsl */ `
|
|
3
|
-
fn
|
|
3
|
+
fn sQ(value: vec3f) -> vec3f {
|
|
4
4
|
let linear = clamp(value, vec3f(0.0), vec3f(1.0));
|
|
5
5
|
return select(1.055 * pow(linear, vec3f(1.0 / 2.4)) - 0.055,
|
|
6
6
|
12.92 * linear, linear <= vec3f(0.0031308));
|
|
7
7
|
}
|
|
8
|
-
fn
|
|
8
|
+
fn sP(value: vec3f) -> vec3f {
|
|
9
9
|
let encoded = clamp(value, vec3f(0.0), vec3f(1.0));
|
|
10
10
|
return select(pow((encoded + 0.055) / 1.055, vec3f(2.4)),
|
|
11
11
|
encoded / 12.92, encoded <= vec3f(0.04045));
|
|
12
12
|
}
|
|
13
|
-
fn
|
|
13
|
+
fn rG(value: vec3f) -> vec3f {
|
|
14
14
|
return clamp(value, vec3f(0.0), vec3f(1.0));
|
|
15
15
|
}
|
|
16
16
|
`;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const PHOTON_BYTES = 20;
|
|
2
|
+
export declare const PHOTON_GRID_SIZE = 262144;
|
|
3
|
+
export declare const PHOTON_SCAN_BLOCK = 256;
|
|
4
|
+
export declare const PHOTON_REFERENCE_COUNT: number;
|
|
5
|
+
export type PhotonRadiusScaling = 'none' | 'ppm' | 'constant-count';
|
|
6
|
+
/** Internal density A/B, with the same progressive schedule in all modes. */
|
|
7
|
+
export declare function photonRadius(initial: number, batch: number, alpha?: number, photons?: number, scaling?: PhotonRadiusScaling): number;
|
|
8
|
+
/** Default photon-map batch: pixel count / 4, capped at 2^18. */
|
|
9
|
+
export declare function defaultPhotonMapPhotons(width: number, height: number, divisor?: number): number;
|
|
10
|
+
/** Power-of-two hash capacity, bounded independently of large photon batches. */
|
|
11
|
+
export declare function photonBucketCount(photons: number): number;
|
|
12
|
+
/** Shared texture address contract; payload is stored once, indices twice. */
|
|
13
|
+
export declare function photonLayout(count: number, perCasterRadius?: boolean): {
|
|
14
|
+
buckets: number;
|
|
15
|
+
coarseHeaders: number;
|
|
16
|
+
fineHeaders: number;
|
|
17
|
+
coarseIndices: number;
|
|
18
|
+
fineIndices: number;
|
|
19
|
+
directions: number;
|
|
20
|
+
texels: number;
|
|
21
|
+
};
|
|
22
|
+
/** Batch-local hash buckets: count, two-level parallel prefix sum, then parallel scatter. */
|
|
23
|
+
export declare const photonGridCompute = "\n struct Bucket {\n count: atomic<u32>,\n offset: u32,\n cursor: atomic<u32>,\n padding: u32,\n }\n struct Parameters {\n radius: f32,\n count: u32,\n screenPixels: f32,\n skipQuery: f32,\n buckets: u32,\n fineRadius: f32,\n experiments: u32,\n padding2: u32,\n }\n @group(0)@binding(0)var photons:texture_2d<u32>;\n @group(0)@binding(1)var<storage,read_write>grid:array<Bucket>;\n @group(0)@binding(2)var<uniform>parameters:Parameters;\n @group(0)@binding(4)var headers:texture_storage_2d<r32uint,write>;\n fn hashCell(cell:vec3i)->u32 {\n let p=bitcast<vec3u>(cell);\n return ((p.x*73856093u)^(p.y*19349663u)^(p.z*83492791u))&(parameters.buckets-1u);\n }\n fn hashPhoton(p:vec3f,layer:u32)->u32 {\n let radius=select(parameters.radius,parameters.fineRadius,layer==1u);\n let cellSize=select(radius,2.0*radius,layer==1u);\n return hashCell(vec3i(floor(p/cellSize)));\n }\n fn gridStart(layer:u32)->u32 {\n return layer*(parameters.buckets+parameters.buckets/256u);\n }\n fn storeIndex(i:u32,value:u32) {\n let width=textureDimensions(headers).x;\n textureStore(headers,vec2i(vec2u(i%width,i/width)),vec4u(value));\n }\n fn photonRecord(i:u32)->vec4u {\n let width=textureDimensions(photons).x;\n return textureLoad(photons,vec2i(vec2u(i%width,i/width)),0);\n }\n fn photonPosition(i:u32)->vec3f {\n return bitcast<vec3f>(photonRecord(i).xyz);\n }\n @compute @workgroup_size(64)\n fn count(@builtin(global_invocation_id)id:vec3u) {\n if(id.x+id.y*4194240u>=parameters.count) {\n return;\n }\n let index=id.x+id.y*4194240u;\n if(photonRecord(index).w==0u) {\n return;\n }\n for(var layer=0u;layer<2u;layer++) {\n atomicAdd(&grid[gridStart(layer)+hashPhoton(photonPosition(index),layer)].count,1u);\n }\n }\n // Each block scans 256 buckets; the next workgroup scans chunks of block totals.\n var<workgroup> scan:array<u32,256>;\n fn inclusiveScan(local:u32,value:u32)->u32 {\n scan[local]=value;\n workgroupBarrier();\n for(var stride=1u;stride<256u;stride*=2u) {\n var previous=0u;\n if(local>=stride) {\n previous=scan[local-stride];\n }\n workgroupBarrier();\n scan[local]+=previous;\n workgroupBarrier();\n }\n return scan[local];\n }\n @compute @workgroup_size(256)\n fn scanBlocks(@builtin(local_invocation_index)local:u32,@builtin(workgroup_id)group:vec3u) {\n let index=gridStart(group.y)+group.x*256u+local;\n let count=atomicLoad(&grid[index].count);\n let prefix=inclusiveScan(local,count);\n grid[index].offset=prefix-count;\n if(local==255u) {\n atomicStore(&grid[gridStart(group.y)+parameters.buckets+group.x].count,prefix);\n }\n }\n @compute @workgroup_size(256)\n fn scanSums(@builtin(local_invocation_index)local:u32,@builtin(workgroup_id)group:vec3u) {\n let blocks=parameters.buckets/256u;\n let chunk=(blocks+255u)/256u;\n let first=local*chunk;\n let start=gridStart(group.y)+parameters.buckets;\n var count=0u;\n for(var i=first;i<min(first+chunk,blocks);i++) {\n count+=atomicLoad(&grid[start+i].count);\n }\n let prefix=inclusiveScan(local,count);\n var offset=prefix-count;\n for(var i=first;i<min(first+chunk,blocks);i++) {\n grid[start+i].offset=offset;\n offset+=atomicLoad(&grid[start+i].count);\n }\n if(local==255u&&group.y==0u) {\n storeIndex(0u,bitcast<u32>(parameters.radius));\n storeIndex(1u,prefix);\n storeIndex(2u,bitcast<u32>(parameters.screenPixels));\n storeIndex(3u,bitcast<u32>(parameters.skipQuery));\n storeIndex(4u,parameters.count);\n storeIndex(5u,parameters.buckets);\n storeIndex(6u,bitcast<u32>(parameters.fineRadius));\n storeIndex(7u,parameters.experiments);\n }\n }\n @compute @workgroup_size(64)\n fn scatter(@builtin(global_invocation_id)id:vec3u) {\n let invocation=id.x+id.y*4194240u;\n for(var layer=0u;layer<2u;layer++) {\n let start=gridStart(layer);\n if(invocation<parameters.buckets) {\n let offset=grid[start+invocation].offset+grid[start+parameters.buckets+invocation/256u].offset;\n storeIndex(8u+layer*parameters.buckets*2u+invocation*2u,offset);\n storeIndex(9u+layer*parameters.buckets*2u+invocation*2u,atomicLoad(&grid[start+invocation].count));\n }\n if(invocation<parameters.count&&photonRecord(invocation).w!=0u) {\n let bucket=hashPhoton(photonPosition(invocation),layer);\n let index=grid[start+bucket].offset+grid[start+parameters.buckets+bucket/256u].offset+atomicAdd(&grid[start+bucket].cursor,1u);\n storeIndex(8u+parameters.buckets*4u+layer*parameters.count+index,invocation);\n }\n }\n }\n";
|
|
24
|
+
/** Packed photon payload: position f32 x3, RGBE8 flux, two octahedral directions. */
|
|
25
|
+
export declare const photonPackingWgsl = "\n fn photonOctSign(v:vec2f)->vec2f {\n return select(vec2f(-1.0),vec2f(1.0),v>=vec2f(0.0));\n }\n fn photonEncodeOct(n:vec3f)->vec2f {\n let p=n/(abs(n.x)+abs(n.y)+abs(n.z));\n let uv=select(p.xy,(vec2f(1.0)-abs(p.yx))*photonOctSign(p.xy),p.z<0.0);\n return uv*.5+.5;\n }\n fn photonDecodeOct(uv:vec2f)->vec3f {\n let p=uv*2.0-1.0;\n var n=vec3f(p,1.0-abs(p.x)-abs(p.y));\n if(n.z<0.0) {\n n=vec3f((vec2f(1.0)-abs(n.yx))*photonOctSign(n.xy),n.z);\n }\n return normalize(n);\n }\n // An eight-bit exponent avoids RGB9E5's limited range for very dim/bright lights.\n // Flux is stored before dividing by emitted count, preserving tiny large batches.\n fn photonEncodeFlux(value:vec3f)->u32 {\n let peak=max(max(value.x,value.y),value.z);\n if(!(peak>0.0)) {\n return 0u;\n }\n let exponent=clamp(i32(floor(log2(peak)))+1,-126,127);\n let rgb=vec3u(clamp(round(value*exp2(-f32(exponent))*255.0),vec3f(0.0),vec3f(255.0)));\n return rgb.x|(rgb.y<<8u)|(rgb.z<<16u)|(u32(exponent+127)<<24u);\n }\n fn photonDecodeFlux(value:u32)->vec3f {\n if(value==0u) {\n return vec3f(0.0);\n }\n return vec3f(f32(value&255u),f32((value>>8u)&255u),f32((value>>16u)&255u))*exp2(f32(i32(value>>24u)-127))/255.0;\n }\n";
|
|
26
|
+
export declare const photonQueryWgsl = "\n fn photonOctSign(v:vec2f)->vec2f {\n return select(vec2f(-1.0),vec2f(1.0),v>=vec2f(0.0));\n }\n fn photonEncodeOct(n:vec3f)->vec2f {\n let p=n/(abs(n.x)+abs(n.y)+abs(n.z));\n let uv=select(p.xy,(vec2f(1.0)-abs(p.yx))*photonOctSign(p.xy),p.z<0.0);\n return uv*.5+.5;\n }\n fn photonDecodeOct(uv:vec2f)->vec3f {\n let p=uv*2.0-1.0;\n var n=vec3f(p,1.0-abs(p.x)-abs(p.y));\n if(n.z<0.0) {\n n=vec3f((vec2f(1.0)-abs(n.yx))*photonOctSign(n.xy),n.z);\n }\n return normalize(n);\n }\n // An eight-bit exponent avoids RGB9E5's limited range for very dim/bright lights.\n // Flux is stored before dividing by emitted count, preserving tiny large batches.\n fn photonEncodeFlux(value:vec3f)->u32 {\n let peak=max(max(value.x,value.y),value.z);\n if(!(peak>0.0)) {\n return 0u;\n }\n let exponent=clamp(i32(floor(log2(peak)))+1,-126,127);\n let rgb=vec3u(clamp(round(value*exp2(-f32(exponent))*255.0),vec3f(0.0),vec3f(255.0)));\n return rgb.x|(rgb.y<<8u)|(rgb.z<<16u)|(u32(exponent+127)<<24u);\n }\n fn photonDecodeFlux(value:u32)->vec3f {\n if(value==0u) {\n return vec3f(0.0);\n }\n return vec3f(f32(value&255u),f32((value>>8u)&255u),f32((value>>16u)&255u))*exp2(f32(i32(value>>24u)-127))/255.0;\n }\n\n @group(1)@binding(11)var photonMapData:texture_2d<u32>;\n @group(1)@binding(12)var photonMapGrid:texture_2d<u32>;\n fn photonLoad(i:u32)->vec4u {\n let width=textureDimensions(photonMapData).x;\n return textureLoad(photonMapData,vec2i(vec2u(i%width,i/width)),0);\n }\n fn photonIndexWord(i:u32)->u32 {\n let width=textureDimensions(photonMapGrid).x;\n return textureLoad(photonMapGrid,vec2i(vec2u(i%width,i/width)),0).x;\n }\n fn photonHash(cell:vec3i)->u32 {\n let p=bitcast<vec3u>(cell);\n return ((p.x*73856093u)^(p.y*19349663u)^(p.z*83492791u))&(photonIndexWord(5u)-1u);\n }\n // Approximate a specular prefix by the camera-space depth of its first diffuse\n // receiver. Orthographic footprints do not grow with distance. Grazing surfaces\n // expand the disk conservatively; the progressive world radius remains the cap.\n fn photonPixelFootprint(si:SurfaceInteraction)->f32 {\n let inverse=cameraUniform.viewProjectionInv;\n let a=inverse*vec4f(0.0,0.0,-1.0,1.0);\n let b=inverse*vec4f(2.0/rtUniform.outputSize.x,0.0,-1.0,1.0);\n let origin=a.xyz/a.w;\n let offset=b.xyz/b.w;\n let eye=cameraUniform.viewInv[3].xyz;\n let forward=normalize(cameraUniform.viewInv[2].xyz);\n let depth=abs(dot(si.position-eye,forward));\n let nearDepth=max(abs(dot(origin-eye,forward)),1e-8);\n let perspective=abs(inverse[2].w)>1e-8;\n let footprint=length(offset-origin)*select(1.0,depth/nearDepth,perspective);\n let cosine=abs(dot(si.faceNormal,normalize(si.position-eye)));\n return max(1e-8,footprint/sqrt(max(.0625,cosine)));\n }\n fn photonContribution(si:SurfaceInteraction,prepared:OpenPbrPreparedBsdf,primary:bool,visible:bool)->vec3f {\n if(samplingBounce>CAUSTIC_PHOTON_MAX_DEPTH||isCausticSpecular(prepared.material)||prepared.material.materialType==SHADOW_CATCHER) {\n return vec3f(0.0);\n }\n if(CAUSTIC_LIGHT_TRACING&&primary) {\n return vec3f(0.0);\n }\n let globalRadius=bitcast<f32>(photonIndexWord(0u));\n let screenPixels=bitcast<f32>(photonIndexWord(2u));\n if(!(globalRadius>0.0)||bitcast<f32>(photonIndexWord(3u))==1.0||(bitcast<f32>(photonIndexWord(3u))==2.0&&visible)) {\n return vec3f(0.0);\n }\n var radius=globalRadius;\n let experiments=photonIndexWord(7u);\n let deepPixels=f32(experiments>>8u);\n let queryPixels=select(deepPixels,screenPixels,visible);\n if(queryPixels>0.0) {\n radius=min(radius,photonPixelFootprint(si)*queryPixels);\n }\n let layer=select(0u,1u,visible&&screenPixels>0.0);\n let cellSize=select(globalRadius,2.0*bitcast<f32>(photonIndexWord(6u)),layer==1u);\n let firstCell=vec3i(floor((si.position-vec3f(radius))/cellSize));\n let lastCell=vec3i(floor((si.position+vec3f(radius))/cellSize));\n let buckets=photonIndexWord(5u);\n let headerStart=8u+layer*buckets*2u;\n let indexStart=8u+buckets*4u+layer*photonIndexWord(4u);\n let emitted=f32(photonIndexWord(4u));\n var sum=vec3f(0.0);\n for(var z=firstCell.z;z<=lastCell.z;z++) {\n for(var y=firstCell.y;y<=lastCell.y;y++) {\n for(var x=firstCell.x;x<=lastCell.x;x++) {\n let queryCell=vec3i(x,y,z);\n // Reject cube corners before loading their photon lists. Padding keeps\n // the bound conservative when cell multiplication rounds in f32.\n let cellMin=vec3f(queryCell)*cellSize;\n let padding=max(vec3f(cellSize*1e-5),abs(cellMin)*1e-6);\n let closest=clamp(si.position,cellMin-padding,cellMin+vec3f(cellSize)+padding);\n if(distance(closest,si.position)>=radius) { continue; }\n let bucket=photonHash(queryCell);\n let offset=photonIndexWord(headerStart+bucket*2u);\n let count=photonIndexWord(headerStart+1u+bucket*2u);\n for(var i=offset;i<offset+count;i++) {\n let index=photonIndexWord(indexStart+i);\n let record=photonLoad(index);\n let position=bitcast<vec3f>(record.xyz);\n // Hash collisions and neighboring buckets never count a photon twice.\n if(any(vec3i(floor(position/cellSize))!=queryCell)||distance(position,si.position)>=radius) {\n continue;\n }\n var kernelRadius=radius;\n if((experiments&1u)!=0u) {\n let scale=bitcast<f32>(photonIndexWord(8u+buckets*4u+u32(emitted)*3u+index));\n kernelRadius=min(radius,globalRadius*scale);\n if(!(kernelRadius>0.0)||distance(position,si.position)>=kernelRadius) { continue; }\n }\n let directions=photonIndexWord(8u+buckets*4u+u32(emitted)*2u+index);\n let normal=photonDecodeOct(vec2f(f32(directions&255u)/255.0,f32((directions>>8u)&127u)/127.0));\n if(dot(normal,si.faceNormal)<0.9) {\n continue;\n }\n if(CAUSTIC_MNEE&&samplingBounce<=CAUSTIC_MNEE_MAX_DEPTH&&(directions&32768u)!=0u&&prepared.material.baseWeight*(1.0-prepared.material.baseMetalness)*(1.0-prepared.material.transmissionWeight)>0.0&&prepared.material.subsurfaceWeight==0.0) {\n continue;\n }\n let incoming=photonDecodeOct(vec2f(f32((directions>>16u)&255u),f32(directions>>24u))/255.0);\n let cosine=abs(dot(si.faceNormal,incoming));\n if(cosine<=0.0) {\n continue;\n }\n var flux=photonDecodeFlux(record.w)/emitted;\n if(SPECTRAL) {\n flux=sampling_spectral_rgb_filter(flux,si.spectralChannel);\n }\n var pdf:f32;\n let response=openpbr_eval_prepared(prepared,incoming,&pdf);\n sum+=response*flux/cosine*(radius*radius)/(kernelRadius*kernelRadius);\n }\n }\n }\n }\n return sum/(PI*radius*radius);\n }\n";
|
|
27
|
+
export declare function photonDirectQuerySource(enabled?: boolean): string;
|
|
28
|
+
/** Evidence-only per-query counters; no extra bindings or public render options. */
|
|
29
|
+
export declare function photonQuerySource(debugGroup?: number, directSubset?: boolean): string;
|