@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
|
@@ -3,7 +3,6 @@ import { oidnAuxiliaryDefine } from './wgsl/oidnAuxiliary.wgsl.js';
|
|
|
3
3
|
import { displayAovKind, DEFAULT_AOV_DISPLAY } from './aovDisplay.js';
|
|
4
4
|
import { WGPUAov } from './WGPUAov.js';
|
|
5
5
|
import { aovMask } from './aov.js';
|
|
6
|
-
import { scheduleFrame } from '../util/frame.js';
|
|
7
6
|
import { DisplayPostProcess } from './DisplayPostProcess.js';
|
|
8
7
|
import { customDenoiseLayersMain, customDenoiseCoverageMain } from './wgsl/customDenoise.wgsl.js';
|
|
9
8
|
import { WGPUCanvasSurface } from './WGPUCanvasSurface.js';
|
|
@@ -28,16 +27,16 @@ export const oidnAlbedoSrgbEncodeMain = /* wgsl */ `
|
|
|
28
27
|
if (globalId.x >= u32(imageSize.x) || globalId.y >= u32(imageSize.y)) { return; }
|
|
29
28
|
let index = globalId.x + globalId.y * u32(imageSize.x);
|
|
30
29
|
let raw = textureLoad(in_albedo, vec2u(globalId.xy), 0);
|
|
31
|
-
let encoded =
|
|
30
|
+
let encoded = sQ(raw.rgb);
|
|
32
31
|
out_albedo[index] = vec4f(encoded, raw.a);
|
|
33
32
|
`;
|
|
34
33
|
export const oidnAlbedoSrgbDecodeMain = /* wgsl */ `
|
|
35
34
|
if (globalId.x >= u32(imageSize.x) || globalId.y >= u32(imageSize.y)) { return; }
|
|
36
35
|
let index = globalId.x + globalId.y * u32(imageSize.x);
|
|
37
36
|
let filtered = in_albedo[index];
|
|
38
|
-
let linear =
|
|
37
|
+
let linear = sP(filtered.rgb);
|
|
39
38
|
var result = linear;
|
|
40
|
-
let
|
|
39
|
+
let jj = textureLoad(in_rawAlbedo, vec2i(globalId.xy), 0).a;
|
|
41
40
|
if (preserveSurfaceTexture != 0u) {
|
|
42
41
|
|
|
43
42
|
|
|
@@ -45,33 +44,33 @@ if (preserveSurfaceTexture != 0u) {
|
|
|
45
44
|
let pixel = vec2i(globalId.xy);
|
|
46
45
|
let center = textureLoad(in_rawNormal, pixel, 0);
|
|
47
46
|
let n = normalize(center.rgb * 2.0 - 1.0 + vec3f(1e-8));
|
|
48
|
-
var
|
|
47
|
+
var nS = 0.0;
|
|
49
48
|
for (var y = -1; y <= 1; y++) {
|
|
50
49
|
for (var x = -1; x <= 1; x++) {
|
|
51
|
-
let
|
|
50
|
+
let vI = textureLoad(in_rawNormal,
|
|
52
51
|
clamp(pixel + vec2i(x, y), vec2i(0), imageSize - 1), 0);
|
|
53
|
-
let nn = normalize(
|
|
54
|
-
|
|
55
|
-
max(1.0 - dot(n, nn), abs(center.a -
|
|
52
|
+
let nn = normalize(vI.rgb * 2.0 - 1.0 + vec3f(1e-8));
|
|
53
|
+
nS = max(nS,
|
|
54
|
+
max(1.0 - dot(n, nn), abs(center.a - vI.a)));
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
|
-
let
|
|
57
|
+
let wc = smoothstep(0.02, 0.1, nS);
|
|
59
58
|
let raw = clamp(textureLoad(in_rawAlbedo, pixel, 0).rgb,
|
|
60
59
|
vec3f(0.0), vec3f(1.0));
|
|
61
|
-
result = mix(raw, linear,
|
|
60
|
+
result = mix(raw, linear, wc);
|
|
62
61
|
}
|
|
63
|
-
out_albedo[index] = vec4f(result,
|
|
62
|
+
out_albedo[index] = vec4f(result, jj);
|
|
64
63
|
`;
|
|
65
64
|
export const oidnNormalSanitizeMain = /* wgsl */ `
|
|
66
65
|
if (globalId.x >= u32(imageSize.x) || globalId.y >= u32(imageSize.y)) { return; }
|
|
67
66
|
let index = globalId.x + globalId.y * u32(imageSize.x);
|
|
68
|
-
out_normal[index] = vec4f(
|
|
67
|
+
out_normal[index] = vec4f(rG(in_normal[index].rgb), 1.0);
|
|
69
68
|
`;
|
|
70
69
|
function createTimeQuery(device) {
|
|
71
70
|
try {
|
|
72
71
|
const querySet = device.createQuerySet({
|
|
73
72
|
type: 'timestamp',
|
|
74
|
-
count:
|
|
73
|
+
count: 16
|
|
75
74
|
});
|
|
76
75
|
const resolveBuffer = device.createBuffer({
|
|
77
76
|
size: querySet.count * 8,
|
|
@@ -100,6 +99,9 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
|
|
|
100
99
|
// the next presentation or read resolves them once.
|
|
101
100
|
let realtimeDeferPostProcess = false;
|
|
102
101
|
let postProcessPending = false;
|
|
102
|
+
// Resolve uses the configuration that produced these buffers, even if another
|
|
103
|
+
// target has since changed the shared trace pass's caustic settings.
|
|
104
|
+
let sampledOutput;
|
|
103
105
|
let offlineSamplesPerBatch = 0;
|
|
104
106
|
let deferPostProcess = false;
|
|
105
107
|
let sampleSequenceOffset = 0;
|
|
@@ -109,6 +111,7 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
|
|
|
109
111
|
let elapsedFrameTime = 32;
|
|
110
112
|
let elapsedTileTime;
|
|
111
113
|
let tileTimingGeneration = 0;
|
|
114
|
+
let causticBatchTimeMs = 0, photonBatchTimeMs = 0;
|
|
112
115
|
let lastGpuTraceTiming;
|
|
113
116
|
let displayTrace;
|
|
114
117
|
let diagnosticsReadbackPromise = Promise.resolve();
|
|
@@ -235,6 +238,8 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
|
|
|
235
238
|
tileTimingGeneration++;
|
|
236
239
|
tileRenderWithPredict?.needsUpdatePredicting();
|
|
237
240
|
lastGpuTraceTiming = undefined;
|
|
241
|
+
causticBatchTimeMs = 0;
|
|
242
|
+
photonBatchTimeMs = 0;
|
|
238
243
|
// A changed render configuration needs fresh timing. Refresh
|
|
239
244
|
// its estimator without submitting a hidden probe in that mode.
|
|
240
245
|
needsUpdatePredicting = offlineSamplesPerBatch === 0;
|
|
@@ -261,9 +266,9 @@ function makeWGPUAccumulationTarget(canvas, device, rayTracePass, surface, scrat
|
|
|
261
266
|
var color = load_colorTex(uv, 0);
|
|
262
267
|
let coverage = clamp(load_coverageTex(uv, 0).a, 0.0, 1.0);
|
|
263
268
|
color = vec4f(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
269
|
+
jx(color.r, coverage, flatBackgroundColor.a > 0.5, true),
|
|
270
|
+
jx(color.g, coverage, flatBackgroundColor.a > 0.5, true),
|
|
271
|
+
jx(color.b, coverage, flatBackgroundColor.a > 0.5, true), color.a);
|
|
267
272
|
output.color = color;
|
|
268
273
|
`
|
|
269
274
|
}));
|
|
@@ -387,11 +392,11 @@ output.color = color;
|
|
|
387
392
|
oidnNormalSanitizePass.setOutputParams({ normal: { channels: 4 } });
|
|
388
393
|
const outputPass = scratch.get('outputPass', () => new WGPUFullQuadPass('output', device, {
|
|
389
394
|
fsMain: /* wgsl */ `
|
|
390
|
-
let
|
|
395
|
+
let xW = min(
|
|
391
396
|
vec2i(uv2 * vec2f(colorTexRegion())),
|
|
392
397
|
vec2i(colorTexRegion()) - vec2i(1)
|
|
393
398
|
);
|
|
394
|
-
var color = load_colorTex(
|
|
399
|
+
var color = load_colorTex(xW, 0);
|
|
395
400
|
color = vec4(color.rgb * color.a, color.a);
|
|
396
401
|
output.color = color;
|
|
397
402
|
`,
|
|
@@ -424,7 +429,8 @@ output.color = color;
|
|
|
424
429
|
_updateSeed(renderWidth, renderHeight);
|
|
425
430
|
const activeTimeQuery = timeQuery;
|
|
426
431
|
const isUnmapped = activeTimeQuery?.resultBuffer.mapState === 'unmapped';
|
|
427
|
-
rayTracePass.createPass(encoder, clear, tiles, activeTimeQuery ? { querySet: activeTimeQuery.querySet } : undefined);
|
|
432
|
+
const measuredCausticBatch = rayTracePass.createPass(encoder, clear, tiles, activeTimeQuery ? { querySet: activeTimeQuery.querySet } : undefined);
|
|
433
|
+
sampledOutput = rayTracePass.getOutputBuffer();
|
|
428
434
|
if (activeTimeQuery) {
|
|
429
435
|
encoder.resolveQuerySet(activeTimeQuery.querySet, 0, activeTimeQuery.querySet.count, activeTimeQuery.resolveBuffer, 0);
|
|
430
436
|
if (isUnmapped) {
|
|
@@ -440,14 +446,25 @@ output.color = color;
|
|
|
440
446
|
diagnosticsReadbackPromise = activeTimeQuery.resultBuffer
|
|
441
447
|
.mapAsync(GPUMapMode.READ).then(() => {
|
|
442
448
|
const mappedRange = activeTimeQuery.resultBuffer.getMappedRange();
|
|
443
|
-
const times = new BigInt64Array(mappedRange, 0,
|
|
444
|
-
const
|
|
449
|
+
const times = new BigInt64Array(mappedRange, 0, 16);
|
|
450
|
+
const causticTime = (measuredCausticBatch & 1) ? Math.max(Number(times[3] - times[2] + times[5] - times[4]) / 1_000_000, 0) : 0;
|
|
451
|
+
// Independent timestamp pairs avoid Metal's cross-pass counter bug.
|
|
452
|
+
const photonTime = (measuredCausticBatch & 2) ? Math.max(Number(times[7] - times[6] + times[9] - times[8] + times[11] - times[10] + times[13] - times[12] + times[15] - times[14]) / 1_000_000, 0) : 0;
|
|
453
|
+
const ptTime = Math.max(Number(times[1] - times[0]) / 1_000_000, 0);
|
|
445
454
|
// A readback may finish after scene preparation or a mode switch.
|
|
446
455
|
// It must not overwrite throughput learned for the current scene.
|
|
447
456
|
const timingIsCurrent = !disposed && submittedTimingGeneration === tileTimingGeneration &&
|
|
448
457
|
!isFirstFrame;
|
|
449
458
|
if (timingIsCurrent) {
|
|
459
|
+
if (measuredCausticBatch & 1)
|
|
460
|
+
causticBatchTimeMs = causticTime;
|
|
461
|
+
if (measuredCausticBatch & 2)
|
|
462
|
+
photonBatchTimeMs = photonTime;
|
|
463
|
+
const traceTime = Math.max(ptTime + (causticBatchTimeMs + photonBatchTimeMs) / submittedTileCount, .1);
|
|
450
464
|
lastGpuTraceTiming = {
|
|
465
|
+
causticTimeMs: causticBatchTimeMs, photonMappingTimeMs: photonBatchTimeMs,
|
|
466
|
+
photonStagesMs: (measuredCausticBatch & 2) ? [6, 8, 10, 12, 14].map(i => Math.max(Number(times[i + 1] - times[i]) / 1_000_000, 0)) : undefined,
|
|
467
|
+
pathTracingTimeMs: ptTime,
|
|
451
468
|
tileTimeMs: traceTime,
|
|
452
469
|
tileTimePerSampleMs: traceTime,
|
|
453
470
|
estimatedFullFrameTimeMs: traceTime * submittedTileCount,
|
|
@@ -556,7 +573,7 @@ output.color = color;
|
|
|
556
573
|
denoisedTexture = prepareDenoisedTexture(encoder, denoisedBuffer, denoisedTexture);
|
|
557
574
|
if (resolve) {
|
|
558
575
|
rayTraceOutputPass.setSampleCount(sampleCount);
|
|
559
|
-
rayTraceOutputPass.createPass(encoder, rayTracePass.getOutputBuffer(), resolvedHasShadowCatcher);
|
|
576
|
+
rayTraceOutputPass.createPass(encoder, sampledOutput ?? rayTracePass.getOutputBuffer(), resolvedHasShadowCatcher);
|
|
560
577
|
}
|
|
561
578
|
composePass.setUniform('shadowCatcherEnabled', +resolvedHasShadowCatcher);
|
|
562
579
|
let foregroundTexture = getFrameInput(resolvedHasShadowCatcher ? 'foreground' : 'color');
|
|
@@ -674,19 +691,25 @@ output.color = color;
|
|
|
674
691
|
drawPostProcess(device.createCommandEncoder(), false, true);
|
|
675
692
|
}
|
|
676
693
|
function trace(camera, maxSamples) {
|
|
694
|
+
applyTraceQuality();
|
|
677
695
|
// A call to draw means accumulation has been invalidated. Cancel OIDN
|
|
678
696
|
// before checking shader compilation: pipeline-affecting parameter changes
|
|
679
697
|
// otherwise leave the previous asynchronous denoise alive while resources
|
|
680
698
|
// and bind groups are being replaced.
|
|
681
699
|
cancelDenoise();
|
|
682
|
-
if (rayTracePass.isCompilingShader()) {
|
|
683
|
-
isFirstFrame = true;
|
|
684
|
-
sampleCount = 0;
|
|
685
|
-
return true;
|
|
686
|
-
}
|
|
687
700
|
// Update the camera before compiling and sampling.
|
|
688
701
|
rayTracePass.setCamera(camera);
|
|
689
702
|
aovCamera = camera;
|
|
703
|
+
rayTracePass.updatePipeline();
|
|
704
|
+
const pipelineError = rayTracePass.getPipelineError();
|
|
705
|
+
if (pipelineError)
|
|
706
|
+
throw pipelineError;
|
|
707
|
+
// Waiting for a shader is not an input change: this render's samples and
|
|
708
|
+
// complete image stay valid, and only Render's restart discards them.
|
|
709
|
+
if (rayTracePass.isCompilingShader() || !rayTracePass.isPipelineReady())
|
|
710
|
+
return true;
|
|
711
|
+
if (execution?.aovs?.length && !rayTracePass.prepareAovs(execution.aovs))
|
|
712
|
+
return true;
|
|
690
713
|
const resetAccumulation = isFirstFrame;
|
|
691
714
|
if (resetAccumulation)
|
|
692
715
|
aov.reset();
|
|
@@ -696,20 +719,11 @@ output.color = color;
|
|
|
696
719
|
denoiseValid = false;
|
|
697
720
|
tileTimingGeneration++;
|
|
698
721
|
elapsedTileTime = undefined;
|
|
699
|
-
rayTracePass.setCamera(camera);
|
|
700
722
|
(tileRenderWithPredict || tileRender).reset();
|
|
701
723
|
// Reset
|
|
702
724
|
isFirstFrame = false;
|
|
703
725
|
sampleCount = 0;
|
|
704
726
|
}
|
|
705
|
-
rayTracePass.updatePipeline();
|
|
706
|
-
if (rayTracePass.isCompilingShader() || !rayTracePass.isPipelineReady()) {
|
|
707
|
-
isFirstFrame = true;
|
|
708
|
-
sampleCount = 0;
|
|
709
|
-
return true;
|
|
710
|
-
}
|
|
711
|
-
if (execution?.aovs?.length && !rayTracePass.prepareAovs(execution.aovs))
|
|
712
|
-
return true;
|
|
713
727
|
// Keep the last completed denoise visible while a static while-converging batch
|
|
714
728
|
// accumulates, including the incomplete first sample after a scene edit.
|
|
715
729
|
if (!preserveDenoisedOutput || isFirstFrame) {
|
|
@@ -840,6 +854,7 @@ output.color = color;
|
|
|
840
854
|
// The target retains its complete presentation texture through the resize.
|
|
841
855
|
clearDenoisedOutput();
|
|
842
856
|
tileTimingGeneration++;
|
|
857
|
+
sampledOutput = undefined;
|
|
843
858
|
renderWidth = nextRenderWidth;
|
|
844
859
|
renderHeight = nextRenderHeight;
|
|
845
860
|
(tileRenderWithPredict || tileRender).setSize(renderWidth, renderHeight);
|
|
@@ -1289,24 +1304,30 @@ output.color = color;
|
|
|
1289
1304
|
rayTraceOutputPass.dispose();
|
|
1290
1305
|
});
|
|
1291
1306
|
}
|
|
1307
|
+
// Keep tracing quality out of presentation: an old fallback must not
|
|
1308
|
+
// invalidate a new caustic pipeline while it is compiling.
|
|
1309
|
+
function applyTraceQuality() {
|
|
1310
|
+
if (execution) {
|
|
1311
|
+
rayTracePass.setQuality(execution);
|
|
1312
|
+
rayTracePass.setBevelSamples(execution.bevelSamples);
|
|
1313
|
+
rayTracePass.setAlphaBlendStrategy(execution.alphaBlendStrategy);
|
|
1314
|
+
rayTracePass.setSamplingPattern(execution.samplingPattern, execution.maxSamples);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1292
1317
|
function activate() {
|
|
1293
1318
|
rayTracePass.useTarget(targetKey);
|
|
1294
1319
|
if (renderWidth && renderHeight)
|
|
1295
1320
|
rayTracePass.setSize(renderWidth, renderHeight, screenWidth / screenHeight);
|
|
1296
1321
|
if (execution) {
|
|
1297
|
-
rayTracePass.setQuality(execution);
|
|
1298
1322
|
rayTracePass.setClamping(execution.clamping);
|
|
1299
1323
|
rayTracePass.setTransmissiveOutputAlphaMin(execution.transmissiveOutputAlphaMin);
|
|
1300
|
-
rayTracePass.setBevelSamples(execution.bevelSamples);
|
|
1301
|
-
rayTracePass.setAlphaBlendStrategy(execution.alphaBlendStrategy);
|
|
1302
|
-
rayTracePass.setSamplingPattern(execution.samplingPattern, execution.maxSamples);
|
|
1303
1324
|
}
|
|
1304
1325
|
}
|
|
1305
1326
|
return {
|
|
1306
1327
|
invalidateTiming: invalidateTilePrediction,
|
|
1307
1328
|
invalidateDenoisedOutput() { cancelDenoise(); denoiseValid = false; preserveDenoisedOutput = false; },
|
|
1308
1329
|
configure(settings) {
|
|
1309
|
-
const timingKeys = ['bounces', 'bevel', 'bevelSamples', 'directLightCandidates', 'dispersionWavelengths', 'alphaBlendStrategy', 'samplingPattern', 'clamping', 'transmissiveOutputAlphaMin'];
|
|
1330
|
+
const timingKeys = ['bounces', 'bevel', 'bevelSamples', 'directLightCandidates', 'dispersionWavelengths', 'alphaBlendStrategy', 'samplingPattern', 'clamping', 'transmissiveOutputAlphaMin', 'caustics'];
|
|
1310
1331
|
if (!execution || timingKeys.some(key => execution[key] !== settings[key]))
|
|
1311
1332
|
invalidateTilePrediction();
|
|
1312
1333
|
if (settings.aovs?.length && (!Number.isInteger(settings.aovSamples ?? 16) || (settings.aovSamples ?? 16) < 1))
|
|
@@ -1341,7 +1362,8 @@ output.color = color;
|
|
|
1341
1362
|
},
|
|
1342
1363
|
setRealtimeBatchBudget(milliseconds) { realtimeBatchBudgetMs = milliseconds; },
|
|
1343
1364
|
setRealtimeDeferPostProcess(defer) { realtimeDeferPostProcess = defer; },
|
|
1344
|
-
getRealtimeSampleTime() { return lastGpuTraceTiming?.
|
|
1365
|
+
getRealtimeSampleTime() { return lastGpuTraceTiming?.estimatedFullFrameTimeMs; },
|
|
1366
|
+
getRealtimeTileTime() { return lastGpuTraceTiming?.tileTimePerSampleMs; },
|
|
1345
1367
|
whenTraceAvailable() { return traceQueue.whenAvailable(); },
|
|
1346
1368
|
get presentationComplete() { return !!presentationTexture; },
|
|
1347
1369
|
get presentationDenoised() { return presentationDenoised; },
|
|
@@ -1434,9 +1456,13 @@ output.color = color;
|
|
|
1434
1456
|
refineAovs(camera, samples = sampleCount) {
|
|
1435
1457
|
if (samples < 1 || !execution?.aovs?.length)
|
|
1436
1458
|
return true;
|
|
1459
|
+
applyTraceQuality();
|
|
1437
1460
|
rayTracePass.setCamera(camera);
|
|
1438
1461
|
aovCamera = camera;
|
|
1439
1462
|
rayTracePass.updatePipeline();
|
|
1463
|
+
const pipelineError = rayTracePass.getPipelineError();
|
|
1464
|
+
if (pipelineError)
|
|
1465
|
+
throw pipelineError;
|
|
1440
1466
|
if (rayTracePass.isCompilingShader() || !rayTracePass.isPipelineReady())
|
|
1441
1467
|
return false;
|
|
1442
1468
|
return rayTracePass.renderAovs(aov, camera, samples, execution.aovSamples ?? 16, execution.aovs);
|
|
@@ -1444,11 +1470,21 @@ output.color = color;
|
|
|
1444
1470
|
async readAov(kind) {
|
|
1445
1471
|
if (!execution?.aovs?.includes(kind) || !aovCamera || (sampleCount < 1 && aov.samples < 1))
|
|
1446
1472
|
throw new Error('AOV output is not ready');
|
|
1447
|
-
|
|
1448
|
-
while (!rayTracePass.renderAovs(aov, aovCamera, Math.max(sampleCount, aov.samples), execution.aovSamples ?? 16, execution.aovs)) {
|
|
1473
|
+
for (;;) {
|
|
1449
1474
|
if (disposed)
|
|
1450
1475
|
throw new Error('AOV compilation was interrupted');
|
|
1451
|
-
|
|
1476
|
+
activate();
|
|
1477
|
+
applyTraceQuality();
|
|
1478
|
+
rayTracePass.setCamera(aovCamera);
|
|
1479
|
+
rayTracePass.updatePipeline();
|
|
1480
|
+
const pipelineError = rayTracePass.getPipelineError();
|
|
1481
|
+
if (pipelineError)
|
|
1482
|
+
throw pipelineError;
|
|
1483
|
+
if (!rayTracePass.isCompilingShader() && rayTracePass.isPipelineReady() &&
|
|
1484
|
+
rayTracePass.renderAovs(aov, aovCamera, Math.max(sampleCount, aov.samples), execution.aovSamples ?? 16, execution.aovs))
|
|
1485
|
+
break;
|
|
1486
|
+
// Display frames stop on a hidden page, but compilation still completes.
|
|
1487
|
+
await new Promise(resolve => setTimeout(resolve, 16));
|
|
1452
1488
|
}
|
|
1453
1489
|
return aov.read(kind);
|
|
1454
1490
|
},
|
|
@@ -1532,7 +1568,7 @@ output.color = color;
|
|
|
1532
1568
|
setSize(input.width, input.height);
|
|
1533
1569
|
rayTracePass.useTarget(targetKey);
|
|
1534
1570
|
rayTracePass.setSize(renderWidth, renderHeight, screenWidth / screenHeight);
|
|
1535
|
-
const buffers = rayTracePass.getOutputBuffer();
|
|
1571
|
+
const buffers = sampledOutput = rayTracePass.getOutputBuffer();
|
|
1536
1572
|
const shadow = new Float32Array(input.width * input.height * 12);
|
|
1537
1573
|
for (let i = 0; i < input.width * input.height; i++) {
|
|
1538
1574
|
shadow.set(input.shadow.subarray(i * 8, i * 8 + 8), i * 12);
|