@meimu/mutracer 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +222 -0
- package/LICENSES/FidelityFX-FSR.txt +19 -0
- package/LICENSES/pbrt-v4-Apache-2.0.txt +202 -0
- package/README.md +3 -0
- package/THIRD_PARTY_NOTICES.md +18 -4
- package/dist/assets/bvh.worker.js +1 -1
- package/dist/mutracer.umd.js +9328 -7614
- package/docs/api.md +83 -35
- package/docs/caustics.md +80 -0
- package/docs/materials.md +9 -6
- package/docs/performance.md +7 -0
- package/docs/post-processing.md +62 -9
- package/docs/progressive-rendering.md +53 -9
- package/docs/sampling.md +4 -0
- package/docs/technical/acceleration.md +52 -0
- package/docs/technical/aovs.md +79 -0
- package/docs/technical/caustics.md +109 -0
- package/docs/technical/continuous-spectrum.md +122 -0
- package/docs/technical/display-upscale.md +82 -0
- package/docs/technical/openpbr.md +99 -0
- package/docs/technical/pbrt-import.md +168 -0
- package/docs/technical/tiling.md +74 -0
- package/docs/technical/webgl.md +53 -0
- package/docs/updates.md +3 -1
- package/docs/viewer-checklist.md +65 -0
- package/docs/viewer.md +18 -6
- package/lib/Display.d.ts +19 -5
- package/lib/Display.js +10 -7
- package/lib/Display.js.map +1 -1
- package/lib/Engine.d.ts +4 -1
- package/lib/Engine.js +77 -14
- package/lib/Engine.js.map +1 -1
- package/lib/Render.d.ts +81 -24
- package/lib/Render.js +201 -26
- 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 +4 -2
- package/lib/main.js +1 -0
- package/lib/main.js.map +1 -1
- package/lib/oidn.d.ts +1 -1
- package/lib/renderer/AovPrimitiveCache.js +39 -8
- package/lib/renderer/AovPrimitiveCache.js.map +1 -1
- package/lib/renderer/DisplayPostProcess.d.ts +8 -3
- package/lib/renderer/DisplayPostProcess.js +51 -18
- package/lib/renderer/DisplayPostProcess.js.map +1 -1
- 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/MaterialData.js +7 -2
- package/lib/renderer/MaterialData.js.map +1 -1
- package/lib/renderer/RenderingPipeline.d.ts +11 -1
- package/lib/renderer/RenderingPipeline.js.map +1 -1
- package/lib/renderer/TileRender.d.ts +2 -2
- package/lib/renderer/TileRender.js +128 -7
- package/lib/renderer/TileRender.js.map +1 -1
- package/lib/renderer/WGPUAov.d.ts +6 -1
- package/lib/renderer/WGPUAov.js +108 -14
- package/lib/renderer/WGPUAov.js.map +1 -1
- package/lib/renderer/WGPUCanvasSurface.js +12 -1
- package/lib/renderer/WGPUCanvasSurface.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 +19 -19
- 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 +65 -21
- package/lib/renderer/WGPURayTracePass.js +730 -409
- package/lib/renderer/WGPURayTracePass.js.map +1 -1
- package/lib/renderer/WGPURenderingPipeline.js +110 -68
- package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLAov.js +3 -3
- package/lib/renderer/WebGLAov.js.map +1 -1
- package/lib/renderer/WebGLFullQuadPass.d.ts +2 -1
- package/lib/renderer/WebGLFullQuadPass.js +10 -0
- package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
- package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
- package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
- package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
- package/lib/renderer/WebGLRayTracePass.d.ts +20 -11
- package/lib/renderer/WebGLRayTracePass.js +157 -116
- package/lib/renderer/WebGLRayTracePass.js.map +1 -1
- package/lib/renderer/WebGLRenderingPipeline.js +17 -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/aov.d.ts +13 -1
- package/lib/renderer/aov.js +21 -2
- package/lib/renderer/aov.js.map +1 -1
- package/lib/renderer/aovDisplay.js +2 -2
- package/lib/renderer/aovDisplay.js.map +1 -1
- package/lib/renderer/binnedSahBvh.d.ts +2 -1
- package/lib/renderer/binnedSahBvh.js +24 -17
- package/lib/renderer/binnedSahBvh.js.map +1 -1
- package/lib/renderer/bvhAccel.d.ts +3 -1
- package/lib/renderer/bvhAccel.js +36 -6
- package/lib/renderer/bvhAccel.js.map +1 -1
- package/lib/renderer/cameraUniform.d.ts +1 -1
- package/lib/renderer/cameraUniform.js +6 -2
- package/lib/renderer/cameraUniform.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/compactVertices.d.ts +14 -0
- package/lib/renderer/compactVertices.js +124 -0
- package/lib/renderer/compactVertices.js.map +1 -0
- package/lib/renderer/easu.d.ts +11 -0
- package/lib/renderer/easu.js +156 -0
- package/lib/renderer/easu.js.map +1 -0
- package/lib/renderer/geometryUpdateState.d.ts +1 -0
- package/lib/renderer/geometryUpdateState.js.map +1 -1
- package/lib/renderer/geometryUpdates.js +3 -2
- package/lib/renderer/geometryUpdates.js.map +1 -1
- 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 +45 -37
- package/lib/renderer/glsl/aovTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.js +16 -0
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +1 -1
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -16
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -1
- 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 +478 -465
- 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 +70 -63
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js +89 -75
- 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 +160 -118
- 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 +88 -91
- 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/spectralPrefix.glsl.d.ts +6 -0
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js +47 -0
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js.map +1 -0
- 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 +13 -7
- package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
- 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 +338 -252
- package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/shadowCatcher.frag.js +27 -26
- package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
- package/lib/renderer/glsl/webglPipeline.frag.js +59 -59
- package/lib/renderer/gpuMemory.js +1 -1
- package/lib/renderer/gpuMemory.js.map +1 -1
- 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/openPbrEnergyLut.d.ts +2 -1
- package/lib/renderer/openPbrEnergyLut.js +18 -1
- package/lib/renderer/openPbrEnergyLut.js.map +1 -1
- package/lib/renderer/pathLimits.d.ts +5 -4
- package/lib/renderer/pathLimits.js +6 -5
- package/lib/renderer/pathLimits.js.map +1 -1
- package/lib/renderer/prepareMeshBVH.d.ts +2 -0
- package/lib/renderer/prepareMeshBVH.js +5 -3
- package/lib/renderer/prepareMeshBVH.js.map +1 -1
- package/lib/renderer/progressiveScheduler.js +5 -4
- package/lib/renderer/progressiveScheduler.js.map +1 -1
- package/lib/renderer/renderPipeline.d.ts +5 -0
- package/lib/renderer/renderPipeline.js +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/sceneAssembly.d.ts +1 -1
- package/lib/renderer/sceneAssembly.js +4 -3
- package/lib/renderer/sceneAssembly.js.map +1 -1
- package/lib/renderer/sceneChangeDetector.d.ts +1 -1
- package/lib/renderer/sceneChangeDetector.js +3 -1
- package/lib/renderer/sceneChangeDetector.js.map +1 -1
- package/lib/renderer/sceneLayoutSchema.d.ts +2 -0
- package/lib/renderer/sceneLayoutSchema.js +3 -3
- package/lib/renderer/sceneLayoutSchema.js.map +1 -1
- package/lib/renderer/scenePreparation.d.ts +3 -2
- package/lib/renderer/scenePreparation.js +18 -2
- package/lib/renderer/scenePreparation.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/staticBvhPreparation.d.ts +9 -0
- package/lib/renderer/staticBvhPreparation.js +8 -2
- package/lib/renderer/staticBvhPreparation.js.map +1 -1
- package/lib/renderer/surfaceHit.d.ts +10 -0
- package/lib/renderer/surfaceHit.js +22 -0
- package/lib/renderer/surfaceHit.js.map +1 -0
- package/lib/renderer/tangentRequirements.d.ts +2 -0
- package/lib/renderer/tangentRequirements.js +7 -0
- package/lib/renderer/tangentRequirements.js.map +1 -0
- package/lib/renderer/textureAtlas.d.ts +4 -0
- package/lib/renderer/textureAtlas.js +48 -2
- package/lib/renderer/textureAtlas.js.map +1 -1
- package/lib/renderer/webgl.js +4 -0
- package/lib/renderer/webgl.js.map +1 -1
- 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/webglVertexAttributes.d.ts +17 -0
- package/lib/renderer/webglVertexAttributes.js +44 -0
- package/lib/renderer/webglVertexAttributes.js.map +1 -0
- package/lib/renderer/wgpuBindlessSource.js +3 -3
- package/lib/renderer/wgpuMaterialConstants.js +4 -3
- package/lib/renderer/wgpuMaterialConstants.js.map +1 -1
- package/lib/renderer/wgpuSceneUniform.js +2 -2
- package/lib/renderer/wgpuSceneUniform.js.map +1 -1
- package/lib/renderer/wgpuShaderSource.d.ts +22 -0
- package/lib/renderer/wgpuShaderSource.js +3 -1
- package/lib/renderer/wgpuShaderSource.js.map +1 -1
- package/lib/renderer/wgsl/aovCompact.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/aovCompact.wgsl.js +26 -0
- package/lib/renderer/wgsl/aovCompact.wgsl.js.map +1 -0
- 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.d.ts +4 -0
- package/lib/renderer/wgsl/aovResolve.wgsl.js +21 -2
- package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js +2 -2
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/aovTrace.wgsl.js +33 -33
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js +56 -0
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js.map +1 -0
- 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 +539 -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.d.ts +6 -2
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +634 -620
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +23 -21
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +3 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +77 -74
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +795 -795
- 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 +5 -1
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +45 -29
- 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 +228 -189
- 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 +88 -92
- 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/spectralPrefix.wgsl.d.ts +6 -0
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js +66 -0
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js +61 -0
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.js +100 -98
- package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
- package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/depthQuery.wgsl.js +12 -3
- package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/easu.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/easu.wgsl.js +80 -0
- package/lib/renderer/wgsl/easu.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.d.ts +21 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.js +230 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/jnlm.compute.js +74 -74
- package/lib/renderer/wgsl/jnlm.compute.js.map +1 -1
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +26 -26
- 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 +23 -1
- package/lib/renderer/wgsl/rayTrace.compute.js +531 -543
- 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/scene/Scene.js.map +1 -1
- package/lib/settings/render.d.ts +22 -0
- package/lib/settings/render.js +2 -0
- package/lib/settings/render.js.map +1 -1
- package/lib/util/fromTHREE.js +23 -16
- 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 +7 -4
- package/lib/oidnBundledWeights.cdn.d.ts +0 -2
- package/lib/oidnBundledWeights.cdn.js +0 -5
- package/lib/oidnBundledWeights.cdn.js.map +0 -1
- package/lib/renderer/bvh.worker.d.ts +0 -1
- package/lib/renderer/bvh.worker.js +0 -16
- package/lib/renderer/bvh.worker.js.map +0 -1
- package/lib/renderer/bvhWorkerBuild.d.ts +0 -13
- package/lib/renderer/bvhWorkerBuild.js +0 -17
- package/lib/renderer/bvhWorkerBuild.js.map +0 -1
- package/lib/renderer/lightCore.d.ts +0 -12
- package/lib/renderer/lightCore.js +0 -13
- package/lib/renderer/lightCore.js.map +0 -1
- package/lib/renderer/materialCore.d.ts +0 -8
- package/lib/renderer/materialCore.js +0 -9
- package/lib/renderer/materialCore.js.map +0 -1
- package/lib/scene/PixelTexture.d.ts +0 -6
- package/lib/scene/PixelTexture.js +0 -10
- package/lib/scene/PixelTexture.js.map +0 -1
- package/lib/util/studioLighting.d.ts +0 -18
- package/lib/util/studioLighting.js +0 -36
- package/lib/util/studioLighting.js.map +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Surface color AOVs
|
|
2
|
+
|
|
3
|
+
MuTracer has two pairs of surface color outputs. `diffuseAlbedo` and
|
|
4
|
+
`specularAlbedo` report how much light a surface reflects. `diffuseColor` and
|
|
5
|
+
`specularColor` report the material colors that produce it. Usage and the exact
|
|
6
|
+
definitions are in [surface outputs](../api.md#surface-outputs); this note explains
|
|
7
|
+
why both pairs exist, how they are named and how they are stored.
|
|
8
|
+
|
|
9
|
+
## Reflectance and color
|
|
10
|
+
|
|
11
|
+
The albedo kinds are directional-hemispherical reflectance: the fraction of
|
|
12
|
+
uniform incident light that the prepared OpenPBR BSDF reflects toward the view
|
|
13
|
+
direction. They integrate the BSDF by quadrature (`aovReflectance*.wgsl.ts` and
|
|
14
|
+
`.glsl.ts`), so they cost more than the other outputs and support only materials
|
|
15
|
+
the quadrature models. Coat, fuzz, anisotropy and similar hits are marked
|
|
16
|
+
unsupported.
|
|
17
|
+
|
|
18
|
+
The color kinds read resolved material inputs without integration:
|
|
19
|
+
|
|
20
|
+
- diffuse: base weight × base color × (1 − metalness)
|
|
21
|
+
- specular: metalness × base weight × base color + (1 − metalness) ×
|
|
22
|
+
specular weight × specular color × F0, with F0 from the specular IOR
|
|
23
|
+
|
|
24
|
+
Both are multiplied by the coat color, weighted by the coat weight. Transmission,
|
|
25
|
+
partial alpha, media and nonstandard materials have zero validity.
|
|
26
|
+
|
|
27
|
+
EASU detail recovery needs the color kinds, not reflectance. It compares
|
|
28
|
+
display-resolution colors with their average over each render pixel and scales
|
|
29
|
+
the part of the upscaled radiance that follows color by that ratio. Layer factors
|
|
30
|
+
that are uniform across a surface, such as coat or fuzz, cancel in the ratio, so
|
|
31
|
+
the cheap estimate covers more surfaces than the quadrature does. Reflectance
|
|
32
|
+
remains the right input for compositing and other uses that need reflected energy.
|
|
33
|
+
|
|
34
|
+
## Names
|
|
35
|
+
|
|
36
|
+
Renderers use "albedo" for both quantities:
|
|
37
|
+
|
|
38
|
+
| Renderer | Integrated reflectance | Material color |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| [MoonRay](https://docs.openmoonray.org/user-reference/how-to-guides/render-outputs/material-aovs/) | `albedo`: response to unoccluded white light from all directions | `color` |
|
|
41
|
+
| [Mitsuba 3](https://mitsuba.readthedocs.io/en/stable/src/generated/plugins_integrators.html) | `albedo`: diffuse reflectance, approximate for some materials | none |
|
|
42
|
+
| [Arnold](https://help.autodesk.com/cloudhelp/ENU/AR-Core/files/ac-output-aovs/arnold_user_guide_ac_output_aovs_ac_aovs_html.html) | none | `diffuse_albedo`, `specular_albedo`: colors without lighting |
|
|
43
|
+
| [Cycles](https://docs.blender.org/manual/en/latest/render/layers/passes.html) | none | `Diffuse Color`, `Glossy Color`: BSDF color weights |
|
|
44
|
+
| V-Ray, Redshift | none | `Diffuse Filter` |
|
|
45
|
+
|
|
46
|
+
MuTracer's names match MoonRay: albedo for integrated reflectance, color for
|
|
47
|
+
material inputs. Albedo for reflectance also matches Mitsuba and the
|
|
48
|
+
"directional albedo" of energy compensation work. Arnold uses albedo for colors,
|
|
49
|
+
so documentation always states the definition next to the name. No surveyed
|
|
50
|
+
renderer names an AOV "reflectance"; the viewer uses it only in labels.
|
|
51
|
+
|
|
52
|
+
These outputs are separate from the OIDN `albedo` guide, which follows its own
|
|
53
|
+
path rules for denoising.
|
|
54
|
+
|
|
55
|
+
## Storage
|
|
56
|
+
|
|
57
|
+
The WebGPU accumulation has four `vec4f` lanes per pixel (`AOV_LAYOUT`):
|
|
58
|
+
depth with roughness, position with hit count, diffuse and specular. A lobe's
|
|
59
|
+
albedo and color share its lane, selected per kind by mask bits 3–4 and 7–8, so a
|
|
60
|
+
render may request only one of them per lobe. Resolve, display and snapshot shaders
|
|
61
|
+
see a color kind as the albedo kind of its lane (`aovLaneKind`), so they need no
|
|
62
|
+
color-specific code. Separate lanes would add 32 bytes per pixel to every AOV
|
|
63
|
+
render. If both are ever needed together, adding lanes lifts the restriction
|
|
64
|
+
without changing the API.
|
|
65
|
+
|
|
66
|
+
Display-resolution renders requesting only `depth`, `diffuseColor` and
|
|
67
|
+
`specularColor` use a compact 24-byte layout: float depth and hit count, plus two
|
|
68
|
+
colors in half precision. It skips the center pass, so it has no ID or motion.
|
|
69
|
+
Half-precision sums lose precision as the sample count grows, which is acceptable
|
|
70
|
+
only because display resolution stops at 4 samples (`DISPLAY_AOV_SAMPLE_CAP`).
|
|
71
|
+
For detail recovery, 4 jittered samples matched 16 within measurement noise.
|
|
72
|
+
Render resolution keeps the full layout for any request.
|
|
73
|
+
|
|
74
|
+
## Native
|
|
75
|
+
|
|
76
|
+
Native shares `aovTraceDisplay.wgsl.ts` but still requests display-resolution
|
|
77
|
+
colors through the albedo bits with the `AOV_DISPLAY` override. The web build never
|
|
78
|
+
sets that override. Native should adopt the color kinds when it is next aligned
|
|
79
|
+
with web AOVs.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Caustic estimators
|
|
2
|
+
|
|
3
|
+
Path tracing finds caustics only when a BSDF sample happens to hit the light
|
|
4
|
+
through a smooth surface, because shadow rays treat glass as an occluder. MuTracer
|
|
5
|
+
adds two WebGPU estimators for those paths: light tracing and progressive photon
|
|
6
|
+
mapping. Usage, costs and limits are in the [caustics guide](../caustics.md); this
|
|
7
|
+
note explains how the paths are divided and how the estimators work.
|
|
8
|
+
|
|
9
|
+
## Path partition
|
|
10
|
+
|
|
11
|
+
A surface is *smooth* when `isCausticSpecular` holds: no diffuse, subsurface, fuzz
|
|
12
|
+
or coat weight, and specular roughness at most `CAUSTIC_ROUGHNESS_MAX` (0.1). The
|
|
13
|
+
test depends only on the material, never on the lobe a sample chose, so every
|
|
14
|
+
estimator classifies a vertex the same way (`src/renderer/caustics.ts`).
|
|
15
|
+
|
|
16
|
+
Counting from the light, the *receiver* is the first non-smooth surface vertex, k is
|
|
17
|
+
the number of smooth vertices between the light and the receiver, and the *camera
|
|
18
|
+
prefix* is the path from the camera to the receiver. Surfaces skipped through alpha
|
|
19
|
+
are not vertices.
|
|
20
|
+
|
|
21
|
+
| Paths | Estimator |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| k = 0 | Path tracing, unchanged |
|
|
24
|
+
| k ≥ 1, empty camera prefix (the camera sees the receiver directly), light tracing on | Light tracing |
|
|
25
|
+
| Other k ≥ 1, photon mapping on | Photon mapping |
|
|
26
|
+
| Anything else | Path tracing's BSDF hits |
|
|
27
|
+
|
|
28
|
+
Path tracing tracks the smooth chain length and whether the receiver is the first
|
|
29
|
+
visible surface. When it hits a light on a path that an enabled estimator owns, the
|
|
30
|
+
contribution is zero. Each path is therefore counted by exactly one estimator.
|
|
31
|
+
When an estimator is off or unsupported (WebGL 2), its rows fall back to path
|
|
32
|
+
tracing, so every configuration has the same expected image and differs only in
|
|
33
|
+
noise. Scenes whose smooth casters use stochastic blend coverage turn both
|
|
34
|
+
estimators off, because their photon transport does not yet match path-tracing
|
|
35
|
+
energy.
|
|
36
|
+
|
|
37
|
+
## Casters and emission
|
|
38
|
+
|
|
39
|
+
The renderer collects caster meshes and instances automatically from smooth
|
|
40
|
+
materials, with one conservative world-space sphere per instance. Photons are
|
|
41
|
+
emitted only toward caster spheres: a path whose first surface from the light is
|
|
42
|
+
not smooth belongs to path tracing, so restricting emission loses no estimator's
|
|
43
|
+
paths. Emission samples the full light surface, then accepts directions toward
|
|
44
|
+
the caster mixture; the direction PDF accounts for overlapping cones
|
|
45
|
+
(`casterDirectionPdf`). Lights are chosen by a separate power PMF, not the NEE
|
|
46
|
+
selection table (`causticEmission.ts`). Directional and environment light emit
|
|
47
|
+
from a mixture of projected caster disks.
|
|
48
|
+
|
|
49
|
+
## Light tracing
|
|
50
|
+
|
|
51
|
+
Light tracing is BDPT's t = 1 strategy. Photons follow smooth vertices with adjoint
|
|
52
|
+
BSDF corrections. At the receiver, the pass samples a lens point, connects to the
|
|
53
|
+
camera, tests visibility and splats into the pixel with float32 compare-and-swap
|
|
54
|
+
atomics. It runs once per sample batch, after the last tile, in its own pass and
|
|
55
|
+
bind group, because the main integrator already uses the baseline eight storage
|
|
56
|
+
buffers. The result accumulates separately; resolve adds it to the path-traced
|
|
57
|
+
radiance, so readback, denoising and display see the combined image. Adaptive
|
|
58
|
+
sampling measures variance only on the path-traced part.
|
|
59
|
+
|
|
60
|
+
## Photon mapping
|
|
61
|
+
|
|
62
|
+
Photon mapping uses probabilistic progressive photon mapping (Knaus and Zwicker
|
|
63
|
+
2011). Each sample batch emits a new photon map on the first tile, which later tiles
|
|
64
|
+
reuse. The gather radius shrinks as r_i = r_1 · i^((α − 1)/2) with α = 2/3
|
|
65
|
+
(`photonRadius`). The first radius is `initialRadius`, or 3% of the caster sphere
|
|
66
|
+
radius. At the first non-smooth camera vertex the radius is further limited to
|
|
67
|
+
about two projected pixels (`photonVisibleRadius`); mirror prefixes use an
|
|
68
|
+
approximate footprint, and deeper vertices use the global radius. The pixel cap
|
|
69
|
+
reduces blotches after denoising, at the cost of grainier raw output.
|
|
70
|
+
|
|
71
|
+
Photons are stored at the first non-smooth surface after at least one smooth
|
|
72
|
+
vertex, whatever camera prefix will later find them; queries at directly visible
|
|
73
|
+
receivers skip them when light tracing owns those paths. Camera paths query at every non-smooth vertex within `bounces`, with a
|
|
74
|
+
normal-consistent surface kernel.
|
|
75
|
+
|
|
76
|
+
Each photon takes 20 bytes: float32 position and RGBE8 flux, and two octahedral
|
|
77
|
+
directions (incident direction and normal). Two hash-grid layers with different
|
|
78
|
+
cell sizes, one for first visible receivers and one for deeper queries, each sort
|
|
79
|
+
only a 4-byte index, for 28 bytes per photon. Grids are rebuilt every batch with a
|
|
80
|
+
count, a two-level parallel prefix sum and a scatter; bucket counts are powers of
|
|
81
|
+
two up to 262144. Batches are reduced to fit device limits and a 128 MiB budget.
|
|
82
|
+
|
|
83
|
+
Quantized flux and directions limit precision. More batches shrink the radius
|
|
84
|
+
but do not remove that error, so photon mapping is consistent only up to storage
|
|
85
|
+
precision.
|
|
86
|
+
|
|
87
|
+
## Rejected and paused work
|
|
88
|
+
|
|
89
|
+
- **MNEE and SMS** (manifold next-event estimation and specular manifold sampling)
|
|
90
|
+
are paused and excluded from builds. Behind a wavy refractive surface, each
|
|
91
|
+
receiver can have dozens of manifold roots; Newton's method finds one, and SMS
|
|
92
|
+
with its 64-trial cap covered only part of their weight, so neither converged
|
|
93
|
+
to an unbiased result. The code remains in
|
|
94
|
+
`src/research/mnee/`, registered explicitly by tests and research scripts. A
|
|
95
|
+
restart should address multiple roots, for example with manifold path guiding
|
|
96
|
+
(Fan et al. 2023).
|
|
97
|
+
- **Separate photon denoising**, filtering photon contributions apart from path
|
|
98
|
+
tracing, increased error in comparisons and is not used.
|
|
99
|
+
- **Photon-count radius scaling**, per-caster radii and larger shrinking screen
|
|
100
|
+
radii remain internal diagnostics (`causticDiagnostics.ts`). None improved
|
|
101
|
+
equal-error time on every test scene.
|
|
102
|
+
|
|
103
|
+
## Changing this code
|
|
104
|
+
|
|
105
|
+
- The partition runs in WGSL. WebGL traces plain paths and needs no zeroing; its
|
|
106
|
+
GLSL chain state exists only for the paused MNEE research path.
|
|
107
|
+
- Native shares the WGSL and exposes the same two estimators.
|
|
108
|
+
- Compare raw HDR, not denoised output, when judging energy; see the guide's
|
|
109
|
+
limits for denoiser artifacts.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Continuous-wavelength dispersion
|
|
2
|
+
|
|
3
|
+
MuTracer renders dispersion with continuous wavelengths inside an RGB renderer.
|
|
4
|
+
Wavelength decides how light refracts and how its energy divides between RGB
|
|
5
|
+
channels. Lights, materials and media stay RGB, so this is not spectral rendering.
|
|
6
|
+
The implementation is in `src/renderer/spectrum.ts`, and it runs only when a material
|
|
7
|
+
has `transmissionDispersionScale > 0`.
|
|
8
|
+
|
|
9
|
+
## Spectral response
|
|
10
|
+
|
|
11
|
+
`spectrumRgb` converts a wavelength in 400–700 nm to linear sRGB weights:
|
|
12
|
+
|
|
13
|
+
1. Evaluate the CIE 1931 matching functions with the multi-lobe fit from Wyman, Sloan
|
|
14
|
+
and Shirley, "Simple Analytic Approximations to the CIE XYZ Color Matching
|
|
15
|
+
Functions", JCGT 2(2), 2013.
|
|
16
|
+
2. Convert XYZ to linear sRGB and clamp negative values to zero.
|
|
17
|
+
3. Scale each channel so its mean over a uniform wavelength is 1.
|
|
18
|
+
|
|
19
|
+
The scale keeps white light white on average. The clamp keeps out-of-gamut colors
|
|
20
|
+
saturated instead of colorimetrically exact, and it leaves red with a small violet
|
|
21
|
+
lobe, which is why the short end of a rainbow looks violet instead of blue.
|
|
22
|
+
|
|
23
|
+
## Sampling
|
|
24
|
+
|
|
25
|
+
Both integrators sample from 5 nm inverse CDF tables. They use different estimators
|
|
26
|
+
because they carry different quantities.
|
|
27
|
+
|
|
28
|
+
| | Camera paths | Caustic photons |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Distribution | The response of the path's RGB channel | The sum of the RGB responses |
|
|
31
|
+
| Carries | One RGB channel | RGB flux |
|
|
32
|
+
| Energy weight | None; the distribution is the response | `spectrumRgb(λ) / (pdf(λ) · 300)` |
|
|
33
|
+
| Random number | `CAMERA_WAVELENGTH`, shared by a sample's three paths | Photon emission dimension 69 |
|
|
34
|
+
|
|
35
|
+
Camera paths evaluate no response, so their effective response is a 5 nm histogram of
|
|
36
|
+
the fit. Photons apply the weight exactly. Sharing one random number across a camera
|
|
37
|
+
sample's channels keeps their error correlated with the other common random numbers.
|
|
38
|
+
|
|
39
|
+
`dispersionWavelengths: 3` traces one path per channel in each sample. With
|
|
40
|
+
`dispersionWavelengths: 1`, a dispersive primary hit selects one channel at random
|
|
41
|
+
and multiplies the result by 3; other primary hits trace full RGB. This is not hero
|
|
42
|
+
wavelength sampling, which carries several wavelengths along one path and combines
|
|
43
|
+
them with MIS.
|
|
44
|
+
|
|
45
|
+
## Channels and gathering
|
|
46
|
+
|
|
47
|
+
A path stores its channel and its refracting wavelength separately:
|
|
48
|
+
`spectralChannel` selects the radiance it keeps, and `wavelength` only drives
|
|
49
|
+
`sampling_cauchy_ior`. A channel of 0 keeps full RGB. Red paths can sample violet, so
|
|
50
|
+
the channel cannot be derived from the wavelength.
|
|
51
|
+
|
|
52
|
+
Photon gathering filters photon flux by the camera path's channel. This splits RGB
|
|
53
|
+
across the camera paths and applies no second spectral weight, so energy is shared
|
|
54
|
+
between path tracing and caustics the same way as without dispersion.
|
|
55
|
+
|
|
56
|
+
## Shared prefixes
|
|
57
|
+
|
|
58
|
+
With `dispersionWavelengths: 3`, the three channel paths of a pixel sample are
|
|
59
|
+
identical until the first wavelength-dependent IOR: they use the same random numbers
|
|
60
|
+
and carry full RGB until then. The integrators trace that prefix once, checkpoint
|
|
61
|
+
the path, material, auxiliary outputs and random-stream state at the first
|
|
62
|
+
dispersive interaction, and replay only the wavelength-specific suffix for each
|
|
63
|
+
channel. RGB results completed before any dispersion are reused for all three.
|
|
64
|
+
WGSL replays the suffixes inside the flat, alpha, volume and guide paths; GLSL
|
|
65
|
+
traces all three in one fragment invocation (`spectralPrefix.glsl.ts`). Images are
|
|
66
|
+
the same as with independent paths; only the work is shared. MNEE keeps independent
|
|
67
|
+
paths, because its connection solver can disperse before the camera boundary.
|
|
68
|
+
|
|
69
|
+
Tracing three suffixes in one WebGL draw makes that draw about three times longer.
|
|
70
|
+
See [WebGL 2 backend](./webgl.md) for the timeout risk this adds on large images.
|
|
71
|
+
|
|
72
|
+
## Direct-light resampling
|
|
73
|
+
|
|
74
|
+
Direct lighting selects among `directLightCandidates` light samples by resampled
|
|
75
|
+
importance sampling. When the three channel paths share a prefix, they share one
|
|
76
|
+
reservoir, so the target cannot depend on the channel a path carries. The target
|
|
77
|
+
is the full RGB contribution with equal channel weights; only the final estimator
|
|
78
|
+
keeps the path's channel (`sampleMaterial.wgsl.ts`). A luminance target would
|
|
79
|
+
underweight saturated red and blue light and raise their noise. Equal weights reduce
|
|
80
|
+
that, but a strongly colored region can still converge more slowly in one channel
|
|
81
|
+
than with independent per-channel paths; [sampling](../sampling.md) documents this
|
|
82
|
+
caveat. Single-wavelength previews and non-dispersive renders keep the luminance
|
|
83
|
+
target. WebGL draws one light candidate and has no reservoir.
|
|
84
|
+
|
|
85
|
+
## Short-wavelength IOR limit
|
|
86
|
+
|
|
87
|
+
Cauchy IOR rises quickly at short wavelengths. At strong dispersion scales, violet
|
|
88
|
+
light reaches IORs that reflect or trap much of it, and wide caustics turn yellow.
|
|
89
|
+
`spectrumIorWavelength` therefore eases the refracting wavelength below 500 nm toward
|
|
90
|
+
475 nm, while color keeps the sampled wavelength. The mapping is monotonic and
|
|
91
|
+
continuous, so the gradient has no hard edge.
|
|
92
|
+
|
|
93
|
+
This limit is an artistic choice and not physically based. It narrows the violet end
|
|
94
|
+
of the spectrum, and strong dispersion scales still lose some blue.
|
|
95
|
+
|
|
96
|
+
## Differences from spectral rendering
|
|
97
|
+
|
|
98
|
+
| Area | Spectral rendering | MuTracer |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| Lights | Emission varies with wavelength | RGB, with an implicit broad spectrum; a sodium lamp still disperses into a full rainbow |
|
|
101
|
+
| Materials and textures | Reflectance varies with wavelength, often upsampled from RGB | RGB, so metamerism cannot appear |
|
|
102
|
+
| Media | Absorption and scattering vary with wavelength | Three RGB coefficients |
|
|
103
|
+
| Thin film | Interference is integrated over wavelength | Evaluated at 620, 540 and 450 nm |
|
|
104
|
+
| Refractive index | Often measured curves or Sellmeier equations | Cauchy from IOR and Abbe number, with the short-wavelength limit |
|
|
105
|
+
| Wavelengths per path | Often several, combined with MIS | One per path or photon |
|
|
106
|
+
| Output color | Integrated from the spectrum into the output color space | Fixed clamped sRGB weights, normalized per channel |
|
|
107
|
+
|
|
108
|
+
These differences matter most for narrow-band lights, colored absorption over long
|
|
109
|
+
paths, metamerism and predictive color. Clear glass and crystal under broad lights are
|
|
110
|
+
closer to the spectral result, because their color comes mainly from refraction.
|
|
111
|
+
|
|
112
|
+
Full spectral rendering would change the light, material, texture and medium data
|
|
113
|
+
models, and requires RGB-to-spectrum upsampling in both shader backends and native.
|
|
114
|
+
|
|
115
|
+
## Changing this code
|
|
116
|
+
|
|
117
|
+
- Update WGSL and GLSL together. Both are generated from `spectrum.ts`; caustics are
|
|
118
|
+
WGSL only.
|
|
119
|
+
- `spectralChannel` must be set wherever a path's wavelength is set.
|
|
120
|
+
- `tests/unit/spectrum.test.ts` covers white balance, weight bounds, channel
|
|
121
|
+
distributions and the IOR limit. Check the image result on a real GPU in both
|
|
122
|
+
backends, as described in `AGENTS.md`.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Display upscale
|
|
2
|
+
|
|
3
|
+
`createEasuPass` enlarges a reduced-resolution render to the canvas, and with
|
|
4
|
+
`albedoDetail` it restores surface texture detail from full-resolution color AOVs.
|
|
5
|
+
Usage, costs and limits are in [post-processing](../post-processing.md); the AOV
|
|
6
|
+
side is in [surface color AOVs](./aovs.md). This note explains the algorithm. The
|
|
7
|
+
code is `src/renderer/easu.ts` with `wgsl/easu.wgsl.ts` and
|
|
8
|
+
`wgsl/easuDetail.wgsl.ts`.
|
|
9
|
+
|
|
10
|
+
## Pipeline position
|
|
11
|
+
|
|
12
|
+
The pass is a display post-process: it runs after composition, tone mapping and
|
|
13
|
+
denoising, on display-encoded RGB. A pass can change the image size through
|
|
14
|
+
`outputSize`, so the upscale is ordinary chain state and needs no special case in
|
|
15
|
+
composition, export or denoising. Beauty, its denoising and the AOVs keep their own
|
|
16
|
+
resolutions; only the displayed image is enlarged.
|
|
17
|
+
|
|
18
|
+
An input at the output size is copied, and a larger input is area-averaged, so one
|
|
19
|
+
registration serves both a reduced preview and a full-resolution final render.
|
|
20
|
+
|
|
21
|
+
## EASU
|
|
22
|
+
|
|
23
|
+
The enlargement is AMD FidelityFX FSR 1 EASU, without RCAS sharpening. It estimates
|
|
24
|
+
a local edge direction and filters along it with a 12-tap lobe. FSR expects inputs
|
|
25
|
+
in [0, 1], so extended-range output normalizes the neighborhood only for the
|
|
26
|
+
direction estimate and filters the original values. EASU cannot invent detail that
|
|
27
|
+
the reduced render does not contain.
|
|
28
|
+
|
|
29
|
+
## Detail compensation
|
|
30
|
+
|
|
31
|
+
Texture detail lost at render resolution is still present in the display-resolution
|
|
32
|
+
`diffuseColor` and `specularColor` AOVs. Compensation transfers it:
|
|
33
|
+
|
|
34
|
+
1. **Low guides.** The full-resolution colors are area-averaged over each render
|
|
35
|
+
pixel's exact footprint, including noninteger scales, so the low guides match
|
|
36
|
+
what beauty integrated. No second AOV allocation is needed.
|
|
37
|
+
2. **Local model.** For each render pixel, a guided-filter regression over a 3×3
|
|
38
|
+
window fits scene-linear radiance as `slope × color + intercept` per channel.
|
|
39
|
+
Diffuse shading follows color (slope), while highlights and reflections do not
|
|
40
|
+
(intercept). Flat colors give a slope near zero, so they are left alone.
|
|
41
|
+
3. **Upsampling.** The low guides are enlarged with exactly the same EASU taps and
|
|
42
|
+
weights as beauty, so beauty and guides share one footprint.
|
|
43
|
+
4. **Ratio.** At each output pixel, the full-resolution color replaces the
|
|
44
|
+
upsampled one inside the model: `(slope × hi + intercept) / (slope × low +
|
|
45
|
+
intercept)`, clamped per channel to [0.7, 1.43]. Without a valid model it falls
|
|
46
|
+
back to the plain color ratio `hi / low`.
|
|
47
|
+
5. **Display transform.** The ratio is scene-linear, but the image is tone-mapped.
|
|
48
|
+
A lookup table built from the current tone mapping and grading maps displayed
|
|
49
|
+
RGB back to scene-linear per channel, applies the ratio and maps it forward, so
|
|
50
|
+
curve shoulders and toes respond as the tone mapper would. Only the change is
|
|
51
|
+
added to the displayed value, which keeps it exact where the ratio is 1.
|
|
52
|
+
|
|
53
|
+
Compensation is skipped, leaving EASU alone, where it would be wrong:
|
|
54
|
+
|
|
55
|
+
- AOV validity or coverage below 0.95 (transmission, cutouts, background,
|
|
56
|
+
unsupported materials);
|
|
57
|
+
- silhouettes, detected from a change in hit coverage or a break in the planarity
|
|
58
|
+
of inverse depth (which is linear in screen space on any plane, so sloped
|
|
59
|
+
surfaces are not silhouettes);
|
|
60
|
+
- color below 10⁻³, treated as black.
|
|
61
|
+
|
|
62
|
+
Clipped highlights cannot be recovered: the inverse tone mapping has no
|
|
63
|
+
information above the display maximum.
|
|
64
|
+
|
|
65
|
+
## Retained alternatives
|
|
66
|
+
|
|
67
|
+
`createEasuPassImpl` keeps three internal variants for comparisons:
|
|
68
|
+
|
|
69
|
+
- **Plain color ratio.** Scaling all displayed radiance by `hi / low` also scaled
|
|
70
|
+
highlights and other light that does not follow color, which limited the usable
|
|
71
|
+
ratio range. The guided model widened it to the current default.
|
|
72
|
+
- **Separate lobes.** Diffuse and specular ratios weighted by lobe shares estimated
|
|
73
|
+
from the low colors; beauty has no separate lobes to weight them exactly.
|
|
74
|
+
- **Silhouette reconstruction.** Front and back colors from depth-matched
|
|
75
|
+
low-resolution neighbors, mixed by full-resolution coverage. It sharpens
|
|
76
|
+
backgrounds but loses detail on thin structures, glass and reflections
|
|
77
|
+
compared with EASU alone.
|
|
78
|
+
|
|
79
|
+
Ratios were first applied to encoded display RGB, which over-darkened dark decals;
|
|
80
|
+
applying them in linear and then through the display transform let the clamp range
|
|
81
|
+
grow. The public tuning options were removed; `EASU_DETAIL` holds the shared
|
|
82
|
+
defaults, which native also uses.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# OpenPBR implementation
|
|
2
|
+
|
|
3
|
+
`OpenPBRMaterial` follows the OpenPBR Surface specification with a compact GPU
|
|
4
|
+
BSDF. Parameters, units and user-facing limits are in the
|
|
5
|
+
[materials guide](../materials.md); this note describes how the implementation
|
|
6
|
+
is organized and the rules for changing it.
|
|
7
|
+
|
|
8
|
+
## Data flow
|
|
9
|
+
|
|
10
|
+
- **Layout table.** `materialLayoutSchema.ts` lists every material buffer row
|
|
11
|
+
(one `vec4` each) with its source field and type. The same table generates the
|
|
12
|
+
TypeScript packing, the WGSL struct (`materialBufferWgsl`) and the GLSL row
|
|
13
|
+
constants (`materialRowsGlsl`), so the three cannot drift. Reserved rows keep
|
|
14
|
+
their legacy contents; reusing one is an intentional migration.
|
|
15
|
+
- **Texture slots.** `materialTextureSlots.ts` lists every map with its target
|
|
16
|
+
parameters, channels, color space, shader define and feature bit. Slot order is
|
|
17
|
+
the atlas index contract. Public map names live in the scene layer
|
|
18
|
+
(`materialTextureNames.ts`).
|
|
19
|
+
- **Feature specialization.** Features that a scene does not use, such as
|
|
20
|
+
anisotropy directions or coat normals, are compiled out by generating different
|
|
21
|
+
WGSL source, not by patching strings after generation.
|
|
22
|
+
|
|
23
|
+
## BSDF
|
|
24
|
+
|
|
25
|
+
The BSDF (`openPbrBsdf.wgsl.ts` and its GLSL counterpart) follows the
|
|
26
|
+
prepare/eval/sample/pdf organization of Adobe's
|
|
27
|
+
[openpbr-bsdf](https://github.com/adobe/openpbr-bsdf) and the
|
|
28
|
+
[OpenPBR viewer](https://github.com/portsmouth/OpenPBR-viewer):
|
|
29
|
+
|
|
30
|
+
- `openpbr_prepare` resolves the layered material once per path vertex. NEE, BSDF
|
|
31
|
+
sampling and MIS reuse the result, which made WebGPU samples about 11–15% faster
|
|
32
|
+
than preparing per evaluation.
|
|
33
|
+
- The lobes are fuzz, coat, metal, dielectric specular, transmission, diffuse and
|
|
34
|
+
subsurface. Their weights and probabilities are stored as arrays indexed by lobe,
|
|
35
|
+
rather than one variable per lobe.
|
|
36
|
+
- Metal uses the F82-tint Fresnel; specular anisotropy uses the specification's
|
|
37
|
+
roughness mapping. The coat roughens the base, changes the IOR ratio below it,
|
|
38
|
+
absorbs, and darkens through internal reflection (`coatDarkening`, default 1).
|
|
39
|
+
- Fuzz uses an analytic approximation. The specification's LTC fuzz (Zeltner et al.
|
|
40
|
+
2022) is not implemented.
|
|
41
|
+
|
|
42
|
+
## Energy compensation
|
|
43
|
+
|
|
44
|
+
GGX loses energy to single scattering as roughness grows. The renderer uses Adobe's
|
|
45
|
+
tables for opaque dielectric base coupling, ideal-metal multiple scattering and
|
|
46
|
+
solid ideal-dielectric reflection and transmission (`openPbrEnergyLut.ts`). Before
|
|
47
|
+
these tables, rough glass lost 5–36% and rough metal 1.5–20% of its energy in white
|
|
48
|
+
furnace tests.
|
|
49
|
+
|
|
50
|
+
The tables are stored as 8-bit samples normalized per row, with 16-bit row bounds,
|
|
51
|
+
differences between consecutive rows and exact 16-bit averages. This keeps the
|
|
52
|
+
module about 44 KB gzipped while adding the multiple-scattering tables. On the GPU
|
|
53
|
+
they occupy about 280 KB.
|
|
54
|
+
|
|
55
|
+
Thin-walled rough transmission has no compensation, as in the reference.
|
|
56
|
+
|
|
57
|
+
## Import decisions
|
|
58
|
+
|
|
59
|
+
- Three.js and glTF clearcoat import with `coatDarkening = 0`, because glTF's
|
|
60
|
+
clearcoat does not darken the base. `userData.mutracerOpenPBR` overrides it.
|
|
61
|
+
- Specification names (`specularRoughnessAnisotropy`, `coatRoughnessAnisotropy`,
|
|
62
|
+
`subsurfaceScatterAnisotropy`, `geometryOpacity`, `geometryThinWalled`) are the
|
|
63
|
+
primary names; older names remain deprecated aliases.
|
|
64
|
+
- glTF anisotropy is converted after texture sampling, selected by
|
|
65
|
+
`specularAnisotropyModel: 'gltf'`.
|
|
66
|
+
|
|
67
|
+
## Not implemented
|
|
68
|
+
|
|
69
|
+
- Statistical mixing of two materials.
|
|
70
|
+
- LTC fuzz.
|
|
71
|
+
- Resampled direct lighting on WebGL. It waits for the cause of a small diffuse
|
|
72
|
+
residual with 8 or 16 WebGPU light candidates; the default of 4 is unaffected.
|
|
73
|
+
|
|
74
|
+
## Known accuracy limits
|
|
75
|
+
|
|
76
|
+
- Rough solid glass remains slightly dark in white furnace tests, under 1% without
|
|
77
|
+
a coat and under 1.5% with one at roughness 0.3. With compensation off it is
|
|
78
|
+
about 2 percentage points darker than the reference, so the remaining loss is in
|
|
79
|
+
the transmission integration, not the tables.
|
|
80
|
+
- Strongly tilted coat normals lose about 5% of their energy, because lobes are
|
|
81
|
+
clipped to the geometric hemisphere. The materials guide documents this.
|
|
82
|
+
- Strong anisotropic metal can retain a small energy error, because the tables use
|
|
83
|
+
isotropic roughness.
|
|
84
|
+
- A coat with a higher IOR than the base can produce spurious total internal
|
|
85
|
+
reflection in the thin film, as in the reference.
|
|
86
|
+
|
|
87
|
+
## Acceptance rules
|
|
88
|
+
|
|
89
|
+
These maintainer rules apply to material and BSDF changes:
|
|
90
|
+
|
|
91
|
+
- A white furnace may deviate from 1 by at most 0.5%, and a coated material from
|
|
92
|
+
its uncoated control by at most 0.5%.
|
|
93
|
+
- Re-encoding the tables may change any material on either backend by at most 0.1%.
|
|
94
|
+
- Measure cold shader compilation with caches invalidated; increases above 10% need
|
|
95
|
+
a maintainer decision.
|
|
96
|
+
- Sparse pixel differences of at most one half-float step from compiler
|
|
97
|
+
reassociation are acceptable.
|
|
98
|
+
- Refactors keep default materials (base weight 1, no coat, isotropic, specular
|
|
99
|
+
color 1) pixel-identical on both backends.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# PBRT import mapping
|
|
2
|
+
|
|
3
|
+
This contributor note describes the viewer/tool importer. Usage and limits are
|
|
4
|
+
in [the tool guide](../../tools/pbrt/README.md).
|
|
5
|
+
|
|
6
|
+
## Coordinates and state
|
|
7
|
+
|
|
8
|
+
The reference is `mmp/pbrt-v4@b0bdf461ba5dd6504b70ebf0932acc0fe7aa744f`.
|
|
9
|
+
PBRT's camera looks along local +Z. With `M = diag(1,1,-1,1)`, geometry uses
|
|
10
|
+
`M * objectToWorld` and the Three camera uses `M * cameraToWorld * M`.
|
|
11
|
+
The world reflection is baked into geometry so emissive triangles have consistent
|
|
12
|
+
world-space winding and normals. The winding changes when the baked transform
|
|
13
|
+
changes handedness, XOR `ReverseOrientation`; explicit normals only change sign
|
|
14
|
+
for `ReverseOrientation`. Triangle winding is then face-forwarded to shading
|
|
15
|
+
normals, matching PBRT meshes with authored N. Instances retain shared geometry
|
|
16
|
+
and use `M * T * M`.
|
|
17
|
+
Loop shapes refine the control mesh and push vertices to the limit surface;
|
|
18
|
+
area-weighted normals approximate the reference limit-surface tangents.
|
|
19
|
+
A reflection is absorbed into a geometry variant for negative instance transforms.
|
|
20
|
+
|
|
21
|
+
`LookAt` sets world-to-camera, so its inverse is captured at `Camera`. `WorldBegin`
|
|
22
|
+
resets the object transform. Include filenames and all asset filenames resolve
|
|
23
|
+
against the main scene directory, as `SetSearchDirectory`/`ResolveFilename` do.
|
|
24
|
+
`Import` inherits graphics state but restores it afterward; definitions and scene
|
|
25
|
+
objects remain. Deprecated transform blocks follow PBRT-v4's attribute-block
|
|
26
|
+
rewrite. Only the start transform is retained for animated scenes.
|
|
27
|
+
|
|
28
|
+
## Camera and microfacets
|
|
29
|
+
|
|
30
|
+
For aspect `a = width/height`, the vertical field of view is `fov` when `a >= 1`,
|
|
31
|
+
otherwise `2 atan(tan(fov/2)/a)`. Lens conversion uses a 24 mm sensor height:
|
|
32
|
+
`focalLength = .024/(2 tan(verticalFov/2))` metres and
|
|
33
|
+
`fStop = focalLength/(2 lensRadius)` for metre scene units.
|
|
34
|
+
The focus distance stays in scene units. The linear exposure multiplier is
|
|
35
|
+
`ISO/100 * (shutterClose-shutterOpen)`. Film exposuretime is not a PBRT-v4
|
|
36
|
+
parameter and is warned and ignored, as is whitebalance. Unsupported sensors
|
|
37
|
+
produce a separate warning.
|
|
38
|
+
|
|
39
|
+
The pinned `TrowbridgeReitzDistribution::RoughnessToAlpha` returns `sqrt(r)`.
|
|
40
|
+
Since OpenPBR uses `alpha = roughness²`, the imported roughness is `r^(1/4)` with
|
|
41
|
+
remapping and `sqrt(r)` without it. For anisotropic alphas, the scalar roughness
|
|
42
|
+
is `((alphaU²+alphaV²)/2)^(1/4)` and anisotropy is
|
|
43
|
+
`1-min(alphaU,alphaV)/max(alphaU,alphaV)` (zero for two zero axes). This inverts
|
|
44
|
+
OpenPBR's RMS-preserving formula for both base and coat. The larger alpha is
|
|
45
|
+
assigned to the tangent axis; rotation is π/2 when v is larger, so u stays dpdu.
|
|
46
|
+
Anisotropic meshes also carry UV-derived tangents for the zero-rotation path.
|
|
47
|
+
|
|
48
|
+
## Colors and light units
|
|
49
|
+
|
|
50
|
+
RGB inputs are linear sRGB. RGB illumination preserves the RGB multiplier;
|
|
51
|
+
PBRT normalizes the illuminant separately in `SpectrumToPhotometric`. The pinned
|
|
52
|
+
implementation does **not** multiply this integral by 683. The Film's CIE sensor
|
|
53
|
+
integrates the emitted spectrum; this cancels the illuminant normalization for
|
|
54
|
+
white light. Consequently a point light's RGB intensity maps directly to the
|
|
55
|
+
zero-radius SphereLight intensity, and an area light's RGB radiance maps to mesh
|
|
56
|
+
emission. Spot cone angles are half angles and use cosine smoothstep on both sides.
|
|
57
|
+
Distant intensity is irradiance facing the light. Sphere emitters retain meshes:
|
|
58
|
+
MuTracer analytic sphere lights currently do not supply visible primary-ray
|
|
59
|
+
emission, and adding a second emissive sampler would count the source twice.
|
|
60
|
+
|
|
61
|
+
Power multiplies point intensity by `power/(4π)`. For a spot it multiplies by
|
|
62
|
+
`power/[2π(1-(cos(inner)+cos(outer))/2)]`. Area-light power divides by
|
|
63
|
+
`π * area * (twosided ? 2 : 1)`. Image emission also requires texture-average
|
|
64
|
+
normalization; that case remains an approximation. Constant environment
|
|
65
|
+
illuminance multiplies radiance by `illuminance/π`. Image illuminance follows
|
|
66
|
+
the pinned renderer's `2π/N * sum(Y(pixel)*max(z,0))` normalization in light space.
|
|
67
|
+
|
|
68
|
+
Named optical data and CIE/D65 tables come from the pinned Apache-2.0 source.
|
|
69
|
+
Conductor normal and edge reflectances integrate Fresnel at cosines 1 and 1/7
|
|
70
|
+
under D65, then convert XYZ to linear sRGB. OpenPBR takes an F82 **tint**,
|
|
71
|
+
so the edge value is divided by `F0+(1-F0)*(6/7)^5` and limited to [0,1]. Glass uses interpolated eta at
|
|
72
|
+
587.56 nm and Abbe `(etaD-1)/(etaF-etaC)`, at 486.13 and 656.27 nm.
|
|
73
|
+
Blackbody emission is normalized to unit luminance before light scaling.
|
|
74
|
+
An RGB renderer and PBRT's spectral renderer can retain material-dependent
|
|
75
|
+
biases; comparisons report them without changing either renderer's algorithms.
|
|
76
|
+
Coated conductor inputs keep `conductor.*` substrate parameters separate from
|
|
77
|
+
`interface.*` coat parameters. Both roughness layers use the same remap rule;
|
|
78
|
+
optical constants are read as curves from named data or SPD files before Fresnel
|
|
79
|
+
integration. Coat IOR and anisotropy use the existing OpenPBR metadata fields.
|
|
80
|
+
|
|
81
|
+
For coefficient-based subsurface materials, each RGB extinction mean free path is
|
|
82
|
+
`1 / (scale * (sigma_a + sigma_s))`. The largest channel becomes the OpenPBR
|
|
83
|
+
radius and channel ratios become radius scales. Single-scattering albedo
|
|
84
|
+
`sigma_s / (sigma_a + sigma_s)` is converted to the artist-facing subsurface color
|
|
85
|
+
by inverting the existing material packer's mapping. Authored diffuse reflectance
|
|
86
|
+
is already an effective scattering color. These mappings preserve the RGB medium
|
|
87
|
+
coefficients but do not reproduce PBRT's spectral diffusion model.
|
|
88
|
+
Interior homogeneous media encode total extinction, not absorption, in
|
|
89
|
+
transmission color: choose depth `d=1/max(1,max(sigma_t))`, set color
|
|
90
|
+
`exp(-sigma_t*d)` and scatter color `sigma_s/sigma_t`, with scaled coefficients.
|
|
91
|
+
This preserves the existing packer's coefficients without hitting its color floor.
|
|
92
|
+
`MediumInterface` orders inside then outside. The geometric normal points toward
|
|
93
|
+
outside, after ReverseOrientation and handedness. The importer rejects scenes
|
|
94
|
+
with a camera medium. If only an outside medium remains, conversion flips
|
|
95
|
+
winding and normals together and encodes it as the material interior. Two
|
|
96
|
+
media cannot be represented: conversion warns and uses inside only.
|
|
97
|
+
Material variants include both names to avoid sharing different boundaries.
|
|
98
|
+
|
|
99
|
+
The extra medium-side reversal reciprocates thick dielectric IOR: PBRT's
|
|
100
|
+
DielectricBxDF exchanges eta across its final normal. ReverseOrientation and
|
|
101
|
+
coordinate handedness already affect both normals and do not independently
|
|
102
|
+
reciprocate IOR. ThinDielectricBxDF uses AbsCosTheta and keeps eta unchanged.
|
|
103
|
+
Base specular IOR below one survives Three conversion and material packing;
|
|
104
|
+
both backends use the ratio for Fresnel, total internal reflection and refraction.
|
|
105
|
+
Coat IOR is clamped to at least one and the coat is exterior-only, so reversed
|
|
106
|
+
coats and coat IOR below one receive an ior-orientation warning and are excluded
|
|
107
|
+
from strict comparison. Reciprocal spectral dispersion retains the original
|
|
108
|
+
Abbe number, but a reciprocal Cauchy curve is not itself the same Cauchy fit;
|
|
109
|
+
this receives an ior-dispersion approximation warning and comparison exclusion.
|
|
110
|
+
|
|
111
|
+
Ordinary PBRT surfaces accept primary back-face hits. One-sided area emission
|
|
112
|
+
uses FrontSide because MuTracer couples primary visibility and emission sidedness;
|
|
113
|
+
its missing back-side surface visibility is warned about.
|
|
114
|
+
|
|
115
|
+
PBRT image textures evaluate `(s,1-t)`. Decoded images use top-down rows and
|
|
116
|
+
Three textures set `flipY=true`. Infinite lights use the equal-area square map,
|
|
117
|
+
reprojected to world-space latitude/longitude. The direct importer uses nearest
|
|
118
|
+
source lookup to match ImageInfiniteLight. Each target texel averages 4×4
|
|
119
|
+
jittered samples uniform in azimuth and cos(theta), then per-channel spherical
|
|
120
|
+
integrals correct residual quadrature energy error. Source texels use area 4π/N;
|
|
121
|
+
target bands use exact cosine differences. This preserves small bright features'
|
|
122
|
+
total energy while approximating their subpixel distribution. The existing glTF
|
|
123
|
+
metadata adapter retains its previous bilinear reprojection.
|
|
124
|
+
|
|
125
|
+
Material displacement uses forward UV finite differences with PBRT's `.0005`
|
|
126
|
+
fallback step, including scalar texture scale and UV repeat. The image-row
|
|
127
|
+
v derivative changes sign for `(s,1-t)`. The result is a tangent normal
|
|
128
|
+
`normalize(-dh/du,-dh/dv,1)`, never a geometric height field. This static bake
|
|
129
|
+
assumes unit tangents and omits footprint-dependent steps and curvature terms;
|
|
130
|
+
it is warned and excluded from strict comparison. Only shape displacement uses
|
|
131
|
+
the height-field mapping. In the pinned `interaction.cpp`, NormalMap and BumpMap
|
|
132
|
+
are alternatives (`if/else`): normalmap takes precedence when both exist.
|
|
133
|
+
|
|
134
|
+
## Comparison and memory
|
|
135
|
+
|
|
136
|
+
Ordinary byte color maps retain their original data and declared color space;
|
|
137
|
+
unmodified linear HDR maps also share decoded pixel data. Scale graphs carry
|
|
138
|
+
separate multipliers. Scalar and transformed maps retain
|
|
139
|
+
floating-point values. Rectangular/non-power-of-two height fields are resampled
|
|
140
|
+
to the existing displacement layout, with a warning.
|
|
141
|
+
|
|
142
|
+
The comparison sets PBRT's pixel filter to box with radius 0.5 to match MuTracer's
|
|
143
|
+
uniform pixel jitter. It overrides spp and output resolution, removes Film crop
|
|
144
|
+
windows and pixel bounds, preserves maxdepth,
|
|
145
|
+
sets an opaque black background when no environment exists, removes Film sensor exposure from the reference HDR and never tone maps numerical
|
|
146
|
+
inputs. AOV material IDs identify approximate surface regions. This primary-hit
|
|
147
|
+
mask does not isolate indirect paths that touch approximate materials. PBRT uses
|
|
148
|
+
seeds 0/1; MuTracer uses disjoint sample blocks starting at 0/N with the same Sobol
|
|
149
|
+
scramble. Their difference gives a diagnostic noise estimate, not independent
|
|
150
|
+
Monte Carlo replicas or statistical proof of equivalence.
|
|
151
|
+
Whole-frame RMSE retains every comparable pixel and its noise margin. Regional
|
|
152
|
+
material/tile tests exclude discontinuities in object, instance or material IDs,
|
|
153
|
+
dilated by one pixel. Their statistic is absolute channel mean bias / standard
|
|
154
|
+
error, with threshold 6. Standard error is sqrt(sum of per-pixel replica-difference
|
|
155
|
+
variances) / pixel count; squaring a region-sum difference instead gives an
|
|
156
|
+
unstable single observation. Whole-frame and regional statuses are separate.
|
|
157
|
+
Each MuTracer run uses a fresh Chrome process to avoid retaining both scenes' caches
|
|
158
|
+
and allocations during memory measurement.
|
|
159
|
+
|
|
160
|
+
Text and gzip Includes are decoded by statements to avoid the single-string size
|
|
161
|
+
limit. The viewer parses them and PLY data in a Worker. Inline P/N/UV/index
|
|
162
|
+
arrays become
|
|
163
|
+
transferable typed views before leaving the Worker; statement locations share
|
|
164
|
+
the same parameter objects. Binary assets are prefetched six at a time before
|
|
165
|
+
conversion; progress sums completed and in-flight bytes. The download preflight
|
|
166
|
+
uses unique encoded input sizes and an 8x expansion estimate against an 8 GiB
|
|
167
|
+
working budget. This estimate is deliberately conservative and cannot predict
|
|
168
|
+
total process/GPU memory or prevent every browser allocation failure.
|