@meimu/mutracer 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/GLSL-PathTracer-MIT.txt +21 -0
- package/LICENSES/GlMatrix-MIT.txt +19 -0
- package/LICENSES/KinoBloom-MIT.txt +21 -0
- package/LICENSES/OIDNWeb-MIT.txt +21 -0
- package/LICENSES/Octicons-MIT.txt +21 -0
- package/LICENSES/RayTracingRenderer-MIT.txt +21 -0
- package/LICENSES/TinyBVH-MIT.txt +21 -0
- package/LICENSES/WebGPUUtils-MIT.txt +21 -0
- package/LICENSES/ZetaRay-MIT.txt +21 -0
- package/README.md +195 -2
- package/THIRD_PARTY_NOTICES.md +160 -0
- package/dist/assets/bvh.worker.js +1 -0
- package/dist/mutracer.umd.js +14352 -0
- package/docs/api.md +394 -0
- package/docs/bvh.md +141 -0
- package/docs/denoising.md +301 -0
- package/docs/getting-started.md +308 -0
- package/docs/materials.md +281 -0
- package/docs/performance.md +85 -0
- package/docs/post-processing.md +87 -0
- package/docs/progressive-rendering.md +144 -0
- package/docs/sampling.md +40 -0
- package/docs/threejs.md +273 -0
- package/docs/todo.md +61 -0
- package/docs/updates.md +208 -0
- package/lib/Display.d.ts +72 -0
- package/lib/Display.js +121 -0
- package/lib/Display.js.map +1 -0
- package/lib/Engine.d.ts +161 -0
- package/lib/Engine.js +681 -0
- package/lib/Engine.js.map +1 -0
- package/lib/Render.d.ts +256 -0
- package/lib/Render.js +671 -0
- package/lib/Render.js.map +1 -0
- package/lib/RenderLoop.d.ts +76 -0
- package/lib/RenderLoop.js +204 -0
- package/lib/RenderLoop.js.map +1 -0
- package/lib/Sync.d.ts +19 -0
- package/lib/Sync.js +19 -0
- package/lib/Sync.js.map +1 -0
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +3 -0
- package/lib/constants.js.map +1 -0
- package/lib/main.d.ts +56 -0
- package/lib/main.js +43 -0
- package/lib/main.js.map +1 -0
- package/lib/math.d.ts +23 -0
- package/lib/math.js +56 -0
- package/lib/math.js.map +1 -0
- package/lib/oidn.d.ts +45 -0
- package/lib/oidn.js +42 -0
- package/lib/oidn.js.map +1 -0
- package/lib/oidnBundledWeights.cdn.d.ts +2 -0
- package/lib/oidnBundledWeights.cdn.js +5 -0
- package/lib/oidnBundledWeights.cdn.js.map +1 -0
- package/lib/oidnBundledWeights.d.ts +2 -0
- package/lib/oidnBundledWeights.js +4 -0
- package/lib/oidnBundledWeights.js.map +1 -0
- package/lib/renderer/DisplayPostProcess.d.ts +14 -0
- package/lib/renderer/DisplayPostProcess.js +41 -0
- package/lib/renderer/DisplayPostProcess.js.map +1 -0
- package/lib/renderer/MaterialTable.d.ts +119 -0
- package/lib/renderer/MaterialTable.js +550 -0
- package/lib/renderer/MaterialTable.js.map +1 -0
- package/lib/renderer/OfflineAdaptiveSampling.d.ts +47 -0
- package/lib/renderer/OfflineAdaptiveSampling.js +36 -0
- package/lib/renderer/OfflineAdaptiveSampling.js.map +1 -0
- package/lib/renderer/RenderingPipeline.d.ts +232 -0
- package/lib/renderer/RenderingPipeline.js +18 -0
- package/lib/renderer/RenderingPipeline.js.map +1 -0
- package/lib/renderer/ScratchPool.d.ts +13 -0
- package/lib/renderer/ScratchPool.js +21 -0
- package/lib/renderer/ScratchPool.js.map +1 -0
- package/lib/renderer/TileRender.d.ts +44 -0
- package/lib/renderer/TileRender.js +283 -0
- package/lib/renderer/TileRender.js.map +1 -0
- package/lib/renderer/WGPUBloomPass.d.ts +17 -0
- package/lib/renderer/WGPUBloomPass.js +243 -0
- package/lib/renderer/WGPUBloomPass.js.map +1 -0
- package/lib/renderer/WGPUCanvasSurface.d.ts +21 -0
- package/lib/renderer/WGPUCanvasSurface.js +48 -0
- package/lib/renderer/WGPUCanvasSurface.js.map +1 -0
- package/lib/renderer/WGPUComputePass.d.ts +73 -0
- package/lib/renderer/WGPUComputePass.js +317 -0
- package/lib/renderer/WGPUComputePass.js.map +1 -0
- package/lib/renderer/WGPUFullQuadPass.d.ts +73 -0
- package/lib/renderer/WGPUFullQuadPass.js +389 -0
- package/lib/renderer/WGPUFullQuadPass.js.map +1 -0
- package/lib/renderer/WGPUHDRPeakMeter.d.ts +19 -0
- package/lib/renderer/WGPUHDRPeakMeter.js +112 -0
- package/lib/renderer/WGPUHDRPeakMeter.js.map +1 -0
- package/lib/renderer/WGPUJNLMDenoiser.d.ts +61 -0
- package/lib/renderer/WGPUJNLMDenoiser.js +412 -0
- package/lib/renderer/WGPUJNLMDenoiser.js.map +1 -0
- package/lib/renderer/WGPURayTraceOutput.d.ts +44 -0
- package/lib/renderer/WGPURayTraceOutput.js +368 -0
- package/lib/renderer/WGPURayTraceOutput.js.map +1 -0
- package/lib/renderer/WGPURayTracePass.d.ts +284 -0
- package/lib/renderer/WGPURayTracePass.js +2323 -0
- package/lib/renderer/WGPURayTracePass.js.map +1 -0
- package/lib/renderer/WGPURenderingPipeline.d.ts +9 -0
- package/lib/renderer/WGPURenderingPipeline.js +1446 -0
- package/lib/renderer/WGPURenderingPipeline.js.map +1 -0
- package/lib/renderer/WGPUSceneFeatures.d.ts +3 -0
- package/lib/renderer/WGPUSceneFeatures.js +20 -0
- package/lib/renderer/WGPUSceneFeatures.js.map +1 -0
- package/lib/renderer/WGPUScratchBuffer.d.ts +9 -0
- package/lib/renderer/WGPUScratchBuffer.js +21 -0
- package/lib/renderer/WGPUScratchBuffer.js.map +1 -0
- package/lib/renderer/WGPUScratchTexture.d.ts +10 -0
- package/lib/renderer/WGPUScratchTexture.js +27 -0
- package/lib/renderer/WGPUScratchTexture.js.map +1 -0
- package/lib/renderer/WGPUShaderCache.d.ts +26 -0
- package/lib/renderer/WGPUShaderCache.js +103 -0
- package/lib/renderer/WGPUShaderCache.js.map +1 -0
- package/lib/renderer/WebGLBloomPass.d.ts +18 -0
- package/lib/renderer/WebGLBloomPass.js +113 -0
- package/lib/renderer/WebGLBloomPass.js.map +1 -0
- package/lib/renderer/WebGLFullQuadPass.d.ts +65 -0
- package/lib/renderer/WebGLFullQuadPass.js +208 -0
- package/lib/renderer/WebGLFullQuadPass.js.map +1 -0
- package/lib/renderer/WebGLJNLMDenoiser.d.ts +32 -0
- package/lib/renderer/WebGLJNLMDenoiser.js +328 -0
- package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -0
- package/lib/renderer/WebGLRayTraceOutputPass.d.ts +20 -0
- package/lib/renderer/WebGLRayTraceOutputPass.js +106 -0
- package/lib/renderer/WebGLRayTraceOutputPass.js.map +1 -0
- package/lib/renderer/WebGLRayTracePass.d.ts +142 -0
- package/lib/renderer/WebGLRayTracePass.js +845 -0
- package/lib/renderer/WebGLRayTracePass.js.map +1 -0
- package/lib/renderer/WebGLReadback.d.ts +4 -0
- package/lib/renderer/WebGLReadback.js +75 -0
- package/lib/renderer/WebGLReadback.js.map +1 -0
- package/lib/renderer/WebGLRenderingPipeline.d.ts +4 -0
- package/lib/renderer/WebGLRenderingPipeline.js +510 -0
- package/lib/renderer/WebGLRenderingPipeline.js.map +1 -0
- package/lib/renderer/WebGLScratchCopy.d.ts +10 -0
- package/lib/renderer/WebGLScratchCopy.js +27 -0
- package/lib/renderer/WebGLScratchCopy.js.map +1 -0
- package/lib/renderer/accumulationTarget.d.ts +26 -0
- package/lib/renderer/accumulationTarget.js +2 -0
- package/lib/renderer/accumulationTarget.js.map +1 -0
- package/lib/renderer/binnedSahBvh.d.ts +31 -0
- package/lib/renderer/binnedSahBvh.js +263 -0
- package/lib/renderer/binnedSahBvh.js.map +1 -0
- package/lib/renderer/bvh.worker.d.ts +1 -0
- package/lib/renderer/bvh.worker.js +16 -0
- package/lib/renderer/bvh.worker.js.map +1 -0
- package/lib/renderer/bvhAccel.d.ts +81 -0
- package/lib/renderer/bvhAccel.js +621 -0
- package/lib/renderer/bvhAccel.js.map +1 -0
- package/lib/renderer/bvhWorkerBuild.d.ts +12 -0
- package/lib/renderer/bvhWorkerBuild.js +17 -0
- package/lib/renderer/bvhWorkerBuild.js.map +1 -0
- package/lib/renderer/bvhWorkerClient.d.ts +57 -0
- package/lib/renderer/bvhWorkerClient.js +166 -0
- package/lib/renderer/bvhWorkerClient.js.map +1 -0
- package/lib/renderer/cameraLens.d.ts +5 -0
- package/lib/renderer/cameraLens.js +15 -0
- package/lib/renderer/cameraLens.js.map +1 -0
- package/lib/renderer/cameraSnapshot.d.ts +3 -0
- package/lib/renderer/cameraSnapshot.js +7 -0
- package/lib/renderer/cameraSnapshot.js.map +1 -0
- package/lib/renderer/committedScene.d.ts +13 -0
- package/lib/renderer/committedScene.js +121 -0
- package/lib/renderer/committedScene.js.map +1 -0
- package/lib/renderer/dataTextureUtil.d.ts +32 -0
- package/lib/renderer/dataTextureUtil.js +46 -0
- package/lib/renderer/dataTextureUtil.js.map +1 -0
- package/lib/renderer/denoiser.d.ts +65 -0
- package/lib/renderer/denoiser.js +2 -0
- package/lib/renderer/denoiser.js.map +1 -0
- package/lib/renderer/depthQuery.d.ts +14 -0
- package/lib/renderer/depthQuery.js +14 -0
- package/lib/renderer/depthQuery.js.map +1 -0
- package/lib/renderer/deviceRequirements.d.ts +23 -0
- package/lib/renderer/deviceRequirements.js +50 -0
- package/lib/renderer/deviceRequirements.js.map +1 -0
- package/lib/renderer/envMapCreation.d.ts +10 -0
- package/lib/renderer/envMapCreation.js +96 -0
- package/lib/renderer/envMapCreation.js.map +1 -0
- package/lib/renderer/envMapDistribution.d.ts +9 -0
- package/lib/renderer/envMapDistribution.js +107 -0
- package/lib/renderer/envMapDistribution.js.map +1 -0
- package/lib/renderer/float16.d.ts +1 -0
- package/lib/renderer/float16.js +19 -0
- package/lib/renderer/float16.js.map +1 -0
- package/lib/renderer/geometryBvh.d.ts +11 -0
- package/lib/renderer/geometryBvh.js +24 -0
- package/lib/renderer/geometryBvh.js.map +1 -0
- package/lib/renderer/geometryUpdates.d.ts +28 -0
- package/lib/renderer/geometryUpdates.js +131 -0
- package/lib/renderer/geometryUpdates.js.map +1 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +37 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/common.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/common.glsl.js +17 -0
- package/lib/renderer/glsl/chunks/common.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/envMap.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/envMap.glsl.js +192 -0
- package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/intersect.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/intersect.glsl.js +1091 -0
- package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +371 -0
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +1767 -0
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/rand.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/rand.glsl.js +26 -0
- package/lib/renderer/glsl/chunks/rand.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/random.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/random.glsl.js +27 -0
- package/lib/renderer/glsl/chunks/random.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +287 -0
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/sampleLight.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js +254 -0
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +279 -0
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +48 -0
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/sampling.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/sampling.glsl.js +194 -0
- package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/sobol.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/sobol.glsl.js +170 -0
- package/lib/renderer/glsl/chunks/sobol.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/textureLinear.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/textureLinear.glsl.js +27 -0
- package/lib/renderer/glsl/chunks/textureLinear.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/uvProjection.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js +72 -0
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js.map +1 -0
- package/lib/renderer/glsl/depthQuery.frag.d.ts +3 -0
- package/lib/renderer/glsl/depthQuery.frag.js +55 -0
- package/lib/renderer/glsl/depthQuery.frag.js.map +1 -0
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.d.ts +6 -0
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +46 -0
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js.map +1 -0
- package/lib/renderer/glsl/rayTrace.frag.d.ts +2 -0
- package/lib/renderer/glsl/rayTrace.frag.js +619 -0
- package/lib/renderer/glsl/rayTrace.frag.js.map +1 -0
- package/lib/renderer/glsl/shadowCatcher.frag.d.ts +3 -0
- package/lib/renderer/glsl/shadowCatcher.frag.js +119 -0
- package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -0
- package/lib/renderer/glsl/webglPipeline.frag.d.ts +4 -0
- package/lib/renderer/glsl/webglPipeline.frag.js +208 -0
- package/lib/renderer/glsl/webglPipeline.frag.js.map +1 -0
- package/lib/renderer/gpuMemory.d.ts +2 -0
- package/lib/renderer/gpuMemory.js +10 -0
- package/lib/renderer/gpuMemory.js.map +1 -0
- package/lib/renderer/halton.d.ts +1 -0
- package/lib/renderer/halton.js +15 -0
- package/lib/renderer/halton.js.map +1 -0
- package/lib/renderer/jnlm.d.ts +85 -0
- package/lib/renderer/jnlm.js +87 -0
- package/lib/renderer/jnlm.js.map +1 -0
- package/lib/renderer/lightSampling.d.ts +75 -0
- package/lib/renderer/lightSampling.js +305 -0
- package/lib/renderer/lightSampling.js.map +1 -0
- package/lib/renderer/lightsUtil.d.ts +26 -0
- package/lib/renderer/lightsUtil.js +154 -0
- package/lib/renderer/lightsUtil.js.map +1 -0
- package/lib/renderer/materialChanges.d.ts +13 -0
- package/lib/renderer/materialChanges.js +59 -0
- package/lib/renderer/materialChanges.js.map +1 -0
- package/lib/renderer/materialComparison.generated.d.ts +5 -0
- package/lib/renderer/materialComparison.generated.js +655 -0
- package/lib/renderer/materialComparison.generated.js.map +1 -0
- package/lib/renderer/materialConstants.d.ts +6 -0
- package/lib/renderer/materialConstants.js +3 -0
- package/lib/renderer/materialConstants.js.map +1 -0
- package/lib/renderer/materialEmission.d.ts +9 -0
- package/lib/renderer/materialEmission.js +21 -0
- package/lib/renderer/materialEmission.js.map +1 -0
- package/lib/renderer/materialIndices.d.ts +7 -0
- package/lib/renderer/materialIndices.js +34 -0
- package/lib/renderer/materialIndices.js.map +1 -0
- package/lib/renderer/materialLayout.d.ts +102 -0
- package/lib/renderer/materialLayout.js +189 -0
- package/lib/renderer/materialLayout.js.map +1 -0
- package/lib/renderer/materialTextureSlots.d.ts +537 -0
- package/lib/renderer/materialTextureSlots.js +219 -0
- package/lib/renderer/materialTextureSlots.js.map +1 -0
- package/lib/renderer/mergeMeshesToGeometry.d.ts +8 -0
- package/lib/renderer/mergeMeshesToGeometry.js +236 -0
- package/lib/renderer/mergeMeshesToGeometry.js.map +1 -0
- package/lib/renderer/meshInstances.d.ts +23 -0
- package/lib/renderer/meshInstances.js +66 -0
- package/lib/renderer/meshInstances.js.map +1 -0
- package/lib/renderer/meshMembership.d.ts +10 -0
- package/lib/renderer/meshMembership.js +72 -0
- package/lib/renderer/meshMembership.js.map +1 -0
- package/lib/renderer/oidnNetwork.d.ts +20 -0
- package/lib/renderer/oidnNetwork.js +123 -0
- package/lib/renderer/oidnNetwork.js.map +1 -0
- package/lib/renderer/openPbrEnergyLut.d.ts +32 -0
- package/lib/renderer/openPbrEnergyLut.js +965 -0
- package/lib/renderer/openPbrEnergyLut.js.map +1 -0
- package/lib/renderer/pathLimits.d.ts +4 -0
- package/lib/renderer/pathLimits.js +7 -0
- package/lib/renderer/pathLimits.js.map +1 -0
- package/lib/renderer/prepareMeshBVH.d.ts +110 -0
- package/lib/renderer/prepareMeshBVH.js +857 -0
- package/lib/renderer/prepareMeshBVH.js.map +1 -0
- package/lib/renderer/progressiveScheduler.d.ts +11 -0
- package/lib/renderer/progressiveScheduler.js +19 -0
- package/lib/renderer/progressiveScheduler.js.map +1 -0
- package/lib/renderer/renderPipeline.d.ts +57 -0
- package/lib/renderer/renderPipeline.js +49 -0
- package/lib/renderer/renderPipeline.js.map +1 -0
- package/lib/renderer/sampling.d.ts +10 -0
- package/lib/renderer/sampling.js +28 -0
- package/lib/renderer/sampling.js.map +1 -0
- package/lib/renderer/sceneChangeDetector.d.ts +29 -0
- package/lib/renderer/sceneChangeDetector.js +232 -0
- package/lib/renderer/sceneChangeDetector.js.map +1 -0
- package/lib/renderer/sceneLightChanges.d.ts +14 -0
- package/lib/renderer/sceneLightChanges.js +34 -0
- package/lib/renderer/sceneLightChanges.js.map +1 -0
- package/lib/renderer/scratchSampling.d.ts +3 -0
- package/lib/renderer/scratchSampling.js +39 -0
- package/lib/renderer/scratchSampling.js.map +1 -0
- package/lib/renderer/shader.d.ts +37 -0
- package/lib/renderer/shader.js +41 -0
- package/lib/renderer/shader.js.map +1 -0
- package/lib/renderer/staticBvhPreparation.d.ts +24 -0
- package/lib/renderer/staticBvhPreparation.js +116 -0
- package/lib/renderer/staticBvhPreparation.js.map +1 -0
- package/lib/renderer/textureRegion.d.ts +8 -0
- package/lib/renderer/textureRegion.js +9 -0
- package/lib/renderer/textureRegion.js.map +1 -0
- package/lib/renderer/texturesFromMaterials.d.ts +6 -0
- package/lib/renderer/texturesFromMaterials.js +37 -0
- package/lib/renderer/texturesFromMaterials.js.map +1 -0
- package/lib/renderer/util.d.ts +17 -0
- package/lib/renderer/util.js +56 -0
- package/lib/renderer/util.js.map +1 -0
- package/lib/renderer/webgl.d.ts +131 -0
- package/lib/renderer/webgl.js +586 -0
- package/lib/renderer/webgl.js.map +1 -0
- package/lib/renderer/webglShaders.d.ts +4 -0
- package/lib/renderer/webglShaders.js +41 -0
- package/lib/renderer/webglShaders.js.map +1 -0
- package/lib/renderer/wgsl/chunks/common.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/common.wgsl.js +23 -0
- package/lib/renderer/wgsl/chunks/common.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js +128 -0
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +6 -0
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +1441 -0
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +8 -0
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +85 -0
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +7 -0
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +315 -0
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.d.ts +3 -0
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +1737 -0
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +352 -0
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/rand.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/rand.wgsl.js +25 -0
- package/lib/renderer/wgsl/chunks/rand.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/random.wgsl.d.ts +1 -0
- package/lib/renderer/wgsl/chunks/random.wgsl.js +2 -0
- package/lib/renderer/wgsl/chunks/random.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +5 -0
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +328 -0
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +400 -0
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +3 -0
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +439 -0
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +40 -0
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js +198 -0
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.d.ts +8 -0
- package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js +16 -0
- package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/sobol.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js +170 -0
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +42 -0
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +5 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.js +218 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/customDenoise.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/customDenoise.wgsl.js +28 -0
- package/lib/renderer/wgsl/customDenoise.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +3 -0
- package/lib/renderer/wgsl/depthQuery.wgsl.js +34 -0
- package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/offlineAdaptive.compute.d.ts +2 -0
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +108 -0
- package/lib/renderer/wgsl/offlineAdaptive.compute.js.map +1 -0
- package/lib/renderer/wgsl/rayTrace.compute.d.ts +16 -0
- package/lib/renderer/wgsl/rayTrace.compute.js +923 -0
- package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -0
- package/lib/scene/AmbientLight.d.ts +17 -0
- package/lib/scene/AmbientLight.js +15 -0
- package/lib/scene/AmbientLight.js.map +1 -0
- package/lib/scene/Camera.d.ts +78 -0
- package/lib/scene/Camera.js +111 -0
- package/lib/scene/Camera.js.map +1 -0
- package/lib/scene/DirectionalLight.d.ts +18 -0
- package/lib/scene/DirectionalLight.js +17 -0
- package/lib/scene/DirectionalLight.js.map +1 -0
- package/lib/scene/EnvironmentLight.d.ts +14 -0
- package/lib/scene/EnvironmentLight.js +14 -0
- package/lib/scene/EnvironmentLight.js.map +1 -0
- package/lib/scene/Geometry.d.ts +87 -0
- package/lib/scene/Geometry.js +108 -0
- package/lib/scene/Geometry.js.map +1 -0
- package/lib/scene/IESProfile.d.ts +19 -0
- package/lib/scene/IESProfile.js +165 -0
- package/lib/scene/IESProfile.js.map +1 -0
- package/lib/scene/InstancedMesh.d.ts +43 -0
- package/lib/scene/InstancedMesh.js +79 -0
- package/lib/scene/InstancedMesh.js.map +1 -0
- package/lib/scene/Mesh.d.ts +14 -0
- package/lib/scene/Mesh.js +17 -0
- package/lib/scene/Mesh.js.map +1 -0
- package/lib/scene/OpenPBRMaterial.d.ts +224 -0
- package/lib/scene/OpenPBRMaterial.js +240 -0
- package/lib/scene/OpenPBRMaterial.js.map +1 -0
- package/lib/scene/RectLight.d.ts +31 -0
- package/lib/scene/RectLight.js +26 -0
- package/lib/scene/RectLight.js.map +1 -0
- package/lib/scene/Scene.d.ts +55 -0
- package/lib/scene/Scene.js +2 -0
- package/lib/scene/Scene.js.map +1 -0
- package/lib/scene/SceneNode.d.ts +16 -0
- package/lib/scene/SceneNode.js +33 -0
- package/lib/scene/SceneNode.js.map +1 -0
- package/lib/scene/SphereLight.d.ts +22 -0
- package/lib/scene/SphereLight.js +20 -0
- package/lib/scene/SphereLight.js.map +1 -0
- package/lib/scene/SpotLight.d.ts +35 -0
- package/lib/scene/SpotLight.js +29 -0
- package/lib/scene/SpotLight.js.map +1 -0
- package/lib/scene/Texture.d.ts +38 -0
- package/lib/scene/Texture.js +37 -0
- package/lib/scene/Texture.js.map +1 -0
- package/lib/scene/anisotropyParameters.d.ts +1 -0
- package/lib/scene/anisotropyParameters.js +13 -0
- package/lib/scene/anisotropyParameters.js.map +1 -0
- package/lib/scene/geometryChanges.d.ts +5 -0
- package/lib/scene/geometryChanges.js +18 -0
- package/lib/scene/geometryChanges.js.map +1 -0
- package/lib/scene/materialTextureNames.d.ts +2 -0
- package/lib/scene/materialTextureNames.js +9 -0
- package/lib/scene/materialTextureNames.js.map +1 -0
- package/lib/scene/openPbrSchema.d.ts +400 -0
- package/lib/scene/openPbrSchema.js +149 -0
- package/lib/scene/openPbrSchema.js.map +1 -0
- package/lib/scene/thinFilmParameters.d.ts +4 -0
- package/lib/scene/thinFilmParameters.js +12 -0
- package/lib/scene/thinFilmParameters.js.map +1 -0
- package/lib/settings/display.d.ts +118 -0
- package/lib/settings/display.js +34 -0
- package/lib/settings/display.js.map +1 -0
- package/lib/settings/engine.d.ts +37 -0
- package/lib/settings/engine.js +26 -0
- package/lib/settings/engine.js.map +1 -0
- package/lib/settings/render.d.ts +178 -0
- package/lib/settings/render.js +36 -0
- package/lib/settings/render.js.map +1 -0
- package/lib/tinybvh/LICENSE +21 -0
- package/lib/tinybvh/TinyBvhBuilder.d.ts +17 -0
- package/lib/tinybvh/TinyBvhBuilder.js +211 -0
- package/lib/tinybvh/TinyBvhBuilder.js.map +1 -0
- package/lib/tinybvh/tinybvh.wasm +0 -0
- package/lib/types.d.ts +13 -0
- package/lib/types.js +2 -0
- package/lib/types.js.map +1 -0
- package/lib/util/canvas.d.ts +2 -0
- package/lib/util/canvas.js +13 -0
- package/lib/util/canvas.js.map +1 -0
- package/lib/util/commonGeometry.d.ts +15 -0
- package/lib/util/commonGeometry.js +240 -0
- package/lib/util/commonGeometry.js.map +1 -0
- package/lib/util/events.d.ts +7 -0
- package/lib/util/events.js +23 -0
- package/lib/util/events.js.map +1 -0
- package/lib/util/frame.d.ts +2 -0
- package/lib/util/frame.js +10 -0
- package/lib/util/frame.js.map +1 -0
- package/lib/util/fromTHREE.d.ts +100 -0
- package/lib/util/fromTHREE.js +1063 -0
- package/lib/util/fromTHREE.js.map +1 -0
- package/lib/util/geometry.d.ts +13 -0
- package/lib/util/geometry.js +292 -0
- package/lib/util/geometry.js.map +1 -0
- package/lib/util/loadRGBE.d.ts +7 -0
- package/lib/util/loadRGBE.js +168 -0
- package/lib/util/loadRGBE.js.map +1 -0
- package/lib/util/math.d.ts +8 -0
- package/lib/util/math.js +64 -0
- package/lib/util/math.js.map +1 -0
- package/lib/util/mesh.d.ts +7 -0
- package/lib/util/mesh.js +20 -0
- package/lib/util/mesh.js.map +1 -0
- package/lib/util/threeDeformation.d.ts +20 -0
- package/lib/util/threeDeformation.js +218 -0
- package/lib/util/threeDeformation.js.map +1 -0
- package/lib/version.d.ts +2 -0
- package/lib/version.js +3 -0
- package/lib/version.js.map +1 -0
- package/llms.txt +62 -0
- package/oidn/weights/LICENSE.txt +202 -0
- package/oidn/weights/README.md +43 -0
- package/oidn/weights/rt_hdr_alb_nrm.tza +0 -0
- package/oidn/weights/rt_hdr_alb_nrm_small.tza +0 -0
- package/package.json +124 -4
package/lib/Render.js
ADDED
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
import { Events } from './util/events.js';
|
|
2
|
+
import { cameraSnapshot } from './renderer/cameraSnapshot.js';
|
|
3
|
+
import { collectTraceSettings, imageSettingsKey } from './settings/render.js';
|
|
4
|
+
import { DEFAULT_JNLM_OPTIONS, createJNLMDenoiser } from './renderer/jnlm.js';
|
|
5
|
+
import { nextPreviewScale } from './renderer/util.js';
|
|
6
|
+
let oidnModule;
|
|
7
|
+
const loadOIDN = () => oidnModule ??= import('./renderer/oidnNetwork.js');
|
|
8
|
+
function validateDenoiserOptions(options) {
|
|
9
|
+
if (!options || typeof options !== 'object' || (options.type !== 'jnlm' && options.type !== 'oidn' && options.type !== 'custom'))
|
|
10
|
+
throw new Error('Denoiser type must be jnlm, oidn or custom.');
|
|
11
|
+
const allowed = options.type === 'jnlm'
|
|
12
|
+
? ['type', 'schedule', ...Object.keys(DEFAULT_JNLM_OPTIONS)]
|
|
13
|
+
: options.type === 'custom' ? ['type', 'schedule', 'denoiser']
|
|
14
|
+
: ['type', 'schedule', 'model', 'weightsBaseUrl', 'weightsUrl', 'aux', 'hdr', 'hdrTransfer', 'auxiliaryModelUrls', 'engine', 'precision', 'dynamicTile', 'maxTileSize', 'signal'];
|
|
15
|
+
for (const key of Object.keys(options))
|
|
16
|
+
if (!allowed.includes(key))
|
|
17
|
+
throw new Error(`Denoiser field ${key} does not belong to ${options.type}.`);
|
|
18
|
+
if (options.schedule !== undefined && !['converged', 'progressive', 'every-sample'].includes(options.schedule))
|
|
19
|
+
throw new Error('Unknown denoise schedule.');
|
|
20
|
+
if (options.type === 'jnlm')
|
|
21
|
+
createJNLMDenoiser(options);
|
|
22
|
+
else if (options.type === 'custom') {
|
|
23
|
+
if (!options.denoiser || typeof options.denoiser !== 'object' || typeof options.denoiser.denoise !== 'function' || (options.denoiser.prepare !== undefined && typeof options.denoiser.prepare !== 'function'))
|
|
24
|
+
throw new Error('Custom denoiser must implement denoise and optional prepare.');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
if (options.weightsUrl !== undefined) {
|
|
28
|
+
if (options.model !== undefined || options.weightsBaseUrl !== undefined)
|
|
29
|
+
throw new Error('weightsUrl is mutually exclusive with model and weightsBaseUrl.');
|
|
30
|
+
}
|
|
31
|
+
else if (options.aux !== undefined || options.hdr !== undefined || options.hdrTransfer !== undefined)
|
|
32
|
+
throw new Error('aux, hdr and hdrTransfer require weightsUrl.');
|
|
33
|
+
for (const key of ['weightsUrl', 'weightsBaseUrl'])
|
|
34
|
+
if (options[key] !== undefined && !isURL(options[key]))
|
|
35
|
+
throw new Error(`${key} must be a nonempty string or URL.`);
|
|
36
|
+
if (options.auxiliaryModelUrls !== undefined) {
|
|
37
|
+
const urls = options.auxiliaryModelUrls;
|
|
38
|
+
if (!urls || !isURL(urls.albedo) || !isURL(urls.normal) || Object.keys(urls).some(key => !['albedo', 'normal'].includes(key)))
|
|
39
|
+
throw new Error('auxiliaryModelUrls requires only albedo and normal URLs.');
|
|
40
|
+
}
|
|
41
|
+
for (const [key, values] of [['engine', ['auto', 'wgsl', 'webnn']], ['precision', ['auto', 'fp32', 'fp16']], ['hdrTransfer', ['pu', 'log']]]) {
|
|
42
|
+
if (options[key] !== undefined && !values.includes(options[key]))
|
|
43
|
+
throw new Error(`Unknown OIDN ${key}.`);
|
|
44
|
+
}
|
|
45
|
+
for (const key of ['aux', 'hdr'])
|
|
46
|
+
if (options[key] !== undefined && typeof options[key] !== 'boolean')
|
|
47
|
+
throw new Error(`${key} must be boolean.`);
|
|
48
|
+
if (options.dynamicTile !== undefined && typeof options.dynamicTile !== 'boolean') {
|
|
49
|
+
if (!options.dynamicTile || typeof options.dynamicTile !== 'object')
|
|
50
|
+
throw new Error('dynamicTile must be boolean or tile settings.');
|
|
51
|
+
for (const [key, value] of Object.entries(options.dynamicTile)) {
|
|
52
|
+
if (!['minTileSize', 'initialTileSize', 'targetTileTimeMs', 'adjustmentStep'].includes(key) || (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value) || value <= 0)))
|
|
53
|
+
throw new Error(`Invalid dynamicTile ${key}.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (options.model !== undefined && !['standard', 'small', 'cleanAuxLarge'].includes(options.model))
|
|
57
|
+
throw new Error('Unknown OIDN model.');
|
|
58
|
+
if (options.maxTileSize !== undefined && (!Number.isInteger(options.maxTileSize) || options.maxTileSize < 1))
|
|
59
|
+
throw new Error('maxTileSize must be a positive integer.');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function isURL(value) { return (typeof value === 'string' && value.length > 0) || value instanceof URL; }
|
|
63
|
+
// Snapshot nested values too, so application edits cannot silently change a cache key.
|
|
64
|
+
function snapshotDenoiserOptions(options) {
|
|
65
|
+
if (options.type !== 'oidn')
|
|
66
|
+
return Object.freeze({ ...options });
|
|
67
|
+
const next = { ...options };
|
|
68
|
+
if (options.weightsBaseUrl !== undefined)
|
|
69
|
+
next.weightsBaseUrl = String(options.weightsBaseUrl);
|
|
70
|
+
if (options.weightsUrl !== undefined)
|
|
71
|
+
next.weightsUrl = String(options.weightsUrl);
|
|
72
|
+
if (options.auxiliaryModelUrls !== undefined)
|
|
73
|
+
next.auxiliaryModelUrls = Object.freeze({ albedo: String(options.auxiliaryModelUrls.albedo), normal: String(options.auxiliaryModelUrls.normal) });
|
|
74
|
+
if (typeof options.dynamicTile === 'object')
|
|
75
|
+
next.dynamicTile = Object.freeze({ ...options.dynamicTile });
|
|
76
|
+
return Object.freeze(next);
|
|
77
|
+
}
|
|
78
|
+
function denoiserKey(options) {
|
|
79
|
+
if (options.type === 'custom')
|
|
80
|
+
return options.denoiser;
|
|
81
|
+
if (options.type === 'jnlm')
|
|
82
|
+
return JSON.stringify({ type: 'jnlm', ...Object.fromEntries(Object.entries(DEFAULT_JNLM_OPTIONS).map(([key, value]) => [key, options[key] ?? value])) });
|
|
83
|
+
const tile = options.dynamicTile;
|
|
84
|
+
return JSON.stringify({ type: 'oidn',
|
|
85
|
+
...(options.weightsUrl === undefined ? { model: options.model ?? 'standard', weightsBaseUrl: options.weightsBaseUrl?.toString() } : { weightsUrl: String(options.weightsUrl), aux: options.aux ?? true, hdr: options.hdr ?? true, hdrTransfer: options.hdrTransfer ?? 'pu' }),
|
|
86
|
+
auxiliaryModelUrls: options.auxiliaryModelUrls && { albedo: String(options.auxiliaryModelUrls.albedo), normal: String(options.auxiliaryModelUrls.normal) },
|
|
87
|
+
maxTileSize: options.maxTileSize, engine: options.engine ?? 'auto', precision: options.precision ?? 'auto',
|
|
88
|
+
dynamicTile: tile === false ? false : { minTileSize: typeof tile === 'object' ? tile.minTileSize ?? 256 : 256,
|
|
89
|
+
initialTileSize: typeof tile === 'object' ? tile.initialTileSize ?? 432 : 432,
|
|
90
|
+
targetTileTimeMs: typeof tile === 'object' ? tile.targetTileTimeMs ?? 16 : 16,
|
|
91
|
+
adjustmentStep: typeof tile === 'object' ? tile.adjustmentStep ?? 16 : 16 }
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** One independently configured image and its accumulation, owned by an engine. */
|
|
95
|
+
export default class Render {
|
|
96
|
+
/** Maximum complete samples. Default 2048. */ maxSamples = 2048;
|
|
97
|
+
/**
|
|
98
|
+
* Maximum scattering depth, rounded and clamped to [1, 20] (NaN becomes 1).
|
|
99
|
+
* Total path events, including transmission and alpha skips, are capped at 20
|
|
100
|
+
* and at three times this depth. Intel Mac WebGL uses min(depth, 3), doubled
|
|
101
|
+
* for scenes with transmission or alpha, with its existing early termination.
|
|
102
|
+
* Default 3.
|
|
103
|
+
*/ bounces = 3;
|
|
104
|
+
/** Per-sample radiance clamp; 0 disables it. Default 0. */ clamping = 0;
|
|
105
|
+
/** Sampling sequence. Default sobol. */ samplingPattern = 'sobol';
|
|
106
|
+
/** WebGPU light candidates per vertex; ignored on WebGL. Default 4. */ directLightCandidates = 4;
|
|
107
|
+
/** Rounded material edges. Default true. */ bevel = true;
|
|
108
|
+
/** Bevel probes, clamped to 1–32. Default 8. */ bevelSamples = 8;
|
|
109
|
+
/** Dispersion wavelengths per sample. Default 3. */ dispersionWavelengths = 3;
|
|
110
|
+
/** WebGPU primary-ray alpha policy; ignored on WebGL. Default stochastic. */ alphaBlendStrategy = 'stochastic';
|
|
111
|
+
/** Minimum transmissive path alpha. Default 1. Changing it restarts this render. */ transmissiveOutputAlphaMin = 1;
|
|
112
|
+
/** Execution budget in milliseconds. Default 21. */ timeBudgetMs = 21;
|
|
113
|
+
/** Maximum tiles per frame. Default Infinity. */ maxTiles = Infinity;
|
|
114
|
+
/** Allow several samples per frame when possible. Default false. */ allowMultipleSamplesPerFrame = false;
|
|
115
|
+
/** Adaptive resolution controller, or false. Default false. */ adaptiveResolution = false;
|
|
116
|
+
_resolutionScale = 1;
|
|
117
|
+
/** Canvas-relative scale. Default 1; cannot be assigned on a fixed-size render. */
|
|
118
|
+
get resolutionScale() { return this._resolutionScale; }
|
|
119
|
+
set resolutionScale(value) {
|
|
120
|
+
if (this._fixed)
|
|
121
|
+
throw new Error('Fixed-size renders cannot use resolutionScale.');
|
|
122
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
123
|
+
throw new Error('resolutionScale must be positive.');
|
|
124
|
+
this._resolutionScale = value;
|
|
125
|
+
}
|
|
126
|
+
_fallback = null;
|
|
127
|
+
/** Single-level fallback on this engine. Default null; chains and cycles are rejected. */
|
|
128
|
+
get fallback() { return this._fallback; }
|
|
129
|
+
set fallback(value) {
|
|
130
|
+
if (value && (value._engine !== this._engine || value === this || value.fallback))
|
|
131
|
+
throw new Error('Fallback must be a render on the same engine with no fallback.');
|
|
132
|
+
if (value && this._dependents.size)
|
|
133
|
+
throw new Error('Fallback renders cannot have their own fallback.');
|
|
134
|
+
this._fallback?._dependents.delete(this);
|
|
135
|
+
this._fallback = value;
|
|
136
|
+
value?._dependents.add(this);
|
|
137
|
+
}
|
|
138
|
+
_dependents = new Set();
|
|
139
|
+
_denoiserOptions = null;
|
|
140
|
+
/** Frozen configuration snapshot. Default null. Change it with {@link Render.setDenoiser}. */
|
|
141
|
+
get denoiser() { return this._denoiserOptions; }
|
|
142
|
+
/**
|
|
143
|
+
* Replaces the denoising configuration; null disables denoising. Invalid options throw synchronously
|
|
144
|
+
* before replacing any state. Resolves when the filter is ready to use (after OIDN weights load) or this
|
|
145
|
+
* configuration is replaced; rejects when loading fails. An equal configuration returns the current
|
|
146
|
+
* promise without reloading.
|
|
147
|
+
*/
|
|
148
|
+
setDenoiser(options) {
|
|
149
|
+
if (options !== null)
|
|
150
|
+
validateDenoiserOptions(options);
|
|
151
|
+
const next = options ? snapshotDenoiserOptions(options) : null;
|
|
152
|
+
const current = this._denoiserOptions;
|
|
153
|
+
if (current === null && next === null)
|
|
154
|
+
return this._denoiserReady;
|
|
155
|
+
if (next && current && denoiserKey(next) === denoiserKey(current)
|
|
156
|
+
&& next.schedule === current.schedule && (next.type !== 'oidn' ||
|
|
157
|
+
(current.type === 'oidn' && next.signal === current.signal)))
|
|
158
|
+
return this._denoiserReady;
|
|
159
|
+
this._denoiserOptions = next;
|
|
160
|
+
return this._refreshDenoiser() ?? this._denoiserReady;
|
|
161
|
+
}
|
|
162
|
+
_denoiserReady = Promise.resolve();
|
|
163
|
+
_fixed;
|
|
164
|
+
_target;
|
|
165
|
+
_status = 'preparing';
|
|
166
|
+
_disposed = false;
|
|
167
|
+
_busy = false;
|
|
168
|
+
_offlineCamera = false;
|
|
169
|
+
_input = { scene: -1, camera: -1, settings: '' };
|
|
170
|
+
_adaptiveScale = 1;
|
|
171
|
+
_lastScale = 1;
|
|
172
|
+
_frameTime = 0;
|
|
173
|
+
_events = new Events();
|
|
174
|
+
/** Owning engine. */ get engine() { return this._engine; }
|
|
175
|
+
/** Whether inference is queued or running, including intermediate updates. Default false. */ get denoising() { return !!this._denoisePending; }
|
|
176
|
+
/** Subscribes to every complete sample on this render; returns unsubscribe. */
|
|
177
|
+
on(event, listener) { return this._events.on(event, listener); }
|
|
178
|
+
_filter;
|
|
179
|
+
_filterKey = '';
|
|
180
|
+
_warnedWebGPUFilter = false;
|
|
181
|
+
_denoiseController;
|
|
182
|
+
_filterRevision = 0;
|
|
183
|
+
_filterPending;
|
|
184
|
+
_denoiseRevision = 0;
|
|
185
|
+
_denoisePending;
|
|
186
|
+
_denoisedSamples = 0;
|
|
187
|
+
_lastDenoiseTime = 0;
|
|
188
|
+
_warnedDenoisedReadback = false;
|
|
189
|
+
/** @internal */ _engine;
|
|
190
|
+
constructor(engine, options = {}) {
|
|
191
|
+
this._engine = engine;
|
|
192
|
+
if (options.denoiser != null)
|
|
193
|
+
validateDenoiserOptions(options.denoiser);
|
|
194
|
+
if ('width' in options || 'height' in options) {
|
|
195
|
+
if ('resolutionScale' in options || !Number.isInteger(options.width) || !Number.isInteger(options.height) || options.width < 1 || options.height < 1)
|
|
196
|
+
throw new Error('Provide positive integer width and height, or resolutionScale, exclusively.');
|
|
197
|
+
this._fixed = { width: options.width, height: options.height };
|
|
198
|
+
}
|
|
199
|
+
const { width: _width, height: _height, resolutionScale, fallback, denoiser, ...settings } = options;
|
|
200
|
+
Object.assign(this, settings);
|
|
201
|
+
if (resolutionScale !== undefined)
|
|
202
|
+
this.resolutionScale = resolutionScale;
|
|
203
|
+
this._adaptiveScale = this._resolutionScale;
|
|
204
|
+
this._lastScale = this._resolutionScale;
|
|
205
|
+
this._validate();
|
|
206
|
+
this.fallback = fallback ?? null;
|
|
207
|
+
engine._register(this);
|
|
208
|
+
if (denoiser)
|
|
209
|
+
void this.setDenoiser(denoiser).catch(error => this._engine._notifyError(error));
|
|
210
|
+
}
|
|
211
|
+
/** Actual target width; before allocation uses the requested dimensions. */ get width() { return this._target?.getMemory().width || this._size().width; }
|
|
212
|
+
/** Actual target height; before allocation uses the requested dimensions. */ get height() { return this._target?.getMemory().height || this._size().height; }
|
|
213
|
+
/** Complete samples since the last restart; stale engine inputs report 0. Default 0. */
|
|
214
|
+
get samples() { return this._current ? this._target?.getTotalSamplesRendered() ?? 0 : 0; }
|
|
215
|
+
/** Whether complete samples reached maxSamples. Default false. */ get converged() { return this.samples >= this.maxSamples; }
|
|
216
|
+
/** Current execution state. Default preparing. */ get status() {
|
|
217
|
+
if (!this._current && this._status !== 'error')
|
|
218
|
+
return this._engine._ready ? 'converging' : 'preparing';
|
|
219
|
+
return this._status;
|
|
220
|
+
}
|
|
221
|
+
get _current() { const inputs = this._engine._inputs; return inputs.scene === this._input.scene && inputs.camera === this._input.camera && !this._disposed; }
|
|
222
|
+
/** @internal */ get _complete() { return this._current && !!this._target?.presentationComplete && !this._target.isFirstFrame() && this.samples > 0; }
|
|
223
|
+
/** @internal */ get _output() { if (this._disposed)
|
|
224
|
+
throw new Error('Render is disposed.'); return this._target; }
|
|
225
|
+
_validate() {
|
|
226
|
+
if (!Number.isFinite(this.maxSamples) || this.maxSamples < 1)
|
|
227
|
+
throw new Error('maxSamples must be positive.');
|
|
228
|
+
if (this.dispersionWavelengths !== 1 && this.dispersionWavelengths !== 3)
|
|
229
|
+
throw new Error('dispersionWavelengths must be 1 or 3.');
|
|
230
|
+
const adaptive = this.adaptiveResolution;
|
|
231
|
+
if (adaptive && (this._fixed || !Number.isFinite(adaptive.targetFrameMs) || adaptive.targetFrameMs <= 0 || !Number.isFinite(adaptive.minScale) || adaptive.minScale <= 0 || adaptive.minScale > this._resolutionScale))
|
|
232
|
+
throw new Error('adaptiveResolution requires a scale-based render with positive targetFrameMs and minScale <= resolutionScale.');
|
|
233
|
+
}
|
|
234
|
+
_size() {
|
|
235
|
+
if (this._fixed)
|
|
236
|
+
return this._fixed;
|
|
237
|
+
const scale = this.adaptiveResolution ? Math.min(this._adaptiveScale, this._resolutionScale) : this._resolutionScale;
|
|
238
|
+
return { width: Math.max(1, Math.round(this._engine.display.canvas.width * scale)), height: Math.max(1, Math.round(this._engine.display.canvas.height * scale)) };
|
|
239
|
+
}
|
|
240
|
+
_settings(sampleCap = this.maxSamples) {
|
|
241
|
+
return collectTraceSettings(this, sampleCap);
|
|
242
|
+
}
|
|
243
|
+
_synchronize(sampleCap = this.maxSamples, offline = false) {
|
|
244
|
+
this._validate();
|
|
245
|
+
if (this._lastScale !== this._resolutionScale) {
|
|
246
|
+
this._adaptiveScale = this._resolutionScale;
|
|
247
|
+
this._lastScale = this._resolutionScale;
|
|
248
|
+
}
|
|
249
|
+
const target = this._target ??= this._engine._createTarget();
|
|
250
|
+
if (!target)
|
|
251
|
+
return;
|
|
252
|
+
const settings = this._settings(sampleCap), size = this._size();
|
|
253
|
+
const key = imageSettingsKey(settings, size);
|
|
254
|
+
const inputs = this._engine._inputs;
|
|
255
|
+
target.configure(settings);
|
|
256
|
+
target.activate();
|
|
257
|
+
if ((!offline && this._offlineCamera) || inputs.scene !== this._input.scene || inputs.camera !== this._input.camera || key !== this._input.settings) {
|
|
258
|
+
if (!offline)
|
|
259
|
+
this._offlineCamera = false;
|
|
260
|
+
this._cancelDenoise();
|
|
261
|
+
target.restartSamples();
|
|
262
|
+
target.setSize(size.width, size.height);
|
|
263
|
+
this._input = { scene: inputs.scene, camera: inputs.camera, settings: key };
|
|
264
|
+
}
|
|
265
|
+
target.setOnSampleRendered((samples, isFirstFrame, frameTimeMs) => { this._frameTime = frameTimeMs; this._events.emit('sample', { samples, isFirstFrame, frameTimeMs }); });
|
|
266
|
+
return target;
|
|
267
|
+
}
|
|
268
|
+
/** Accumulates within this frame's budget. Rejects calls during converge or after disposal. */
|
|
269
|
+
refine() {
|
|
270
|
+
if (this._busy)
|
|
271
|
+
throw new Error('Cannot refine a render while converge is running.');
|
|
272
|
+
if (this._disposed)
|
|
273
|
+
throw new Error('Render is disposed.');
|
|
274
|
+
this._engine._setRenderError();
|
|
275
|
+
try {
|
|
276
|
+
return this._refine();
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
this._engine._setRenderError(this._engine._notifyError(error));
|
|
280
|
+
return this._status = 'error';
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
this._engine._reportShaderProgress();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
_refine() {
|
|
287
|
+
if (this._engine._initializationError)
|
|
288
|
+
throw this._engine._initializationError;
|
|
289
|
+
this._reloadDenoiser();
|
|
290
|
+
if (!this._engine._ready) {
|
|
291
|
+
const generation = this._engine._deviceGeneration;
|
|
292
|
+
void this._engine.init().catch(error => {
|
|
293
|
+
if (this._disposed || generation !== this._engine._deviceGeneration)
|
|
294
|
+
return;
|
|
295
|
+
this._status = 'error';
|
|
296
|
+
this._engine._notifyError(error);
|
|
297
|
+
});
|
|
298
|
+
return this._status = 'preparing';
|
|
299
|
+
}
|
|
300
|
+
const target = this._synchronize();
|
|
301
|
+
if (!target)
|
|
302
|
+
return this._status = 'preparing';
|
|
303
|
+
if (this._fallback && this.samples === 0 && !target.canCompleteSampleWithin(this.timeBudgetMs) && !this._fallback._complete)
|
|
304
|
+
this._fallback._refineOne();
|
|
305
|
+
target.activate();
|
|
306
|
+
if (this._denoisePending)
|
|
307
|
+
return this._status = this.converged ? 'denoising' : 'converging';
|
|
308
|
+
target.setPreserveDenoisedOutput?.(!!this._filter && this._schedule() === 'progressive');
|
|
309
|
+
const limit = this._nextSampleTarget();
|
|
310
|
+
if (this.samples < limit) {
|
|
311
|
+
if (target.trace(this._engine._inputs.value, limit))
|
|
312
|
+
return this._status = 'compiling';
|
|
313
|
+
}
|
|
314
|
+
this._maybeDenoise(false, limit);
|
|
315
|
+
if (this._denoisePending)
|
|
316
|
+
return this._status = this.converged ? 'denoising' : 'converging';
|
|
317
|
+
if (this._filterPending && this.converged)
|
|
318
|
+
return this._status = 'preparing';
|
|
319
|
+
if (this.adaptiveResolution && this._frameTime > 0 && this.samples > 0)
|
|
320
|
+
this._adaptiveScale = nextPreviewScale(this._adaptiveScale, this._frameTime, this.adaptiveResolution.targetFrameMs, this._resolutionScale, this.adaptiveResolution.minScale);
|
|
321
|
+
return this._status = this.converged ? 'finished' : 'converging';
|
|
322
|
+
}
|
|
323
|
+
_refineOne() {
|
|
324
|
+
if (this._busy || this._disposed || !this._engine._ready)
|
|
325
|
+
return;
|
|
326
|
+
this._reloadDenoiser();
|
|
327
|
+
const target = this._synchronize();
|
|
328
|
+
if (!target)
|
|
329
|
+
return;
|
|
330
|
+
target.activate();
|
|
331
|
+
if (this.samples < 1)
|
|
332
|
+
this._status = target.trace(this._engine._inputs.value, 1) ? 'compiling' : 'converging';
|
|
333
|
+
this._maybeDenoise();
|
|
334
|
+
}
|
|
335
|
+
_schedule() { return this._denoiserOptions?.schedule ?? 'converged'; }
|
|
336
|
+
_nextSampleTarget() {
|
|
337
|
+
if (!this._filter)
|
|
338
|
+
return this.maxSamples;
|
|
339
|
+
if (this._schedule() === 'every-sample')
|
|
340
|
+
return Math.min(this.maxSamples, this.samples + 1);
|
|
341
|
+
if (this._schedule() === 'converged')
|
|
342
|
+
return this.maxSamples;
|
|
343
|
+
if (this._denoisedSamples === 0)
|
|
344
|
+
return 1;
|
|
345
|
+
if (performance.now() - this._lastDenoiseTime >= 10000)
|
|
346
|
+
return Math.min(this.maxSamples, this.samples + 1);
|
|
347
|
+
return Math.min(this.maxSamples, Math.max(4, this._denoisedSamples * 2));
|
|
348
|
+
}
|
|
349
|
+
/** Reloads a filter dropped by device recovery; failures report through engine errors. */
|
|
350
|
+
_reloadDenoiser() { void this._refreshDenoiser()?.catch(error => this._engine._notifyError(error)); }
|
|
351
|
+
/** Starts loading the configured filter; returns its readiness when a new configuration was applied. */
|
|
352
|
+
_refreshDenoiser() {
|
|
353
|
+
if (this._disposed)
|
|
354
|
+
return;
|
|
355
|
+
const options = this._denoiserOptions;
|
|
356
|
+
const key = options ? denoiserKey(options) : '';
|
|
357
|
+
if (key === this._filterKey)
|
|
358
|
+
return;
|
|
359
|
+
this._filterKey = key;
|
|
360
|
+
const revision = ++this._filterRevision;
|
|
361
|
+
this._cancelDenoise();
|
|
362
|
+
if (this._filter && this._filter.kind !== 'custom')
|
|
363
|
+
this._engine._releaseDenoiser(this._filter);
|
|
364
|
+
this._target?.invalidateDenoisedOutput();
|
|
365
|
+
this._filter = undefined;
|
|
366
|
+
this._filterPending = undefined;
|
|
367
|
+
if (!options)
|
|
368
|
+
return this._denoiserReady = Promise.resolve();
|
|
369
|
+
if (options.type === 'jnlm') {
|
|
370
|
+
this._filter = this._engine._retainDenoiser(`jnlm:${key}`, () => ({ kind: 'jnlm', denoiser: createJNLMDenoiser(options) }));
|
|
371
|
+
return this._denoiserReady = Promise.resolve();
|
|
372
|
+
}
|
|
373
|
+
const task = (async () => {
|
|
374
|
+
await this._engine.init();
|
|
375
|
+
if (this._engine.backend !== 'webgpu') {
|
|
376
|
+
if (revision === this._filterRevision && !this._warnedWebGPUFilter) {
|
|
377
|
+
this._warnedWebGPUFilter = true;
|
|
378
|
+
console.warn('This denoiser requires WebGPU; denoising is disabled for this render.');
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (revision !== this._filterRevision || this._disposed)
|
|
383
|
+
return;
|
|
384
|
+
if (options.type === 'custom') {
|
|
385
|
+
this._filter = { kind: 'custom', denoiser: options.denoiser };
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const { loadOIDNNetwork } = await loadOIDN();
|
|
389
|
+
const filter = await this._engine._acquireDenoiser(key, async () => ({ kind: 'oidn', denoiser: await loadOIDNNetwork(this._engine, options) }));
|
|
390
|
+
if (revision !== this._filterRevision || this._disposed) {
|
|
391
|
+
this._engine._releaseDenoiser(filter);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
this._filter = filter;
|
|
395
|
+
this._warmDenoiser();
|
|
396
|
+
})();
|
|
397
|
+
this._filterPending = task;
|
|
398
|
+
// Superseded or disposed loads resolve instead of reporting obsolete failures.
|
|
399
|
+
return this._denoiserReady = task.catch(error => { if (revision === this._filterRevision && !this._disposed)
|
|
400
|
+
throw error; })
|
|
401
|
+
.finally(() => { if (this._filterPending === task)
|
|
402
|
+
this._filterPending = undefined; });
|
|
403
|
+
}
|
|
404
|
+
_warmDenoiser() {
|
|
405
|
+
const filter = this._filter, revision = this._filterRevision;
|
|
406
|
+
if (!filter || filter.kind !== 'oidn')
|
|
407
|
+
return;
|
|
408
|
+
const network = filter.denoiser;
|
|
409
|
+
const filters = [network, network.auxiliaryDenoisers?.albedo, network.auxiliaryDenoisers?.normal];
|
|
410
|
+
const width = this.width, height = this.height;
|
|
411
|
+
const task = this._engine._enqueueDenoise(async () => {
|
|
412
|
+
if (revision !== this._filterRevision || filter !== this._filter || this._disposed)
|
|
413
|
+
return;
|
|
414
|
+
await Promise.all(filters.map(network => network?.prepareForImage?.(width, height, { tileOverlap: this._schedule() === 'converged' ? undefined : 80 })));
|
|
415
|
+
});
|
|
416
|
+
void task.catch(error => {
|
|
417
|
+
if (revision === this._filterRevision && filter === this._filter && !this._disposed)
|
|
418
|
+
this._engine._notifyError(error);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
_cancelDenoise() { this._denoiseController?.abort(); this._denoiseController = undefined; this._denoiseRevision++; this._target?.cancelDenoise?.(); this._denoisePending = undefined; this._denoisedSamples = 0; }
|
|
422
|
+
/** @internal */ _inputsChanged(resetTiming = false) { this._cancelDenoise(); if (resetTiming)
|
|
423
|
+
this._target?.invalidateTiming?.(); }
|
|
424
|
+
/** @internal */ _deviceLost(recovering) {
|
|
425
|
+
this._cancelDenoise();
|
|
426
|
+
this._filterRevision++;
|
|
427
|
+
this._filter = undefined;
|
|
428
|
+
this._filterPending = undefined;
|
|
429
|
+
this._filterKey = '';
|
|
430
|
+
this._target = undefined;
|
|
431
|
+
this._input = { scene: -1, camera: -1, settings: '' };
|
|
432
|
+
this._status = recovering ? 'preparing' : 'error';
|
|
433
|
+
}
|
|
434
|
+
/** @internal */ _displayChanged() { this._cancelDenoise(); this._target?.invalidateDenoisedOutput(); }
|
|
435
|
+
_maybeDenoise(force = false, sampleTarget = this._nextSampleTarget()) {
|
|
436
|
+
const target = this._target, filter = this._filter;
|
|
437
|
+
if (!target || !filter || this._denoisePending || this.samples < 1 || this._denoisedSamples === this.samples)
|
|
438
|
+
return;
|
|
439
|
+
if (!force && this._schedule() === 'converged' && !this.converged)
|
|
440
|
+
return;
|
|
441
|
+
if (!force && this._schedule() === 'progressive' && this.samples < sampleTarget)
|
|
442
|
+
return;
|
|
443
|
+
this._engine.display._configure(this);
|
|
444
|
+
target.activate();
|
|
445
|
+
target.drawPostProcess();
|
|
446
|
+
const revision = ++this._denoiseRevision, samples = this.samples;
|
|
447
|
+
const controller = this._denoiseController = new AbortController();
|
|
448
|
+
// One shared scratch lease across all renders; queued stale jobs do no GPU work.
|
|
449
|
+
const task = this._engine._enqueueDenoise(async () => {
|
|
450
|
+
if (revision !== this._denoiseRevision || this._disposed)
|
|
451
|
+
return;
|
|
452
|
+
target.activate();
|
|
453
|
+
this._engine.display._configure(this);
|
|
454
|
+
if (revision !== this._denoiseRevision || this._disposed)
|
|
455
|
+
return;
|
|
456
|
+
target.drawPostProcess();
|
|
457
|
+
if (filter.kind === 'custom') {
|
|
458
|
+
await this._engine._prepareCustomDenoiser(filter.denoiser, this.width, this.height);
|
|
459
|
+
if (controller.signal.aborted || revision !== this._denoiseRevision || this._disposed)
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const complete = await target.performDenoise?.(filter, undefined, this._schedule(), controller.signal);
|
|
463
|
+
if (revision !== this._denoiseRevision || this._disposed)
|
|
464
|
+
return;
|
|
465
|
+
if (complete) {
|
|
466
|
+
target.activate();
|
|
467
|
+
target.drawPostProcess();
|
|
468
|
+
this._denoisedSamples = samples;
|
|
469
|
+
this._lastDenoiseTime = performance.now();
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
this._denoisePending = task;
|
|
473
|
+
void task.catch(error => { if (revision === this._denoiseRevision && !this._disposed)
|
|
474
|
+
this._engine._notifyError(error); }).finally(() => { if (this._denoisePending === task) {
|
|
475
|
+
this._denoiseController = undefined;
|
|
476
|
+
this._denoisePending = undefined;
|
|
477
|
+
this._status = this.converged ? 'finished' : 'converging';
|
|
478
|
+
} });
|
|
479
|
+
}
|
|
480
|
+
/** Reads native RGBA float32, top row first. Default hdr. Custom denoised output is resolved linear HDR ray color before display background/catcher composition; built-ins retain their native display-space output. Unavailable denoised output falls back to hdr. */
|
|
481
|
+
async readPixels(kind = 'hdr') {
|
|
482
|
+
if (this._disposed)
|
|
483
|
+
throw new Error('Render is disposed.');
|
|
484
|
+
const target = this._target;
|
|
485
|
+
if (!target)
|
|
486
|
+
return { width: 0, height: 0, data: new Float32Array(0) };
|
|
487
|
+
if (kind === 'denoised' && this._denoisedSamples === 0) {
|
|
488
|
+
if (!this._warnedDenoisedReadback) {
|
|
489
|
+
this._warnedDenoisedReadback = true;
|
|
490
|
+
console.warn('Denoised output is not ready; reading HDR samples instead.');
|
|
491
|
+
}
|
|
492
|
+
kind = 'hdr';
|
|
493
|
+
}
|
|
494
|
+
target.activate();
|
|
495
|
+
return target.readOutput(kind);
|
|
496
|
+
}
|
|
497
|
+
/** Borrows a read-only WebGPU texture; undefined on WebGL or before a complete sample. Kind is required. HDR is native resolved linear ray color before denoising/display composition, with DenoiseInput.color normalization and coverage. Display is the latest compose, including filters and display passes. Valid only until this render's next refine/converge, display present/setSize, restart/dispose or device loss; never retain, write or destroy it. */
|
|
498
|
+
getOutputTexture(kind) {
|
|
499
|
+
if (!this._complete || this._engine.backend !== 'webgpu')
|
|
500
|
+
return;
|
|
501
|
+
return this._target?.getOutputTexture?.(kind);
|
|
502
|
+
}
|
|
503
|
+
/** Discards only this render's accumulation and pending denoising. */
|
|
504
|
+
restart() { if (this._disposed)
|
|
505
|
+
throw new Error('Render is disposed.'); this._cancelDenoise(); this._target?.restartSamples(); this._status = 'converging'; }
|
|
506
|
+
/** Releases only this render's image resources and denoiser. */
|
|
507
|
+
dispose() {
|
|
508
|
+
if (this._disposed)
|
|
509
|
+
return;
|
|
510
|
+
this._disposed = true;
|
|
511
|
+
this._events.clear();
|
|
512
|
+
this._filterRevision++;
|
|
513
|
+
this._cancelDenoise();
|
|
514
|
+
if (this._target)
|
|
515
|
+
this._engine._releaseTarget(this._target);
|
|
516
|
+
if (this._filter && this._filter.kind !== 'custom')
|
|
517
|
+
this._engine._releaseDenoiser(this._filter);
|
|
518
|
+
this._target = undefined;
|
|
519
|
+
this._filter = undefined;
|
|
520
|
+
this._engine._unregister(this);
|
|
521
|
+
this._fallback?._dependents.delete(this);
|
|
522
|
+
for (const dependent of this._dependents)
|
|
523
|
+
dependent._fallback = null;
|
|
524
|
+
this._dependents.clear();
|
|
525
|
+
}
|
|
526
|
+
/** Deterministically renders this image. Rejects on abort/timeout/input revision changes and blocks refine on this render. */
|
|
527
|
+
async converge(options) {
|
|
528
|
+
if (this._busy)
|
|
529
|
+
throw new Error('Converge is already running on this render.');
|
|
530
|
+
if (this._disposed)
|
|
531
|
+
throw new Error('Render is disposed.');
|
|
532
|
+
const inputs = this._engine._inputs;
|
|
533
|
+
const deviceGeneration = this._engine._deviceGeneration;
|
|
534
|
+
if (!inputs.value)
|
|
535
|
+
throw new Error('Commit engine.scene and engine.camera with engine.update() before converge.');
|
|
536
|
+
const camera = cameraSnapshot(options.camera ?? inputs.value);
|
|
537
|
+
const samples = Math.max(1, Math.round(options.samples));
|
|
538
|
+
if (!Number.isFinite(samples))
|
|
539
|
+
throw new Error('samples must be finite and positive.');
|
|
540
|
+
const batchLimit = Math.max(1, Math.round(options.samplesPerBatch ?? 8));
|
|
541
|
+
const sequenceOffset = Math.max(0, Math.round(options.sampleSequenceOffset ?? 0));
|
|
542
|
+
const timeout = Math.max(1, options.timeoutMs ?? 600000);
|
|
543
|
+
const check = () => {
|
|
544
|
+
if (this._disposed)
|
|
545
|
+
throw new Error('Render is disposed.');
|
|
546
|
+
if (this._engine._deviceGeneration !== deviceGeneration)
|
|
547
|
+
throw this._engine._lostError;
|
|
548
|
+
if (options.signal?.aborted)
|
|
549
|
+
throw options.signal.reason ?? new DOMException('Convergence aborted', 'AbortError');
|
|
550
|
+
const current = this._engine._inputs;
|
|
551
|
+
if (current.scene !== inputs.scene || current.camera !== inputs.camera)
|
|
552
|
+
throw new Error('Engine inputs changed during converge.');
|
|
553
|
+
};
|
|
554
|
+
this._busy = true;
|
|
555
|
+
const abortConverge = () => this._cancelDenoise();
|
|
556
|
+
options.signal?.addEventListener('abort', abortConverge, { once: true });
|
|
557
|
+
let target;
|
|
558
|
+
const start = performance.now();
|
|
559
|
+
try {
|
|
560
|
+
await this._engine._awaitDevice(this._engine.init());
|
|
561
|
+
check();
|
|
562
|
+
while (!this._engine._ready) {
|
|
563
|
+
check();
|
|
564
|
+
if (performance.now() - start > timeout)
|
|
565
|
+
throw new Error('Timed out preparing convergence.');
|
|
566
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
567
|
+
}
|
|
568
|
+
target = this._synchronize(samples, true);
|
|
569
|
+
this._offlineCamera = !!options.camera;
|
|
570
|
+
if (!target)
|
|
571
|
+
throw new Error('The render target is not ready.');
|
|
572
|
+
this._cancelDenoise();
|
|
573
|
+
target.restartSamples();
|
|
574
|
+
this._reloadDenoiser();
|
|
575
|
+
await this._engine._awaitDevice(Promise.resolve(this._filterPending));
|
|
576
|
+
check();
|
|
577
|
+
const stage = async (cap, name, offset) => {
|
|
578
|
+
check();
|
|
579
|
+
this._cancelDenoise();
|
|
580
|
+
target.activate();
|
|
581
|
+
target.restartSamples();
|
|
582
|
+
target.configure({ ...this._settings(cap), allowMultipleSamplesPerFrame: true });
|
|
583
|
+
let batch = options.targetBatchTimeMs && this._engine.device ? 1 : Math.min(batchLimit, cap);
|
|
584
|
+
let previous = -1, lastPreview = performance.now();
|
|
585
|
+
const started = performance.now();
|
|
586
|
+
for (;;) {
|
|
587
|
+
check();
|
|
588
|
+
if (performance.now() - started > timeout)
|
|
589
|
+
throw new Error(`Timed out rendering the offline ${name} pass.`);
|
|
590
|
+
target.activate();
|
|
591
|
+
target.setOfflineRenderOptions({ samplesPerBatch: batch, deferPostProcess: true, sampleSequenceOffset: offset });
|
|
592
|
+
const before = target.getTotalSamplesRendered(), batchStarted = performance.now();
|
|
593
|
+
this._status = target.trace(camera, cap) ? 'compiling' : 'converging';
|
|
594
|
+
const count = target.getTotalSamplesRendered();
|
|
595
|
+
if (count !== previous) {
|
|
596
|
+
previous = count;
|
|
597
|
+
options.onProgress?.({ stage: name, samples: Math.min(count, cap), targetSamples: cap });
|
|
598
|
+
if (name === 'final' && options.previewIntervalMs !== undefined && count > 0 && count < cap && performance.now() - lastPreview >= options.previewIntervalMs) {
|
|
599
|
+
target.drawPostProcess();
|
|
600
|
+
lastPreview = performance.now();
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (count >= cap)
|
|
604
|
+
break;
|
|
605
|
+
if (count > before && this._engine.device)
|
|
606
|
+
await this._engine._awaitDevice(this._engine.device.queue.onSubmittedWorkDone());
|
|
607
|
+
else
|
|
608
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
609
|
+
if (options.targetBatchTimeMs && this._engine.device && count > before) {
|
|
610
|
+
const desired = Math.max(1, Math.min(batchLimit, Math.round(options.targetBatchTimeMs * (count - before) / Math.max(1, performance.now() - batchStarted))));
|
|
611
|
+
batch = desired > batch ? Math.min(desired, batch * 2) : desired;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
await this._engine._awaitDevice(Promise.resolve(this._engine.device?.queue.onSubmittedWorkDone()));
|
|
615
|
+
check();
|
|
616
|
+
};
|
|
617
|
+
let result = { samples, averageSamplesPerPixel: samples, pilotSamples: 0, adaptiveSampling: false };
|
|
618
|
+
if (options.adaptiveSampling && this._engine.device) {
|
|
619
|
+
const pilotSamples = Math.min(samples, Math.max(2, Math.round(options.adaptiveSampling.pilotSamples ?? 8)));
|
|
620
|
+
target.activate();
|
|
621
|
+
target.setVarianceMoments(true);
|
|
622
|
+
target.setAdaptiveSamplingTargets(undefined);
|
|
623
|
+
await stage(pilotSamples, 'pilot', sequenceOffset);
|
|
624
|
+
target.activate();
|
|
625
|
+
const plan = await this._engine._awaitDevice(target.prepareOfflineAdaptiveSampling({ ...options.adaptiveSampling, maxSamples: samples }));
|
|
626
|
+
if (plan) {
|
|
627
|
+
target.activate();
|
|
628
|
+
target.setVarianceMoments(false);
|
|
629
|
+
await stage(plan.maximumTarget, 'final', sequenceOffset + pilotSamples);
|
|
630
|
+
result = { samples: plan.maximumTarget, averageSamplesPerPixel: plan.averageTarget, pilotSamples, varianceHistory: plan.history, adaptiveSampling: true };
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
target.setVarianceMoments(false);
|
|
634
|
+
target.setAdaptiveSamplingTargets(undefined);
|
|
635
|
+
await stage(samples, 'final', sequenceOffset);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
target.activate();
|
|
640
|
+
target.setVarianceMoments(false);
|
|
641
|
+
target.setAdaptiveSamplingTargets(undefined);
|
|
642
|
+
await stage(samples, 'final', sequenceOffset);
|
|
643
|
+
}
|
|
644
|
+
if (this._filter) {
|
|
645
|
+
options.onProgress?.({ stage: 'denoising', samples: result.samples, targetSamples: result.samples });
|
|
646
|
+
this._status = 'denoising';
|
|
647
|
+
this._maybeDenoise(true);
|
|
648
|
+
await this._engine._awaitDevice(Promise.resolve(this._denoisePending));
|
|
649
|
+
check();
|
|
650
|
+
}
|
|
651
|
+
this._status = 'finished';
|
|
652
|
+
return result;
|
|
653
|
+
}
|
|
654
|
+
catch (error) {
|
|
655
|
+
if (this._engine._deviceGeneration === deviceGeneration)
|
|
656
|
+
this._status = 'error';
|
|
657
|
+
throw error;
|
|
658
|
+
}
|
|
659
|
+
finally {
|
|
660
|
+
if (target && !this._disposed && this._engine._deviceGeneration === deviceGeneration) {
|
|
661
|
+
target.activate();
|
|
662
|
+
target.setVarianceMoments(false);
|
|
663
|
+
target.setAdaptiveSamplingTargets(undefined);
|
|
664
|
+
target.setOfflineRenderOptions({ samplesPerBatch: 0, deferPostProcess: false, sampleSequenceOffset: 0 });
|
|
665
|
+
}
|
|
666
|
+
options.signal?.removeEventListener('abort', abortConverge);
|
|
667
|
+
this._busy = false;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
//# sourceMappingURL=Render.js.map
|