@meimu/mutracer 0.1.5 → 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/LICENSES/Classroom-CC0.txt +121 -0
- package/README.md +10 -7
- package/THIRD_PARTY_NOTICES.md +13 -8
- package/dist/assets/bvh.worker.js +1 -1
- package/dist/mutracer.umd.js +12316 -9228
- package/docs/api.md +232 -21
- package/docs/caustics.md +80 -0
- package/docs/denoising.md +30 -15
- package/docs/materials.md +6 -5
- package/docs/performance.md +5 -2
- package/docs/progressive-rendering.md +73 -1
- package/docs/technical/continuous-spectrum.md +93 -0
- package/docs/threejs.md +14 -5
- package/docs/updates.md +46 -2
- package/docs/viewer-checklist.md +65 -0
- package/docs/viewer.md +15 -8
- package/lib/Display.d.ts +13 -2
- package/lib/Display.js +28 -7
- package/lib/Display.js.map +1 -1
- package/lib/Engine.d.ts +4 -0
- package/lib/Engine.js +99 -37
- package/lib/Engine.js.map +1 -1
- package/lib/Render.d.ts +98 -15
- package/lib/Render.js +275 -27
- package/lib/Render.js.map +1 -1
- package/lib/RenderLoop.d.ts +11 -1
- package/lib/RenderLoop.js +120 -15
- package/lib/RenderLoop.js.map +1 -1
- package/lib/main.d.ts +6 -3
- package/lib/main.js +1 -0
- package/lib/main.js.map +1 -1
- package/lib/math/access.d.ts +4 -0
- package/lib/math/access.js +10 -0
- package/lib/math/access.js.map +1 -0
- package/lib/math/mat3.d.ts +4 -0
- package/lib/math/mat3.js +54 -0
- package/lib/math/mat3.js.map +1 -0
- package/lib/math/mat4.d.ts +19 -0
- package/lib/math/mat4.js +413 -0
- package/lib/math/mat4.js.map +1 -0
- package/lib/math/storage.d.ts +6 -0
- package/lib/math/storage.js +22 -0
- package/lib/math/storage.js.map +1 -0
- package/lib/math/types.d.ts +3 -0
- package/lib/math/types.js +2 -0
- package/lib/math/types.js.map +1 -0
- package/lib/math/vec2.d.ts +13 -0
- package/lib/math/vec2.js +52 -0
- package/lib/math/vec2.js.map +1 -0
- package/lib/math/vec3.d.ts +23 -0
- package/lib/math/vec3.js +139 -0
- package/lib/math/vec3.js.map +1 -0
- package/lib/math.d.ts +5 -17
- package/lib/math.js +5 -55
- package/lib/math.js.map +1 -1
- package/lib/oidn.d.ts +1 -1
- package/lib/oidn.js +4 -2
- package/lib/oidn.js.map +1 -1
- package/lib/oidnBundledWeights.cdn.d.ts +2 -2
- package/lib/renderer/AovPrimitiveCache.d.ts +10 -0
- package/lib/renderer/AovPrimitiveCache.js +48 -0
- package/lib/renderer/AovPrimitiveCache.js.map +1 -0
- package/lib/renderer/Box3.d.ts +5 -0
- package/lib/renderer/Box3.js +9 -0
- package/lib/renderer/Box3.js.map +1 -0
- package/lib/renderer/GPUTraceQueue.d.ts +11 -0
- package/lib/renderer/GPUTraceQueue.js +33 -0
- package/lib/renderer/GPUTraceQueue.js.map +1 -0
- package/lib/renderer/MaterialData.d.ts +15 -0
- package/lib/renderer/MaterialData.js +61 -0
- package/lib/renderer/MaterialData.js.map +1 -0
- package/lib/renderer/MaterialTable.d.ts +11 -98
- package/lib/renderer/MaterialTable.js +34 -412
- package/lib/renderer/MaterialTable.js.map +1 -1
- package/lib/renderer/RenderingPipeline.d.ts +36 -13
- package/lib/renderer/RenderingPipeline.js +1 -17
- package/lib/renderer/RenderingPipeline.js.map +1 -1
- package/lib/renderer/TileRender.d.ts +0 -1
- package/lib/renderer/TileRender.js +14 -1
- package/lib/renderer/TileRender.js.map +1 -1
- package/lib/renderer/WGPUAov.d.ts +39 -0
- package/lib/renderer/WGPUAov.js +239 -0
- package/lib/renderer/WGPUAov.js.map +1 -0
- package/lib/renderer/WGPUBindlessMaterialData.d.ts +17 -0
- package/lib/renderer/WGPUBindlessMaterialData.js +48 -0
- package/lib/renderer/WGPUBindlessMaterialData.js.map +1 -0
- package/lib/renderer/WGPUBindlessTextures.d.ts +47 -0
- package/lib/renderer/WGPUBindlessTextures.js +180 -0
- package/lib/renderer/WGPUBindlessTextures.js.map +1 -0
- package/lib/renderer/WGPUBloomPass.js +17 -97
- package/lib/renderer/WGPUBloomPass.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/WGPUComputePass.d.ts +1 -1
- package/lib/renderer/WGPUComputePass.js.map +1 -1
- package/lib/renderer/WGPUEnvMapDistribution.d.ts +12 -0
- package/lib/renderer/WGPUEnvMapDistribution.js +150 -0
- package/lib/renderer/WGPUEnvMapDistribution.js.map +1 -0
- package/lib/renderer/WGPUFullQuadPass.js +10 -9
- package/lib/renderer/WGPUFullQuadPass.js.map +1 -1
- package/lib/renderer/WGPUJNLMDenoiser.d.ts +1 -20
- package/lib/renderer/WGPUJNLMDenoiser.js +4 -267
- package/lib/renderer/WGPUJNLMDenoiser.js.map +1 -1
- 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 +132 -29
- package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
- package/lib/renderer/WGPURayTracePass.d.ts +83 -56
- package/lib/renderer/WGPURayTracePass.js +884 -837
- package/lib/renderer/WGPURayTracePass.js.map +1 -1
- package/lib/renderer/WGPURenderingPipeline.d.ts +5 -3
- package/lib/renderer/WGPURenderingPipeline.js +297 -82
- package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
- package/lib/renderer/WGPUShaderCache.d.ts +2 -2
- package/lib/renderer/WGPUShaderCache.js +10 -5
- package/lib/renderer/WGPUShaderCache.js.map +1 -1
- package/lib/renderer/WGPUShaderCapabilities.d.ts +10 -0
- package/lib/renderer/WGPUShaderCapabilities.js +54 -0
- package/lib/renderer/WGPUShaderCapabilities.js.map +1 -0
- package/lib/renderer/WGPUSkyBaker.d.ts +13 -0
- package/lib/renderer/WGPUSkyBaker.js +85 -0
- package/lib/renderer/WGPUSkyBaker.js.map +1 -0
- package/lib/renderer/WebGLAov.d.ts +41 -0
- package/lib/renderer/WebGLAov.js +106 -0
- package/lib/renderer/WebGLAov.js.map +1 -0
- package/lib/renderer/WebGLFullQuadPass.d.ts +7 -4
- package/lib/renderer/WebGLFullQuadPass.js +22 -2
- package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
- package/lib/renderer/WebGLJNLMDenoiser.d.ts +1 -1
- package/lib/renderer/WebGLJNLMDenoiser.js +83 -74
- package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
- package/lib/renderer/WebGLRayTraceOutputPass.js +7 -4
- package/lib/renderer/WebGLRayTraceOutputPass.js.map +1 -1
- package/lib/renderer/WebGLRayTracePass.d.ts +18 -3
- package/lib/renderer/WebGLRayTracePass.js +121 -9
- package/lib/renderer/WebGLRayTracePass.js.map +1 -1
- package/lib/renderer/WebGLRenderingPipeline.js +126 -22
- package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLSkyBaker.d.ts +39 -0
- package/lib/renderer/WebGLSkyBaker.js +422 -0
- package/lib/renderer/WebGLSkyBaker.js.map +1 -0
- package/lib/renderer/WebGLSkySource.d.ts +9 -0
- package/lib/renderer/WebGLSkySource.js +28 -0
- package/lib/renderer/WebGLSkySource.js.map +1 -0
- package/lib/renderer/accumulationTarget.d.ts +6 -0
- package/lib/renderer/accumulationTarget.js.map +1 -1
- package/lib/renderer/aov.d.ts +42 -0
- package/lib/renderer/aov.js +50 -0
- package/lib/renderer/aov.js.map +1 -0
- package/lib/renderer/aovDisplay.d.ts +14 -0
- package/lib/renderer/aovDisplay.js +32 -0
- package/lib/renderer/aovDisplay.js.map +1 -0
- package/lib/renderer/aovScene.d.ts +21 -0
- package/lib/renderer/aovScene.js +139 -0
- package/lib/renderer/aovScene.js.map +1 -0
- package/lib/renderer/binnedSahBvh.js +2 -1
- package/lib/renderer/binnedSahBvh.js.map +1 -1
- package/lib/renderer/bvhAccel.d.ts +20 -10
- package/lib/renderer/bvhAccel.js +168 -58
- package/lib/renderer/bvhAccel.js.map +1 -1
- package/lib/renderer/bvhWorkerBuild.d.ts +1 -0
- package/lib/renderer/cameraSnapshot.js +2 -1
- package/lib/renderer/cameraSnapshot.js.map +1 -1
- package/lib/renderer/cameraUniform.d.ts +2 -0
- package/lib/renderer/cameraUniform.js +12 -0
- package/lib/renderer/cameraUniform.js.map +1 -0
- 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/committedScene.js +4 -0
- package/lib/renderer/committedScene.js.map +1 -1
- package/lib/renderer/denoiser.d.ts +3 -11
- package/lib/renderer/denoiser.js.map +1 -1
- package/lib/renderer/depthQuery.js +4 -1
- package/lib/renderer/depthQuery.js.map +1 -1
- package/lib/renderer/displacementPreparation.d.ts +11 -0
- package/lib/renderer/displacementPreparation.js +351 -0
- package/lib/renderer/displacementPreparation.js.map +1 -0
- package/lib/renderer/displacementRange.d.ts +1 -0
- package/lib/renderer/displacementRange.js +9 -0
- package/lib/renderer/displacementRange.js.map +1 -0
- package/lib/renderer/displayParityDiagnostics.d.ts +11 -0
- package/lib/renderer/displayParityDiagnostics.js +2 -0
- package/lib/renderer/displayParityDiagnostics.js.map +1 -0
- package/lib/renderer/envMapCreation.d.ts +9 -8
- package/lib/renderer/envMapCreation.js +36 -12
- package/lib/renderer/envMapCreation.js.map +1 -1
- package/lib/renderer/envMapDistribution.d.ts +12 -2
- package/lib/renderer/envMapDistribution.js +43 -34
- package/lib/renderer/envMapDistribution.js.map +1 -1
- package/lib/renderer/geometryBvhBounds.d.ts +4 -0
- package/lib/renderer/geometryBvhBounds.js +82 -0
- package/lib/renderer/geometryBvhBounds.js.map +1 -0
- package/lib/renderer/geometryUpdateState.d.ts +32 -0
- package/lib/renderer/geometryUpdateState.js +2 -0
- package/lib/renderer/geometryUpdateState.js.map +1 -0
- package/lib/renderer/geometryUpdates.d.ts +17 -9
- package/lib/renderer/geometryUpdates.js +92 -33
- package/lib/renderer/geometryUpdates.js.map +1 -1
- package/lib/renderer/glsl/aovDisplay.frag.d.ts +3 -0
- package/lib/renderer/glsl/aovDisplay.frag.js +54 -0
- package/lib/renderer/glsl/aovDisplay.frag.js.map +1 -0
- package/lib/renderer/glsl/aovReflectance.glsl.d.ts +2 -0
- package/lib/renderer/glsl/aovReflectance.glsl.js +87 -0
- package/lib/renderer/glsl/aovReflectance.glsl.js.map +1 -0
- package/lib/renderer/glsl/aovReflectanceSamples.glsl.d.ts +2 -0
- package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +135 -0
- package/lib/renderer/glsl/aovReflectanceSamples.glsl.js.map +1 -0
- package/lib/renderer/glsl/aovTrace.frag.d.ts +2 -0
- package/lib/renderer/glsl/aovTrace.frag.js +121 -0
- package/lib/renderer/glsl/aovTrace.frag.js.map +1 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +12 -12
- 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 -67
- package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/intersect.glsl.js +432 -434
- 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 +160 -157
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +802 -802
- 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 +72 -67
- 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 +143 -120
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +21 -18
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampling.glsl.js +91 -94
- 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 +12 -12
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js.map +1 -1
- package/lib/renderer/glsl/depthQuery.frag.js +7 -7
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +17 -9
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js.map +1 -1
- package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
- package/lib/renderer/glsl/rayTrace.frag.js +271 -248
- package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/shadowCatcher.frag.js +37 -32
- package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
- package/lib/renderer/glsl/webglPipeline.frag.js +65 -60
- package/lib/renderer/glsl/webglPipeline.frag.js.map +1 -1
- package/lib/renderer/lightConstants.d.ts +10 -0
- package/lib/renderer/lightConstants.js +11 -0
- package/lib/renderer/lightConstants.js.map +1 -0
- package/lib/renderer/lightCore.d.ts +12 -0
- package/lib/renderer/lightCore.js +13 -0
- package/lib/renderer/lightCore.js.map +1 -0
- package/lib/renderer/lightSampling.d.ts +22 -18
- package/lib/renderer/lightSampling.js +135 -62
- package/lib/renderer/lightSampling.js.map +1 -1
- package/lib/renderer/lightsData.d.ts +21 -0
- package/lib/renderer/lightsData.js +192 -0
- package/lib/renderer/lightsData.js.map +1 -0
- package/lib/renderer/lightsUtil.d.ts +3 -26
- package/lib/renderer/lightsUtil.js +3 -153
- package/lib/renderer/lightsUtil.js.map +1 -1
- package/lib/renderer/materialBufferData.d.ts +70 -0
- package/lib/renderer/materialBufferData.js +2 -0
- package/lib/renderer/materialBufferData.js.map +1 -0
- package/lib/renderer/materialConstants.d.ts +11 -0
- package/lib/renderer/materialConstants.js +11 -0
- package/lib/renderer/materialConstants.js.map +1 -1
- package/lib/renderer/materialCore.d.ts +8 -0
- package/lib/renderer/materialCore.js +9 -0
- package/lib/renderer/materialCore.js.map +1 -0
- package/lib/renderer/materialEmission.d.ts +2 -2
- package/lib/renderer/materialEmission.js +3 -3
- package/lib/renderer/materialEmission.js.map +1 -1
- package/lib/renderer/materialLayout.d.ts +2 -101
- package/lib/renderer/materialLayout.js +110 -172
- package/lib/renderer/materialLayout.js.map +1 -1
- package/lib/renderer/materialLayoutSchema.d.ts +26 -0
- package/lib/renderer/materialLayoutSchema.js +172 -0
- package/lib/renderer/materialLayoutSchema.js.map +1 -0
- package/lib/renderer/materialParams.d.ts +69 -0
- package/lib/renderer/materialParams.js +272 -0
- package/lib/renderer/materialParams.js.map +1 -0
- package/lib/renderer/materialTextureSlots.d.ts +14 -324
- package/lib/renderer/materialTextureSlots.js +21 -8
- package/lib/renderer/materialTextureSlots.js.map +1 -1
- package/lib/renderer/materialTextures.d.ts +6 -0
- package/lib/renderer/{texturesFromMaterials.js → materialTextures.js} +1 -2
- package/lib/renderer/materialTextures.js.map +1 -0
- package/lib/renderer/mergeMeshesToGeometry.js +6 -147
- package/lib/renderer/mergeMeshesToGeometry.js.map +1 -1
- package/lib/renderer/meshInstances.d.ts +4 -21
- package/lib/renderer/meshInstances.js +10 -56
- package/lib/renderer/meshInstances.js.map +1 -1
- package/lib/renderer/oidnNetwork.d.ts +2 -2
- package/lib/renderer/oidnNetwork.js +1 -1
- package/lib/renderer/oidnNetwork.js.map +1 -1
- package/lib/renderer/openPbrEnergyLut.js +850 -846
- package/lib/renderer/openPbrEnergyLut.js.map +1 -1
- package/lib/renderer/ownedDenoiser.d.ts +9 -0
- package/lib/renderer/ownedDenoiser.js +2 -0
- package/lib/renderer/ownedDenoiser.js.map +1 -0
- package/lib/renderer/packedMeshInstances.d.ts +23 -0
- package/lib/renderer/packedMeshInstances.js +80 -0
- package/lib/renderer/packedMeshInstances.js.map +1 -0
- package/lib/renderer/prepareMeshBVH.d.ts +12 -47
- package/lib/renderer/prepareMeshBVH.js +21 -642
- package/lib/renderer/prepareMeshBVH.js.map +1 -1
- package/lib/renderer/proceduralEnvironmentPower.d.ts +3 -0
- package/lib/renderer/proceduralEnvironmentPower.js +8 -0
- package/lib/renderer/proceduralEnvironmentPower.js.map +1 -0
- package/lib/renderer/progressiveScheduler.d.ts +1 -0
- package/lib/renderer/progressiveScheduler.js +7 -3
- package/lib/renderer/progressiveScheduler.js.map +1 -1
- package/lib/renderer/renderPipeline.d.ts +4 -1
- package/lib/renderer/renderPipeline.js.map +1 -1
- package/lib/renderer/renderingLimits.d.ts +9 -0
- package/lib/renderer/renderingLimits.js +18 -0
- package/lib/renderer/renderingLimits.js.map +1 -0
- 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 +73 -0
- package/lib/renderer/sceneAssembly.js +109 -0
- package/lib/renderer/sceneAssembly.js.map +1 -0
- package/lib/renderer/sceneChangeCore.d.ts +39 -0
- package/lib/renderer/sceneChangeCore.js +307 -0
- package/lib/renderer/sceneChangeCore.js.map +1 -0
- package/lib/renderer/sceneChangeDetector.d.ts +3 -6
- package/lib/renderer/sceneChangeDetector.js +24 -150
- package/lib/renderer/sceneChangeDetector.js.map +1 -1
- package/lib/renderer/sceneLayoutSchema.d.ts +119 -0
- package/lib/renderer/sceneLayoutSchema.js +111 -0
- package/lib/renderer/sceneLayoutSchema.js.map +1 -0
- package/lib/renderer/sceneLightChanges.d.ts +3 -3
- package/lib/renderer/sceneLightChanges.js.map +1 -1
- package/lib/renderer/scenePreparation.d.ts +55 -0
- package/lib/renderer/scenePreparation.js +360 -0
- package/lib/renderer/scenePreparation.js.map +1 -0
- package/lib/renderer/scratchSampling.js +18 -18
- package/lib/renderer/scratchSampling.js.map +1 -1
- package/lib/renderer/shader.d.ts +2 -0
- package/lib/renderer/shader.js +2 -0
- package/lib/renderer/shader.js.map +1 -1
- package/lib/renderer/shaderCapabilities.d.ts +23 -0
- package/lib/renderer/shaderCapabilities.js +55 -0
- package/lib/renderer/shaderCapabilities.js.map +1 -0
- package/lib/renderer/shaderCapacity.d.ts +2 -0
- package/lib/renderer/shaderCapacity.js +5 -0
- package/lib/renderer/shaderCapacity.js.map +1 -0
- package/lib/renderer/skyModel.d.ts +9 -0
- package/lib/renderer/skyModel.js +10 -0
- package/lib/renderer/skyModel.js.map +1 -0
- 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/textureAtlas.d.ts +60 -0
- package/lib/renderer/textureAtlas.js +145 -0
- package/lib/renderer/textureAtlas.js.map +1 -0
- package/lib/renderer/textureAtlasPixels.d.ts +7 -0
- package/lib/renderer/textureAtlasPixels.js +68 -0
- package/lib/renderer/textureAtlasPixels.js.map +1 -0
- package/lib/renderer/util.d.ts +1 -1
- package/lib/renderer/util.js.map +1 -1
- package/lib/renderer/webgl.d.ts +9 -2
- package/lib/renderer/webgl.js +54 -9
- 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/wgpuBindless.d.ts +26 -0
- package/lib/renderer/wgpuBindless.js +95 -0
- package/lib/renderer/wgpuBindless.js.map +1 -0
- package/lib/renderer/wgpuBindlessSource.d.ts +2 -0
- package/lib/renderer/wgpuBindlessSource.js +51 -0
- package/lib/renderer/wgpuBindlessSource.js.map +1 -0
- package/lib/renderer/wgpuMaterialConstants.d.ts +4 -0
- package/lib/renderer/wgpuMaterialConstants.js +52 -0
- package/lib/renderer/wgpuMaterialConstants.js.map +1 -0
- package/lib/renderer/wgpuSceneUniform.d.ts +42 -0
- package/lib/renderer/wgpuSceneUniform.js +125 -0
- package/lib/renderer/wgpuSceneUniform.js.map +1 -0
- package/lib/renderer/wgpuShaderSource.d.ts +22 -0
- package/lib/renderer/wgpuShaderSource.js +33 -0
- package/lib/renderer/wgpuShaderSource.js.map +1 -0
- package/lib/renderer/wgsl/aovDisplay.wgsl.d.ts +1 -0
- package/lib/renderer/wgsl/aovDisplay.wgsl.js +70 -0
- package/lib/renderer/wgsl/aovDisplay.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovReflectance.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/aovReflectance.wgsl.js +98 -0
- package/lib/renderer/wgsl/aovReflectance.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +135 -0
- package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +5 -0
- package/lib/renderer/wgsl/aovResolve.wgsl.js +38 -0
- package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovSnapshot.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js +21 -0
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovTrace.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/aovTrace.wgsl.js +115 -0
- package/lib/renderer/wgsl/aovTrace.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/bloom.wgsl.d.ts +13 -0
- package/lib/renderer/wgsl/bloom.wgsl.js +92 -0
- package/lib/renderer/wgsl/bloom.wgsl.js.map +1 -0
- 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.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js +41 -35
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +13 -1
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +747 -704
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +16 -16
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +4 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +83 -79
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +855 -857
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +137 -137
- package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +3 -1
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +52 -32
- 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 +152 -144
- 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 +269 -245
- 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 +27 -14
- 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 +91 -95
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js +1 -0
- package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +12 -12
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +8 -3
- package/lib/renderer/wgsl/compose.frag.wgsl.js +143 -118
- 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.js +7 -7
- package/lib/renderer/wgsl/jnlm.compute.d.ts +25 -0
- package/lib/renderer/wgsl/jnlm.compute.js +315 -0
- package/lib/renderer/wgsl/jnlm.compute.js.map +1 -0
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +28 -28
- package/lib/renderer/wgsl/oidnAuxiliary.wgsl.d.ts +1 -0
- package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +17 -0
- package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js.map +1 -0
- 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.d.ts +1 -0
- package/lib/renderer/wgsl/proceduralSky.compute.js +198 -0
- package/lib/renderer/wgsl/proceduralSky.compute.js.map +1 -0
- package/lib/renderer/wgsl/rayTrace.compute.d.ts +25 -1
- package/lib/renderer/wgsl/rayTrace.compute.js +645 -500
- package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
- package/lib/scene/Camera.js +7 -3
- package/lib/scene/Camera.js.map +1 -1
- package/lib/scene/EnvironmentLight.d.ts +5 -9
- package/lib/scene/EnvironmentLight.js +4 -14
- package/lib/scene/EnvironmentLight.js.map +1 -1
- package/lib/scene/EnvironmentLightState.d.ts +18 -0
- package/lib/scene/EnvironmentLightState.js +19 -0
- package/lib/scene/EnvironmentLightState.js.map +1 -0
- package/lib/scene/Geometry.d.ts +12 -6
- package/lib/scene/Geometry.js +37 -13
- package/lib/scene/Geometry.js.map +1 -1
- package/lib/scene/InstanceState.d.ts +39 -0
- package/lib/scene/InstanceState.js +77 -0
- package/lib/scene/InstanceState.js.map +1 -0
- package/lib/scene/InstancedMesh.d.ts +1 -1
- package/lib/scene/InstancedMesh.js +3 -0
- package/lib/scene/InstancedMesh.js.map +1 -1
- package/lib/scene/MaterialState.d.ts +209 -0
- package/lib/scene/MaterialState.js +231 -0
- package/lib/scene/MaterialState.js.map +1 -0
- package/lib/scene/Mesh.d.ts +4 -6
- package/lib/scene/Mesh.js +3 -11
- package/lib/scene/Mesh.js.map +1 -1
- package/lib/scene/MeshState.d.ts +20 -0
- package/lib/scene/MeshState.js +35 -0
- package/lib/scene/MeshState.js.map +1 -0
- package/lib/scene/OpenPBRMaterial.d.ts +6 -168
- package/lib/scene/OpenPBRMaterial.js +5 -223
- package/lib/scene/OpenPBRMaterial.js.map +1 -1
- package/lib/scene/PixelTexture.d.ts +6 -0
- package/lib/scene/PixelTexture.js +10 -0
- package/lib/scene/PixelTexture.js.map +1 -0
- package/lib/scene/ProceduralSky.d.ts +24 -0
- package/lib/scene/ProceduralSky.js +40 -0
- package/lib/scene/ProceduralSky.js.map +1 -0
- package/lib/scene/RectLight.d.ts +2 -13
- package/lib/scene/RectLight.js +3 -21
- package/lib/scene/RectLight.js.map +1 -1
- package/lib/scene/RectLightState.d.ts +31 -0
- package/lib/scene/RectLightState.js +26 -0
- package/lib/scene/RectLightState.js.map +1 -0
- package/lib/scene/Scene.d.ts +15 -4
- package/lib/scene/Scene.js.map +1 -1
- package/lib/scene/SceneNode.js +7 -6
- package/lib/scene/SceneNode.js.map +1 -1
- package/lib/scene/Texture.d.ts +10 -41
- package/lib/scene/Texture.js +4 -33
- package/lib/scene/Texture.js.map +1 -1
- package/lib/scene/TextureState.d.ts +35 -0
- package/lib/scene/TextureState.js +35 -0
- package/lib/scene/TextureState.js.map +1 -0
- package/lib/scene/attributeData.d.ts +4 -0
- package/lib/scene/attributeData.js +10 -0
- package/lib/scene/attributeData.js.map +1 -0
- package/lib/scene/lightState.d.ts +8 -0
- package/lib/scene/lightState.js +2 -0
- package/lib/scene/lightState.js.map +1 -0
- package/lib/scene/openPbrSchema.d.ts +7 -12
- package/lib/scene/openPbrSchema.js +273 -28
- package/lib/scene/openPbrSchema.js.map +1 -1
- package/lib/scene/skyParameters.d.ts +20 -0
- package/lib/scene/skyParameters.js +28 -0
- package/lib/scene/skyParameters.js.map +1 -0
- package/lib/scene/textureData.d.ts +9 -0
- package/lib/scene/textureData.js +2 -0
- package/lib/scene/textureData.js.map +1 -0
- package/lib/scene/texturePixels.d.ts +6 -0
- package/lib/scene/texturePixels.js +10 -0
- package/lib/scene/texturePixels.js.map +1 -0
- package/lib/settings/display.d.ts +33 -0
- package/lib/settings/display.js +7 -0
- package/lib/settings/display.js.map +1 -1
- package/lib/settings/render.d.ts +36 -3
- package/lib/settings/render.js +4 -1
- package/lib/settings/render.js.map +1 -1
- package/lib/tinybvh/tinybvh.wasm +0 -0
- package/lib/util/commonGeometry.js +7 -7
- package/lib/util/commonGeometry.js.map +1 -1
- package/lib/util/fromTHREE.d.ts +4 -1
- package/lib/util/fromTHREE.js +20 -7
- package/lib/util/fromTHREE.js.map +1 -1
- package/lib/util/geometry.js +42 -29
- package/lib/util/geometry.js.map +1 -1
- package/lib/util/loadRGBE.js +3 -4
- package/lib/util/loadRGBE.js.map +1 -1
- package/lib/util/studioLighting.d.ts +18 -0
- package/lib/util/studioLighting.js +36 -0
- package/lib/util/studioLighting.js.map +1 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/llms.txt +5 -0
- package/package.json +33 -7
- package/lib/renderer/texturesFromMaterials.d.ts +0 -6
- package/lib/renderer/texturesFromMaterials.js.map +0 -1
|
@@ -17,6 +17,7 @@ edits start final immediately; consecutive changes without explicit sync activit
|
|
|
17
17
|
hold preview for idleMs (default 150 ms). When interaction ends, final starts after
|
|
18
18
|
the current preview completes; its fallback remains visible until final completes a sample.
|
|
19
19
|
With intermediate denoising enabled, it stays visible until the first filtered final image is ready.
|
|
20
|
+
To keep the GPU busy while the view is still, enable [sample batching](#sample-batching) on final.
|
|
20
21
|
|
|
21
22
|
```ts
|
|
22
23
|
loop.select = ({changing}) => changing || slider.dragging ? 'preview' : 'final';
|
|
@@ -84,6 +85,68 @@ it runs, object edits and scene/camera replacement have no effect on tracing.
|
|
|
84
85
|
Call it once after updating your scene and controls, even when several renders
|
|
85
86
|
are refined that frame. See [scene updates](updates.md) for notifications.
|
|
86
87
|
|
|
88
|
+
## Sample batching
|
|
89
|
+
|
|
90
|
+
Without batching, each call advances one sample or tile, so a fast GPU can idle
|
|
91
|
+
between display frames. With `batchSamples`, sampling works on two levels:
|
|
92
|
+
|
|
93
|
+
- **Per call.** One `refine()` may submit several samples within an estimated
|
|
94
|
+
`timeBudgetMs` of GPU work, or one longer sample or tile, and returns without waiting for them.
|
|
95
|
+
Without `batchSamples`, a call traces one sample or tile.
|
|
96
|
+
- **Between frames.** RenderLoop also refines its final render each time the GPU
|
|
97
|
+
finishes queued work, until the next display frame. It keeps about 4 ms of work
|
|
98
|
+
queued, or one sample or tile if that is longer. Expensive tiled samples can
|
|
99
|
+
continue between display frames when each measured tile fits `timeBudgetMs`;
|
|
100
|
+
longer tiles wait for display frames to bound input delay. Presentation still
|
|
101
|
+
follows the display frame rate.
|
|
102
|
+
|
|
103
|
+
Batching is off by default. Enable it on the loop's final render with
|
|
104
|
+
`final: {batchSamples: true}`, or on a Render you supply. RenderLoop stops
|
|
105
|
+
batching while the view is changing.
|
|
106
|
+
|
|
107
|
+
Prefer RenderLoop for between-frame refilling. For a custom loop, use
|
|
108
|
+
`refineUntil(deadline, {signal})`. It synchronously calls `refine()` once, so
|
|
109
|
+
`present()` belongs immediately after the call. On WebGPU it then refills short
|
|
110
|
+
batches until the deadline, cancellation, a hidden page or sampling/display
|
|
111
|
+
conditions prevent more work. WebGL performs only the synchronous call.
|
|
112
|
+
|
|
113
|
+
This example assumes `engine` and `render` are created with
|
|
114
|
+
`render.batchSamples = true` and the final beauty channel selected. Adjust the
|
|
115
|
+
60 Hz deadline to your application's cadence and update controls before
|
|
116
|
+
`engine.update()`.
|
|
117
|
+
|
|
118
|
+
<!-- own-loop-refill -->
|
|
119
|
+
```js
|
|
120
|
+
let refill;
|
|
121
|
+
const stop = () => refill?.abort();
|
|
122
|
+
for (const type of ['pointerdown', 'pointermove', 'pointerup', 'wheel', 'keydown', 'input', 'change'])
|
|
123
|
+
addEventListener(type, stop, {capture: true, passive: true});
|
|
124
|
+
|
|
125
|
+
function frame(timestamp) {
|
|
126
|
+
requestAnimationFrame(frame);
|
|
127
|
+
stop();
|
|
128
|
+
engine.update();
|
|
129
|
+
refill = new AbortController();
|
|
130
|
+
void render.refineUntil(timestamp + 1000 / 60, {signal: refill.signal});
|
|
131
|
+
engine.display.present(render);
|
|
132
|
+
}
|
|
133
|
+
requestAnimationFrame(frame);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Call `stop()` before pausing, exporting or switching to another render, and skip
|
|
137
|
+
`refineUntil()` while paused. A new call automatically ends the previous refill.
|
|
138
|
+
The signal cancels future submissions; work already queued on the GPU completes.
|
|
139
|
+
The returned Promise resolves when refilling stops, including after an
|
|
140
|
+
asynchronous error (reported through `render.status` and `engine.lastError`).
|
|
141
|
+
|
|
142
|
+
The library automatically continues the remaining tiles of the current sample
|
|
143
|
+
between presentations. `samples` increases only after the whole sample;
|
|
144
|
+
presentation keeps the previous complete sample until then. Committed scene or
|
|
145
|
+
camera edits discard an unfinished sample and restart against the new inputs.
|
|
146
|
+
`maxTiles` caps the sample's tile grid (rounded up to a rectangular grid), so a
|
|
147
|
+
smaller value makes larger tiles. It does not cap work per frame or per call;
|
|
148
|
+
use `timeBudgetMs` and the between-frame deadline to control queued work.
|
|
149
|
+
|
|
87
150
|
## Reading and exporting
|
|
88
151
|
|
|
89
152
|
A fixed-size render does not need to be displayed. Its camera defaults to the
|
|
@@ -136,7 +199,8 @@ lower preview's scale; resizing the display canvas affects both.
|
|
|
136
199
|
|
|
137
200
|
Call `render.setDenoiser({ type: 'jnlm', schedule: 'converged' })` with JNLM or an OIDN
|
|
138
201
|
configuration. The schedules are `converged` (default), `progressive` (first
|
|
139
|
-
sample, then
|
|
202
|
+
sample, then doubling counts at least 500 ms apart; see [scheduling](./denoising.md#scheduling)),
|
|
203
|
+
and `every-sample`. Same-engine
|
|
140
204
|
renders share equal filter configurations and OIDN weight downloads. The engine
|
|
141
205
|
releases a network when its last render lease is released. OIDN is ignored with
|
|
142
206
|
a warning on WebGL; JNLM works on both backends.
|
|
@@ -150,6 +214,14 @@ final sample does not render the fallback. `present` selects the requested
|
|
|
150
214
|
complete image, then its complete fallback, and otherwise leaves the canvas
|
|
151
215
|
unchanged. It never traces.
|
|
152
216
|
|
|
217
|
+
Sample batching on WebGPU needs GPU timestamps; without them, a call traces one
|
|
218
|
+
sample, and between-frame refines are WebGPU-only. A larger `timeBudgetMs`
|
|
219
|
+
batches more per call, but an edit made just after waits for that work before its
|
|
220
|
+
preview starts. Batching keeps the GPU at full speed until `maxSamples`, which
|
|
221
|
+
draws more power than one sample per frame. `stop()` ends between-frame refines
|
|
222
|
+
at once, though submitted work still finishes; a manual `tick()` refines between
|
|
223
|
+
frames only until the next display frame.
|
|
224
|
+
|
|
153
225
|
`prepare(nextScene)` performs optional CPU BVH preparation without disturbing
|
|
154
226
|
the current GPU scene. Setting `engine.scene` and calling `update` commits a
|
|
155
227
|
scene switch for every render. Only one GPU scene resides in an engine.
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
## Short-wavelength IOR limit
|
|
57
|
+
|
|
58
|
+
Cauchy IOR rises quickly at short wavelengths. At strong dispersion scales, violet
|
|
59
|
+
light reaches IORs that reflect or trap much of it, and wide caustics turn yellow.
|
|
60
|
+
`spectrumIorWavelength` therefore eases the refracting wavelength below 500 nm toward
|
|
61
|
+
475 nm, while color keeps the sampled wavelength. The mapping is monotonic and
|
|
62
|
+
continuous, so the gradient has no hard edge.
|
|
63
|
+
|
|
64
|
+
This limit is an artistic choice and not physically based. It narrows the violet end
|
|
65
|
+
of the spectrum, and strong dispersion scales still lose some blue.
|
|
66
|
+
|
|
67
|
+
## Differences from spectral rendering
|
|
68
|
+
|
|
69
|
+
| Area | Spectral rendering | MuTracer |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| Lights | Emission varies with wavelength | RGB, with an implicit broad spectrum; a sodium lamp still disperses into a full rainbow |
|
|
72
|
+
| Materials and textures | Reflectance varies with wavelength, often upsampled from RGB | RGB, so metamerism cannot appear |
|
|
73
|
+
| Media | Absorption and scattering vary with wavelength | Three RGB coefficients |
|
|
74
|
+
| Thin film | Interference is integrated over wavelength | Evaluated at 620, 540 and 450 nm |
|
|
75
|
+
| Refractive index | Often measured curves or Sellmeier equations | Cauchy from IOR and Abbe number, with the short-wavelength limit |
|
|
76
|
+
| Wavelengths per path | Often several, combined with MIS | One per path or photon |
|
|
77
|
+
| Output color | Integrated from the spectrum into the output color space | Fixed clamped sRGB weights, normalized per channel |
|
|
78
|
+
|
|
79
|
+
These differences matter most for narrow-band lights, colored absorption over long
|
|
80
|
+
paths, metamerism and predictive color. Clear glass and crystal under broad lights are
|
|
81
|
+
closer to the spectral result, because their color comes mainly from refraction.
|
|
82
|
+
|
|
83
|
+
Full spectral rendering would change the light, material, texture and medium data
|
|
84
|
+
models, and requires RGB-to-spectrum upsampling in both shader backends and native.
|
|
85
|
+
|
|
86
|
+
## Changing this code
|
|
87
|
+
|
|
88
|
+
- Update WGSL and GLSL together. Both are generated from `spectrum.ts`; caustics are
|
|
89
|
+
WGSL only.
|
|
90
|
+
- `spectralChannel` must be set wherever a path's wavelength is set.
|
|
91
|
+
- `tests/unit/spectrum.test.ts` covers white balance, weight bounds, channel
|
|
92
|
+
distributions and the IOR limit. Check the image result on a real GPU in both
|
|
93
|
+
backends, as described in `AGENTS.md`.
|
package/docs/threejs.md
CHANGED
|
@@ -45,6 +45,10 @@ For an application-owned animation frame, update the animation mixer first,
|
|
|
45
45
|
then call `loop.tick()`. With first-layer frame control, call `sync.update()`,
|
|
46
46
|
`engine.update()`, `render.refine()` and `engine.display.present(render)` in order.
|
|
47
47
|
|
|
48
|
+
For a library-generated sky, pass `environment: new ProceduralSky()` in the
|
|
49
|
+
conversion or sync options. See [ProceduralSky](./api.md#proceduralsky) for
|
|
50
|
+
configuration and backend limits.
|
|
51
|
+
|
|
48
52
|
## What is converted
|
|
49
53
|
|
|
50
54
|
| Three.js | MuTracer |
|
|
@@ -69,7 +73,7 @@ then call `loop.tick()`. With first-layer frame control, call `sync.update()`,
|
|
|
69
73
|
| `RectAreaLight` | `RectLight` |
|
|
70
74
|
| `AmbientLight` | `AmbientLight` |
|
|
71
75
|
| `scene.environment` (equirectangular float `DataTexture`, e.g. from `HDRLoader`/`RGBELoader`) | `EnvironmentLight`; orientation follows Three.js, so a `DataTexture` with `flipY = false` has its first row at the bottom |
|
|
72
|
-
| `scene.background` color / texture |
|
|
76
|
+
| `scene.background` color / texture | Explicit background, independent of environment lighting |
|
|
73
77
|
|
|
74
78
|
Three.js `opacity` maps to `geometryOpacity`; thin-shell choices map to
|
|
75
79
|
`geometryThinWalled`. Metadata accepts the five [canonical and compatibility
|
|
@@ -95,10 +99,15 @@ Material textures preserve independent `wrapS` and `wrapT`: repeat,
|
|
|
95
99
|
clamp-to-edge and mirrored repeat. UV repeat and offset apply before wrapping;
|
|
96
100
|
later wrap edits synchronize automatically. Displacement uses the same modes.
|
|
97
101
|
|
|
98
|
-
`scene.environmentIntensity`
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
`scene.environmentIntensity` scales environment lighting (`0` disables it);
|
|
103
|
+
ambient lights and explicit backgrounds keep their own brightness.
|
|
104
|
+
`scene.backgroundIntensity` scales an explicit texture background; colors are
|
|
105
|
+
unaffected. `scene.environmentRotation` and `scene.backgroundRotation`
|
|
106
|
+
independently rotate environment lighting and explicit texture backgrounds. All
|
|
107
|
+
of these synchronize automatically; rotations preserve Euler order. An unset
|
|
108
|
+
background follows the environment. `mutracerGroundedSkybox` uses only its own
|
|
109
|
+
`rotation` (default `0`) and `intensity` (default `1`), ignoring
|
|
110
|
+
`scene.backgroundRotation` and `scene.backgroundIntensity`.
|
|
102
111
|
|
|
103
112
|
Thin-film ranges keep their endpoint order, including minimum greater than
|
|
104
113
|
maximum, and retain the converter's 0–20 µm endpoint clamp. The converter uses
|
package/docs/updates.md
CHANGED
|
@@ -114,10 +114,54 @@ The notification range is validated.
|
|
|
114
114
|
## Materials, textures and lights
|
|
115
115
|
|
|
116
116
|
Material parameter edits repack material parameters without touching geometry
|
|
117
|
-
or BVHs. Emission edits also refresh light-sampling state
|
|
118
|
-
rebuild the texture atlas.
|
|
117
|
+
or BVHs. Emission edits also refresh light-sampling state. With atlas bindings,
|
|
118
|
+
texture edits rebuild the texture atlas. With [bindless bindings](./api.md#texture-bindings),
|
|
119
|
+
UV assignments, wrap and color-space edits update sampling metadata, while pixel edits
|
|
120
|
+
upload the changed images. Dimension, budget or shared storage-precision changes
|
|
121
|
+
can require more images to be uploaded. `Texture.markUpdated()` invalidates image
|
|
122
|
+
pixels as well as in-place UV edits. Displacement settings that move geometry require a
|
|
119
123
|
[full mesh update](#full-mesh-updates).
|
|
120
124
|
|
|
125
|
+
WebGPU can compile a new path-tracing shader for the following changes. Feature
|
|
126
|
+
presence is scene-wide: adding another material or light that uses an already
|
|
127
|
+
supported feature does not by itself need another variant.
|
|
128
|
+
|
|
129
|
+
Within compatible transport settings and data layouts, WebGPU retains prepared
|
|
130
|
+
material, texture and lighting support for later edits. Turning a feature off
|
|
131
|
+
and back on can reuse that support. The base shader supports diffuse, dielectric
|
|
132
|
+
and metal materials: changing `baseMetalness` between 0 and 1 does not itself
|
|
133
|
+
require another shader. Coat and fuzz are prepared together on the first use of
|
|
134
|
+
either: switching between them or combining them does not itself require another
|
|
135
|
+
shader. Transmission, thin film and subsurface are prepared as needed; dispersion
|
|
136
|
+
and other transport/layout changes below can still require compilation.
|
|
137
|
+
|
|
138
|
+
| Change | When a different shader variant is needed |
|
|
139
|
+
| --- | --- |
|
|
140
|
+
| Material, texture or lighting features | Newly required support is not covered by a prepared shader: coat/fuzz, thin film, subsurface, transmission, shadow catchers, a texture type, an analytic-light type, sampled emissive triangles or environment illumination |
|
|
141
|
+
| Transport and transparency | Enabling/disabling medium or dispersion support, changing whether any non-opaque material exists, or changing whether deterministic primary BLEND splitting is needed |
|
|
142
|
+
| Shading and geometry structure | Changing required UV/tangent/coat-normal frames, displacement or material-bevel support, vertex/BVH layouts or required traversal capacity |
|
|
143
|
+
| Render settings | Changing `samplingPattern`, `bevelSamples`, or `alphaBlendStrategy` while BLEND materials exist |
|
|
144
|
+
| Texture capacity | Atlas: increasing the texture count beyond the current capacity. Both modes: first use or last removal of UV1 texture sampling also changes the shader |
|
|
145
|
+
|
|
146
|
+
With `alphaMode: 'auto'`, opacity, cutoff or alpha-map edits can change the
|
|
147
|
+
resolved transparency mode. Texture edits can also enable independent coat-normal
|
|
148
|
+
or anisotropy frames. These count as structural changes above.
|
|
149
|
+
|
|
150
|
+
Within an unchanged feature/structure combination, colors, roughness, metalness,
|
|
151
|
+
existing layer weights, light transforms/intensity, texture pixels and camera/output size
|
|
152
|
+
do not recompile the path tracer. Neither do changes to `bounces`,
|
|
153
|
+
`directLightCandidates`, clamping, `dispersionWavelengths` (1 or 3), the render's
|
|
154
|
+
bevel switch, sample count or seed. Data uploads, atlas/BVH work and accumulation
|
|
155
|
+
restarts may still be needed.
|
|
156
|
+
|
|
157
|
+
A render waiting for a shader keeps its samples and image, and other renders keep
|
|
158
|
+
sampling. Returning to a cached compatible combination reuses its pipeline, even
|
|
159
|
+
while another combination is still compiling. Prepared
|
|
160
|
+
combinations may be discarded after many different edits; recreating the Engine
|
|
161
|
+
or recovering a lost device also requires preparing shaders again. Compilation time depends
|
|
162
|
+
on the feature combination, BVH layout, browser and GPU driver. Denoising and
|
|
163
|
+
post-processing passes have their own shaders and initialization costs.
|
|
164
|
+
|
|
121
165
|
Analytic-light edits keep the environment map. Ambient and environment edits
|
|
122
166
|
rebuild it. Rect-light texture edits require a full mesh update, because those
|
|
123
167
|
textures live in the material atlas.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Viewer feature checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist with the [Web viewer](https://mutracer.meimu-studio.com/viewer/)
|
|
4
|
+
and [native viewer](../native/viewer/README.md). Start with material spheres,
|
|
5
|
+
then use a glTF with nested objects, cameras, lights and animation. A checked
|
|
6
|
+
item means you exercised the behavior in the version being reviewed; it does
|
|
7
|
+
not promise identical rendered pixels between devices or backends.
|
|
8
|
+
|
|
9
|
+
## Workflow
|
|
10
|
+
|
|
11
|
+
| Check | Action and expected result |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| [ ] Open | Open a GLB, a glTF with external buffers/images, a folder and a model URL; geometry and textures load. Drop files on the viewport. On Web, a fresh load uses the collection's curated view or the file's first camera, including orthographic cameras; restoring a saved view takes precedence. Failed or cancelled loads leave the previous scene usable. |
|
|
14
|
+
| [ ] Examples | Open **Examples** in the toolbar; switch between MuTracer collection and glTF Research Scenes, load a thumbnail and check its camera and authored lighting. |
|
|
15
|
+
| [ ] Scene | Search objects or materials and expand nested groups and meshes; select a material child to open its editor. Select an object from the tree or viewport; selection reveals its ancestors. Hide/show a mesh and a group. Select an authored camera. |
|
|
16
|
+
| [ ] Navigation | Drag to orbit, right-drag to pan, scroll to zoom, **F** to fit. Moving an authored camera continues in Orbit. |
|
|
17
|
+
| [ ] History | Undo/redo material, visibility, lighting and render edits; one continuous drag is one step. Reset all restores defaults. On Web, it also restores the example's render choices and initial camera, or fits the model when no camera is provided. |
|
|
18
|
+
| [ ] Panels | **1–4** opens Lighting, Material, Camera, Render respectively. **[**, **]** toggle scene/inspector; click the active rail tab to close it. **H** hides the interface. Text input must not trigger shortcuts. |
|
|
19
|
+
| [ ] Playback | **Space** plays/pauses animation when present, otherwise pauses/resumes rendering. Choose another clip and seek the timeline. |
|
|
20
|
+
| [ ] Render dock | Change sample target, viewport resolution and denoising; pause/resume and inspect sample progress, elapsed time and completion. **D** toggles denoising. |
|
|
21
|
+
| [ ] Export | **E** opens a preview; save the displayed viewport PNG. Render Viewport/1080p/2K/4K/Square PNG with a separate sample budget, denoising and optional transparency. Cancel an export and continue using the original image. |
|
|
22
|
+
| [ ] Code/help | Open Code and copy a setup for the corresponding SDK; open keyboard help. **⌘O / Ctrl+O** opens files. |
|
|
23
|
+
|
|
24
|
+
## Lighting, materials, camera and rendering
|
|
25
|
+
|
|
26
|
+
| Check | Controls and expected result |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| [ ] Environment | Switch HDRI / Studio and model lighting where available. Load a local HDR or browse Poly Haven; change HDR resolution, intensity and rotation. Failed downloads keep the previous lighting. |
|
|
29
|
+
| [ ] Studio | Choose each rig; adjust intensity, rotation, size, ambient strength and color. |
|
|
30
|
+
| [ ] Background | Switch environment, color, transparent and grounded modes where offered. Adjust projection height/radius; verify auto values and transparency in exported PNG. |
|
|
31
|
+
| [ ] Ground | Enable ground shadow and change opacity; inspect contact with the model. |
|
|
32
|
+
| [ ] Material selection | Pick a mesh/material, check shared-material edits, apply a preset and reset to loaded values. |
|
|
33
|
+
| [ ] Material layers | Exercise base color/weight, metalness, roughness, diffuse roughness, IOR/specular, anisotropy, transmission/volume/thin wall, subsurface, coat, fuzz, thin film, emission, opacity/alpha and double-sided/unlit controls where offered. |
|
|
34
|
+
| [ ] Textures | Upload, replace and remove each exposed slot; change Wrap S/T and Repeat S/T, including negative repeats. Apply a Poly Haven set with optional displacement; cancel/replace downloads and switch materials during download. |
|
|
35
|
+
| [ ] Displacement | Change scale, bias, subdivision and smoothing; verify silhouettes and return to zero displacement. |
|
|
36
|
+
| [ ] MaterialX (Web) | Import a .zip package or .mtlx with images; check converted layers and textures. |
|
|
37
|
+
| [ ] Camera | Switch Perspective/Orthographic, adjust FOV, auto-rotate and Fit. Authored cameras keep their projection/FOV until Orbit resumes. |
|
|
38
|
+
| [ ] Depth of field | Enable DOF, adjust f-number, area autofocus and focus frame; move the frame, manually edit focus or pick a point; choose automatic or explicit scene units. Orthographic views disable DOF. |
|
|
39
|
+
| [ ] Quality | Change max samples, bounces, resolution, sampling pattern and clamping. Web also offers a BVH builder. |
|
|
40
|
+
| [ ] Caustics | Toggle light tracing and photon mapping; compare each alone and together on a glass scene. Web's master Caustics switch gates both. |
|
|
41
|
+
| [ ] Denoiser | Toggle JNLM/OIDN; adjust JNLM strength, search/patch radius, albedo/normal tolerance and passes; choose OIDN Standard/Small/Large and tile size. Reset selected parameters. |
|
|
42
|
+
| [ ] Color | Change AgX/ACES/Cineon/Reinhard/Linear, exposure, contrast, saturation, temperature and tint; verify exported colors. |
|
|
43
|
+
| [ ] Effects | Enable bloom, threshold/radius and vignette; turn them off and verify the image returns. |
|
|
44
|
+
| [ ] Debug | Expand/collapse Debug; inspect Final, Albedo, Normal, Depth, Position, Roughness, Diffuse/Specular reflectance, ID and Motion. Adjust channel ranges and ID component; toggle interactive preview and max preview scale. Overlay gestures must not orbit/select the scene. |
|
|
45
|
+
| [ ] Window size | Check wide and narrow windows, hidden panels and long names; controls remain readable and the viewport remains usable. Web also provides the mobile bottom sheet. |
|
|
46
|
+
|
|
47
|
+
## Platform options and limits
|
|
48
|
+
|
|
49
|
+
| Area | Web | Native |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| Rendering device | WebGPU; WebGL 2 fallback reloads the page | HWRT / Software BVH; device availability is reported in the UI |
|
|
52
|
+
| Denoising | WebGL 2 supports JNLM; OIDN needs WebGPU | JNLM/OIDN; optional Windows DLSS RR build |
|
|
53
|
+
| HDR display | WebGPU plus compatible browser/display; falls back to SDR | Viewer window is SDR; HDR toggle is disabled |
|
|
54
|
+
| BVH builder | tinybvh / builtin | No builder selector |
|
|
55
|
+
| MaterialX import | .zip or .mtlx with images | No MaterialX import UI |
|
|
56
|
+
| Caustics controls | Master switch plus two methods; methods require WebGPU | Independent method switches; both off disables caustics |
|
|
57
|
+
| File access | Multi-file/folder picker; URLs need CORS | File/folder picker; folder Open selects a top-level glTF/GLB; resources resolve beside the model |
|
|
58
|
+
| Code | JavaScript setup | Rust SDK setup |
|
|
59
|
+
| Examples browser | Popover with optional pinned panel | Toolbar opens a docked panel |
|
|
60
|
+
| Extra native controls | — | Fixed-pixel render sizes, directional key light |
|
|
61
|
+
| Small screens | Mobile sheet and responsive toolbar | Desktop panels; scene list hides when space is limited |
|
|
62
|
+
|
|
63
|
+
Native and Web use different UI toolkits and fonts. Check icon meaning,
|
|
64
|
+
label order, alignment and control availability; file dialogs, window controls,
|
|
65
|
+
font rasterization and responsive behavior follow each platform.
|
package/docs/viewer.md
CHANGED
|
@@ -5,6 +5,11 @@ Open **Examples → MuTracer collection** for models curated for this viewer, or
|
|
|
5
5
|
[glTF Research Scenes](https://github.com/ErfanMo77/gltf-research-scenes) collection.
|
|
6
6
|
Scenes download on demand from GitHub; cards show approximate download sizes
|
|
7
7
|
and link to each scene's source and license. Large scenes need more memory.
|
|
8
|
+
glTF Research Scenes load with **Ground shadow** off; you can enable it in Lighting.
|
|
9
|
+
|
|
10
|
+
On desktop, choose **Pin to right panel** in Examples to keep the collection
|
|
11
|
+
open while loading models. **Unpin examples** returns it to the popover.
|
|
12
|
+
The pinned layout is saved in this browser.
|
|
8
13
|
|
|
9
14
|
glTF/GLB imports include directional, point and spot lights and emissive meshes.
|
|
10
15
|
Benchmark scenes also load their sunlight and available environment maps.
|
|
@@ -16,17 +21,17 @@ resampled to at most 2K width. If a source map is missing, the model still opens
|
|
|
16
21
|
and the Lighting panel explains which map is unavailable; choose an environment
|
|
17
22
|
there to replace it.
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
MuTracer collection examples open with a curated view, under the procedural
|
|
25
|
+
sky or a Poly Haven HDRI. A few also set their own tone mapping and bloom, which
|
|
26
|
+
return to the defaults when you leave them. Other models with cameras open in their
|
|
27
|
+
first camera. You can select any
|
|
28
|
+
imported camera in the separate camera toolbar at the bottom right; it appears
|
|
29
|
+
only for models with cameras. Drag, pan or zoom after selecting a camera to
|
|
30
|
+
continue in **Orbit** from that view.
|
|
25
31
|
Hover over a camera in the scene tree and click its camera action to apply it
|
|
26
32
|
directly. **Fit to model** in the bottom toolbar (or **F**) returns to Orbit
|
|
27
33
|
and frames the model.
|
|
28
|
-
Reloading the current model restores your saved camera selection
|
|
29
|
-
showing the prompt again.
|
|
34
|
+
Reloading the current model restores your saved camera selection.
|
|
30
35
|
|
|
31
36
|
Picking an object in the viewport reveals it in the scene tree and scrolls it
|
|
32
37
|
into view. Material rows start collapsed; expand a mesh to see its materials.
|
|
@@ -49,6 +54,8 @@ https://mutracer.meimu-studio.com/viewer/?hdrOutputEnabled=true&maxSamples=128#m
|
|
|
49
54
|
The viewer updates the URL as lighting, render and display settings change.
|
|
50
55
|
Copy the address bar to share those settings and the selected example model.
|
|
51
56
|
Settings also work in the hash, such as `#model=dragon&hdrOutputEnabled=true`.
|
|
57
|
+
A link with only `#model=…` opens the example with its own render settings, as
|
|
58
|
+
the Examples menu does. Settings in a link win over the example's.
|
|
52
59
|
|
|
53
60
|
### Options
|
|
54
61
|
|
package/lib/Display.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type AovIdComponent } from './renderer/aovDisplay.js';
|
|
2
|
+
export type { AovIdComponent } from './renderer/aovDisplay.js';
|
|
1
3
|
import type Render from './Render.js';
|
|
2
4
|
import type { ToneMapping, DisplayChannel } from './renderer/RenderingPipeline.js';
|
|
3
5
|
import type { ColorRGB } from './types.js';
|
|
@@ -21,7 +23,11 @@ export interface DisplaySettings {
|
|
|
21
23
|
/** Bloom luminance threshold. Default 1. */ bloomThreshold?: number;
|
|
22
24
|
/** Bloom radius in 0–1. Default 0.6. */ bloomRadius?: number;
|
|
23
25
|
/** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled?: boolean;
|
|
24
|
-
/** Display image channel. Default final. */ channel?: DisplayChannel;
|
|
26
|
+
/** Display image channel. Default final. AOV channels require explicit Render.aovs. */ channel?: DisplayChannel;
|
|
27
|
+
/** Finite float32 scene-unit depths mapped to black/white; 0 <= near < far. Default [0, 10]. */ aovDepthRange?: readonly [number, number];
|
|
28
|
+
/** Finite positive float32 scene-unit half-range around the origin for position RGB. Default 1. */ aovPositionScale?: number;
|
|
29
|
+
/** Finite positive float32 input-pixel displacement mapped to full motion brightness. Default 16. */ aovMotionScale?: number;
|
|
30
|
+
/** Stable ID lane to colorize. Default object. */ aovIdComponent?: AovIdComponent;
|
|
25
31
|
/** Linear shadow-catcher color. Default black. */ shadowCatcherColor?: ColorRGB;
|
|
26
32
|
/** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha?: number;
|
|
27
33
|
}
|
|
@@ -52,12 +58,17 @@ export default class Display {
|
|
|
52
58
|
/** Bloom luminance threshold. Default 1. */ bloomThreshold: number;
|
|
53
59
|
/** Bloom radius in 0–1. Default 0.6. */ bloomRadius: number;
|
|
54
60
|
/** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled: boolean;
|
|
55
|
-
/** Display image channel. Default final. */ channel: DisplayChannel;
|
|
61
|
+
/** Display image channel. Default final. AOV channels require explicit Render.aovs. */ channel: DisplayChannel;
|
|
62
|
+
/** Finite float32 scene-unit depths mapped to black/white; 0 <= near < far. Default [0, 10]. */ aovDepthRange: readonly [number, number];
|
|
63
|
+
/** Finite positive float32 scene-unit half-range around the origin for position RGB. Default 1. */ aovPositionScale: number;
|
|
64
|
+
/** Finite positive float32 input-pixel displacement mapped to full motion brightness. Default 16. */ aovMotionScale: number;
|
|
65
|
+
/** Stable ID lane to colorize. Default object. */ aovIdComponent: AovIdComponent;
|
|
56
66
|
/** Linear shadow-catcher color. Default black. */ shadowCatcherColor: ColorRGB;
|
|
57
67
|
/** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha: number;
|
|
58
68
|
private constructor();
|
|
59
69
|
/** Resizes the drawing buffer; scale-based renders resize at their next refine. */
|
|
60
70
|
setSize(width: number, height: number): void;
|
|
71
|
+
private readonly _filterSettings;
|
|
61
72
|
private readonly settings;
|
|
62
73
|
private readonly _postProcesses;
|
|
63
74
|
private _warnedPostProcess;
|
package/lib/Display.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { displayAovKind, validateAovDisplay } from './renderer/aovDisplay.js';
|
|
1
2
|
import { createCanvas } from './util/canvas.js';
|
|
2
|
-
import { displaySettingsKey, applyDisplaySettings } from './settings/display.js';
|
|
3
|
+
import { displaySettingsKey, displayFilterSettingsKey, applyDisplaySettings } from './settings/display.js';
|
|
3
4
|
/** Canvas presentation and shared display settings; obtained from engine.display. */
|
|
4
5
|
export default class Display {
|
|
5
6
|
engine;
|
|
@@ -15,7 +16,11 @@ export default class Display {
|
|
|
15
16
|
/** Bloom luminance threshold. Default 1. */ bloomThreshold = 1;
|
|
16
17
|
/** Bloom radius in 0–1. Default 0.6. */ bloomRadius = 0.6;
|
|
17
18
|
/** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled = false;
|
|
18
|
-
/** Display image channel. Default final. */ channel = 'final';
|
|
19
|
+
/** Display image channel. Default final. AOV channels require explicit Render.aovs. */ channel = 'final';
|
|
20
|
+
/** Finite float32 scene-unit depths mapped to black/white; 0 <= near < far. Default [0, 10]. */ aovDepthRange = [0, 10];
|
|
21
|
+
/** Finite positive float32 scene-unit half-range around the origin for position RGB. Default 1. */ aovPositionScale = 1;
|
|
22
|
+
/** Finite positive float32 input-pixel displacement mapped to full motion brightness. Default 16. */ aovMotionScale = 16;
|
|
23
|
+
/** Stable ID lane to colorize. Default object. */ aovIdComponent = 'object';
|
|
19
24
|
/** Linear shadow-catcher color. Default black. */ shadowCatcherColor = [0, 0, 0];
|
|
20
25
|
/** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha = 1;
|
|
21
26
|
constructor(engine, canvas) {
|
|
@@ -34,6 +39,7 @@ export default class Display {
|
|
|
34
39
|
if (this.canvas.height !== height)
|
|
35
40
|
this.canvas.height = height;
|
|
36
41
|
}
|
|
42
|
+
_filterSettings = new WeakMap();
|
|
37
43
|
settings = new WeakMap();
|
|
38
44
|
/** @internal */ _configure(render) {
|
|
39
45
|
if (render._engine !== this.engine)
|
|
@@ -41,12 +47,20 @@ export default class Display {
|
|
|
41
47
|
const target = render._output;
|
|
42
48
|
if (!target)
|
|
43
49
|
return;
|
|
50
|
+
const kind = displayAovKind(this.channel);
|
|
51
|
+
if (!kind && !['final', 'normal', 'albedo', 'shadow', 'shadowCatcher'].includes(this.channel))
|
|
52
|
+
throw new RangeError('Unknown display channel');
|
|
53
|
+
if (kind && !render.aovs.includes(kind))
|
|
54
|
+
throw new Error(`AOV ${kind} is not enabled on the selected render`);
|
|
55
|
+
validateAovDisplay({ depthRange: this.aovDepthRange, positionScale: this.aovPositionScale, motionScale: this.aovMotionScale, idComponent: this.aovIdComponent });
|
|
44
56
|
const key = displaySettingsKey(this);
|
|
57
|
+
const filterKey = displayFilterSettingsKey(this);
|
|
45
58
|
const previous = this.settings.get(render);
|
|
46
59
|
if (previous !== key) {
|
|
47
60
|
this.settings.set(render, key);
|
|
48
|
-
if (previous !== undefined)
|
|
61
|
+
if (previous !== undefined && this._filterSettings.get(render) !== filterKey)
|
|
49
62
|
render._displayChanged();
|
|
63
|
+
this._filterSettings.set(render, filterKey);
|
|
50
64
|
}
|
|
51
65
|
target.activate();
|
|
52
66
|
applyDisplaySettings(this, target);
|
|
@@ -72,7 +86,14 @@ export default class Display {
|
|
|
72
86
|
if (render._engine !== this.engine)
|
|
73
87
|
throw new Error('Render belongs to another engine.');
|
|
74
88
|
const target = render._output;
|
|
75
|
-
if (!target
|
|
89
|
+
if (!target)
|
|
90
|
+
return;
|
|
91
|
+
const kind = displayAovKind(this.channel);
|
|
92
|
+
if (!kind && !target.presentationComplete)
|
|
93
|
+
return;
|
|
94
|
+
if (kind && !render.aovs.includes(kind))
|
|
95
|
+
throw new Error(`AOV ${kind} is not enabled on the selected render`);
|
|
96
|
+
if (kind && target.aovReady && !target.aovReady(kind))
|
|
76
97
|
return;
|
|
77
98
|
this._configure(render);
|
|
78
99
|
target.drawPostProcess();
|
|
@@ -90,9 +111,9 @@ export default class Display {
|
|
|
90
111
|
present(render) {
|
|
91
112
|
if (render._engine !== this.engine)
|
|
92
113
|
throw new Error('Render belongs to another engine.');
|
|
93
|
-
const ready = this.channel === 'final' && render.fallback ? render._presentable : render.
|
|
114
|
+
const ready = this.channel === 'final' && render.fallback ? render._presentable : render._completeFor(this.channel);
|
|
94
115
|
const fallback = render.fallback;
|
|
95
|
-
const selected = ready ? render : fallback && (this.channel === 'final' ? fallback._presentable : fallback.
|
|
116
|
+
const selected = ready ? render : fallback && (this.channel === 'final' ? fallback._presentable : fallback._completeFor(this.channel)) ? fallback : undefined;
|
|
96
117
|
if (!selected)
|
|
97
118
|
return;
|
|
98
119
|
const target = this.compose(selected);
|
|
@@ -106,7 +127,7 @@ export default class Display {
|
|
|
106
127
|
const target = this.compose(render);
|
|
107
128
|
if (!target)
|
|
108
129
|
throw new Error('Render has no complete image.');
|
|
109
|
-
const image = await target.readPresentation();
|
|
130
|
+
const image = render._cropOutput(await target.readPresentation());
|
|
110
131
|
const canvas = createCanvas(image.width, image.height, 'convertToBlob' in this.canvas);
|
|
111
132
|
const context = canvas.getContext('2d');
|
|
112
133
|
if (!context)
|
package/lib/Display.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Display.js","sourceRoot":"","sources":["../src/Display.ts"],"names":[],"mappings":"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","sourcesContent":["import {createCanvas} from './util/canvas.js';\nimport type Engine from './Engine.js';\nimport type Render from './Render.js';\nimport type { ToneMapping, DisplayChannel } from './renderer/RenderingPipeline.js';\nimport type { ColorRGB } from './types.js';\nimport { displaySettingsKey, applyDisplaySettings } from './settings/display.js';\n/** Display image channels. Default final. */\nexport type {DisplayChannel} from './renderer/RenderingPipeline.js';\n/** Image encoding options for Display.toBlob. */\nexport interface BlobOptions {\n /** Browser image MIME type. Default image/png. */ type?: string;\n /** Encoder quality in 0–1. Default undefined uses the browser default. */ quality?: number;\n}\n/** Optional shared display settings; defaults match Display. */\nexport interface DisplaySettings {\n /** Tone mapping transform. Default agx. */ toneMapping?: ToneMapping;\n /** Linear exposure multiplier. Default 1. */ toneMappingExposure?: number;\n /** Contrast multiplier. Default 1. */ contrast?: number;\n /** Saturation multiplier. Default 1. */ saturation?: number;\n /** White balance temperature shift in -1–1. Default 0. */ temperature?: number;\n /** Green/magenta tint in -1–1. Default 0. */ tint?: number;\n /** Vignette strength in 0–1. Default 0. */ vignette?: number;\n /** Bloom intensity; 0 disables it. Default 0. */ bloomIntensity?: number;\n /** Bloom luminance threshold. Default 1. */ bloomThreshold?: number;\n /** Bloom radius in 0–1. Default 0.6. */ bloomRadius?: number;\n /** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled?: boolean;\n /** Display image channel. Default final. */ channel?: DisplayChannel;\n /** Linear shadow-catcher color. Default black. */ shadowCatcherColor?: ColorRGB;\n /** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha?: number;\n}\n/** Borrowed WebGPU images for one synchronous display pass. */\nexport interface PostProcessContext {\n /** Engine device; may change after recovery. */ device: GPUDevice;\n /** Record commands here; the library finishes and submits it. */ encoder: GPUCommandEncoder;\n /** Read-only composed display image, top row first; no additional color conversion. */ input: GPUTexture;\n /** Fully write this image. Same format and dimensions as input; supports render, storage and copy writes. */ output: GPUTexture;\n /** Actual render width. */ width: number;\n /** Actual render height. */ height: number;\n /** Selected complete render, including a selected fallback. */ render: Render;\n}\n/** Synchronous display pass. Images and encoder are borrowed only during the call; do not retain or destroy them. */\nexport type PostProcess = (context: PostProcessContext) => void;\n/** Canvas presentation and shared display settings; obtained from engine.display. */\nexport default class Display {\n /** Display canvas. Default the supplied Engine canvas, or a new canvas (OffscreenCanvas without document). */ readonly canvas: HTMLCanvasElement | OffscreenCanvas;\n /** Tone mapping transform. Default agx. */ toneMapping: ToneMapping = 'agx';\n /** Linear exposure multiplier. Default 1. */ toneMappingExposure = 1;\n /** Contrast multiplier. Default 1. */ contrast = 1;\n /** Saturation multiplier. Default 1. */ saturation = 1;\n /** White balance temperature shift in -1–1. Default 0. */ temperature = 0;\n /** Green/magenta tint in -1–1. Default 0. */ tint = 0;\n /** Vignette strength in 0–1. Default 0. */ vignette = 0;\n /** Bloom intensity; 0 disables it. Default 0. */ bloomIntensity = 0;\n /** Bloom luminance threshold. Default 1. */ bloomThreshold = 1;\n /** Bloom radius in 0–1. Default 0.6. */ bloomRadius = 0.6;\n /** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled = false;\n /** Display image channel. Default final. */ channel: DisplayChannel = 'final';\n /** Linear shadow-catcher color. Default black. */ shadowCatcherColor: ColorRGB = [0, 0, 0];\n /** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha = 1;\n private constructor(private readonly engine: Engine, canvas: HTMLCanvasElement | OffscreenCanvas) { this.canvas = canvas; }\n /** @internal */ static _create(engine: Engine, canvas: HTMLCanvasElement | OffscreenCanvas) { return new Display(engine, canvas); }\n /** Resizes the drawing buffer; scale-based renders resize at their next refine. */\n setSize(width: number, height: number) {\n if (!Number.isFinite(width) || !Number.isFinite(height) || width < 1 || height < 1) throw new Error('Display dimensions must be positive.');\n width = Math.round(width); height = Math.round(height);\n if (this.canvas.width !== width) this.canvas.width = width;\n if (this.canvas.height !== height) this.canvas.height = height;\n }\n private readonly settings = new WeakMap<Render, string>();\n /** @internal */ _configure(render: Render) {\n if (render._engine !== this.engine) throw new Error('Render belongs to another engine.');\n const target = render._output;\n if (!target) return;\n const key = displaySettingsKey(this);\n const previous = this.settings.get(render);\n if (previous !== key) {\n this.settings.set(render, key);\n if (previous !== undefined) render._displayChanged();\n }\n target.activate();\n applyDisplaySettings(this, target);\n }\n private readonly _postProcesses: {pass: PostProcess}[] = [];\n private _warnedPostProcess = false;\n /** Registers a display pass in order and returns an idempotent removal function. Default no passes. WebGPU only; WebGL skips passes with one warning. Runs after composition on every present/toBlob, without tracing or invalidating denoising. A thrown error discards the whole chain, presents the original image and emits engine error. */\n addPostProcess(pass: PostProcess): () => void {\n const entry = {pass};\n this._postProcesses.push(entry);\n if (this.engine.backend === 'webgl') this.warnPostProcess();\n return () => { const index = this._postProcesses.indexOf(entry); if (index >= 0) this._postProcesses.splice(index, 1); };\n }\n private warnPostProcess() {\n if (!this._warnedPostProcess) { this._warnedPostProcess = true; console.warn('Display post-processing requires WebGPU; passes are ignored on WebGL.'); }\n }\n private compose(render: Render) {\n if (render._engine !== this.engine) throw new Error('Render belongs to another engine.');\n const target = render._output;\n if (!target?.presentationComplete) return;\n this._configure(render);\n target.drawPostProcess();\n if (this._postProcesses.length && this.engine.backend === 'webgl') this.warnPostProcess();\n try { target.applyPostProcesses?.(this._postProcesses.map(entry => entry.pass), render); }\n catch (error) { this.engine._notifyError(error); }\n return target;\n }\n /** Presents a complete image or fallback. Keeps fallback visible until the first intermediate filter finishes. Does not trace. */\n present(render: Render): Render | undefined {\n if (render._engine !== this.engine) throw new Error('Render belongs to another engine.');\n const ready = this.channel === 'final' && render.fallback ? render._presentable : render._complete;\n const fallback = render.fallback;\n const selected = ready ? render : fallback && (this.channel === 'final' ? fallback._presentable : fallback._complete) ? fallback : undefined;\n if (!selected) return;\n const target = this.compose(selected);\n if (!target) return;\n this.engine._present(target);\n return selected;\n }\n /** Encodes this render at its actual dimensions using these settings; leaves the display canvas unchanged. */\n async toBlob(render: Render, options: BlobOptions = {}): Promise<Blob> {\n const target = this.compose(render);\n if (!target) throw new Error('Render has no complete image.');\n const image = await target.readPresentation();\n const canvas = createCanvas(image.width, image.height, 'convertToBlob' in this.canvas);\n const context = canvas.getContext('2d') as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;\n if (!context) throw new Error('The image encoding context is not available.');\n const bytes = new Uint8ClampedArray(image.data.length);\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.round(Math.min(1, Math.max(0, image.data[i])) * 255);\n context.putImageData(new ImageData(bytes, image.width, image.height), 0, 0);\n if ('convertToBlob' in canvas) return canvas.convertToBlob({type: options.type ?? 'image/png', quality: options.quality});\n return new Promise((resolve, reject) => canvas.toBlob(blob => blob ? resolve(blob) : reject(new Error('The image could not be encoded')), options.type ?? 'image/png', options.quality));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Display.js","sourceRoot":"","sources":["../src/Display.ts"],"names":[],"mappings":"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","sourcesContent":["import {displayAovKind, validateAovDisplay, type AovIdComponent} from './renderer/aovDisplay.js';\nexport type {AovIdComponent} from './renderer/aovDisplay.js';\nimport {createCanvas} from './util/canvas.js';\nimport type Engine from './Engine.js';\nimport type Render from './Render.js';\nimport type { ToneMapping, DisplayChannel } from './renderer/RenderingPipeline.js';\nimport type { ColorRGB } from './types.js';\nimport { displaySettingsKey, displayFilterSettingsKey, applyDisplaySettings } from './settings/display.js';\n/** Display image channels. Default final. */\nexport type {DisplayChannel} from './renderer/RenderingPipeline.js';\n/** Image encoding options for Display.toBlob. */\nexport interface BlobOptions {\n /** Browser image MIME type. Default image/png. */ type?: string;\n /** Encoder quality in 0–1. Default undefined uses the browser default. */ quality?: number;\n}\n/** Optional shared display settings; defaults match Display. */\nexport interface DisplaySettings {\n /** Tone mapping transform. Default agx. */ toneMapping?: ToneMapping;\n /** Linear exposure multiplier. Default 1. */ toneMappingExposure?: number;\n /** Contrast multiplier. Default 1. */ contrast?: number;\n /** Saturation multiplier. Default 1. */ saturation?: number;\n /** White balance temperature shift in -1–1. Default 0. */ temperature?: number;\n /** Green/magenta tint in -1–1. Default 0. */ tint?: number;\n /** Vignette strength in 0–1. Default 0. */ vignette?: number;\n /** Bloom intensity; 0 disables it. Default 0. */ bloomIntensity?: number;\n /** Bloom luminance threshold. Default 1. */ bloomThreshold?: number;\n /** Bloom radius in 0–1. Default 0.6. */ bloomRadius?: number;\n /** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled?: boolean;\n /** Display image channel. Default final. AOV channels require explicit Render.aovs. */ channel?: DisplayChannel;\n /** Finite float32 scene-unit depths mapped to black/white; 0 <= near < far. Default [0, 10]. */ aovDepthRange?: readonly [number, number];\n /** Finite positive float32 scene-unit half-range around the origin for position RGB. Default 1. */ aovPositionScale?: number;\n /** Finite positive float32 input-pixel displacement mapped to full motion brightness. Default 16. */ aovMotionScale?: number;\n /** Stable ID lane to colorize. Default object. */ aovIdComponent?: AovIdComponent;\n /** Linear shadow-catcher color. Default black. */ shadowCatcherColor?: ColorRGB;\n /** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha?: number;\n}\n/** Borrowed WebGPU images for one synchronous display pass. */\nexport interface PostProcessContext {\n /** Engine device; may change after recovery. */ device: GPUDevice;\n /** Record commands here; the library finishes and submits it. */ encoder: GPUCommandEncoder;\n /** Read-only composed display image, top row first; no additional color conversion. */ input: GPUTexture;\n /** Fully write this image. Same format and dimensions as input; supports render, storage and copy writes. */ output: GPUTexture;\n /** Actual render width. */ width: number;\n /** Actual render height. */ height: number;\n /** Selected complete render, including a selected fallback. */ render: Render;\n}\n/** Synchronous display pass. Images and encoder are borrowed only during the call; do not retain or destroy them. */\nexport type PostProcess = (context: PostProcessContext) => void;\n/** Canvas presentation and shared display settings; obtained from engine.display. */\nexport default class Display {\n /** Display canvas. Default the supplied Engine canvas, or a new canvas (OffscreenCanvas without document). */ readonly canvas: HTMLCanvasElement | OffscreenCanvas;\n /** Tone mapping transform. Default agx. */ toneMapping: ToneMapping = 'agx';\n /** Linear exposure multiplier. Default 1. */ toneMappingExposure = 1;\n /** Contrast multiplier. Default 1. */ contrast = 1;\n /** Saturation multiplier. Default 1. */ saturation = 1;\n /** White balance temperature shift in -1–1. Default 0. */ temperature = 0;\n /** Green/magenta tint in -1–1. Default 0. */ tint = 0;\n /** Vignette strength in 0–1. Default 0. */ vignette = 0;\n /** Bloom intensity; 0 disables it. Default 0. */ bloomIntensity = 0;\n /** Bloom luminance threshold. Default 1. */ bloomThreshold = 1;\n /** Bloom radius in 0–1. Default 0.6. */ bloomRadius = 0.6;\n /** Extended-range WebGPU presentation, ignored on WebGL. Default false. */ hdrOutputEnabled = false;\n /** Display image channel. Default final. AOV channels require explicit Render.aovs. */ channel: DisplayChannel = 'final';\n /** Finite float32 scene-unit depths mapped to black/white; 0 <= near < far. Default [0, 10]. */ aovDepthRange: readonly [number, number] = [0, 10];\n /** Finite positive float32 scene-unit half-range around the origin for position RGB. Default 1. */ aovPositionScale = 1;\n /** Finite positive float32 input-pixel displacement mapped to full motion brightness. Default 16. */ aovMotionScale = 16;\n /** Stable ID lane to colorize. Default object. */ aovIdComponent: AovIdComponent = 'object';\n /** Linear shadow-catcher color. Default black. */ shadowCatcherColor: ColorRGB = [0, 0, 0];\n /** Shadow-catcher opacity multiplier. Default 1. */ shadowCatcherAlpha = 1;\n private constructor(private readonly engine: Engine, canvas: HTMLCanvasElement | OffscreenCanvas) { this.canvas = canvas; }\n /** @internal */ static _create(engine: Engine, canvas: HTMLCanvasElement | OffscreenCanvas) { return new Display(engine, canvas); }\n /** Resizes the drawing buffer; scale-based renders resize at their next refine. */\n setSize(width: number, height: number) {\n if (!Number.isFinite(width) || !Number.isFinite(height) || width < 1 || height < 1) throw new Error('Display dimensions must be positive.');\n width = Math.round(width); height = Math.round(height);\n if (this.canvas.width !== width) this.canvas.width = width;\n if (this.canvas.height !== height) this.canvas.height = height;\n }\n private readonly _filterSettings = new WeakMap<Render, string>();\n private readonly settings = new WeakMap<Render, string>();\n /** @internal */ _configure(render: Render) {\n if (render._engine !== this.engine) throw new Error('Render belongs to another engine.');\n const target = render._output;\n if (!target) return;\n const kind = displayAovKind(this.channel);\n if (!kind && !['final','normal','albedo','shadow','shadowCatcher'].includes(this.channel)) throw new RangeError('Unknown display channel');\n if (kind && !render.aovs.includes(kind)) throw new Error(`AOV ${kind} is not enabled on the selected render`);\n validateAovDisplay({depthRange: this.aovDepthRange, positionScale: this.aovPositionScale, motionScale: this.aovMotionScale, idComponent: this.aovIdComponent});\n const key = displaySettingsKey(this);\n const filterKey = displayFilterSettingsKey(this);\n const previous = this.settings.get(render);\n if (previous !== key) {\n this.settings.set(render, key);\n if (previous !== undefined && this._filterSettings.get(render) !== filterKey) render._displayChanged();\n this._filterSettings.set(render, filterKey);\n }\n target.activate();\n applyDisplaySettings(this, target);\n }\n private readonly _postProcesses: {pass: PostProcess}[] = [];\n private _warnedPostProcess = false;\n /** Registers a display pass in order and returns an idempotent removal function. Default no passes. WebGPU only; WebGL skips passes with one warning. Runs after composition on every present/toBlob, without tracing or invalidating denoising. A thrown error discards the whole chain, presents the original image and emits engine error. */\n addPostProcess(pass: PostProcess): () => void {\n const entry = {pass};\n this._postProcesses.push(entry);\n if (this.engine.backend === 'webgl') this.warnPostProcess();\n return () => { const index = this._postProcesses.indexOf(entry); if (index >= 0) this._postProcesses.splice(index, 1); };\n }\n private warnPostProcess() {\n if (!this._warnedPostProcess) { this._warnedPostProcess = true; console.warn('Display post-processing requires WebGPU; passes are ignored on WebGL.'); }\n }\n private compose(render: Render) {\n if (render._engine !== this.engine) throw new Error('Render belongs to another engine.');\n const target = render._output;\n if (!target) return;\n const kind = displayAovKind(this.channel);\n if (!kind && !target.presentationComplete) return;\n if (kind && !render.aovs.includes(kind)) throw new Error(`AOV ${kind} is not enabled on the selected render`);\n if (kind && target.aovReady && !target.aovReady(kind)) return;\n this._configure(render);\n target.drawPostProcess();\n if (this._postProcesses.length && this.engine.backend === 'webgl') this.warnPostProcess();\n try { target.applyPostProcesses?.(this._postProcesses.map(entry => entry.pass), render); }\n catch (error) { this.engine._notifyError(error); }\n return target;\n }\n /** Presents a complete image or fallback. Keeps fallback visible until the first intermediate filter finishes. Does not trace. */\n present(render: Render): Render | undefined {\n if (render._engine !== this.engine) throw new Error('Render belongs to another engine.');\n const ready = this.channel === 'final' && render.fallback ? render._presentable : render._completeFor(this.channel);\n const fallback = render.fallback;\n const selected = ready ? render : fallback && (this.channel === 'final' ? fallback._presentable : fallback._completeFor(this.channel)) ? fallback : undefined;\n if (!selected) return;\n const target = this.compose(selected);\n if (!target) return;\n this.engine._present(target);\n return selected;\n }\n /** Encodes this render at its actual dimensions using these settings; leaves the display canvas unchanged. */\n async toBlob(render: Render, options: BlobOptions = {}): Promise<Blob> {\n const target = this.compose(render);\n if (!target) throw new Error('Render has no complete image.');\n const image = render._cropOutput(await target.readPresentation());\n const canvas = createCanvas(image.width, image.height, 'convertToBlob' in this.canvas);\n const context = canvas.getContext('2d') as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;\n if (!context) throw new Error('The image encoding context is not available.');\n const bytes = new Uint8ClampedArray(image.data.length);\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.round(Math.min(1, Math.max(0, image.data[i])) * 255);\n context.putImageData(new ImageData(bytes, image.width, image.height), 0, 0);\n if ('convertToBlob' in canvas) return canvas.convertToBlob({type: options.type ?? 'image/png', quality: options.quality});\n return new Promise((resolve, reject) => canvas.toBlob(blob => blob ? resolve(blob) : reject(new Error('The image could not be encoded')), options.type ?? 'image/png', options.quality));\n }\n}\n"]}
|