@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
|
@@ -1,267 +1,7 @@
|
|
|
1
1
|
import { getTargetShaderCache } from './WGPUShaderCache.js';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export const JNLM_WORKGROUP_SIZE = 8;
|
|
6
|
-
const paramsWGSL = /* wgsl */ `
|
|
7
|
-
struct JNLMParams {
|
|
8
|
-
size: vec2u,
|
|
9
|
-
colorSensitivity: f32,
|
|
10
|
-
|
|
11
|
-
dilation: f32,
|
|
12
|
-
}
|
|
13
|
-
@group(0) @binding(0) var<uniform> params: JNLMParams;
|
|
14
|
-
`;
|
|
15
|
-
/**
|
|
16
|
-
* Pass 1: the guide mean and the variance of that mean from the accumulated
|
|
17
|
-
* moments. Ray buffers are stored bottom-up; guides use texture rows.
|
|
18
|
-
*/
|
|
19
|
-
export const jnlmGuideWGSL = /* wgsl */ `
|
|
20
|
-
${paramsWGSL}
|
|
21
|
-
${shadowCatcherAccumulationWGSL}
|
|
22
|
-
@group(0) @binding(1) var<storage, read> accumulation: array<ShadowCatcherAccumulation>;
|
|
23
|
-
@group(0) @binding(2) var<storage, read> normalBuffer: array<vec4f>;
|
|
24
|
-
@group(0) @binding(3) var<storage, read_write> rawGuide: array<vec2f>;
|
|
25
|
-
|
|
26
|
-
@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
|
|
27
|
-
fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
28
|
-
let size = params.size;
|
|
29
|
-
if (id.x >= size.x || id.y >= size.y) { return; }
|
|
30
|
-
let ua = id.x + (size.y - 1u - id.y) * size.x;
|
|
31
|
-
let n = normalBuffer[ua].a;
|
|
32
|
-
let moments = accumulation[ua].moments;
|
|
33
|
-
let mean = moments.x / max(n, 1.0);
|
|
34
|
-
|
|
35
|
-
var variance = -1.0;
|
|
36
|
-
if (n >= 2.0) {
|
|
37
|
-
variance = max(moments.y - n * mean * mean, 0.0) / (n * (n - 1.0));
|
|
38
|
-
}
|
|
39
|
-
rawGuide[id.x + id.y * size.x] = vec2f(mean, variance);
|
|
40
|
-
}
|
|
41
|
-
`;
|
|
42
|
-
/**
|
|
43
|
-
* Pass 2: smooth the noisy per-pixel variance over 3 x 3 pixels. Pixels with
|
|
44
|
-
* a single sample take the spatial variance of their neighborhood instead.
|
|
45
|
-
*/
|
|
46
|
-
export const jnlmVarianceWGSL = /* wgsl */ `
|
|
47
|
-
${paramsWGSL}
|
|
48
|
-
@group(0) @binding(1) var<storage, read> rawGuide: array<vec2f>;
|
|
49
|
-
@group(0) @binding(2) var<storage, read_write> guide: array<vec2f>;
|
|
50
|
-
|
|
51
|
-
@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
|
|
52
|
-
fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
53
|
-
let size = params.size;
|
|
54
|
-
if (id.x >= size.x || id.y >= size.y) { return; }
|
|
55
|
-
let center = rawGuide[id.x + id.y * size.x];
|
|
56
|
-
var lu = 0.0;
|
|
57
|
-
var jc = 0.0;
|
|
58
|
-
var mY = 0.0;
|
|
59
|
-
var iX = 0.0;
|
|
60
|
-
for (var dy = -1; dy <= 1; dy++) {
|
|
61
|
-
for (var dx = -1; dx <= 1; dx++) {
|
|
62
|
-
let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);
|
|
63
|
-
let value = rawGuide[u32(q.x) + u32(q.y) * size.x];
|
|
64
|
-
mY += value.x;
|
|
65
|
-
iX += value.x * value.x;
|
|
66
|
-
if (value.y >= 0.0) {
|
|
67
|
-
lu += value.y;
|
|
68
|
-
jc += 1.0;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
var variance: f32;
|
|
73
|
-
if (center.y >= 0.0) {
|
|
74
|
-
variance = lu / jc;
|
|
75
|
-
} else {
|
|
76
|
-
let lt = mY / 9.0;
|
|
77
|
-
variance = max(iX / 9.0 - lt * lt, 0.0) * 9.0 / 8.0;
|
|
78
|
-
}
|
|
79
|
-
guide[id.x + id.y * size.x] = vec2f(center.x, variance);
|
|
80
|
-
}
|
|
81
|
-
`;
|
|
82
|
-
/** Copies the composed image into the filter's color buffer. */
|
|
83
|
-
export const jnlmLoadColorWGSL = /* wgsl */ `
|
|
84
|
-
${paramsWGSL}
|
|
85
|
-
@group(0) @binding(1) var colorTex: texture_2d<f32>;
|
|
86
|
-
@group(0) @binding(2) var<storage, read_write> outColor: array<vec4f>;
|
|
87
|
-
|
|
88
|
-
@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
|
|
89
|
-
fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
90
|
-
if (id.x >= params.size.x || id.y >= params.size.y) { return; }
|
|
91
|
-
outColor[id.x + id.y * params.size.x] = textureLoad(colorTex, vec2i(id.xy), 0);
|
|
92
|
-
}
|
|
93
|
-
`;
|
|
94
|
-
/**
|
|
95
|
-
* Pass 3: the joint NL-means filter of the composed image. It also filters
|
|
96
|
-
* the guide with the same weights, with the variance of the weighted mean,
|
|
97
|
-
* for a following pass. The albedo regression corrects color only, keeping
|
|
98
|
-
* uncertain fitted texture responses out of the matching guide.
|
|
99
|
-
*/
|
|
100
|
-
export function createJNLMFilterWGSL({ searchRadius, patchRadius, albedoBandwidth, normalBandwidth } = JNLM_DEFAULT_SHAPE) {
|
|
101
|
-
const patchSize = (2 * patchRadius + 1) ** 2;
|
|
102
|
-
return /* wgsl */ `
|
|
103
|
-
${paramsWGSL}
|
|
104
|
-
@group(0) @binding(1) var<storage, read> guide: array<vec2f>;
|
|
105
|
-
@group(0) @binding(2) var<storage, read> color: array<vec4f>;
|
|
106
|
-
@group(0) @binding(3) var albedoTex: texture_2d<f32>;
|
|
107
|
-
@group(0) @binding(4) var normalTex: texture_2d<f32>;
|
|
108
|
-
@group(0) @binding(5) var<storage, read_write> outColor: array<vec4f>;
|
|
109
|
-
@group(0) @binding(6) var<storage, read_write> outGuide: array<vec2f>;
|
|
110
|
-
@group(0) @binding(7) var shadowCatcherTex: texture_2d<f32>;
|
|
111
|
-
|
|
112
|
-
const SEARCH_RADIUS = ${searchRadius};
|
|
113
|
-
const PATCH_RADIUS = ${patchRadius};
|
|
114
|
-
const PATCH_SIZE = ${patchSize};
|
|
115
|
-
|
|
116
|
-
const VARIANCE_CANCELLATION = 1.0;
|
|
117
|
-
|
|
118
|
-
const INV_ALBEDO_BANDWIDTH2 = ${(1 / albedoBandwidth ** 2).toFixed(6)};
|
|
119
|
-
const INV_COVERAGE_BANDWIDTH2 = ${(1 / JNLM_COVERAGE_BANDWIDTH ** 2).toFixed(6)};
|
|
120
|
-
const INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const CENTER_WEIGHT_MIN = 0.01;
|
|
124
|
-
|
|
125
|
-
fn hg(p: vec2i) -> u32 {
|
|
126
|
-
let q = clamp(p, vec2i(0), vec2i(params.size) - 1);
|
|
127
|
-
return u32(q.x) + u32(q.y) * params.size.x;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
fn lw(q: vec2i, bs: vec4f, gT: vec3f) -> f32 {
|
|
131
|
-
let albedo = textureLoad(albedoTex, q, 0);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
let pf = max((albedo.rgb + bs.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
135
|
-
let ld = (albedo.rgb - bs.rgb) / pf;
|
|
136
|
-
let iU = albedo.a - bs.a;
|
|
137
|
-
let lp = textureLoad(normalTex, q, 0).rgb - gT;
|
|
138
|
-
return max(
|
|
139
|
-
dot(ld, ld) * INV_ALBEDO_BANDWIDTH2
|
|
140
|
-
+ iU * iU * INV_COVERAGE_BANDWIDTH2,
|
|
141
|
-
dot(lp, lp) * INV_NORMAL_BANDWIDTH2
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
fn premultiplied(c: vec4f) -> vec4f {
|
|
146
|
-
return vec4f(c.rgb * c.a, c.a);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)
|
|
150
|
-
fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
151
|
-
let size = vec2i(params.size);
|
|
152
|
-
let p = vec2i(id.xy);
|
|
153
|
-
if (p.x >= size.x || p.y >= size.y) { return; }
|
|
154
|
-
let step = i32(params.dilation);
|
|
155
|
-
let bs = textureLoad(albedoTex, p, 0);
|
|
156
|
-
let fD = textureLoad(normalTex, p, 0);
|
|
157
|
-
let gT = fD.rgb;
|
|
158
|
-
let index = hg(p);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (fD.a <= 0.0 && textureLoad(shadowCatcherTex, p, 0).r <= 0.0) {
|
|
162
|
-
outColor[index] = color[index];
|
|
163
|
-
outGuide[index] = guide[index];
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
var lf: array<vec2f, PATCH_SIZE>;
|
|
168
|
-
var k = 0;
|
|
169
|
-
for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
|
|
170
|
-
for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
|
|
171
|
-
lf[k] = guide[hg(p + vec2i(dx, dy) * step)];
|
|
172
|
-
k++;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
let k2 = params.colorSensitivity * params.colorSensitivity;
|
|
176
|
-
|
|
177
|
-
var sum = vec4f(0.0);
|
|
178
|
-
let gW = max(bs.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
179
|
-
var mp = vec3f(0.0);
|
|
180
|
-
var gy = vec3f(0.0);
|
|
181
|
-
var hs = vec3f(0.0);
|
|
182
|
-
var ps = 0.0;
|
|
183
|
-
var gA = 0.0;
|
|
184
|
-
var nU = 0.0;
|
|
185
|
-
var kM = 0.0;
|
|
186
|
-
for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {
|
|
187
|
-
for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {
|
|
188
|
-
let q = p + vec2i(sx, sy) * step;
|
|
189
|
-
if (
|
|
190
|
-
(sx == 0 && sy == 0) ||
|
|
191
|
-
q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y
|
|
192
|
-
) { continue; }
|
|
193
|
-
|
|
194
|
-
let features = lw(q, bs, gT);
|
|
195
|
-
if (features > 16.0) { continue; }
|
|
196
|
-
|
|
197
|
-
var fY = 0.0;
|
|
198
|
-
k = 0;
|
|
199
|
-
for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
|
|
200
|
-
for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
|
|
201
|
-
let a = lf[k];
|
|
202
|
-
let b = guide[hg(q + vec2i(dx, dy) * step)];
|
|
203
|
-
let qU = a.x - b.x;
|
|
204
|
-
fY += (qU * qU
|
|
205
|
-
- VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))
|
|
206
|
-
/ (1e-10 + k2 * (a.y + b.y));
|
|
207
|
-
k++;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
fY /= f32(PATCH_SIZE);
|
|
211
|
-
|
|
212
|
-
let weight = exp(-max(max(fY, 0.0), features));
|
|
213
|
-
let index = hg(q);
|
|
214
|
-
let c = color[index];
|
|
215
|
-
let g = guide[index];
|
|
216
|
-
|
|
217
|
-
let a = (textureLoad(albedoTex, q, 0).rgb - bs.rgb) / gW;
|
|
218
|
-
let value = premultiplied(c);
|
|
219
|
-
sum += value * weight;
|
|
220
|
-
mp += a * weight;
|
|
221
|
-
gy += a * a * weight;
|
|
222
|
-
hs += a * value.rgb * weight;
|
|
223
|
-
ps += g.x * weight;
|
|
224
|
-
gA += g.y * weight * weight;
|
|
225
|
-
nU += weight;
|
|
226
|
-
kM = max(kM, weight);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
let center = color[index];
|
|
233
|
-
let le = guide[index];
|
|
234
|
-
let dG = max(kM, CENTER_WEIGHT_MIN);
|
|
235
|
-
let totalWeight = nU + dG;
|
|
236
|
-
let tM = premultiplied(center);
|
|
237
|
-
let mean = (sum + tM * dG) / totalWeight;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
let ez = mp / totalWeight;
|
|
241
|
-
let lA = max(gy / totalWeight - ez * ez, vec3f(0.0));
|
|
242
|
-
let qu = hs / totalWeight - ez * mean.rgb;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
let qE = bs.rgb + ez * gW;
|
|
247
|
-
let oz = mean.rgb * gW / max(qE, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
248
|
-
let vB = clamp(qu / (lA + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), oz);
|
|
249
|
-
let rD = mean.rgb - vB * ez;
|
|
250
|
-
let filtered = vec4f(max(rD, vec3f(0.0)), max(mean.a, 0.0));
|
|
251
|
-
let rgb = select(
|
|
252
|
-
center.rgb,
|
|
253
|
-
filtered.rgb / max(filtered.a, 1e-6),
|
|
254
|
-
filtered.a > 1e-6
|
|
255
|
-
);
|
|
256
|
-
outColor[index] = vec4f(rgb, filtered.a);
|
|
257
|
-
outGuide[index] = vec2f(
|
|
258
|
-
(ps + le.x * dG) / totalWeight,
|
|
259
|
-
(gA + le.y * dG * dG)
|
|
260
|
-
/ (totalWeight * totalWeight)
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
`;
|
|
264
|
-
}
|
|
2
|
+
import { JNLM_MAX_ITERATIONS } from './jnlm.js';
|
|
3
|
+
import { JNLM_WORKGROUP_SIZE, jnlmGuideWGSL, jnlmVarianceWGSL, jnlmLoadColorWGSL, createJNLMFilterWGSL, packJNLMParameters } from './wgsl/jnlm.compute.js';
|
|
4
|
+
export { createJNLMFilterWGSL, jnlmGuideWGSL, jnlmVarianceWGSL, jnlmLoadColorWGSL, JNLM_WORKGROUP_SIZE } from './wgsl/jnlm.compute.js';
|
|
265
5
|
const MAX_ITERATIONS = JNLM_MAX_ITERATIONS;
|
|
266
6
|
export class WGPUJNLMDenoisePass {
|
|
267
7
|
_device;
|
|
@@ -337,12 +77,9 @@ export class WGPUJNLMDenoisePass {
|
|
|
337
77
|
const { width, height, shape } = inputs;
|
|
338
78
|
this._ensureBuffers(width, height);
|
|
339
79
|
const iterations = Math.min(Math.max(Math.round(shape.iterations), 1), MAX_ITERATIONS);
|
|
340
|
-
const sensitivity = JNLM_DEFAULT_COLOR_SENSITIVITY * Math.max(inputs.strength, 1e-3);
|
|
341
80
|
this._paramsBuffers.forEach((buffer, i) => {
|
|
342
|
-
const params = new ArrayBuffer(16);
|
|
343
|
-
new Uint32Array(params, 0, 2).set([width, height]);
|
|
344
81
|
// Buffer i (from 1) is filter pass i - 1; index 0 is the prepasses.
|
|
345
|
-
|
|
82
|
+
const params = packJNLMParameters(width, height, inputs.strength, Math.max(i - 1, 0));
|
|
346
83
|
this._device.queue.writeBuffer(buffer, 0, params);
|
|
347
84
|
});
|
|
348
85
|
const device = this._device;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WGPUJNLMDenoiser.js","sourceRoot":"","sources":["../../src/renderer/WGPUJNLMDenoiser.ts"],"names":[],"mappings":"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","sourcesContent":["import { getTargetShaderCache } from './WGPUShaderCache.js';\nimport shadowCatcherAccumulationWGSL from './wgsl/chunks/shadowCatcherAccumulation.wgsl.js';\n\nimport {\n JNLM_DEFAULT_COLOR_SENSITIVITY,\n JNLM_DEFAULT_SHAPE,\n JNLM_ALBEDO_FLOOR,\n JNLM_ALBEDO_REGULARIZATION,\n JNLM_COVERAGE_BANDWIDTH,\n JNLM_MAX_ITERATIONS,\n jnlmPassDilation,\n type JNLMFilterShape\n} from './jnlm.js';\n\n/** WebGPU passes of the JNLM denoiser described in `jnlm.ts`. */\n\nexport const JNLM_WORKGROUP_SIZE = 8;\n\nconst paramsWGSL = /* wgsl */ `\nstruct JNLMParams {\n size: vec2u,\n colorSensitivity: f32,\n // Pixel spacing of the search window and patches in this pass.\n dilation: f32,\n}\n@group(0) @binding(0) var<uniform> params: JNLMParams;\n`;\n\n/**\n * Pass 1: the guide mean and the variance of that mean from the accumulated\n * moments. Ray buffers are stored bottom-up; guides use texture rows.\n */\nexport const jnlmGuideWGSL = /* wgsl */ `\n${paramsWGSL}\n${shadowCatcherAccumulationWGSL}\n@group(0) @binding(1) var<storage, read> accumulation: array<ShadowCatcherAccumulation>;\n@group(0) @binding(2) var<storage, read> normalBuffer: array<vec4f>;\n@group(0) @binding(3) var<storage, read_write> rawGuide: array<vec2f>;\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n let size = params.size;\n if (id.x >= size.x || id.y >= size.y) { return; }\n let rayIndex = id.x + (size.y - 1u - id.y) * size.x;\n let n = normalBuffer[rayIndex].a;\n let moments = accumulation[rayIndex].moments;\n let mean = moments.x / max(n, 1.0);\n // Variance of the mean, or -1 when one sample cannot estimate it.\n var variance = -1.0;\n if (n >= 2.0) {\n variance = max(moments.y - n * mean * mean, 0.0) / (n * (n - 1.0));\n }\n rawGuide[id.x + id.y * size.x] = vec2f(mean, variance);\n}\n`;\n\n/**\n * Pass 2: smooth the noisy per-pixel variance over 3 x 3 pixels. Pixels with\n * a single sample take the spatial variance of their neighborhood instead.\n */\nexport const jnlmVarianceWGSL = /* wgsl */ `\n${paramsWGSL}\n@group(0) @binding(1) var<storage, read> rawGuide: array<vec2f>;\n@group(0) @binding(2) var<storage, read_write> guide: array<vec2f>;\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n let size = params.size;\n if (id.x >= size.x || id.y >= size.y) { return; }\n let center = rawGuide[id.x + id.y * size.x];\n var varianceSum = 0.0;\n var varianceCount = 0.0;\n var meanSum = 0.0;\n var meanSquareSum = 0.0;\n for (var dy = -1; dy <= 1; dy++) {\n for (var dx = -1; dx <= 1; dx++) {\n let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);\n let value = rawGuide[u32(q.x) + u32(q.y) * size.x];\n meanSum += value.x;\n meanSquareSum += value.x * value.x;\n if (value.y >= 0.0) {\n varianceSum += value.y;\n varianceCount += 1.0;\n }\n }\n }\n var variance: f32;\n if (center.y >= 0.0) {\n variance = varianceSum / varianceCount;\n } else {\n let spatialMean = meanSum / 9.0;\n variance = max(meanSquareSum / 9.0 - spatialMean * spatialMean, 0.0) * 9.0 / 8.0;\n }\n guide[id.x + id.y * size.x] = vec2f(center.x, variance);\n}\n`;\n\n/** Copies the composed image into the filter's color buffer. */\nexport const jnlmLoadColorWGSL = /* wgsl */ `\n${paramsWGSL}\n@group(0) @binding(1) var colorTex: texture_2d<f32>;\n@group(0) @binding(2) var<storage, read_write> outColor: array<vec4f>;\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n if (id.x >= params.size.x || id.y >= params.size.y) { return; }\n outColor[id.x + id.y * params.size.x] = textureLoad(colorTex, vec2i(id.xy), 0);\n}\n`;\n\n/**\n * Pass 3: the joint NL-means filter of the composed image. It also filters\n * the guide with the same weights, with the variance of the weighted mean,\n * for a following pass. The albedo regression corrects color only, keeping\n * uncertain fitted texture responses out of the matching guide.\n */\nexport function createJNLMFilterWGSL({\n searchRadius, patchRadius, albedoBandwidth, normalBandwidth\n}: JNLMFilterShape = JNLM_DEFAULT_SHAPE) {\n const patchSize = (2 * patchRadius + 1) ** 2;\n return /* wgsl */ `\n${paramsWGSL}\n@group(0) @binding(1) var<storage, read> guide: array<vec2f>;\n@group(0) @binding(2) var<storage, read> color: array<vec4f>;\n@group(0) @binding(3) var albedoTex: texture_2d<f32>;\n@group(0) @binding(4) var normalTex: texture_2d<f32>;\n@group(0) @binding(5) var<storage, read_write> outColor: array<vec4f>;\n@group(0) @binding(6) var<storage, read_write> outGuide: array<vec2f>;\n@group(0) @binding(7) var shadowCatcherTex: texture_2d<f32>;\n\nconst SEARCH_RADIUS = ${searchRadius};\nconst PATCH_RADIUS = ${patchRadius};\nconst PATCH_SIZE = ${patchSize};\n// Variance cancellation strength alpha of the paper.\nconst VARIANCE_CANCELLATION = 1.0;\n// Inverse squared feature bandwidths. Normals are encoded as n * 0.5 + 0.5.\nconst INV_ALBEDO_BANDWIDTH2 = ${(1 / albedoBandwidth ** 2).toFixed(6)};\nconst INV_COVERAGE_BANDWIDTH2 = ${(1 / JNLM_COVERAGE_BANDWIDTH ** 2).toFixed(6)};\nconst INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};\n// Lower bound of the center weight, so a pixel unlike all of its neighbors\n// (a thin highlight) is kept rather than replaced by them.\nconst CENTER_WEIGHT_MIN = 0.01;\n\nfn pixelIndex(p: vec2i) -> u32 {\n let q = clamp(p, vec2i(0), vec2i(params.size) - 1);\n return u32(q.x) + u32(q.y) * params.size.x;\n}\n\nfn featureDistance(q: vec2i, centerAlbedo: vec4f, centerNormal: vec3f) -> f32 {\n let albedo = textureLoad(albedoTex, q, 0);\n // Absolute differences in linear albedo erase low-contrast dark textures.\n // Measure RGB contrast relative to both pixels; keep coverage absolute.\n let albedoScale = max((albedo.rgb + centerAlbedo.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));\n let albedoDelta = (albedo.rgb - centerAlbedo.rgb) / albedoScale;\n let coverageDelta = albedo.a - centerAlbedo.a;\n let normalDelta = textureLoad(normalTex, q, 0).rgb - centerNormal;\n return max(\n dot(albedoDelta, albedoDelta) * INV_ALBEDO_BANDWIDTH2\n + coverageDelta * coverageDelta * INV_COVERAGE_BANDWIDTH2,\n dot(normalDelta, normalDelta) * INV_NORMAL_BANDWIDTH2\n );\n}\n\nfn premultiplied(c: vec4f) -> vec4f {\n return vec4f(c.rgb * c.a, c.a);\n}\n\n@compute @workgroup_size(${JNLM_WORKGROUP_SIZE}, ${JNLM_WORKGROUP_SIZE}, 1)\nfn main(@builtin(global_invocation_id) id: vec3u) {\n let size = vec2i(params.size);\n let p = vec2i(id.xy);\n if (p.x >= size.x || p.y >= size.y) { return; }\n let step = i32(params.dilation);\n let centerAlbedo = textureLoad(albedoTex, p, 0);\n let centerNormalTexel = textureLoad(normalTex, p, 0);\n let centerNormal = centerNormalTexel.rgb;\n let index = pixelIndex(p);\n // Primary misses show the background directly. It has no features that\n // protect its detail and no noise beyond antialiasing, so keep it.\n if (centerNormalTexel.a <= 0.0 && textureLoad(shadowCatcherTex, p, 0).r <= 0.0) {\n outColor[index] = color[index];\n outGuide[index] = guide[index];\n return;\n }\n\n var centerPatch: array<vec2f, PATCH_SIZE>;\n var k = 0;\n for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {\n for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {\n centerPatch[k] = guide[pixelIndex(p + vec2i(dx, dy) * step)];\n k++;\n }\n }\n let k2 = params.colorSensitivity * params.colorSensitivity;\n\n var sum = vec4f(0.0);\n let featureScale = max(centerAlbedo.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));\n var featureSum = vec3f(0.0);\n var featureSquareSum = vec3f(0.0);\n var featureColorSum = vec3f(0.0);\n var guideSum = 0.0;\n var guideVarianceSum = 0.0;\n var weightSum = 0.0;\n var maxWeight = 0.0;\n for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {\n for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {\n let q = p + vec2i(sx, sy) * step;\n if (\n (sx == 0 && sy == 0) ||\n q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y\n ) { continue; }\n\n let features = featureDistance(q, centerAlbedo, centerNormal);\n if (features > 16.0) { continue; }\n\n var colorDistance = 0.0;\n k = 0;\n for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {\n for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {\n let a = centerPatch[k];\n let b = guide[pixelIndex(q + vec2i(dx, dy) * step)];\n let delta = a.x - b.x;\n colorDistance += (delta * delta\n - VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))\n / (1e-10 + k2 * (a.y + b.y));\n k++;\n }\n }\n colorDistance /= f32(PATCH_SIZE);\n\n let weight = exp(-max(max(colorDistance, 0.0), features));\n let index = pixelIndex(q);\n let c = color[index];\n let g = guide[index];\n // Filter premultiplied color so coverage and color stay consistent.\n let a = (textureLoad(albedoTex, q, 0).rgb - centerAlbedo.rgb) / featureScale;\n let value = premultiplied(c);\n sum += value * weight;\n featureSum += a * weight;\n featureSquareSum += a * a * weight;\n featureColorSum += a * value.rgb * weight;\n guideSum += g.x * weight;\n guideVarianceSum += g.y * weight * weight;\n weightSum += weight;\n maxWeight = max(maxWeight, weight);\n }\n }\n\n // Weight the center like its most similar neighbor (Buades et al. 2005)\n // instead of 1, so isolated outliers are not kept unfiltered.\n let center = color[index];\n let centerGuide = guide[index];\n let centerWeight = max(maxWeight, CENTER_WEIGHT_MIN);\n let totalWeight = weightSum + centerWeight;\n let centerValue = premultiplied(center);\n let mean = (sum + centerValue * centerWeight) / totalWeight;\n // Fit each color channel against relative albedo with the same JNLM weights.\n // Centering at this pixel avoids cancellation when the feature is constant.\n let meanFeature = featureSum / totalWeight;\n let featureVariance = max(featureSquareSum / totalWeight - meanFeature * meanFeature, vec3f(0.0));\n let covariance = featureColorSum / totalWeight - meanFeature * mean.rgb;\n // A 1% contrast ridge stabilizes flat guides. Bound the response between no\n // texture dependence and multiplicative albedo modulation; specular color\n // with an unrelated albedo falls back to the weighted mean.\n let meanAlbedo = centerAlbedo.rgb + meanFeature * featureScale;\n let maximumSlope = mean.rgb * featureScale / max(meanAlbedo, vec3f(${JNLM_ALBEDO_FLOOR}));\n let slope = clamp(covariance / (featureVariance + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), maximumSlope);\n let corrected = mean.rgb - slope * meanFeature;\n let filtered = vec4f(max(corrected, vec3f(0.0)), max(mean.a, 0.0));\n let rgb = select(\n center.rgb,\n filtered.rgb / max(filtered.a, 1e-6),\n filtered.a > 1e-6\n );\n outColor[index] = vec4f(rgb, filtered.a);\n outGuide[index] = vec2f(\n (guideSum + centerGuide.x * centerWeight) / totalWeight,\n (guideVarianceSum + centerGuide.y * centerWeight * centerWeight)\n / (totalWeight * totalWeight)\n );\n}\n`;\n}\n\nexport interface JNLMInputs {\n width: number;\n height: number;\n /** Normalized shadow-catcher mask; red is the catcher coverage. */\n shadowCatcher: GPUTexture;\n /** Ray-trace auxiliary accumulation holding the guide moments. */\n accumulation: GPUBuffer;\n /** Ray-trace normal accumulation; its alpha is the per-pixel sample count. */\n normalAccumulation: GPUBuffer;\n /** Composed linear image to filter. */\n color: GPUTexture;\n albedo: GPUTexture;\n normal: GPUTexture;\n strength: number;\n shape: JNLMFilterShape;\n}\n\nconst MAX_ITERATIONS = JNLM_MAX_ITERATIONS;\n\nexport class WGPUJNLMDenoisePass {\n private _device: GPUDevice;\n private _paramsBuffers: GPUBuffer[] = [];\n private _guidePipeline: GPUComputePipeline;\n private _variancePipeline: GPUComputePipeline;\n private _loadColorPipeline: GPUComputePipeline;\n private _filterPipeline?: GPUComputePipeline;\n private _filterShapeKey = '';\n private _guides: GPUBuffer[] = [];\n private _colors: GPUBuffer[] = [];\n private _width = 0;\n private _height = 0;\n\n constructor(device: GPUDevice) {\n this._device = device;\n // One uniform buffer per pass: every pass of an encoder sees the last\n // writeBuffer() of a shared one.\n for (let i = 0; i <= MAX_ITERATIONS; i++) {\n this._paramsBuffers.push(device.createBuffer({\n label: 'JNLM params',\n size: 16,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n }));\n }\n this._guidePipeline = this._createPipeline('JNLM guide', jnlmGuideWGSL);\n this._variancePipeline = this._createPipeline('JNLM variance', jnlmVarianceWGSL);\n this._loadColorPipeline = this._createPipeline('JNLM load color', jnlmLoadColorWGSL);\n }\n\n private _createPipeline(label: string, code: string) {\n return getTargetShaderCache(this._device).createComputePipeline({\n label,\n layout: 'auto',\n compute: {\n module: getTargetShaderCache(this._device).createShaderModule({ label, code }),\n entryPoint: 'main'\n }\n });\n }\n\n private _getFilterPipeline(shape: JNLMFilterShape) {\n const key = JSON.stringify(shape);\n if (!this._filterPipeline || key !== this._filterShapeKey) {\n this._filterPipeline = this._createPipeline('JNLM filter', createJNLMFilterWGSL(shape));\n this._filterShapeKey = key;\n }\n return this._filterPipeline;\n }\n\n reserveCapacity() {}\n private _ensureBuffers(width: number, height: number) {\n if (width <= this._width && height <= this._height && this._colors.length) return;\n width = Math.max(width, this._width); height = Math.max(height, this._height);\n this._destroyBuffers();\n const pixels = width * height;\n const createBuffer = (label: string, bytes: number) =>\n this._device.createBuffer({\n label,\n size: pixels * bytes,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC\n });\n this._guides = [createBuffer('JNLM guide A', 8), createBuffer('JNLM guide B', 8)];\n this._colors = [createBuffer('JNLM color A', 16), createBuffer('JNLM color B', 16)];\n this._width = width;\n this._height = height;\n }\n\n private _destroyBuffers() {\n for (const buffer of [...this._guides, ...this._colors]) buffer.destroy();\n this._guides = [];\n this._colors = [];\n }\n\n /** Encodes the denoiser and returns the RGBA32F output in texture rows. */\n encode(encoder: GPUCommandEncoder, inputs: JNLMInputs): GPUBuffer {\n const { width, height, shape } = inputs;\n this._ensureBuffers(width, height);\n const iterations = Math.min(Math.max(Math.round(shape.iterations), 1), MAX_ITERATIONS);\n const sensitivity = JNLM_DEFAULT_COLOR_SENSITIVITY * Math.max(inputs.strength, 1e-3);\n this._paramsBuffers.forEach((buffer, i) => {\n const params = new ArrayBuffer(16);\n new Uint32Array(params, 0, 2).set([width, height]);\n // Buffer i (from 1) is filter pass i - 1; index 0 is the prepasses.\n new Float32Array(params, 8, 2).set([sensitivity, jnlmPassDilation(Math.max(i - 1, 0))]);\n this._device.queue.writeBuffer(buffer, 0, params);\n });\n\n const device = this._device;\n const filterPipeline = this._getFilterPipeline(shape);\n const bind = (\n pipeline: GPUComputePipeline,\n paramsBuffer: GPUBuffer,\n resources: GPUBindingResource[]\n ) =>\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: paramsBuffer } },\n ...resources.map((resource, i) => ({ binding: i + 1, resource }))\n ]\n });\n const [guideA, guideB] = this._guides;\n const [colorA, colorB] = this._colors;\n const prepass = this._paramsBuffers[0];\n const passes: [GPUComputePipeline, GPUBindGroup][] = [\n [this._guidePipeline, bind(this._guidePipeline, prepass, [\n { buffer: inputs.accumulation },\n { buffer: inputs.normalAccumulation },\n { buffer: guideB }\n ])],\n [this._variancePipeline, bind(this._variancePipeline, prepass, [\n { buffer: guideB },\n { buffer: guideA }\n ])],\n [this._loadColorPipeline, bind(this._loadColorPipeline, prepass, [\n inputs.color.createView(),\n { buffer: colorA }\n ])]\n ];\n const albedoView = inputs.albedo.createView();\n const normalView = inputs.normal.createView();\n const shadowCatcherView = inputs.shadowCatcher.createView();\n let guides = [guideA, guideB];\n let colors = [colorA, colorB];\n for (let i = 1; i <= iterations; i++) {\n passes.push([filterPipeline, bind(filterPipeline, this._paramsBuffers[i], [\n { buffer: guides[0] },\n { buffer: colors[0] },\n albedoView,\n normalView,\n { buffer: colors[1] },\n { buffer: guides[1] },\n shadowCatcherView\n ])]);\n guides = [guides[1], guides[0]];\n colors = [colors[1], colors[0]];\n }\n const pass = encoder.beginComputePass({ label: 'JNLM denoise' });\n for (const [pipeline, bindGroup] of passes) {\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, bindGroup);\n pass.dispatchWorkgroups(\n Math.ceil(width / JNLM_WORKGROUP_SIZE),\n Math.ceil(height / JNLM_WORKGROUP_SIZE)\n );\n }\n pass.end();\n return colors[0];\n }\n\n getMemoryBytes() {\n return [...this._paramsBuffers, ...this._guides, ...this._colors]\n .reduce((sum, buffer) => sum + buffer.size, 0);\n }\n\n dispose() {\n for (const buffer of this._paramsBuffers) buffer.destroy();\n this._destroyBuffers();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WGPUJNLMDenoiser.js","sourceRoot":"","sources":["../../src/renderer/WGPUJNLMDenoiser.ts"],"names":[],"mappings":"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","sourcesContent":["import {getTargetShaderCache} from './WGPUShaderCache.js';\nimport {JNLM_MAX_ITERATIONS, type JNLMFilterShape} from './jnlm.js';\nimport {\n JNLM_WORKGROUP_SIZE, jnlmGuideWGSL, jnlmVarianceWGSL, jnlmLoadColorWGSL,\n createJNLMFilterWGSL, packJNLMParameters\n} from './wgsl/jnlm.compute.js';\nexport {createJNLMFilterWGSL, jnlmGuideWGSL, jnlmVarianceWGSL, jnlmLoadColorWGSL, JNLM_WORKGROUP_SIZE} from './wgsl/jnlm.compute.js';\n\n/** WebGPU passes of the JNLM denoiser described in `jnlm.ts`. */\n\nexport interface JNLMInputs {\n width: number;\n height: number;\n /** Normalized shadow-catcher mask; red is the catcher coverage. */\n shadowCatcher: GPUTexture;\n /** Ray-trace auxiliary accumulation holding the guide moments. */\n accumulation: GPUBuffer;\n /** Ray-trace normal accumulation; its alpha is the per-pixel sample count. */\n normalAccumulation: GPUBuffer;\n /** Composed linear image to filter. */\n color: GPUTexture;\n albedo: GPUTexture;\n normal: GPUTexture;\n strength: number;\n shape: JNLMFilterShape;\n}\n\nconst MAX_ITERATIONS = JNLM_MAX_ITERATIONS;\n\nexport class WGPUJNLMDenoisePass {\n private _device: GPUDevice;\n private _paramsBuffers: GPUBuffer[] = [];\n private _guidePipeline: GPUComputePipeline;\n private _variancePipeline: GPUComputePipeline;\n private _loadColorPipeline: GPUComputePipeline;\n private _filterPipeline?: GPUComputePipeline;\n private _filterShapeKey = '';\n private _guides: GPUBuffer[] = [];\n private _colors: GPUBuffer[] = [];\n private _width = 0;\n private _height = 0;\n\n constructor(device: GPUDevice) {\n this._device = device;\n // One uniform buffer per pass: every pass of an encoder sees the last\n // writeBuffer() of a shared one.\n for (let i = 0; i <= MAX_ITERATIONS; i++) {\n this._paramsBuffers.push(device.createBuffer({\n label: 'JNLM params',\n size: 16,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n }));\n }\n this._guidePipeline = this._createPipeline('JNLM guide', jnlmGuideWGSL);\n this._variancePipeline = this._createPipeline('JNLM variance', jnlmVarianceWGSL);\n this._loadColorPipeline = this._createPipeline('JNLM load color', jnlmLoadColorWGSL);\n }\n\n private _createPipeline(label: string, code: string) {\n return getTargetShaderCache(this._device).createComputePipeline({\n label,\n layout: 'auto',\n compute: {\n module: getTargetShaderCache(this._device).createShaderModule({ label, code }),\n entryPoint: 'main'\n }\n });\n }\n\n private _getFilterPipeline(shape: JNLMFilterShape) {\n const key = JSON.stringify(shape);\n if (!this._filterPipeline || key !== this._filterShapeKey) {\n this._filterPipeline = this._createPipeline('JNLM filter', createJNLMFilterWGSL(shape));\n this._filterShapeKey = key;\n }\n return this._filterPipeline;\n }\n\n reserveCapacity() {}\n private _ensureBuffers(width: number, height: number) {\n if (width <= this._width && height <= this._height && this._colors.length) return;\n width = Math.max(width, this._width); height = Math.max(height, this._height);\n this._destroyBuffers();\n const pixels = width * height;\n const createBuffer = (label: string, bytes: number) =>\n this._device.createBuffer({\n label,\n size: pixels * bytes,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC\n });\n this._guides = [createBuffer('JNLM guide A', 8), createBuffer('JNLM guide B', 8)];\n this._colors = [createBuffer('JNLM color A', 16), createBuffer('JNLM color B', 16)];\n this._width = width;\n this._height = height;\n }\n\n private _destroyBuffers() {\n for (const buffer of [...this._guides, ...this._colors]) buffer.destroy();\n this._guides = [];\n this._colors = [];\n }\n\n /** Encodes the denoiser and returns the RGBA32F output in texture rows. */\n encode(encoder: GPUCommandEncoder, inputs: JNLMInputs): GPUBuffer {\n const { width, height, shape } = inputs;\n this._ensureBuffers(width, height);\n const iterations = Math.min(Math.max(Math.round(shape.iterations), 1), MAX_ITERATIONS);\n this._paramsBuffers.forEach((buffer, i) => {\n // Buffer i (from 1) is filter pass i - 1; index 0 is the prepasses.\n const params = packJNLMParameters(width, height, inputs.strength, Math.max(i - 1, 0));\n this._device.queue.writeBuffer(buffer, 0, params);\n });\n\n const device = this._device;\n const filterPipeline = this._getFilterPipeline(shape);\n const bind = (\n pipeline: GPUComputePipeline,\n paramsBuffer: GPUBuffer,\n resources: GPUBindingResource[]\n ) =>\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: paramsBuffer } },\n ...resources.map((resource, i) => ({ binding: i + 1, resource }))\n ]\n });\n const [guideA, guideB] = this._guides;\n const [colorA, colorB] = this._colors;\n const prepass = this._paramsBuffers[0];\n const passes: [GPUComputePipeline, GPUBindGroup][] = [\n [this._guidePipeline, bind(this._guidePipeline, prepass, [\n { buffer: inputs.accumulation },\n { buffer: inputs.normalAccumulation },\n { buffer: guideB }\n ])],\n [this._variancePipeline, bind(this._variancePipeline, prepass, [\n { buffer: guideB },\n { buffer: guideA }\n ])],\n [this._loadColorPipeline, bind(this._loadColorPipeline, prepass, [\n inputs.color.createView(),\n { buffer: colorA }\n ])]\n ];\n const albedoView = inputs.albedo.createView();\n const normalView = inputs.normal.createView();\n const shadowCatcherView = inputs.shadowCatcher.createView();\n let guides = [guideA, guideB];\n let colors = [colorA, colorB];\n for (let i = 1; i <= iterations; i++) {\n passes.push([filterPipeline, bind(filterPipeline, this._paramsBuffers[i], [\n { buffer: guides[0] },\n { buffer: colors[0] },\n albedoView,\n normalView,\n { buffer: colors[1] },\n { buffer: guides[1] },\n shadowCatcherView\n ])]);\n guides = [guides[1], guides[0]];\n colors = [colors[1], colors[0]];\n }\n const pass = encoder.beginComputePass({ label: 'JNLM denoise' });\n for (const [pipeline, bindGroup] of passes) {\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, bindGroup);\n pass.dispatchWorkgroups(\n Math.ceil(width / JNLM_WORKGROUP_SIZE),\n Math.ceil(height / JNLM_WORKGROUP_SIZE)\n );\n }\n pass.end();\n return colors[0];\n }\n\n getMemoryBytes() {\n return [...this._paramsBuffers, ...this._guides, ...this._colors]\n .reduce((sum, buffer) => sum + buffer.size, 0);\n }\n\n dispose() {\n for (const buffer of this._paramsBuffers) buffer.destroy();\n this._destroyBuffers();\n }\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { WGPUCausticLightPass } from './WGPUCausticLightPass.js';
|
|
2
|
+
export { photonRadius } from './wgsl/photonMap.compute.js';
|
|
3
|
+
interface Batch {
|
|
4
|
+
grid: GPUBuffer;
|
|
5
|
+
uniform: GPUBuffer;
|
|
6
|
+
data: GPUTexture;
|
|
7
|
+
headers: GPUTexture;
|
|
8
|
+
count: number;
|
|
9
|
+
buckets: number;
|
|
10
|
+
perCasterRadius: boolean;
|
|
11
|
+
group: GPUBindGroup;
|
|
12
|
+
}
|
|
13
|
+
/** Batch-local spatial hash; accumulated estimates live in the camera path target. */
|
|
14
|
+
export declare class WGPUPhotonMap {
|
|
15
|
+
private readonly device;
|
|
16
|
+
readonly placeholder: GPUTexture;
|
|
17
|
+
readonly emission: WGPUCausticLightPass;
|
|
18
|
+
private readonly targets;
|
|
19
|
+
private readonly layout;
|
|
20
|
+
private readonly pipelines;
|
|
21
|
+
constructor(device: GPUDevice);
|
|
22
|
+
ensure(target: object, requested: number): Batch;
|
|
23
|
+
get(target: object): Batch | undefined;
|
|
24
|
+
encode(encoder: GPUCommandEncoder, groups: GPUBindGroup[], target: object, radius: number, options: Parameters<WGPUCausticLightPass['encode']>[3] & {
|
|
25
|
+
progressiveBatch?: number;
|
|
26
|
+
}): void;
|
|
27
|
+
release(target: object): void;
|
|
28
|
+
bytes(target: object): number;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
}
|
|
31
|
+
/** Typical first-receiver footprint at the caster center; query disks stay exact. */
|
|
32
|
+
export declare function photonVisibleRadius(radius: number, options: {
|
|
33
|
+
viewProjection: ArrayLike<number>;
|
|
34
|
+
casterSphere: readonly number[];
|
|
35
|
+
width: number;
|
|
36
|
+
orthographic?: boolean;
|
|
37
|
+
}, screenPixels?: number): number;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { causticDiagnostics } from './causticDiagnostics.js';
|
|
2
|
+
import { WGPUCausticLightPass } from './WGPUCausticLightPass.js';
|
|
3
|
+
import { PHOTON_BYTES, PHOTON_GRID_SIZE, photonLayout, photonGridCompute } from './wgsl/photonMap.compute.js';
|
|
4
|
+
export { photonRadius } from './wgsl/photonMap.compute.js';
|
|
5
|
+
/** Batch-local spatial hash; accumulated estimates live in the camera path target. */
|
|
6
|
+
export class WGPUPhotonMap {
|
|
7
|
+
device;
|
|
8
|
+
placeholder;
|
|
9
|
+
emission;
|
|
10
|
+
targets = new Map();
|
|
11
|
+
layout;
|
|
12
|
+
pipelines;
|
|
13
|
+
constructor(device) {
|
|
14
|
+
this.device = device;
|
|
15
|
+
this.placeholder = device.createTexture({
|
|
16
|
+
label: 'Inactive photon binding',
|
|
17
|
+
size: [1, 1],
|
|
18
|
+
format: 'r32uint',
|
|
19
|
+
usage: GPUTextureUsage.TEXTURE_BINDING
|
|
20
|
+
});
|
|
21
|
+
this.emission = new WGPUCausticLightPass(device, true);
|
|
22
|
+
this.layout = device.createBindGroupLayout({
|
|
23
|
+
entries: [
|
|
24
|
+
{ binding: 0, visibility: 4, texture: { sampleType: 'uint' } },
|
|
25
|
+
{ binding: 1, visibility: 4, buffer: { type: 'storage' } },
|
|
26
|
+
{ binding: 2, visibility: 4, buffer: { type: 'uniform' } },
|
|
27
|
+
{ binding: 4, visibility: 4, storageTexture: { access: 'write-only', format: 'r32uint' } }
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
const module = device.createShaderModule({ label: 'Photon hash grid', code: photonGridCompute }), layout = device.createPipelineLayout({ bindGroupLayouts: [this.layout] });
|
|
31
|
+
this.pipelines = ['count', 'scanBlocks', 'scanSums', 'scatter'].map((entryPoint) => device.createComputePipeline({ label: 'Photon ' + entryPoint, layout, compute: { module, entryPoint } }));
|
|
32
|
+
}
|
|
33
|
+
ensure(target, requested) {
|
|
34
|
+
const device = this.device, limit = device.limits.maxTextureDimension2D;
|
|
35
|
+
const budget = causticDiagnostics.photonBudgetBytes ?? 128 * 1024 * 1024;
|
|
36
|
+
const perCasterRadius = !!causticDiagnostics.photonPerCasterRadius;
|
|
37
|
+
const bytesPerPhoton = perCasterRadius ? 32 : 28;
|
|
38
|
+
let count = Math.max(1, Math.min(Math.round(requested), Math.floor(device.limits.maxStorageBufferBindingSize / PHOTON_BYTES), Math.floor((limit * limit - PHOTON_GRID_SIZE * 4 - 8) / (perCasterRadius ? 4 : 3)), Math.floor(((causticDiagnostics.photonBudgetBytes ?? 128 * 1024 * 1024) - 13 * 1024 * 1024) / bytesPerPhoton)));
|
|
39
|
+
// Include row padding instead of assuming every texture is tightly packed.
|
|
40
|
+
const allocationBytes = (n) => {
|
|
41
|
+
const { buckets, texels } = photonLayout(n, perCasterRadius);
|
|
42
|
+
const capacity = (texels) => Math.min(texels, limit) * Math.ceil(texels / limit);
|
|
43
|
+
return (buckets + buckets / 256) * 32 + capacity(n) * 16 + capacity(texels) * 4 + 32;
|
|
44
|
+
};
|
|
45
|
+
while (count > 1 && allocationBytes(count) > budget) {
|
|
46
|
+
count = Math.max(1, count - Math.ceil((allocationBytes(count) - budget) / bytesPerPhoton));
|
|
47
|
+
}
|
|
48
|
+
const existing = this.targets.get(target);
|
|
49
|
+
if (existing?.count === count && existing.perCasterRadius === perCasterRadius)
|
|
50
|
+
return existing;
|
|
51
|
+
this.release(target);
|
|
52
|
+
const { buckets, texels: headerTexels } = photonLayout(count, perCasterRadius), texels = count, width = Math.min(texels, limit), height = Math.ceil(texels / width);
|
|
53
|
+
// One rgba32uint texel holds position and flux. Direction words live after
|
|
54
|
+
// both sorted indices in the integer grid texture: 20 B payload + 8 B indices.
|
|
55
|
+
const batch = {
|
|
56
|
+
count,
|
|
57
|
+
buckets,
|
|
58
|
+
perCasterRadius,
|
|
59
|
+
grid: device.createBuffer({
|
|
60
|
+
label: 'Photon hash buckets',
|
|
61
|
+
size: (buckets + buckets / 256) * 32,
|
|
62
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
63
|
+
}),
|
|
64
|
+
uniform: device.createBuffer({
|
|
65
|
+
label: 'Photon grid parameters',
|
|
66
|
+
size: 32,
|
|
67
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
68
|
+
}),
|
|
69
|
+
data: device.createTexture({
|
|
70
|
+
label: 'Packed photon positions and flux',
|
|
71
|
+
size: [width, height],
|
|
72
|
+
format: 'rgba32uint',
|
|
73
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC
|
|
74
|
+
}),
|
|
75
|
+
headers: device.createTexture({
|
|
76
|
+
label: 'Photon grid headers',
|
|
77
|
+
size: [
|
|
78
|
+
Math.min(headerTexels, limit),
|
|
79
|
+
Math.ceil((headerTexels) / limit)
|
|
80
|
+
],
|
|
81
|
+
format: 'r32uint',
|
|
82
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
batch.group = this.device.createBindGroup({
|
|
86
|
+
layout: this.layout,
|
|
87
|
+
entries: [
|
|
88
|
+
{ binding: 0, resource: batch.data.createView() },
|
|
89
|
+
{ binding: 1, resource: { buffer: batch.grid } },
|
|
90
|
+
{ binding: 2, resource: { buffer: batch.uniform } },
|
|
91
|
+
{ binding: 4, resource: batch.headers.createView() }
|
|
92
|
+
]
|
|
93
|
+
});
|
|
94
|
+
this.targets.set(target, batch);
|
|
95
|
+
return batch;
|
|
96
|
+
}
|
|
97
|
+
get(target) {
|
|
98
|
+
return this.targets.get(target);
|
|
99
|
+
}
|
|
100
|
+
encode(encoder, groups, target, radius, options) {
|
|
101
|
+
const batch = this.targets.get(target);
|
|
102
|
+
if (causticDiagnostics.capturePhotons)
|
|
103
|
+
causticDiagnostics.photonBatch = {
|
|
104
|
+
device: this.device,
|
|
105
|
+
data: batch.headers,
|
|
106
|
+
emitted: batch.count,
|
|
107
|
+
packed: true
|
|
108
|
+
};
|
|
109
|
+
encoder.clearBuffer(batch.grid);
|
|
110
|
+
this.emission.emit(encoder, groups, batch.data, {
|
|
111
|
+
...options,
|
|
112
|
+
photons: batch.count,
|
|
113
|
+
photonMapping: true,
|
|
114
|
+
photonDirections: batch.headers
|
|
115
|
+
});
|
|
116
|
+
const bytes = new ArrayBuffer(32);
|
|
117
|
+
new Float32Array(bytes)[0] = radius;
|
|
118
|
+
new Uint32Array(bytes)[1] = batch.count;
|
|
119
|
+
new Float32Array(bytes)[2] = causticDiagnostics.photonScreenRadius === false ? 0 : 2;
|
|
120
|
+
new Float32Array(bytes)[3] = causticDiagnostics.photonSkipQuery
|
|
121
|
+
? 1
|
|
122
|
+
: causticDiagnostics.photonSkipVisible
|
|
123
|
+
? 2
|
|
124
|
+
: 0;
|
|
125
|
+
new Uint32Array(bytes)[4] = batch.buckets;
|
|
126
|
+
new Float32Array(bytes)[5] = photonVisibleRadius(radius, options, new Float32Array(bytes)[2]);
|
|
127
|
+
new Uint32Array(bytes)[6] = (+batch.perCasterRadius) |
|
|
128
|
+
(Math.min(65535, Math.max(0, Math.round(causticDiagnostics.photonDeepScreenPixels ?? 0))) << 8);
|
|
129
|
+
this.device.queue.writeBuffer(batch.uniform, 0, bytes);
|
|
130
|
+
const group = batch.group;
|
|
131
|
+
// Dispatch boundaries synchronize storage accesses. Offline batches share one
|
|
132
|
+
// compute pass; timestamp profiling keeps separate passes for stage timings.
|
|
133
|
+
const combined = options.querySet ? undefined : encoder.beginComputePass({ label: 'Photon grid' });
|
|
134
|
+
this.pipelines.forEach((pipeline, index) => {
|
|
135
|
+
const pass = combined ??
|
|
136
|
+
encoder.beginComputePass({
|
|
137
|
+
label: ['Photon count', 'Photon scan blocks', 'Photon scan sums', 'Photon scatter'][index],
|
|
138
|
+
timestampWrites: {
|
|
139
|
+
querySet: options.querySet,
|
|
140
|
+
beginningOfPassWriteIndex: 8 + index * 2,
|
|
141
|
+
endOfPassWriteIndex: 9 + index * 2
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
pass.setPipeline(pipeline);
|
|
145
|
+
pass.setBindGroup(0, group);
|
|
146
|
+
const groups = index === 1
|
|
147
|
+
? batch.buckets / 256
|
|
148
|
+
: index === 2
|
|
149
|
+
? 1
|
|
150
|
+
: Math.ceil((index === 3 ? Math.max(batch.count, batch.buckets) : batch.count) / 64);
|
|
151
|
+
pass.dispatchWorkgroups(Math.min(groups, 65535), index === 1 || index === 2 ? 2 : Math.ceil(groups / 65535));
|
|
152
|
+
if (!combined)
|
|
153
|
+
pass.end();
|
|
154
|
+
});
|
|
155
|
+
combined?.end();
|
|
156
|
+
}
|
|
157
|
+
release(target) {
|
|
158
|
+
const b = this.targets.get(target);
|
|
159
|
+
if (!b)
|
|
160
|
+
return;
|
|
161
|
+
b.grid.destroy();
|
|
162
|
+
b.uniform.destroy();
|
|
163
|
+
b.data.destroy();
|
|
164
|
+
b.headers.destroy();
|
|
165
|
+
this.targets.delete(target);
|
|
166
|
+
}
|
|
167
|
+
bytes(target) {
|
|
168
|
+
const b = this.targets.get(target);
|
|
169
|
+
return b
|
|
170
|
+
? b.grid.size +
|
|
171
|
+
b.uniform.size +
|
|
172
|
+
b.data.width * b.data.height * 16 +
|
|
173
|
+
b.headers.width * b.headers.height * 4
|
|
174
|
+
: 0;
|
|
175
|
+
}
|
|
176
|
+
dispose() {
|
|
177
|
+
for (const target of this.targets.keys())
|
|
178
|
+
this.release(target);
|
|
179
|
+
this.emission.dispose();
|
|
180
|
+
this.placeholder.destroy();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** Typical first-receiver footprint at the caster center; query disks stay exact. */
|
|
184
|
+
export function photonVisibleRadius(radius, options, screenPixels = 2) {
|
|
185
|
+
const m = options.viewProjection, p = options.casterSphere;
|
|
186
|
+
const depth = options.orthographic ? 1 : Math.abs(m[3] * p[0] + m[7] * p[1] + m[11] * p[2] + m[15]);
|
|
187
|
+
const projection = Math.hypot(m[0], m[4], m[8]);
|
|
188
|
+
const footprint = 2 * depth / (options.width * projection) * screenPixels;
|
|
189
|
+
return screenPixels > 0 && Number.isFinite(footprint) && footprint > 0 ? Math.min(radius, Math.max(1e-8, footprint)) : radius;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=WGPUPhotonMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WGPUPhotonMap.js","sourceRoot":"","sources":["../../src/renderer/WGPUPhotonMap.ts"],"names":[],"mappings":"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","sourcesContent":["import {causticDiagnostics} from './causticDiagnostics.js';\nimport {WGPUCausticLightPass} from './WGPUCausticLightPass.js';\nimport {PHOTON_BYTES, PHOTON_GRID_SIZE, photonLayout, photonGridCompute} from './wgsl/photonMap.compute.js';\nexport {photonRadius} from './wgsl/photonMap.compute.js';\ninterface Batch {\n grid: GPUBuffer;\n uniform: GPUBuffer;\n data: GPUTexture;\n headers: GPUTexture;\n count: number;\n buckets: number;\n perCasterRadius: boolean;\n group: GPUBindGroup;\n}\n/** Batch-local spatial hash; accumulated estimates live in the camera path target. */\nexport class WGPUPhotonMap {\n readonly placeholder: GPUTexture;\n readonly emission: WGPUCausticLightPass;\n private readonly targets = new Map<object, Batch>();\n private readonly layout: GPUBindGroupLayout;\n private readonly pipelines: GPUComputePipeline[];\n constructor(private readonly device: GPUDevice) {\n this.placeholder = device.createTexture({\n label: 'Inactive photon binding',\n size: [1, 1],\n format: 'r32uint',\n usage: GPUTextureUsage.TEXTURE_BINDING\n });\n this.emission = new WGPUCausticLightPass(device, true);\n this.layout = device.createBindGroupLayout({\n entries: [\n {binding: 0, visibility: 4, texture: {sampleType: 'uint'}},\n {binding: 1, visibility: 4, buffer: {type: 'storage'}},\n {binding: 2, visibility: 4, buffer: {type: 'uniform'}},\n {binding: 4, visibility: 4, storageTexture: {access: 'write-only', format: 'r32uint'}}\n ]\n });\n const module = device.createShaderModule({label: 'Photon hash grid', code: photonGridCompute}),\n layout = device.createPipelineLayout({bindGroupLayouts: [this.layout]});\n this.pipelines = ['count', 'scanBlocks', 'scanSums', 'scatter'].map((entryPoint) =>\n device.createComputePipeline({label: 'Photon ' + entryPoint, layout, compute: {module, entryPoint}})\n );\n }\n ensure(target: object, requested: number) {\n const device = this.device,\n limit = device.limits.maxTextureDimension2D;\n const budget = causticDiagnostics.photonBudgetBytes ?? 128 * 1024 * 1024;\n const perCasterRadius = !!causticDiagnostics.photonPerCasterRadius;\n const bytesPerPhoton = perCasterRadius ? 32 : 28;\n let count = Math.max(\n 1,\n Math.min(\n Math.round(requested),\n Math.floor(device.limits.maxStorageBufferBindingSize / PHOTON_BYTES),\n Math.floor((limit * limit - PHOTON_GRID_SIZE * 4 - 8) / (perCasterRadius ? 4 : 3)),\n Math.floor(((causticDiagnostics.photonBudgetBytes ?? 128 * 1024 * 1024) - 13 * 1024 * 1024) / bytesPerPhoton)\n )\n );\n // Include row padding instead of assuming every texture is tightly packed.\n const allocationBytes = (n: number) => {\n const {buckets, texels} = photonLayout(n, perCasterRadius);\n const capacity = (texels: number) => Math.min(texels, limit) * Math.ceil(texels / limit);\n return (buckets + buckets / 256) * 32 + capacity(n) * 16 + capacity(texels) * 4 + 32;\n };\n while (count > 1 && allocationBytes(count) > budget) {\n count = Math.max(1, count - Math.ceil((allocationBytes(count) - budget) / bytesPerPhoton));\n }\n const existing = this.targets.get(target);\n if (existing?.count === count && existing.perCasterRadius === perCasterRadius) return existing;\n this.release(target);\n const {buckets, texels: headerTexels} = photonLayout(count, perCasterRadius),\n texels = count,\n width = Math.min(texels, limit),\n height = Math.ceil(texels / width);\n // One rgba32uint texel holds position and flux. Direction words live after\n // both sorted indices in the integer grid texture: 20 B payload + 8 B indices.\n const batch = {\n count,\n buckets,\n perCasterRadius,\n grid: device.createBuffer({\n label: 'Photon hash buckets',\n size: (buckets + buckets / 256) * 32,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST\n }),\n uniform: device.createBuffer({\n label: 'Photon grid parameters',\n size: 32,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n }),\n data: device.createTexture({\n label: 'Packed photon positions and flux',\n size: [width, height],\n format: 'rgba32uint',\n usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC\n }),\n headers: device.createTexture({\n label: 'Photon grid headers',\n size: [\n Math.min(headerTexels, limit),\n Math.ceil((headerTexels) / limit)\n ],\n format: 'r32uint',\n usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC\n })\n } as Batch;\n batch.group = this.device.createBindGroup({\n layout: this.layout,\n entries: [\n {binding: 0, resource: batch.data.createView()},\n {binding: 1, resource: {buffer: batch.grid}},\n {binding: 2, resource: {buffer: batch.uniform}},\n {binding: 4, resource: batch.headers.createView()}\n ]\n });\n this.targets.set(target, batch);\n return batch;\n }\n get(target: object) {\n return this.targets.get(target);\n }\n encode(\n encoder: GPUCommandEncoder,\n groups: GPUBindGroup[],\n target: object,\n radius: number,\n options: Parameters<WGPUCausticLightPass['encode']>[3] & {progressiveBatch?: number}\n ) {\n const batch = this.targets.get(target)!;\n if (causticDiagnostics.capturePhotons)\n causticDiagnostics.photonBatch = {\n device: this.device,\n data: batch.headers,\n emitted: batch.count,\n packed: true\n };\n encoder.clearBuffer(batch.grid);\n this.emission.emit(encoder, groups, batch.data, {\n ...options,\n photons: batch.count,\n photonMapping: true,\n photonDirections: batch.headers\n });\n const bytes = new ArrayBuffer(32);\n new Float32Array(bytes)[0] = radius;\n new Uint32Array(bytes)[1] = batch.count;\n new Float32Array(bytes)[2] = causticDiagnostics.photonScreenRadius === false ? 0 : 2;\n new Float32Array(bytes)[3] = causticDiagnostics.photonSkipQuery\n ? 1\n : causticDiagnostics.photonSkipVisible\n ? 2\n : 0;\n new Uint32Array(bytes)[4] = batch.buckets;\n new Float32Array(bytes)[5] = photonVisibleRadius(radius, options, new Float32Array(bytes)[2]);\n new Uint32Array(bytes)[6] = (+batch.perCasterRadius) |\n (Math.min(65535, Math.max(0, Math.round(causticDiagnostics.photonDeepScreenPixels ?? 0))) << 8);\n this.device.queue.writeBuffer(batch.uniform, 0, bytes);\n const group = batch.group;\n // Dispatch boundaries synchronize storage accesses. Offline batches share one\n // compute pass; timestamp profiling keeps separate passes for stage timings.\n const combined = options.querySet ? undefined : encoder.beginComputePass({label: 'Photon grid'});\n this.pipelines.forEach((pipeline, index) => {\n const pass =\n combined ??\n encoder.beginComputePass({\n label: ['Photon count', 'Photon scan blocks', 'Photon scan sums', 'Photon scatter'][index],\n timestampWrites: {\n querySet: options.querySet!,\n beginningOfPassWriteIndex: 8 + index * 2,\n endOfPassWriteIndex: 9 + index * 2\n }\n });\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, group);\n const groups =\n index === 1\n ? batch.buckets / 256\n : index === 2\n ? 1\n : Math.ceil((index === 3 ? Math.max(batch.count, batch.buckets) : batch.count) / 64);\n pass.dispatchWorkgroups(Math.min(groups, 65535), index === 1 || index === 2 ? 2 : Math.ceil(groups / 65535));\n if (!combined) pass.end();\n });\n combined?.end();\n }\n release(target: object) {\n const b = this.targets.get(target);\n if (!b) return;\n b.grid.destroy();\n b.uniform.destroy();\n b.data.destroy();\n b.headers.destroy();\n this.targets.delete(target);\n }\n bytes(target: object) {\n const b = this.targets.get(target);\n return b\n ? b.grid.size +\n b.uniform.size +\n b.data.width * b.data.height * 16 +\n b.headers.width * b.headers.height * 4\n : 0;\n }\n dispose() {\n for (const target of this.targets.keys()) this.release(target);\n this.emission.dispose();\n this.placeholder.destroy();\n }\n}\n/** Typical first-receiver footprint at the caster center; query disks stay exact. */\nexport function photonVisibleRadius(radius: number, options: {viewProjection: ArrayLike<number>; casterSphere: readonly number[]; width: number; orthographic?: boolean}, screenPixels = 2) {\n const m = options.viewProjection, p = options.casterSphere;\n const depth = options.orthographic ? 1 : Math.abs(m[3]*p[0]+m[7]*p[1]+m[11]*p[2]+m[15]);\n const projection = Math.hypot(m[0], m[4], m[8]);\n const footprint = 2 * depth / (options.width * projection) * screenPixels;\n return screenPixels > 0 && Number.isFinite(footprint) && footprint > 0 ? Math.min(radius, Math.max(1e-8, footprint)) : radius;\n}\n"]}
|