@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openPbrBsdf.wgsl.js","sourceRoot":"","sources":["../../../../src/renderer/wgsl/chunks/openPbrBsdf.wgsl.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,4BAA4B,EAAE,oCAAoC,EAAE,iCAAiC,EAAE,yCAAyC,EAAE,2CAA2C,EAAE,MAAM,2BAA2B,CAAC;AAE1O,MAAM,UAAU,qBAAqB,CAAC,uBAAuB,GAAG,IAAI,EAAE,cAAc,GAAG,KAAK;IAC1F,OAAO,UAAU,CAAC;;;;;;;;;;;;;;;;;;;EAmBlB,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;CAGtC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;EACf,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8If,iCAAiC;iBACjC,iCAAiC;iBACjC,iCAAiC;iBACjC,iCAAiC;iBACjC,iCAAiC;iBACjC,iCAAiC;iBACjC,iCAAiC;iBACjC,iCAAiC;;;;;;;;;;;;;;;;;;;;;kBAqBnC,yCAAyC;kBACzC,yCAAyC;kBACzC,yCAAyC;kBACzC,yCAAyC;;;;;;;;;;;;;;;;;kBAiBzC,2CAA2C;kBAC3C,2CAA2C;kBAC3C,2CAA2C;kBAC3C,2CAA2C;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4BjD,4BAA4B,iBAAoC,4BAA4B;YAC5F,4BAA4B,iBAAoC,4BAA4B;;;;;;;mBAOzF,oCAAoC;qBAC9B,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2iBlF,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;CAetC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;;;;;;;;;;;;;;EAcf,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;EAGrC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;CAO7B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;CASL,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;;EAEf,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,wEAAmF,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgH5G,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,0GAA0G,CAAC,CAAC,CAAC,EAAE;wBAC5F,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY;;wCAEvC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiGhH,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;CAK7B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4EJ,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;CAG7B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsJJ,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,QAAkC,CAAC,CAAC,CAAC,EAAE;;2BAEb,cAAc,CAAC,CAAC,CAAC,wDAAwD,CAAC,CAAC,CAAC,cAAc;;EAEhJ,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;CAG7B,CAAC,CAAC,CAAC,EAAE;;EAEJ,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;MAC7B,cAAc,CAAC,CAAC,CAAC,qDAAqD,CAAC,CAAC,CAAC,YAAY;;;;;;OAMtE,cAAc,CAAC,CAAC,CAAC,oIAAoI,CAAC,CAAC,CAAC,mFAAmF;;;;;;;;;;;;;;;;iDAgBvM,cAAc,CAAC,CAAC,CAAC,4DAA4D,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;CAW9I,CAAC,CAAC,CAAC,UAAU,CAAC;MACL,cAAc,CAAC,CAAC,CAAC,qDAAqD,CAAC,CAAC,CAAC,YAAY;;;;;;;;;;iDAUlC,cAAc,CAAC,CAAC,CAAC,4DAA4D,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;CAW9I;;MAES,cAAc,CAAC,CAAC,CAAC,0DAA0D,CAAC,CAAC,CAAC,YAAY;;;;;;;;;;iDAUvC,cAAc,CAAC,CAAC,CAAC,yDAAyD,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;oBAUpH,cAAc,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC,CAAC,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkF9G,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;uCAMc,cAAc,CAAC,CAAC,CAAC,+IAA+I,CAAC,CAAC,CAAC,mFAAmF;;;;;;;;;;;EAWzS,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;CAM7B,CAAC,CAAC,CAAC,EAAE;;;CAGL,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;CAgBd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8GC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;;;CAG7B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgC4C,cAAc,CAAC,CAAC,CAAC,qHAAqH,CAAC,CAAC,CAAC,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuDhN,CAAC;AAEH,CAAC;AAED,eAAe,qBAAqB,EAAE,CAAC","sourcesContent":["/*\n * OpenPBR energy-compensation, EON and thin-film portions Copyright 2026 Adobe.\n * Licensed under the Apache License, Version 2.0.\n * https://www.apache.org/licenses/LICENSE-2.0\n */\n\n/*\n * Renderer-specific OpenPBR layered BSDF.\n *\n * The prepare/eval/sample/pdf organization and fixed-lobe composition follow:\n * - https://github.com/adobe/openpbr-bsdf\n * - https://github.com/portsmouth/OpenPBR-viewer\n *\n * This compact GPU implementation reuses the renderer's GGX VNDF and volume\n * integrator. Adobe's opaque-dielectric energy tables are used for the base\n * rough-diffuse/specular coupling; fuzz still uses an analytic approximation.\n */\n\nimport { OPENPBR_METAL_ENERGY_LUT_ROW, OPENPBR_METAL_ENERGY_LUT_AVERAGE_ROW, OPENPBR_DIELECTRIC_ENERGY_LUT_ROW, OPENPBR_DIELECTRIC_ENERGY_LUT_AVERAGE_ROW, OPENPBR_DIELECTRIC_REFLECTION_RATIO_LUT_ROW } from '../../openPbrEnergyLut.js';\n\nexport function createOpenPbrBsdfWgsl(hasAnisotropyDirections = true, hasCoatNormals = false) {\n return /* wgsl */ `\nconst OPENPBR_LOBE_FUZZ: i32 = 0;\nconst OPENPBR_LOBE_COAT: i32 = 1;\nconst OPENPBR_LOBE_METAL: i32 = 2;\nconst OPENPBR_LOBE_SPECULAR: i32 = 3;\nconst OPENPBR_LOBE_TRANSMISSION: i32 = 4;\nconst OPENPBR_LOBE_DIFFUSE: i32 = 5;\nconst OPENPBR_LOBE_SUBSURFACE: i32 = 6;\nconst OPENPBR_LOBE_COUNT: i32 = 7;\n\nstruct OpenPbrBasis {\n tangent: vec3f,\n bitangent: vec3f,\n normal: vec3f,\n};\n\nstruct OpenPbrPreparedBsdf {\n material: OpenPbrResolvedMaterial,\n basis: OpenPbrBasis,\n${hasAnisotropyDirections ? /* wgsl */ `\n coatBasis: OpenPbrBasis,\n directionFrames: bool,\n` : /* wgsl */ ``}\n${hasCoatNormals ? /* wgsl */ ` coatViewLocal: vec3f,` : ''}\n viewLocal: vec3f,\n diffuseColor: vec3f,\n specularEtaTOverEtaI: f32,\n refractionEtaTOverEtaI: f32,\n transmissionReflectionIor: f32,\n thinFilmExteriorIor: f32,\n thinFilmBaseIor: f32,\n specularAlpha: f32,\n diffuseSpecularEnergyCompensation: f32,\n coatBaseScale: vec3f,\n metalMsScale: vec3f,\n metalMsFactor: f32,\n metalMsProbability: f32,\n\n dielectricMsReflectionScale: vec3f,\n dielectricMsTransmissionScale: vec3f,\n dielectricMsViewLoss: f32,\n dielectricMsReflectionRatio: f32,\n dielectricMsProbability: f32,\n\n weights: array<f32, OPENPBR_LOBE_COUNT>,\n probabilities: array<f32, OPENPBR_LOBE_COUNT>,\n};\n\nfn openpbr_luminance(color: vec3f) -> f32 {\n return dot(color, vec3f(0.212671, 0.715160, 0.072169));\n}\n\nfn openpbr_f0_from_ior(etaTOverEtaI: f32) -> f32 {\n let value = (etaTOverEtaI - 1.0) / (etaTOverEtaI + 1.0);\n return value * value;\n}\n\nfn openpbr_apply_specular_weight_to_ior(\n etaTOverEtaI: f32,\n specularWeight: f32\n) -> f32 {\n let scaledF0 = min(\n openpbr_f0_from_ior(etaTOverEtaI) * specularWeight,\n 0.9999\n );\n let sqrtF0 = sqrt(scaledF0);\n let externalIor = (1.0 + sqrtF0) / (1.0 - sqrtF0);\n return select(externalIor, 1.0 / externalIor, etaTOverEtaI < 1.0);\n}\n\nfn openpbr_dielectric_fresnel(cosTheta: f32, relativeIor: f32) -> f32 {\n if (abs(relativeIor - 1.0) < 1e-6) {\n return 0.0;\n }\n return sampling_dielectric_fresnel(cosTheta, relativeIor);\n}\n\nfn openpbr_energy_ior_index(ior: f32) -> f32 {\n if (ior < 1.0) {\n return 15.0 - ((1.0 / ior - 1.0) / 1.5) * 15.0;\n }\n return 16.0 + ((ior - 1.0) / 1.5) * 15.0;\n}\n\nfn openpbr_energy_fetch(cosIndex: i32, row: i32) -> f32 {\n return textureLoad(openPbrEnergyLut, vec2i(cosIndex, row), 0).r;\n}\n\nfn openpbr_energy_trilinear(\n exactIor: f32,\n exactAlpha: f32,\n exactCosine: f32\n) -> f32 {\n let iorIndex = clamp(exactIor, 0.0, 31.0);\n let alphaIndex = clamp(exactAlpha, 0.0, 31.0);\n let cosineIndex = clamp(exactCosine, 0.0, 31.0);\n let ior0 = i32(floor(iorIndex));\n let alpha0 = i32(floor(alphaIndex));\n let cosine0 = i32(floor(cosineIndex));\n let ior1 = min(ior0 + 1, 31);\n let alpha1 = min(alpha0 + 1, 31);\n let cosine1 = min(cosine0 + 1, 31);\n let iorMix = iorIndex - f32(ior0);\n let alphaMix = alphaIndex - f32(alpha0);\n let cosineMix = cosineIndex - f32(cosine0);\n\n let v000 = openpbr_energy_fetch(cosine0, ior0 * 32 + alpha0);\n let v001 = openpbr_energy_fetch(cosine1, ior0 * 32 + alpha0);\n let v010 = openpbr_energy_fetch(cosine0, ior0 * 32 + alpha1);\n let v011 = openpbr_energy_fetch(cosine1, ior0 * 32 + alpha1);\n let v100 = openpbr_energy_fetch(cosine0, ior1 * 32 + alpha0);\n let v101 = openpbr_energy_fetch(cosine1, ior1 * 32 + alpha0);\n let v110 = openpbr_energy_fetch(cosine0, ior1 * 32 + alpha1);\n let v111 = openpbr_energy_fetch(cosine1, ior1 * 32 + alpha1);\n let v00 = mix(v000, v100, iorMix);\n let v01 = mix(v001, v101, iorMix);\n let v10 = mix(v010, v110, iorMix);\n let v11 = mix(v011, v111, iorMix);\n return mix(\n mix(v00, v10, alphaMix),\n mix(v01, v11, alphaMix),\n cosineMix\n );\n}\n\nfn openpbr_energy_bilinear(exactIor: f32, exactAlpha: f32) -> f32 {\n let iorIndex = clamp(exactIor, 0.0, 31.0);\n let alphaIndex = clamp(exactAlpha, 0.0, 31.0);\n let ior0 = i32(floor(iorIndex));\n let alpha0 = i32(floor(alphaIndex));\n let ior1 = min(ior0 + 1, 31);\n let alpha1 = min(alpha0 + 1, 31);\n let iorMix = iorIndex - f32(ior0);\n let alphaMix = alphaIndex - f32(alpha0);\n let v00 = openpbr_energy_fetch(alpha0, 1024 + ior0);\n let v01 = openpbr_energy_fetch(alpha1, 1024 + ior0);\n let v10 = openpbr_energy_fetch(alpha0, 1024 + ior1);\n let v11 = openpbr_energy_fetch(alpha1, 1024 + ior1);\n return mix(\n mix(v00, v10, iorMix),\n mix(v01, v11, iorMix),\n alphaMix\n );\n}\n\n// Adobe c91aad1 ideal dielectric tables clamp IOR indices; unlike opaque\n// dielectric data they do not extrapolate outside [0.4, 2.5].\nfn openpbr_ideal_energy_trilinear(\n exactIor: f32,\n exactAlpha: f32,\n exactCosine: f32\n) -> f32 {\n let iorIndex = clamp(exactIor, 0.0, 31.0);\n let alphaIndex = clamp(exactAlpha, 0.0, 31.0);\n let cosineIndex = clamp(exactCosine, 0.0, 31.0);\n let ior0 = i32(floor(iorIndex));\n let alpha0 = i32(floor(alphaIndex));\n let cosine0 = i32(floor(cosineIndex));\n let ior1 = min(ior0 + 1, 31);\n let alpha1 = min(alpha0 + 1, 31);\n let cosine1 = min(cosine0 + 1, 31);\n let iorMix = iorIndex - f32(ior0);\n let alphaMix = alphaIndex - f32(alpha0);\n let cosineMix = cosineIndex - f32(cosine0);\n\n let v000 = openpbr_energy_fetch(cosine0, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior0 * 32 + alpha0);\n let v001 = openpbr_energy_fetch(cosine1, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior0 * 32 + alpha0);\n let v010 = openpbr_energy_fetch(cosine0, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior0 * 32 + alpha1);\n let v011 = openpbr_energy_fetch(cosine1, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior0 * 32 + alpha1);\n let v100 = openpbr_energy_fetch(cosine0, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior1 * 32 + alpha0);\n let v101 = openpbr_energy_fetch(cosine1, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior1 * 32 + alpha0);\n let v110 = openpbr_energy_fetch(cosine0, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior1 * 32 + alpha1);\n let v111 = openpbr_energy_fetch(cosine1, ${OPENPBR_DIELECTRIC_ENERGY_LUT_ROW} + ior1 * 32 + alpha1);\n let v00 = mix(v000, v100, iorMix);\n let v01 = mix(v001, v101, iorMix);\n let v10 = mix(v010, v110, iorMix);\n let v11 = mix(v011, v111, iorMix);\n return mix(\n mix(v00, v10, alphaMix),\n mix(v01, v11, alphaMix),\n cosineMix\n );\n}\n\nfn openpbr_ideal_average_bilinear(exactIor: f32, exactAlpha: f32) -> f32 {\n let iorIndex = clamp(exactIor, 0.0, 31.0);\n let alphaIndex = clamp(exactAlpha, 0.0, 31.0);\n let ior0 = i32(floor(iorIndex));\n let alpha0 = i32(floor(alphaIndex));\n let ior1 = min(ior0 + 1, 31);\n let alpha1 = min(alpha0 + 1, 31);\n let iorMix = iorIndex - f32(ior0);\n let alphaMix = alphaIndex - f32(alpha0);\n let v00 = openpbr_energy_fetch(alpha0, ${OPENPBR_DIELECTRIC_ENERGY_LUT_AVERAGE_ROW} + ior0);\n let v01 = openpbr_energy_fetch(alpha1, ${OPENPBR_DIELECTRIC_ENERGY_LUT_AVERAGE_ROW} + ior0);\n let v10 = openpbr_energy_fetch(alpha0, ${OPENPBR_DIELECTRIC_ENERGY_LUT_AVERAGE_ROW} + ior1);\n let v11 = openpbr_energy_fetch(alpha1, ${OPENPBR_DIELECTRIC_ENERGY_LUT_AVERAGE_ROW} + ior1);\n return mix(\n mix(v00, v10, iorMix),\n mix(v01, v11, iorMix),\n alphaMix\n );\n}\n\nfn openpbr_ideal_ratio_bilinear(exactIor: f32, exactAlpha: f32) -> f32 {\n let iorIndex = clamp(exactIor, 0.0, 31.0);\n let alphaIndex = clamp(exactAlpha, 0.0, 31.0);\n let ior0 = i32(floor(iorIndex));\n let alpha0 = i32(floor(alphaIndex));\n let ior1 = min(ior0 + 1, 31);\n let alpha1 = min(alpha0 + 1, 31);\n let iorMix = iorIndex - f32(ior0);\n let alphaMix = alphaIndex - f32(alpha0);\n let v00 = openpbr_energy_fetch(alpha0, ${OPENPBR_DIELECTRIC_REFLECTION_RATIO_LUT_ROW} + ior0);\n let v01 = openpbr_energy_fetch(alpha1, ${OPENPBR_DIELECTRIC_REFLECTION_RATIO_LUT_ROW} + ior0);\n let v10 = openpbr_energy_fetch(alpha0, ${OPENPBR_DIELECTRIC_REFLECTION_RATIO_LUT_ROW} + ior1);\n let v11 = openpbr_energy_fetch(alpha1, ${OPENPBR_DIELECTRIC_REFLECTION_RATIO_LUT_ROW} + ior1);\n return mix(\n mix(v00, v10, iorMix),\n mix(v01, v11, iorMix),\n alphaMix\n );\n}\n\nfn openpbr_ideal_dielectric_loss(ior: f32, alpha: f32, cosine: f32) -> f32 {\n return openpbr_ideal_energy_trilinear(openpbr_energy_ior_index(ior), sqrt(alpha) * 31.0, cosine * 31.0);\n}\nfn openpbr_ideal_dielectric_average_loss(ior: f32, alpha: f32) -> f32 {\n return openpbr_ideal_average_bilinear(openpbr_energy_ior_index(ior), sqrt(alpha) * 31.0);\n}\nfn openpbr_ideal_dielectric_reflection_ratio(ior: f32, alpha: f32) -> f32 {\n return openpbr_ideal_ratio_bilinear(openpbr_energy_ior_index(ior), sqrt(alpha) * 31.0);\n}\n\n// Adobe openpbr_microfacet_multiple_scattering_{data,lobes}.h (c91aad1):\n// ideal-metal loss E=1-singleScatterEnergy, indexed by sqrt(alpha) and cosine.\nfn openpbr_metal_energy_complement(alpha: f32, cosine: f32) -> f32 {\n let roughnessIndex = clamp(sqrt(alpha) * 31.0, 0.0, 31.0);\n let cosineIndex = clamp(cosine * 31.0, 0.0, 31.0);\n let r0 = i32(floor(roughnessIndex));\n let c0 = i32(floor(cosineIndex));\n let r1 = min(r0 + 1, 31);\n let c1 = min(c0 + 1, 31);\n return mix(\n mix(openpbr_energy_fetch(c0, ${OPENPBR_METAL_ENERGY_LUT_ROW} + r0), openpbr_energy_fetch(c1, ${OPENPBR_METAL_ENERGY_LUT_ROW} + r0), fract(cosineIndex)),\n mix(openpbr_energy_fetch(c0, ${OPENPBR_METAL_ENERGY_LUT_ROW} + r1), openpbr_energy_fetch(c1, ${OPENPBR_METAL_ENERGY_LUT_ROW} + r1), fract(cosineIndex)),\n fract(roughnessIndex));\n}\n\nfn openpbr_metal_average_energy_complement(alpha: f32) -> f32 {\n let index = clamp(sqrt(alpha) * 31.0, 0.0, 31.0);\n let i0 = i32(floor(index));\n return mix(openpbr_energy_fetch(i0, ${OPENPBR_METAL_ENERGY_LUT_AVERAGE_ROW}),\n openpbr_energy_fetch(min(i0 + 1, 31), ${OPENPBR_METAL_ENERGY_LUT_AVERAGE_ROW}), fract(index));\n}\n\nfn openpbr_extrapolate_energy_complement(value: f32, ior: f32) -> f32 {\n if (ior > 2.5 || ior < 0.4) {\n let maxF0 = openpbr_f0_from_ior(2.5);\n let progress = (openpbr_f0_from_ior(ior) - maxF0) / (1.0 - maxF0);\n return (1.0 - progress) * value;\n }\n return value;\n}\n\nfn openpbr_opaque_energy_complement(\n ior: f32,\n alpha: f32,\n cosine: f32\n) -> f32 {\n let value = openpbr_energy_trilinear(\n openpbr_energy_ior_index(ior),\n sqrt(alpha) * 31.0,\n cosine * 31.0\n );\n return openpbr_extrapolate_energy_complement(value, ior);\n}\n\nfn openpbr_opaque_average_energy_complement(ior: f32, alpha: f32) -> f32 {\n let value = openpbr_energy_bilinear(\n openpbr_energy_ior_index(ior),\n sqrt(alpha) * 31.0\n );\n return openpbr_extrapolate_energy_complement(value, ior);\n}\n\nfn openpbr_to_world(basis: OpenPbrBasis, direction: vec3f) -> vec3f {\n return direction.x * basis.tangent\n + direction.y * basis.bitangent\n + direction.z * basis.normal;\n}\n\nfn openpbr_to_local(basis: OpenPbrBasis, direction: vec3f) -> vec3f {\n return vec3f(\n dot(direction, basis.tangent),\n dot(direction, basis.bitangent),\n dot(direction, basis.normal)\n );\n}\n\nfn openpbr_make_basis(\n inputTangent: vec3f,\n normal: vec3f,\n anisotropy: f32\n) -> OpenPbrBasis {\n var basis: OpenPbrBasis;\n basis.normal = normal;\n var tangent = inputTangent;\n var bitangent = vec3f(0.0);\n if (dot(tangent, tangent) < 0.001 || anisotropy <= 0.0) {\n sampling_orthonormal_basis(normal, &tangent, &bitangent);\n }\n else {\n bitangent = normalize(cross(normal, tangent));\n tangent = normalize(cross(bitangent, normal));\n }\n basis.tangent = tangent;\n basis.bitangent = bitangent;\n return basis;\n}\n\nfn openpbr_fresnel_s(\n incidentIor: f32,\n transmittedIor: f32,\n incidentCosine: f32,\n transmittedCosine: f32\n) -> f32 {\n return (incidentIor * incidentCosine - transmittedIor * transmittedCosine)\n / (incidentIor * incidentCosine + transmittedIor * transmittedCosine);\n}\n\nfn openpbr_fresnel_p(\n incidentIor: f32,\n transmittedIor: f32,\n incidentCosine: f32,\n transmittedCosine: f32\n) -> f32 {\n return (transmittedIor * incidentCosine - incidentIor * transmittedCosine)\n / (incidentIor * transmittedCosine + transmittedIor * incidentCosine);\n}\n\nfn openpbr_transmission_s(\n incidentIor: f32,\n transmittedIor: f32,\n incidentCosine: f32,\n transmittedCosine: f32\n) -> f32 {\n return 2.0 * incidentIor * incidentCosine\n / (incidentIor * incidentCosine + transmittedIor * transmittedCosine);\n}\n\nfn openpbr_transmission_p(\n incidentIor: f32,\n transmittedIor: f32,\n incidentCosine: f32,\n transmittedCosine: f32\n) -> f32 {\n return 2.0 * incidentIor * incidentCosine\n / (incidentIor * transmittedCosine + transmittedIor * incidentCosine);\n}\n\nfn openpbr_complex_multiply(a: vec2f, b: vec2f) -> vec2f {\n return vec2f(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);\n}\n\nfn openpbr_complex_divide(a: vec2f, b: vec2f) -> vec2f {\n let denominator = max(dot(b, b), 1e-9);\n return vec2f(\n (a.x * b.x + a.y * b.y) / denominator,\n (a.y * b.x - a.x * b.y) / denominator\n );\n}\n\nfn openpbr_complex_sqrt(value: vec2f) -> vec2f {\n let magnitude = length(value);\n let realPart = sqrt(max(0.0, 0.5 * (magnitude + value.x)));\n let imaginaryMagnitude = sqrt(max(0.0, 0.5 * (magnitude - value.x)));\n return vec2f(realPart, select(-imaginaryMagnitude, imaginaryMagnitude, value.y >= 0.0));\n}\n\nfn openpbr_complex_fresnel_reflection(\n incidentCosine: f32,\n incidentIor: f32,\n transmittedIor: vec2f,\n pPolarized: bool\n) -> vec2f {\n let incidentSine = sqrt(max(0.0, 1.0 - incidentCosine * incidentCosine));\n let iorRatio = openpbr_complex_divide(vec2f(incidentIor, 0.0), transmittedIor);\n let transmittedSine = iorRatio * incidentSine;\n var transmittedCosine = openpbr_complex_sqrt(\n vec2f(1.0, 0.0) - openpbr_complex_multiply(transmittedSine, transmittedSine)\n );\n if (openpbr_complex_multiply(transmittedIor, transmittedCosine).y < 0.0) {\n transmittedCosine = -transmittedCosine;\n }\n\n let incidentIorCosine = vec2f(incidentIor * incidentCosine, 0.0);\n let transmittedIorCosine = openpbr_complex_multiply(transmittedIor, transmittedCosine);\n if (pPolarized) {\n let transmittedIorIncidentCosine = transmittedIor * incidentCosine;\n let incidentIorTransmittedCosine = transmittedCosine * incidentIor;\n return openpbr_complex_divide(\n transmittedIorIncidentCosine - incidentIorTransmittedCosine,\n transmittedIorIncidentCosine + incidentIorTransmittedCosine\n );\n }\n return openpbr_complex_divide(\n incidentIorCosine - transmittedIorCosine,\n incidentIorCosine + transmittedIorCosine\n );\n}\n\nfn openpbr_airy_reflectance(\n reflection12: f32,\n transmission12: f32,\n reflection21: f32,\n transmission21: f32,\n reflection23: vec2f,\n phase: f32\n) -> f32 {\n let phaseRotation = vec2f(cos(phase), sin(phase));\n let reflectedPhase = openpbr_complex_multiply(reflection23, phaseRotation);\n let numerator = reflectedPhase * (transmission12 * transmission21);\n let denominator = vec2f(1.0, 0.0) - reflectedPhase * reflection21;\n let totalReflection = vec2f(reflection12, 0.0)\n + openpbr_complex_divide(numerator, denominator);\n return dot(totalReflection, totalReflection);\n}\n\nfn openpbr_thin_film_reflectance_channel(\n incidentCosine: f32,\n wavelength: f32,\n thickness: f32,\n exteriorIor: f32,\n filmIor: f32,\n substrateIor: vec2f\n) -> f32 {\n let safeIncidentCosine = clamp(abs(incidentCosine), 1e-5, 1.0);\n let filmSineSquared = pow(exteriorIor / filmIor, 2.0)\n * (1.0 - safeIncidentCosine * safeIncidentCosine);\n if (filmSineSquared >= 1.0) {\n return 1.0;\n }\n let filmCosine = sqrt(1.0 - filmSineSquared);\n let reflection12S = openpbr_fresnel_s(\n exteriorIor, filmIor, safeIncidentCosine, filmCosine\n );\n let reflection12P = openpbr_fresnel_p(\n exteriorIor, filmIor, safeIncidentCosine, filmCosine\n );\n let transmission12S = openpbr_transmission_s(\n exteriorIor, filmIor, safeIncidentCosine, filmCosine\n );\n let transmission12P = openpbr_transmission_p(\n exteriorIor, filmIor, safeIncidentCosine, filmCosine\n );\n let transmission21Scale = filmIor * filmCosine\n / max(exteriorIor * safeIncidentCosine, 1e-9);\n let phase = 2.0 * PI * (2.0 * filmIor * thickness * filmCosine) / wavelength;\n var reflectance = 0.0;\n // Both polarizations share Snell's complex solve and the Airy graph.\n for (var polarization = 0u; polarization < (rtUniform.loopUnrollGuard >> 1u); polarization++) {\n let reflection12 = select(reflection12S, reflection12P, polarization == 1u);\n let transmission12 = select(transmission12S, transmission12P, polarization == 1u);\n let reflection23 = openpbr_complex_fresnel_reflection(\n filmCosine, filmIor, substrateIor, polarization == 1u);\n reflectance += openpbr_airy_reflectance(reflection12, transmission12,\n -reflection12, transmission12 * transmission21Scale, reflection23, phase);\n }\n return clamp(0.5 * reflectance, 0.0, 1.0);\n}\n\n\n// OpenPBR 1.1.1 Metal: analytic F82-tint correction to Schlick.\n// Saturation follows Adobe impl/openpbr_lobe_utils.h, openpbr_metal_schlick_with_f82_tint.\nfn openpbr_metal_fresnel(cosine: f32, f0: vec3f, tint: vec3f) -> vec3f {\n let schlick = mix(f0, vec3f(1.0), sampling_schlick_fifth_power(cosine));\n if (all(tint == vec3f(1.0))) { return schlick; }\n let edgeCosine = 1.0 / 7.0;\n let edgeComplement = 1.0 - edgeCosine;\n let edgeFresnel = mix(f0, vec3f(1.0), sampling_schlick_fifth_power(edgeCosine));\n let complement = 1.0 - cosine;\n let correction = cosine * sampling_schlick_fifth_power(cosine) * complement\n / (edgeCosine * pow(edgeComplement, 6.0));\n return clamp(schlick - correction * (edgeFresnel - tint * edgeFresnel), vec3f(0.0), vec3f(1.0));\n}\n\nfn openpbr_metal_complex_ior(f0: f32, f82Tint: f32) -> vec2f {\n let reflectivity = clamp(f0, 0.0, 0.99);\n let sqrtReflectivity = sqrt(reflectivity);\n let minimumIor = (1.0 - reflectivity) / (1.0 + reflectivity);\n let maximumIor = (1.0 + sqrtReflectivity) / max(1.0 - sqrtReflectivity, 1e-9);\n let ior = mix(maximumIor, minimumIor, clamp(f82Tint, 0.0, 1.0));\n let extinctionSquared = (\n (ior + 1.0) * (ior + 1.0) * reflectivity\n - (ior - 1.0) * (ior - 1.0)\n ) / max(1.0 - reflectivity, 1e-9);\n return vec2f(ior, sqrt(max(extinctionSquared, 0.0)));\n}\n\n\nfn openpbr_thin_film_presence(thickness: f32, weight: f32) -> f32 {\n return clamp(weight, 0.0, 1.0) * smoothstep(1e-9, 30.0, thickness);\n}\n\n\n\nfn openpbr_eval_diffuse(\n material: OpenPbrResolvedMaterial,\n color: vec3f,\n viewLocal: vec3f,\n lightLocal: vec3f,\n specularEnergyCompensation: f32,\n pdf: ptr<function, f32>\n) -> vec3f {\n *pdf = 0.0;\n if (lightLocal.z <= 0.0) {\n return vec3f(0.0);\n }\n\n let roughness = material.diffuseRoughness;\n let fonConstantA = 0.5 - 2.0 / (3.0 * PI);\n let fonConstantB = 2.0 / 3.0 - 28.0 / (15.0 * PI);\n let muInput = lightLocal.z;\n let muOutput = viewLocal.z;\n let directional = dot(lightLocal, viewLocal) - muInput * muOutput;\n let directionalOverTangent = select(\n directional,\n directional / max(max(muInput, muOutput), 1e-7),\n directional > 0.0\n );\n let singleScatterA = 1.0 / (1.0 + fonConstantA * roughness);\n let singleScatter = color * INVPI * singleScatterA\n * (1.0 + roughness * directionalOverTangent);\n\n let inputComplement = 1.0 - muInput;\n let outputComplement = 1.0 - muOutput;\n let inputGOverPi = inputComplement * (\n 0.0571085289 + inputComplement * (\n 0.491881867 + inputComplement * (\n -0.332181442 + inputComplement * 0.0714429953\n )\n )\n );\n let outputGOverPi = outputComplement * (\n 0.0571085289 + outputComplement * (\n 0.491881867 + outputComplement * (\n -0.332181442 + outputComplement * 0.0714429953\n )\n )\n );\n let inputAlbedo = (1.0 + roughness * inputGOverPi)\n / (1.0 + fonConstantA * roughness);\n let outputAlbedo = (1.0 + roughness * outputGOverPi)\n / (1.0 + fonConstantA * roughness);\n let averageAlbedo = singleScatterA * (1.0 + fonConstantB * roughness);\n let multipleScatterAlbedo = color * color * averageAlbedo\n / max(vec3f(1e-7), vec3f(1.0) - color * (1.0 - averageAlbedo));\n let multipleScatter = multipleScatterAlbedo * INVPI\n * max(1e-7, 1.0 - outputAlbedo)\n * max(1e-7, 1.0 - inputAlbedo)\n / max(1e-7, 1.0 - averageAlbedo);\n *pdf = lightLocal.z * INVPI;\n return (singleScatter + multipleScatter) * specularEnergyCompensation;\n}\n\nfn openpbr_fuzz_directional_albedo(viewCosine: f32, roughness: f32) -> f32 {\n let x = clamp(viewCosine, 0.0, 1.0);\n let y = clamp(roughness, 0.01, 1.0);\n let scale = y * (0.0206607 + 1.58491 * y)\n / (0.0379424 + y * (1.32227 + y));\n let mean = y * (-0.193854 + y * (-1.14885 + y * (1.7932 - 0.95943 * y * y)))\n / (0.046391 + y);\n let offset = y * (0.000654023 + (-0.0207818 + 0.119681 * y) * y)\n / (1.26264 + y * (-1.92021 + y));\n let gaussian = exp(-0.5 * pow((x - mean) / scale, 2.0))\n / (scale * sqrt(2.0 * PI));\n return max(gaussian + offset, 0.0);\n}\n\nfn openpbr_eval_fuzz(\n material: OpenPbrResolvedMaterial,\n viewLocal: vec3f,\n lightLocal: vec3f,\n pdf: ptr<function, f32>\n) -> vec3f {\n *pdf = 0.0;\n if (viewLocal.z <= 0.0 || lightLocal.z <= 0.0) {\n return vec3f(0.0);\n }\n let albedo = openpbr_fuzz_directional_albedo(\n viewLocal.z,\n material.fuzzRoughness\n );\n *pdf = lightLocal.z * INVPI;\n return material.fuzzColor * albedo * INVPI;\n}\n\nfn openpbr_eval_microfacet_reflection(\n material: OpenPbrResolvedMaterial,\n viewLocal: vec3f,\n lightLocal: vec3f,\n halfVector: vec3f,\n fresnel: vec3f,\n pdf: ptr<function, f32>\n) -> vec3f {\n *pdf = 0.0;\n if (lightLocal.z <= 0.0) {\n return vec3f(0.0);\n }\n\n let alpha = vec2f(material.alphaX, material.alphaY);\n let distribution = sampling_ggx_ndf(halfVector, alpha);\n let masking = sampling_ggx_smith_g1(viewLocal, alpha);\n let maskingShadowing = masking\n * sampling_ggx_smith_g1(lightLocal, alpha);\n\n *pdf = masking * distribution / (4.0 * max(viewLocal.z, 1e-8));\n return fresnel * distribution * maskingShadowing\n / (4.0 * max(lightLocal.z * viewLocal.z, 1e-8));\n}\n\nfn openpbr_eval_microfacet_refraction(\n material: OpenPbrResolvedMaterial,\n relativeIor: f32,\n tint: vec3f,\n viewLocal: vec3f,\n lightLocal: vec3f,\n halfVector: vec3f,\n fresnel: vec3f,\n pdf: ptr<function, f32>\n) -> vec3f {\n *pdf = 0.0;\n if (lightLocal.z >= 0.0) {\n return vec3f(0.0);\n }\n\n let lightHalf = dot(lightLocal, halfVector);\n let viewHalf = dot(viewLocal, halfVector);\n // A refracting microfacet must face the view and the opposite side of the\n // light. Backfacing configurations have no support in the VNDF proposal.\n if (viewHalf <= 0.0 || lightHalf >= 0.0) {\n return vec3f(0.0);\n }\n let alpha = vec2f(material.alphaX, material.alphaY);\n let distribution = sampling_ggx_ndf(halfVector, alpha);\n let masking = sampling_ggx_smith_g1(viewLocal, alpha);\n let maskingShadowing = masking\n * sampling_ggx_smith_g1(lightLocal, alpha);\n var denominator = lightHalf + viewHalf * relativeIor;\n denominator *= denominator;\n let jacobian = abs(lightHalf) / max(denominator, 1e-8);\n let relativeIorSquared = relativeIor * relativeIor;\n\n *pdf = masking * max(0.0, viewHalf) * distribution * jacobian\n / max(viewLocal.z, 1e-8);\n return tint * (vec3f(1.0) - fresnel) * distribution * maskingShadowing\n * abs(viewHalf) * jacobian * relativeIorSquared\n / max(abs(lightLocal.z * viewLocal.z), 1e-8);\n}\n\nfn openpbr_transmission_tint(material: OpenPbrResolvedMaterial) -> vec3f {\n if (HAS_MEDIUM && material.mediumType > 0) {\n return vec3f(1.0);\n }\n return material.transmissionColor;\n}\n\nfn openpbr_thin_wall_fresnel(singleInterfaceFresnel: f32) -> f32 {\n return 2.0 * singleInterfaceFresnel / (1.0 + singleInterfaceFresnel);\n}\n\nfn openpbr_thin_wall_reflection_coefficient(\n singleInterfaceFresnel: vec3f,\n transmissionWeight: f32\n) -> vec3f {\n let windowFresnel = 2.0 * singleInterfaceFresnel\n / (vec3f(1.0) + singleInterfaceFresnel);\n return mix(\n singleInterfaceFresnel,\n windowFresnel,\n clamp(transmissionWeight, 0.0, 1.0)\n );\n}\n\nfn openpbr_final_transmission_tint(\n material: OpenPbrResolvedMaterial,\n incidentCosine: f32,\n etaTOverEtaI: f32\n) -> vec3f {\n let tint = openpbr_transmission_tint(material);\n if (!material.thinWalled) {\n return tint;\n }\n let incidentSineSquared = max(0.0, 1.0 - incidentCosine * incidentCosine);\n let transmittedSineSquared = incidentSineSquared\n / max(etaTOverEtaI * etaTOverEtaI, 1e-9);\n if (transmittedSineSquared >= 1.0) {\n return vec3f(0.0);\n }\n let transmittedCosine = sqrt(1.0 - transmittedSineSquared);\n return pow(max(tint, vec3f(0.0)), vec3f(1.0 / max(transmittedCosine, 1e-5)));\n}\n\nfn openpbr_eval_subsurface_boundary(\n material: OpenPbrResolvedMaterial,\n viewLocal: vec3f,\n lightLocal: vec3f,\n pdf: ptr<function, f32>\n) -> vec3f {\n *pdf = 0.0;\n if (viewLocal.z <= 0.0 || lightLocal.z >= 0.0) {\n return vec3f(0.0);\n }\n let transmittedCosine = -lightLocal.z;\n let entryFresnel = sampling_dielectric_fresnel(\n viewLocal.z,\n material.relativeIor\n );\n *pdf = transmittedCosine * INVPI;\n return vec3f(1.0 - entryFresnel) * INVPI;\n}\n\nfn openpbr_normalize_probabilities(prepared: ptr<function, OpenPbrPreparedBsdf>) {\n // loopUnrollGuard is 4; the dynamic bound covers all seven lobes without\n // asking the driver to unroll array operations across the full BSDF.\n let lobeCount = min(OPENPBR_LOBE_COUNT, i32(rtUniform.loopUnrollGuard * 2u));\n var total = (*prepared).probabilities[OPENPBR_LOBE_FUZZ];\n for (var lobe = 1; lobe < lobeCount; lobe++) {\n total += (*prepared).probabilities[lobe];\n }\n if (total <= 1e-8) {\n for (var lobe = 0; lobe < lobeCount; lobe++) {\n (*prepared).probabilities[lobe] = 0.0;\n }\n return;\n }\n let inverseTotal = 1.0 / total;\n for (var lobe = 0; lobe < lobeCount; lobe++) {\n (*prepared).probabilities[lobe] *= inverseTotal;\n }\n}\n\n// Adapted from Adobe c91aad1 impl/openpbr_lobe_utils.h and\n// impl/openpbr_bsdf.h::openpbr_prepare_lobes (Apache-2.0).\nfn openpbr_average_fresnel(eta: f32) -> f32 {\n if (abs(eta - 1.0) < 1e-6) { return 0.0; }\n if (eta > 1.0) { return (eta - 1.0) / (4.08567 + 1.00071 * eta); }\n return 0.997118 + 0.1014 * eta - 0.965241 * eta * eta - 0.130607 * eta * eta * eta;\n}\n\nfn openpbr_metal_average_fresnel(f0: vec3f, tint: vec3f) -> vec3f {\n let edgeCosine = 1.0 / 7.0;\n let edgeFresnel = mix(f0, vec3f(1.0), sampling_schlick_fifth_power(edgeCosine));\n let b = edgeFresnel * (vec3f(1.0) - tint) / (edgeCosine * pow(1.0 - edgeCosine, 6.0));\n return clamp(f0 + (vec3f(1.0) - f0) / 21.0 - b / 126.0, vec3f(0.0), vec3f(1.0));\n}\n\n// Adobe openpbr_coating_lobe.h: one passage, using the refracted cosine.\n// Partial coverage is mixed separately for each passage, as in the reference.\nfn openpbr_coat_passage(material: OpenPbrResolvedMaterial, cosine: f32) -> vec3f {\n if (cosine <= 0.0) { return vec3f(1.0); }\n let refractedCosine = sqrt(max(0.0, 1.0 - (1.0 - cosine * cosine) / (material.coatIor * material.coatIor)));\n let passage = pow(max(material.coatColor, vec3f(0.0)), vec3f(0.5 / max(refractedCosine, 1e-5)));\n return mix(vec3f(1.0), passage, material.coatWeight);\n}\n\nfn openpbr_coat_energy(material: OpenPbrResolvedMaterial, cosine: f32) -> f32 {\n if (material.coatRoughness <= ROUGHNESS_MIN) {\n return openpbr_dielectric_fresnel(cosine, 1.0 / material.coatIor);\n }\n // The opaque-dielectric table is the complement of coat directional albedo.\n // Adobe uses the original isotropic alpha (r^2) even for anisotropic GGX.\n return clamp(1.0 - openpbr_opaque_energy_complement(material.coatIor,\n material.coatRoughness * material.coatRoughness, cosine), 0.0, 1.0);\n}\n\nfn openpbr_coat_darkening(prepared: OpenPbrPreparedBsdf) -> vec3f {\n let material = prepared.material;\n let dielectric = 1.0 - material.baseMetalness;\n let opaque = dielectric * (1.0 - material.transmissionWeight) * (1.0 - material.subsurfaceWeight);\n let sss = dielectric * (1.0 - material.transmissionWeight) * material.subsurfaceWeight;\n let trans = dielectric * material.transmissionWeight;\n let opaqueSpecularity = openpbr_average_fresnel(prepared.specularEtaTOverEtaI);\n let transSpecularity = openpbr_average_fresnel(1.0 / prepared.transmissionReflectionIor);\n let specularity = clamp(opaque * opaqueSpecularity + (sss + trans) * transSpecularity + material.baseMetalness, 0.0, 1.0);\n let effectiveRoughness = mix(1.0, material.specularRoughness, specularity);\n let ks = openpbr_average_fresnel(material.coatIor);\n let kr = 1.0 - (1.0 - ks) / (material.coatIor * material.coatIor);\n let k = mix(ks, kr, effectiveRoughness);\n let eb = material.baseMetalness * material.specularWeight * openpbr_metal_average_fresnel(material.baseWeight * material.baseColor, material.specularColor)\n + opaque * mix(material.baseWeight * material.baseColor, vec3f(1.0), opaqueSpecularity)\n + sss * material.subsurfaceColor + vec3f(trans);\n let delta = vec3f(1.0 - k) / max(vec3f(1.0) - eb * k, vec3f(1e-6));\n return mix(vec3f(1.0), delta, material.coatWeight * material.coatDarkening);\n}\n\nfn openpbr_coat_base_scale(prepared: OpenPbrPreparedBsdf, lightCosine: f32) -> vec3f {\n if (prepared.material.coatWeight <= 0.0) { return vec3f(1.0); }\n if (prepared.material.inside) {\n // Inside only outgoing transmission crosses the coat; no coat reflection.\n return openpbr_coat_passage(prepared.material, -lightCosine);\n }\n // Default reference mode applies energy partition on the view side only.\n return prepared.coatBaseScale * openpbr_coat_passage(prepared.material, lightCosine);\n}\n\n\n${hasAnisotropyDirections ? /* wgsl */ `\nfn openpbr_direction_basis(fallback: OpenPbrBasis, tangent: vec3f, bitangent: vec3f, direction: vec2f) -> OpenPbrBasis {\n var t = tangent - fallback.normal * dot(fallback.normal, tangent);\n if (dot(t, t) < 1e-8) { t = fallback.tangent; }\n t = normalize(t);\n let b = cross(fallback.normal, t) * select(1.0, -1.0, dot(cross(fallback.normal, t), bitangent) < 0.0);\n t = t * direction.x + b * direction.y;\n if (dot(t, t) < 1e-8) { return fallback; }\n var basis = fallback;\n basis.tangent = normalize(t);\n basis.bitangent = normalize(cross(basis.normal, basis.tangent));\n basis.tangent = normalize(cross(basis.bitangent, basis.normal));\n return basis;\n}\n\n` : /* wgsl */ ``}\nfn openpbr_prepare(\n tangent: vec3f,\n material: OpenPbrResolvedMaterial,\n viewDirection: vec3f,\n normal: vec3f\n) -> OpenPbrPreparedBsdf {\n var prepared: OpenPbrPreparedBsdf;\n prepared.material = material;\n prepared.basis = openpbr_make_basis(\n tangent,\n normal,\n max(material.specularAnisotropy, material.coatAnisotropy)\n );\n${hasAnisotropyDirections ? /* wgsl */ `\n prepared.coatBasis = prepared.basis;\n prepared.directionFrames = false;\n${hasCoatNormals ? /* wgsl */ `\n // Adobe c91aad1 openpbr_prepare_lobes: geometry_coat_basis is independent\n // of the base shading basis; coat passage uses the same coat cosine.\n if (material.coatNormalEnabled) {\n prepared.coatBasis = openpbr_make_basis(material.geometryTangent, material.coatNormal, material.coatAnisotropy);\n prepared.directionFrames = true;\n }\n` : ''}\n if (material.specularAnisotropy > 0.0 && material.anisotropyDirectionEnabled) {\n prepared.basis = openpbr_direction_basis(prepared.basis, material.directionTangent, material.directionBitangent, material.anisotropyDirection);\n prepared.directionFrames = true;\n }\n if (material.coatAnisotropy > 0.0 && material.coatAnisotropyRotation != 0.0) {\n prepared.coatBasis = openpbr_direction_basis(prepared.coatBasis, material.geometryTangent, material.geometryBitangent, vec2f(cos(material.coatAnisotropyRotation), sin(material.coatAnisotropyRotation)));\n prepared.directionFrames = true;\n }\n` : /* wgsl */ ``}\n prepared.viewLocal = openpbr_to_local(prepared.basis, viewDirection);\n${hasCoatNormals ? /* wgsl */ ` prepared.coatViewLocal = openpbr_to_local(prepared.coatBasis, viewDirection);` : ''}\n prepared.diffuseColor = material.baseColor;\n\n let dielectricBaseWeight = 1.0 - material.baseMetalness;\n let opaqueDielectricWeight = dielectricBaseWeight\n * (1.0 - material.transmissionWeight);\n prepared.weights[OPENPBR_LOBE_FUZZ] = material.fuzzWeight;\n prepared.weights[OPENPBR_LOBE_COAT] = material.coatWeight;\n if (material.inside) { prepared.weights[OPENPBR_LOBE_COAT] = 0.0; }\n prepared.weights[OPENPBR_LOBE_METAL] = material.baseMetalness;\n prepared.weights[OPENPBR_LOBE_SPECULAR] = dielectricBaseWeight;\n prepared.weights[OPENPBR_LOBE_TRANSMISSION] = dielectricBaseWeight\n * material.transmissionWeight;\n prepared.weights[OPENPBR_LOBE_DIFFUSE] = opaqueDielectricWeight\n * (1.0 - material.subsurfaceWeight) * material.baseWeight;\n prepared.weights[OPENPBR_LOBE_SUBSURFACE] = opaqueDielectricWeight\n * material.subsurfaceWeight;\n\n prepared.specularEtaTOverEtaI = openpbr_apply_specular_weight_to_ior(\n 1.0 / material.relativeIor,\n material.specularWeight\n );\n prepared.material.relativeIor = 1.0 / prepared.specularEtaTOverEtaI;\n prepared.refractionEtaTOverEtaI = prepared.specularEtaTOverEtaI;\n prepared.transmissionReflectionIor = prepared.material.relativeIor;\n // Adobe openpbr_bsdf.h::openpbr_prepare_lobes: reflect relative to\n // the weighted coat, refract relative to ambient air. Inside ignores coat.\n if (material.coatWeight > 0.0) {\n var weightedCoatIor = 1.0;\n if (!material.inside) { weightedCoatIor = mix(1.0, material.coatIor, material.coatWeight); }\n let weightedBaseIor = weightedCoatIor * openpbr_apply_specular_weight_to_ior(\n material.specularIor / weightedCoatIor, material.specularWeight);\n var reflectionEta = weightedBaseIor / weightedCoatIor;\n if (weightedCoatIor > weightedBaseIor && weightedBaseIor >= 1.0) {\n reflectionEta = 1.0 / reflectionEta;\n }\n prepared.specularEtaTOverEtaI = reflectionEta;\n prepared.transmissionReflectionIor = 1.0 / reflectionEta;\n prepared.refractionEtaTOverEtaI = weightedBaseIor;\n if (material.inside) {\n prepared.refractionEtaTOverEtaI = 1.0 / weightedBaseIor;\n prepared.transmissionReflectionIor = weightedBaseIor;\n }\n prepared.material.relativeIor = 1.0 / prepared.refractionEtaTOverEtaI;\n }\n\n // Adobe openpbr_bsdf.h::openpbr_prepare_lobes: absolute thin-film media.\n // Preserve the existing optical solve for uncoated materials.\n prepared.thinFilmExteriorIor = 1.0;\n prepared.thinFilmBaseIor = prepared.specularEtaTOverEtaI;\n if (material.coatWeight > 0.0) {\n if (material.inside) {\n prepared.thinFilmExteriorIor = 1.0 / prepared.refractionEtaTOverEtaI;\n prepared.thinFilmBaseIor = 1.0;\n }\n else {\n prepared.thinFilmExteriorIor = mix(1.0, material.coatIor, material.coatWeight);\n prepared.thinFilmBaseIor = prepared.refractionEtaTOverEtaI;\n }\n }\n prepared.specularAlpha = material.specularRoughness\n * material.specularRoughness;\n let viewCosine = abs(prepared.viewLocal.z);\n let singleInterfaceFresnel = openpbr_dielectric_fresnel(\n viewCosine,\n 1.0 / prepared.specularEtaTOverEtaI\n );\n let dielectricFresnelEstimate = material.specularColor * select(\n singleInterfaceFresnel,\n mix(\n singleInterfaceFresnel,\n openpbr_thin_wall_fresnel(singleInterfaceFresnel),\n material.transmissionWeight\n ),\n material.thinWalled\n );\n let metalFresnelEstimate = material.specularWeight * openpbr_metal_fresnel(\n viewCosine,\n material.baseWeight * material.baseColor,\n material.specularColor\n );\n let transmissionFresnel = select(\n openpbr_dielectric_fresnel(viewCosine, prepared.transmissionReflectionIor),\n openpbr_thin_wall_fresnel(openpbr_dielectric_fresnel(viewCosine, prepared.transmissionReflectionIor)),\n material.thinWalled\n );\n let transmissionTint = openpbr_final_transmission_tint(\n material,\n viewCosine,\n prepared.refractionEtaTOverEtaI\n );\n let viewEnergyComplement = openpbr_opaque_energy_complement(\n prepared.specularEtaTOverEtaI,\n prepared.specularAlpha,\n viewCosine\n );\n let averageEnergyComplement = openpbr_opaque_average_energy_complement(\n prepared.specularEtaTOverEtaI,\n prepared.specularAlpha\n );\n prepared.diffuseSpecularEnergyCompensation = viewEnergyComplement\n / max(averageEnergyComplement, 1e-12);\n\n prepared.probabilities[OPENPBR_LOBE_FUZZ] = prepared.weights[OPENPBR_LOBE_FUZZ]\n * openpbr_luminance(material.fuzzColor)\n * max(openpbr_fuzz_directional_albedo(\n viewCosine,\n material.fuzzRoughness\n ), 0.02);\n prepared.probabilities[OPENPBR_LOBE_COAT] = 0.0;\n prepared.coatBaseScale = vec3f(1.0);\n if (material.coatWeight > 0.0 && !material.inside) {\n ${hasCoatNormals ? /* wgsl */ `let coatViewCosine = select(viewCosine, max(prepared.coatViewLocal.z, 0.0), material.coatNormalEnabled);` : ''}\n let coatEnergy = openpbr_coat_energy(material, ${hasCoatNormals ? 'coatViewCosine' : 'viewCosine'});\n prepared.probabilities[OPENPBR_LOBE_COAT] = prepared.weights[OPENPBR_LOBE_COAT] * coatEnergy;\n prepared.coatBaseScale = openpbr_coat_passage(material, ${hasCoatNormals ? 'coatViewCosine' : 'viewCosine'})\n * (1.0 - prepared.weights[OPENPBR_LOBE_COAT] * coatEnergy) * openpbr_coat_darkening(prepared);\n }\n prepared.probabilities[OPENPBR_LOBE_METAL] = prepared.weights[OPENPBR_LOBE_METAL]\n * openpbr_luminance(metalFresnelEstimate);\n prepared.metalMsScale = vec3f(0.0);\n prepared.metalMsFactor = 0.0;\n prepared.metalMsProbability = 0.0;\n // Reference suppresses loss below roughness .04 and uses the original\n // isotropic alpha even when the single-scattering lobe is anisotropic.\n if (material.specularRoughness >= 0.04 && prepared.weights[OPENPBR_LOBE_METAL] > 0.0) {\n let averageFresnel = openpbr_metal_average_fresnel(material.baseWeight * material.baseColor, material.specularColor);\n prepared.metalMsScale = material.specularWeight * averageFresnel * averageFresnel;\n let viewLoss = openpbr_metal_energy_complement(prepared.specularAlpha, viewCosine);\n prepared.metalMsFactor = viewLoss / max(openpbr_metal_average_energy_complement(prepared.specularAlpha), 1e-12);\n let msEstimate = prepared.weights[OPENPBR_LOBE_METAL] * openpbr_luminance(prepared.metalMsScale) * viewLoss;\n prepared.probabilities[OPENPBR_LOBE_METAL] += msEstimate;\n prepared.metalMsProbability = msEstimate / max(prepared.probabilities[OPENPBR_LOBE_METAL], 1e-12);\n }\n prepared.probabilities[OPENPBR_LOBE_SPECULAR] = prepared.weights[OPENPBR_LOBE_SPECULAR]\n * openpbr_luminance(dielectricFresnelEstimate);\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] = prepared.weights[OPENPBR_LOBE_TRANSMISSION]\n * (1.0 - transmissionFresnel)\n * openpbr_luminance(transmissionTint);\n // OpenPBR_DielectricMicrofacetMultipleScatteringLobe, Adobe c91aad1\n // (Apache-2.0). Use the refraction IOR even when coat reflection uses a\n // different ratio. Restrict this addition to solid transmissive materials;\n // opaque/subsurface-only and thin-wall paths retain their existing model.\n // Keep the renderer's exact null boundary discrete: upstream avoids eta=1\n // for refraction, and its tabulation has small nonzero loss there.\n prepared.dielectricMsReflectionScale = vec3f(0.0);\n prepared.dielectricMsTransmissionScale = vec3f(0.0);\n prepared.dielectricMsViewLoss = 0.0;\n prepared.dielectricMsReflectionRatio = 0.0;\n prepared.dielectricMsProbability = 0.0;\n if (!material.thinWalled && material.transmissionWeight > 0.0 &&\n prepared.specularAlpha >= 0.0016 && prepared.weights[OPENPBR_LOBE_TRANSMISSION] > 0.0 &&\n abs(prepared.refractionEtaTOverEtaI - 1.0) > 1e-6) {\n let nonOpaqueWeight = prepared.weights[OPENPBR_LOBE_TRANSMISSION] + prepared.weights[OPENPBR_LOBE_SUBSURFACE];\n prepared.dielectricMsReflectionScale = select(material.specularColor, vec3f(1.0), material.inside) * nonOpaqueWeight;\n prepared.dielectricMsTransmissionScale = transmissionTint * prepared.weights[OPENPBR_LOBE_TRANSMISSION]\n + vec3f(prepared.weights[OPENPBR_LOBE_SUBSURFACE]);\n prepared.dielectricMsReflectionRatio = openpbr_ideal_dielectric_reflection_ratio(prepared.refractionEtaTOverEtaI, prepared.specularAlpha);\n prepared.dielectricMsViewLoss = openpbr_ideal_dielectric_loss(prepared.refractionEtaTOverEtaI, prepared.specularAlpha, viewCosine);\n let averageScale = mix(prepared.dielectricMsTransmissionScale, prepared.dielectricMsReflectionScale, prepared.dielectricMsReflectionRatio);\n let msEstimate = openpbr_luminance(averageScale) * prepared.dielectricMsViewLoss;\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] += msEstimate;\n prepared.dielectricMsProbability = msEstimate / max(prepared.probabilities[OPENPBR_LOBE_TRANSMISSION], 1e-12);\n }\n prepared.probabilities[OPENPBR_LOBE_DIFFUSE] = prepared.weights[OPENPBR_LOBE_DIFFUSE]\n * openpbr_luminance(prepared.diffuseColor)\n * prepared.diffuseSpecularEnergyCompensation;\n prepared.probabilities[OPENPBR_LOBE_SUBSURFACE] = prepared.weights[OPENPBR_LOBE_SUBSURFACE]\n * (1.0 - transmissionFresnel)\n * openpbr_luminance(material.subsurfaceColor)\n * prepared.diffuseSpecularEnergyCompensation;\n // Index-matched base interfaces can still reflect through thin film.\n // Keep proposal support without duplicating the Airy optical solve here.\n if (material.coatWeight > 0.0 && HAS_THIN_FILM && material.thinFilmWeight > 0.0) {\n let filmSupport = 0.02 * openpbr_thin_film_presence(material.thinFilmThickness, material.thinFilmWeight);\n prepared.probabilities[OPENPBR_LOBE_SPECULAR] = max(prepared.probabilities[OPENPBR_LOBE_SPECULAR], prepared.weights[OPENPBR_LOBE_SPECULAR] * filmSupport);\n prepared.probabilities[OPENPBR_LOBE_METAL] = max(prepared.probabilities[OPENPBR_LOBE_METAL], prepared.weights[OPENPBR_LOBE_METAL] * material.specularWeight * filmSupport);\n }\n if (material.coatWeight > 0.0 && !material.inside) {\n let baseScale = max(max(prepared.coatBaseScale.x, prepared.coatBaseScale.y), prepared.coatBaseScale.z);\n prepared.probabilities[OPENPBR_LOBE_METAL] *= baseScale;\n prepared.probabilities[OPENPBR_LOBE_SPECULAR] *= baseScale;\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] *= baseScale;\n prepared.probabilities[OPENPBR_LOBE_DIFFUSE] *= baseScale;\n prepared.probabilities[OPENPBR_LOBE_SUBSURFACE] *= baseScale;\n }\n openpbr_normalize_probabilities(&prepared);\n return prepared;\n}\n\n\nfn openpbr_substrate_fresnel(prepared: OpenPbrPreparedBsdf, cosine: f32, reflection: bool) -> f32 {\n if (prepared.material.coatWeight <= 0.0) {\n return openpbr_dielectric_fresnel(cosine, prepared.material.relativeIor);\n }\n let transFresnel = openpbr_dielectric_fresnel(cosine, prepared.transmissionReflectionIor);\n if (!reflection) { return transFresnel; }\n let opaqueFresnel = openpbr_dielectric_fresnel(cosine, 1.0 / prepared.specularEtaTOverEtaI);\n let nonOpaque = prepared.material.transmissionWeight + (1.0 - prepared.material.transmissionWeight) * prepared.material.subsurfaceWeight;\n return mix(opaqueFresnel, transFresnel, nonOpaque);\n}\n\nfn openpbr_eval_prepared_lobe(\n prepared: OpenPbrPreparedBsdf,\n lightDirection: vec3f,\n allowedLobe: i32,\n pdf: ptr<function, f32>\n) -> vec3f {\n let material = prepared.material;\n let viewLocal = prepared.viewLocal;\n let lightLocal = openpbr_to_local(prepared.basis, lightDirection);\n let reflection = lightLocal.z * viewLocal.z > 0.0;\n${hasCoatNormals ? /* wgsl */ `\n let independentCoat = material.coatNormalEnabled;\n let geometricReflection = dot(material.geometricNormal, lightDirection) > 0.0;\n let coatLightCosine = dot(prepared.coatBasis.normal, lightDirection);\n let coatReflection = geometricReflection && prepared.coatViewLocal.z > 0.0 && coatLightCosine > 0.0;\n` : ''}\n\n var halfVector: vec3f;\n if (reflection) {\n halfVector = normalize(lightLocal + viewLocal);\n }\n else {\n halfVector = normalize(lightLocal + viewLocal * material.relativeIor);\n }\n if (halfVector.z < 0.0) {\n halfVector = -halfVector;\n }\n\n var response = vec3f(0.0);\n *pdf = 0.0;\n var lobePdf = 0.0;\n let allowAll = allowedLobe < 0;\n let allowFuzz = allowAll || allowedLobe == OPENPBR_LOBE_FUZZ;\n let allowCoat = allowAll || allowedLobe == OPENPBR_LOBE_COAT;\n let allowMetal = allowAll || allowedLobe == OPENPBR_LOBE_METAL;\n let allowSpecular = allowAll || allowedLobe == OPENPBR_LOBE_SPECULAR;\n let allowTransmission = allowAll ||\n allowedLobe == OPENPBR_LOBE_TRANSMISSION;\n let allowDiffuse = allowAll || allowedLobe == OPENPBR_LOBE_DIFFUSE;\n let allowSubsurface = allowAll ||\n allowedLobe == OPENPBR_LOBE_SUBSURFACE;\n let viewHalf = abs(dot(viewLocal, halfVector));\n // Reflection, solid refraction and thin-wall transmission share the same\n // dielectric optical solve. Select its half angle before evaluating the\n // film, instead of inlining that large solve in each transport branch.\n var thinWallHalf = halfVector;\n var dielectricViewHalf = viewHalf;\n if (!reflection && material.thinWalled) {\n thinWallHalf = normalize(vec3f(lightLocal.xy, -lightLocal.z) + viewLocal);\n if (thinWallHalf.z < 0.0) { thinWallHalf = -thinWallHalf; }\n dielectricViewHalf = abs(dot(viewLocal, thinWallHalf));\n }\n let evaluateDielectric =\n (reflection && prepared.weights[OPENPBR_LOBE_SPECULAR] > 0.0 && allowSpecular) ||\n (!reflection && prepared.weights[OPENPBR_LOBE_TRANSMISSION] > 0.0 && allowTransmission);\n let evaluateMetal = reflection && prepared.weights[OPENPBR_LOBE_METAL] > 0.0 && allowMetal;\n var fresnels: array<vec3f, 2>;\n if (evaluateDielectric) {\n fresnels[0] = vec3f(openpbr_substrate_fresnel(prepared, dielectricViewHalf, reflection));\n }\n if (evaluateMetal) {\n fresnels[1] = openpbr_metal_fresnel(viewHalf, material.baseWeight * material.baseColor, material.specularColor);\n }\n if (HAS_THIN_FILM && material.thinFilmWeight > 0.0) {\n let wavelengths = vec3f(620.0, 540.0, 450.0);\n // Dielectric and conductor substrates share one complete optical graph.\n for (var substrate = 0u; substrate < (rtUniform.loopUnrollGuard >> 1u); substrate++) {\n if (!select(evaluateDielectric, evaluateMetal, substrate == 1u)) { continue; }\n var film = vec3f(0.0);\n let incidentCosine = select(dielectricViewHalf, viewHalf, substrate == 1u);\n for (var channel = 0u; channel + 1u < rtUniform.loopUnrollGuard; channel++) {\n var ior = vec2f(prepared.thinFilmBaseIor, 0.0);\n if (substrate == 1u) {\n ior = openpbr_metal_complex_ior(material.baseWeight * material.baseColor[channel], material.specularColor[channel]);\n }\n film[channel] = openpbr_thin_film_reflectance_channel(incidentCosine,\n wavelengths[channel], material.thinFilmThickness, prepared.thinFilmExteriorIor, material.thinFilmIor, ior);\n }\n fresnels[substrate] = mix(fresnels[substrate], film,\n openpbr_thin_film_presence(material.thinFilmThickness, material.thinFilmWeight));\n }\n }\n let substrateFresnel = fresnels[0];\n let diffuseSpecularEnergyCompensation =\n prepared.diffuseSpecularEnergyCompensation\n * openpbr_opaque_energy_complement(\n prepared.specularEtaTOverEtaI,\n prepared.specularAlpha,\n abs(lightLocal.z)\n );\n\n${hasCoatNormals ? /* wgsl */ `\n // Each lobe retains its own shading hemisphere; topology is geometric.\n if (!independentCoat || (lightLocal.z != 0.0 && reflection == geometricReflection)) {\n` : ''}\n if (reflection) {\n if (prepared.weights[OPENPBR_LOBE_DIFFUSE] > 0.0 && allowDiffuse) {\n response += prepared.weights[OPENPBR_LOBE_DIFFUSE] * openpbr_eval_diffuse(\n material,\n prepared.diffuseColor,\n viewLocal,\n lightLocal,\n diffuseSpecularEnergyCompensation,\n &lobePdf\n );\n *pdf += prepared.probabilities[OPENPBR_LOBE_DIFFUSE] * lobePdf;\n }\n\n if (prepared.weights[OPENPBR_LOBE_SUBSURFACE] > 0.0 && material.thinWalled &&\n allowSubsurface) {\n response += 0.5 * prepared.weights[OPENPBR_LOBE_SUBSURFACE] * openpbr_eval_diffuse(\n material,\n material.subsurfaceColor,\n viewLocal,\n lightLocal,\n diffuseSpecularEnergyCompensation,\n &lobePdf\n );\n *pdf += prepared.probabilities[OPENPBR_LOBE_SUBSURFACE] * 0.5 * lobePdf;\n }\n\n if (prepared.weights[OPENPBR_LOBE_SPECULAR] > 0.0 && allowSpecular) {\n var dielectricFresnel = substrateFresnel;\n if (material.thinWalled) {\n dielectricFresnel = openpbr_thin_wall_reflection_coefficient(\n dielectricFresnel,\n material.transmissionWeight\n );\n }\n let fresnel = material.specularColor * dielectricFresnel;\n response += prepared.weights[OPENPBR_LOBE_SPECULAR] * openpbr_eval_microfacet_reflection(\n material,\n viewLocal,\n lightLocal,\n halfVector,\n fresnel,\n &lobePdf\n );\n *pdf += prepared.probabilities[OPENPBR_LOBE_SPECULAR] * lobePdf;\n }\n\n if (prepared.weights[OPENPBR_LOBE_METAL] > 0.0 && allowMetal) {\n let fresnel = material.specularWeight * fresnels[1];\n response += prepared.weights[OPENPBR_LOBE_METAL] * openpbr_eval_microfacet_reflection(\n material,\n viewLocal,\n lightLocal,\n halfVector,\n fresnel,\n &lobePdf\n );\n if (prepared.metalMsFactor > 0.0) {\n let factor = min(prepared.metalMsFactor * openpbr_metal_energy_complement(prepared.specularAlpha, lightLocal.z), 1.0 / max(lightLocal.z, 1e-8));\n response += prepared.weights[OPENPBR_LOBE_METAL] * prepared.metalMsScale * factor * INVPI;\n lobePdf = mix(lobePdf, 0.5 * INVPI, prepared.metalMsProbability);\n }\n *pdf += prepared.probabilities[OPENPBR_LOBE_METAL] * lobePdf;\n }\n }\n else {\n let fresnel = substrateFresnel;\n if (prepared.weights[OPENPBR_LOBE_TRANSMISSION] > 0.0 && allowTransmission) {\n if (material.thinWalled) {\n let mirroredLight = vec3f(lightLocal.xy, -lightLocal.z);\n let windowFresnel = openpbr_thin_wall_reflection_coefficient(\n substrateFresnel,\n 1.0\n );\n let tint = openpbr_final_transmission_tint(\n material,\n abs(viewLocal.z),\n prepared.refractionEtaTOverEtaI\n );\n response += prepared.weights[OPENPBR_LOBE_TRANSMISSION]\n * openpbr_eval_microfacet_reflection(\n material,\n viewLocal,\n mirroredLight,\n thinWallHalf,\n tint * (vec3f(1.0) - windowFresnel),\n &lobePdf\n );\n }\n else {\n response += prepared.weights[OPENPBR_LOBE_TRANSMISSION]\n * openpbr_eval_microfacet_refraction(\n material,\n material.relativeIor,\n openpbr_transmission_tint(material),\n viewLocal,\n lightLocal,\n halfVector,\n fresnel,\n &lobePdf\n );\n }\n if (prepared.dielectricMsProbability > 0.0) {\n lobePdf *= 1.0 - prepared.dielectricMsProbability;\n }\n *pdf += prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] * lobePdf;\n }\n if (prepared.weights[OPENPBR_LOBE_SUBSURFACE] > 0.0 && allowSubsurface) {\n if (material.thinWalled) {\n let flippedLight = vec3f(lightLocal.xy, -lightLocal.z);\n response += 0.5 * prepared.weights[OPENPBR_LOBE_SUBSURFACE]\n * openpbr_eval_diffuse(\n material,\n material.subsurfaceColor,\n viewLocal,\n flippedLight,\n diffuseSpecularEnergyCompensation,\n &lobePdf\n );\n lobePdf *= 0.5;\n }\n else {\n response += prepared.weights[OPENPBR_LOBE_SUBSURFACE] * openpbr_eval_subsurface_boundary(\n material,\n viewLocal,\n lightLocal,\n &lobePdf\n );\n }\n *pdf += prepared.probabilities[OPENPBR_LOBE_SUBSURFACE] * lobePdf;\n }\n }\n\n // Reference value includes the hemisphere ratio before the grazing clamp.\n // Reference scale_trans has no extra eta^2 factor; single refraction keeps\n // its existing radiance Jacobian. Both proposals share the aggregate PDF.\n if (prepared.dielectricMsProbability > 0.0 && allowTransmission) {\n let cosine = abs(lightLocal.z);\n if (cosine > 0.0) {\n let ior = select(1.0 / prepared.refractionEtaTOverEtaI, prepared.refractionEtaTOverEtaI, reflection);\n let ratio = select(1.0 - prepared.dielectricMsReflectionRatio, prepared.dielectricMsReflectionRatio, reflection);\n let factors = prepared.dielectricMsViewLoss * openpbr_ideal_dielectric_loss(ior, prepared.specularAlpha, cosine)\n / max(openpbr_ideal_dielectric_average_loss(ior, prepared.specularAlpha), 1e-12);\n let factor = min(factors * ratio, 1.0 / cosine);\n let scale = select(prepared.dielectricMsTransmissionScale, prepared.dielectricMsReflectionScale, reflection);\n response += scale * factor * INVPI;\n *pdf += prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] * prepared.dielectricMsProbability * ratio * 0.5 * INVPI;\n }\n }\n\n${hasCoatNormals ? /* wgsl */ ` } // base hemisphere support` : ''}\n if (material.coatWeight > 0.0) {\n response *= openpbr_coat_base_scale(prepared, ${hasCoatNormals ? 'select(lightLocal.z, coatLightCosine, independentCoat)' : 'lightLocal.z'});\n }\n${hasCoatNormals ? /* wgsl */ `\n // Values are BSDF*cos in world solid angle before the frames are combined.\n if (independentCoat) { response *= abs(lightLocal.z); }\n` : ''}\n\n${hasAnisotropyDirections ? /* wgsl */ `\n if (${hasCoatNormals ? 'select(reflection, coatReflection, independentCoat)' : 'reflection'} && prepared.weights[OPENPBR_LOBE_COAT] > 0.0) {\n var coatView = viewLocal;\n var coatLight = lightLocal;\n var coatHalf = halfVector;\n var coatViewHalf = viewHalf;\n if (prepared.directionFrames) {\n coatView = ${hasCoatNormals ? 'select(openpbr_to_local(prepared.coatBasis, openpbr_to_world(prepared.basis, viewLocal)), prepared.coatViewLocal, independentCoat)' : 'openpbr_to_local(prepared.coatBasis, openpbr_to_world(prepared.basis, viewLocal))'};\n coatLight = openpbr_to_local(prepared.coatBasis, lightDirection);\n coatHalf = normalize(coatLight + coatView);\n if (coatHalf.z < 0.0) { coatHalf = -coatHalf; }\n coatViewHalf = abs(dot(coatView, coatHalf));\n }\n\n let coatFresnel = vec3f(openpbr_dielectric_fresnel(\n coatViewHalf,\n 1.0 / material.coatIor\n ));\n var coatMaterial = material;\n let coatAlpha = openpbr_roughness_to_alpha(material.coatRoughness, material.coatAnisotropy);\n coatMaterial.alphaX = coatAlpha.x;\n coatMaterial.alphaY = coatAlpha.y;\n if (allowCoat) {\n response += prepared.weights[OPENPBR_LOBE_COAT]${hasCoatNormals ? ' * select(1.0, max(coatLightCosine, 0.0), independentCoat)' : ''} * openpbr_eval_microfacet_reflection(\n coatMaterial,\n coatView,\n coatLight,\n coatHalf,\n coatFresnel,\n &lobePdf\n );\n *pdf += prepared.probabilities[OPENPBR_LOBE_COAT] * lobePdf;\n }\n }\n` : /* wgsl */ `\n if (${hasCoatNormals ? 'select(reflection, coatReflection, independentCoat)' : 'reflection'} && prepared.weights[OPENPBR_LOBE_COAT] > 0.0) {\n let coatFresnel = vec3f(openpbr_dielectric_fresnel(\n viewHalf,\n 1.0 / material.coatIor\n ));\n var coatMaterial = material;\n let coatAlpha = openpbr_roughness_to_alpha(material.coatRoughness, material.coatAnisotropy);\n coatMaterial.alphaX = coatAlpha.x;\n coatMaterial.alphaY = coatAlpha.y;\n if (allowCoat) {\n response += prepared.weights[OPENPBR_LOBE_COAT]${hasCoatNormals ? ' * select(1.0, max(coatLightCosine, 0.0), independentCoat)' : ''} * openpbr_eval_microfacet_reflection(\n coatMaterial,\n viewLocal,\n lightLocal,\n halfVector,\n coatFresnel,\n &lobePdf\n );\n *pdf += prepared.probabilities[OPENPBR_LOBE_COAT] * lobePdf;\n }\n }\n`}\n\n if (${hasCoatNormals ? 'select(reflection, geometricReflection, independentCoat)' : 'reflection'} && prepared.weights[OPENPBR_LOBE_FUZZ] > 0.0) {\n let fuzzAlbedo = openpbr_fuzz_directional_albedo(\n abs(viewLocal.z),\n material.fuzzRoughness\n );\n response *= max(\n vec3f(0.0),\n vec3f(1.0 - prepared.weights[OPENPBR_LOBE_FUZZ] * fuzzAlbedo)\n );\n if (allowFuzz) {\n response += prepared.weights[OPENPBR_LOBE_FUZZ]${hasCoatNormals ? ' * select(1.0, max(lightLocal.z, 0.0), independentCoat)' : ''} * openpbr_eval_fuzz(\n material,\n viewLocal,\n lightLocal,\n &lobePdf\n );\n *pdf += prepared.probabilities[OPENPBR_LOBE_FUZZ] * lobePdf;\n }\n }\n\n return response * ${hasCoatNormals ? 'select(abs(lightLocal.z), 1.0, independentCoat)' : 'abs(lightLocal.z)'};\n}\n\nfn openpbr_eval_prepared(\n prepared: OpenPbrPreparedBsdf,\n lightDirection: vec3f,\n pdf: ptr<function, f32>\n) -> vec3f {\n return openpbr_eval_prepared_lobe(prepared, lightDirection, -1, pdf);\n}\n\n\n\n\n\nfn openpbr_eval(\n tangent: vec3f,\n material: OpenPbrResolvedMaterial,\n viewDirection: vec3f,\n normal: vec3f,\n lightDirection: vec3f,\n pdf: ptr<function, f32>\n) -> vec3f {\n let prepared = openpbr_prepare(\n tangent,\n material,\n viewDirection,\n normal\n );\n return openpbr_eval_prepared(prepared, lightDirection, pdf);\n}\n\n\n\n\n// Direction-only proposals do not require the layered response or film optics.\nfn openpbr_sample_direction(\n prepared: OpenPbrPreparedBsdf, randomSamples: vec3f,\n lightDirection: ptr<function, vec3f>, isTransmissionEvent: ptr<function, bool>,\n sampledLobeRoughness: ptr<function, f32>, sampledLobeSpecular: ptr<function, bool>,\n sampledLobeDiffuse: ptr<function, bool>, sampledLobeIndex: ptr<function, u32>\n) -> bool {\n let material = prepared.material;\n let viewLocal = prepared.viewLocal;\n var randomX = randomSamples.x;\n let randomY = randomSamples.y;\n let lobeSample = randomSamples.z;\n *isTransmissionEvent = false;\n *sampledLobeRoughness = 1.0;\n *sampledLobeSpecular = false;\n *sampledLobeDiffuse = false;\n *sampledLobeIndex = u32(OPENPBR_LOBE_DIFFUSE);\n *lightDirection = prepared.basis.normal;\n\n var cdf: array<f32, OPENPBR_LOBE_COUNT>;\n cdf[OPENPBR_LOBE_FUZZ] = prepared.probabilities[OPENPBR_LOBE_FUZZ];\n let lobeCount = min(OPENPBR_LOBE_COUNT, i32(rtUniform.loopUnrollGuard * 2u));\n for (var lobe = 1; lobe < lobeCount; lobe++) {\n cdf[lobe] = cdf[lobe - 1] + prepared.probabilities[lobe];\n }\n if (cdf[OPENPBR_LOBE_SUBSURFACE] <= 0.0) {\n return false;\n }\n\n var lightLocal: vec3f;\n if (lobeSample < cdf[OPENPBR_LOBE_FUZZ] || (\n lobeSample >= cdf[OPENPBR_LOBE_TRANSMISSION] && lobeSample < cdf[OPENPBR_LOBE_DIFFUSE]\n )) {\n let sampledFuzz = lobeSample < cdf[OPENPBR_LOBE_FUZZ];\n *sampledLobeRoughness = select(\n 1.0,\n material.fuzzRoughness,\n sampledFuzz\n );\n *sampledLobeDiffuse = !sampledFuzz;\n *sampledLobeIndex = select(\n u32(OPENPBR_LOBE_DIFFUSE),\n u32(OPENPBR_LOBE_FUZZ),\n sampledFuzz\n );\n lightLocal = sampling_cosine_hemisphere(vec2f(randomX, randomY));\n }\n${hasAnisotropyDirections ? /* wgsl */ `\n else if (lobeSample < cdf[OPENPBR_LOBE_COAT]) {\n *sampledLobeRoughness = material.coatRoughness;\n *sampledLobeSpecular = true;\n *sampledLobeIndex = u32(OPENPBR_LOBE_COAT);\n var coatView = viewLocal;\n if (prepared.directionFrames) { coatView = ${hasCoatNormals ? 'select(openpbr_to_local(prepared.coatBasis, openpbr_to_world(prepared.basis, viewLocal)), prepared.coatViewLocal, material.coatNormalEnabled)' : 'openpbr_to_local(prepared.coatBasis, openpbr_to_world(prepared.basis, viewLocal))'}; }\n var halfVector = sampling_ggx_visible_normal(\n coatView,\n // The VNDF must use the same alpha as the evaluated coat PDF.\n openpbr_roughness_to_alpha(material.coatRoughness, material.coatAnisotropy),\n vec2f(randomX, randomY)\n );\n if (halfVector.z < 0.0) {\n halfVector = -halfVector;\n }\n lightLocal = normalize(reflect(-coatView, halfVector));\n${hasCoatNormals ? /* wgsl */ `\n if (material.coatNormalEnabled) {\n // Validate against the sampled coat frame, never the base normal.\n *lightDirection = openpbr_to_world(prepared.coatBasis, lightLocal);\n return lightLocal.z > 0.0 && dot(material.geometricNormal, *lightDirection) > 0.0;\n }\n` : ''}\n if (prepared.directionFrames) { lightLocal = openpbr_to_local(prepared.basis, openpbr_to_world(prepared.coatBasis, lightLocal)); }\n }\n` : /* wgsl */ `\n else if (lobeSample < cdf[OPENPBR_LOBE_COAT]) {\n *sampledLobeRoughness = material.coatRoughness;\n *sampledLobeSpecular = true;\n *sampledLobeIndex = u32(OPENPBR_LOBE_COAT);\n var halfVector = sampling_ggx_visible_normal(\n viewLocal,\n // The VNDF must use the same alpha as the evaluated coat PDF.\n openpbr_roughness_to_alpha(material.coatRoughness, material.coatAnisotropy),\n vec2f(randomX, randomY)\n );\n if (halfVector.z < 0.0) {\n halfVector = -halfVector;\n }\n lightLocal = normalize(reflect(-viewLocal, halfVector));\n }\n`}\n else if (lobeSample < cdf[OPENPBR_LOBE_SPECULAR]) {\n *sampledLobeRoughness = material.specularRoughness;\n *sampledLobeSpecular = true;\n *sampledLobeIndex = select(\n u32(OPENPBR_LOBE_SPECULAR),\n u32(OPENPBR_LOBE_METAL),\n lobeSample < cdf[OPENPBR_LOBE_METAL]\n );\n let isMetal = lobeSample < cdf[OPENPBR_LOBE_METAL];\n let metalDraw = (lobeSample - cdf[OPENPBR_LOBE_COAT]) / max(prepared.probabilities[OPENPBR_LOBE_METAL], 1e-12);\n if (isMetal && metalDraw < prepared.metalMsProbability) {\n let z = randomX;\n let radial = sqrt(max(0.0, 1.0 - z * z));\n let azimuth = TWOPI * randomY;\n lightLocal = vec3f(radial * cos(azimuth), radial * sin(azimuth), z);\n }\n else {\n var halfVector = sampling_ggx_visible_normal(\n viewLocal,\n vec2f(material.alphaX, material.alphaY),\n vec2f(randomX, randomY)\n );\n if (halfVector.z < 0.0) {\n halfVector = -halfVector;\n }\n lightLocal = normalize(reflect(-viewLocal, halfVector));\n }\n }\n else if (lobeSample < cdf[OPENPBR_LOBE_TRANSMISSION]) {\n *sampledLobeRoughness = material.specularRoughness;\n *sampledLobeSpecular = true;\n *isTransmissionEvent = true;\n *sampledLobeIndex = u32(OPENPBR_LOBE_TRANSMISSION);\n // Split the existing BSDF_LOBE interval. BSDF_DIRECTION retains its\n // two dimensions; rand.x selects and remaps the reference hemisphere.\n let msDraw = (lobeSample - cdf[OPENPBR_LOBE_SPECULAR]) / max(prepared.probabilities[OPENPBR_LOBE_TRANSMISSION], 1e-12);\n if (prepared.dielectricMsProbability > 0.0 && msDraw < prepared.dielectricMsProbability) {\n let ratio = prepared.dielectricMsReflectionRatio;\n let reflectMs = randomX < ratio;\n var z: f32;\n if (reflectMs) { z = min(randomX / ratio, 0.99999994); }\n else { z = -min((randomX - ratio) / (1.0 - ratio), 0.99999994); }\n let radial = sqrt(max(0.0, 1.0 - z * z));\n let azimuth = TWOPI * randomY;\n lightLocal = vec3f(radial * cos(azimuth), radial * sin(azimuth), z);\n *isTransmissionEvent = !reflectMs;\n *sampledLobeIndex = select(u32(OPENPBR_LOBE_TRANSMISSION), u32(OPENPBR_LOBE_SPECULAR), reflectMs);\n }\n else {\n var halfVector = sampling_ggx_visible_normal(\n viewLocal,\n vec2f(material.alphaX, material.alphaY),\n vec2f(randomX, randomY)\n );\n if (halfVector.z < 0.0) {\n halfVector = -halfVector;\n }\n if (material.thinWalled) {\n let reflectedLocal = normalize(reflect(-viewLocal, halfVector));\n lightLocal = vec3f(reflectedLocal.xy, -reflectedLocal.z);\n }\n else {\n lightLocal = refract(\n -viewLocal,\n halfVector,\n prepared.material.relativeIor\n );\n if (dot(lightLocal, lightLocal) <= 1e-8) {\n *isTransmissionEvent = false;\n return false;\n }\n lightLocal = normalize(lightLocal);\n }\n }\n }\n else {\n *sampledLobeRoughness = 1.0;\n *sampledLobeDiffuse = true;\n *isTransmissionEvent = true;\n *sampledLobeIndex = u32(OPENPBR_LOBE_SUBSURFACE);\n if (material.thinWalled) {\n let transmit = randomX >= 0.5;\n if (transmit) {\n randomX = (randomX - 0.5) * 2.0;\n }\n else {\n randomX *= 2.0;\n }\n lightLocal = sampling_cosine_hemisphere(vec2f(randomX, randomY));\n if (transmit) {\n lightLocal.z = -lightLocal.z;\n }\n else {\n *isTransmissionEvent = false;\n }\n }\n else {\n lightLocal = sampling_cosine_hemisphere(vec2f(randomX, randomY));\n lightLocal.z = -lightLocal.z;\n }\n }\n\n *lightDirection = openpbr_to_world(prepared.basis, lightLocal);\n // VNDF reflection may land below the macrosurface. A mirrored thin-wall\n // transmission draw can likewise land above it. Reject that draw before\n // aggregate evaluation can accidentally turn it into the opposite lobe.\n if (lightLocal.z == 0.0 || (lightLocal.z < 0.0) != *isTransmissionEvent) {\n return false;\n }\n${hasCoatNormals ? /* wgsl */ `\n if (material.coatNormalEnabled &&\n ((dot(material.geometricNormal, *lightDirection) <= 0.0) != *isTransmissionEvent)) { return false; }\n` : ''}\n return true;\n}\n\nfn openpbr_sample_prepared(\n prepared: OpenPbrPreparedBsdf,\n randomSamples: vec3f,\n lightDirection: ptr<function, vec3f>,\n pdf: ptr<function, f32>,\n isTransmissionEvent: ptr<function, bool>,\n sampledLobeRoughness: ptr<function, f32>,\n sampledLobeSpecular: ptr<function, bool>,\n sampledLobeDiffuse: ptr<function, bool>,\n sampledLobeIndex: ptr<function, u32>,\n marginalPdf: ptr<function, f32>,\n fullResponse: ptr<function, vec3f>\n) -> vec3f {\n *pdf = 0.0;\n *marginalPdf = 0.0;\n *fullResponse = vec3f(0.0);\n // Solid microfacet refraction is singular at exactly eta=1: the usual\n // half vector normalizes light + eta * view, which is zero for straight\n // transmission. Resolve the physically null boundary as a discrete,\n // unit-throughput continuation instead of losing the path to NaNs.\n if (!prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6) {\n *lightDirection = openpbr_to_world(\n prepared.basis,\n -prepared.viewLocal\n );\n let nullBoundaryTint = openpbr_transmission_tint(prepared.material)\n * openpbr_coat_base_scale(prepared, ${hasCoatNormals ? 'select(-prepared.viewLocal.z, dot(prepared.coatBasis.normal, *lightDirection), prepared.material.coatNormalEnabled)' : '-prepared.viewLocal.z'});\n *pdf = 1.0;\n *marginalPdf = 1.0;\n *fullResponse = nullBoundaryTint;\n *isTransmissionEvent = true;\n *sampledLobeRoughness = 0.0;\n *sampledLobeSpecular = true;\n *sampledLobeDiffuse = false;\n *sampledLobeIndex = u32(OPENPBR_LOBE_TRANSMISSION);\n return nullBoundaryTint;\n }\n if (!openpbr_sample_direction(prepared, randomSamples, lightDirection,\n isTransmissionEvent, sampledLobeRoughness, sampledLobeSpecular,\n sampledLobeDiffuse, sampledLobeIndex)) { return vec3f(0.0); }\n let response = openpbr_eval_prepared(prepared, *lightDirection, pdf);\n *marginalPdf = *pdf;\n *fullResponse = response;\n return response;\n}\n\nfn openpbr_sample(\n tangent: vec3f,\n material: OpenPbrResolvedMaterial,\n randomSamples: vec3f,\n viewDirection: vec3f,\n normal: vec3f,\n lightDirection: ptr<function, vec3f>,\n pdf: ptr<function, f32>,\n isTransmissionEvent: ptr<function, bool>,\n sampledLobeRoughness: ptr<function, f32>,\n sampledLobeSpecular: ptr<function, bool>,\n sampledLobeDiffuse: ptr<function, bool>,\n sampledLobeIndex: ptr<function, u32>,\n marginalPdf: ptr<function, f32>\n) -> vec3f {\n let prepared = openpbr_prepare(\n tangent,\n material,\n viewDirection,\n normal\n );\n var fullResponse = vec3f(0.0);\n return openpbr_sample_prepared(\n prepared,\n randomSamples,\n lightDirection,\n pdf,\n isTransmissionEvent,\n sampledLobeRoughness,\n sampledLobeSpecular,\n sampledLobeDiffuse,\n sampledLobeIndex,\n marginalPdf,\n &fullResponse\n );\n}`;\n\n}\n\nexport default createOpenPbrBsdfWgsl();\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const displacementCommon = "\n\n\nstruct MicroTriangleIntersect {\n barycentric: vec3f,\n t: f32,\n normal: vec3f,\n\n}\n\nfn findVT(\n uu: f32,\n pARel: vec3f, pBRel: vec3f,\n eAC: vec3f, eBD: vec3f,\n rayDir: vec3f,\n distMin: f32,\n hitDist: ptr<function, f32>\n) -> bool {\n if (uu >= 0.0 && uu <= 1.0) {\n let pAB = mix(pARel, pBRel, uu);\n let pCD = mix(eAC, eBD, uu);\n var n = cross(rayDir, pCD);\n let recDet = 1.0 / dot(n, n);\n n = cross(n, pAB);\n let tt = dot(n, pCD) * recDet;\n let vv = dot(n, rayDir) * recDet;\n if (vv >= 0.0 && vv <= 1.0 && tt > distMin && tt < *hitDist) {\n *hitDist = tt;\n return true;\n }\n }\n return false;\n}\n\nfn testRayVsBilinearPatch(\n rayOrg: vec3f, rayDir: vec3f, distMin: f32, distMax: f32,\n pA: vec3f, pB: vec3f, pC: vec3f, pD: vec3f,\n hitDist: ptr<function, f32>\n) -> bool {\n let eAB = pB - pA;\n let eAC = pC - pA;\n let eBD = pD - pB;\n let eCD = pD - pC;\n let pARel = pA - rayOrg;\n let pBRel = pB - rayOrg;\n\n var u1: f32;\n var u2: f32;\n {\n let qN = cross(eAB, -eCD);\n let a = dot(qN, rayDir);\n var b = dot(cross(pBRel, rayDir), eBD);\n let c = dot(cross(pARel, rayDir), eAC);\n b -= a + c;\n\n let det = b * b - 4.0 * a * c;\n if (det < 0.0) {\n return false;\n }\n\n if (a == 0.0) {\n u1 = -c / b;\n u2 = -1.0;\n } else {\n let sqrtDet = sqrt(det);\n let temp = -0.5 * (b + sign(b) * sqrtDet);\n u1 = temp / a;\n u2 = c / temp;\n }\n }\n\n *hitDist = distMax;\n\n var hit = false;\n\n hit = findVT(u1, pARel, pBRel, eAC, eBD, rayDir, distMin, hitDist) || \n findVT(u2, pARel, pBRel, eAC, eBD, rayDir, distMin, hitDist);\n if (!hit) {\n return false;\n }\n\n return true;\n}\n\nfn intersectPrism(\n rayOrg: vec3f, rayDir: vec3f, distMin: f32, distMax: f32,\n pA: vec3f, pB: vec3f, pC: vec3f,\n pD: vec3f, pE: vec3f, pF: vec3f,\n\n hitDistMin: ptr<function, f32>,\n hitDistMax: ptr<function, f32>\n) -> bool {\n *hitDistMin = INF;\n *hitDistMax = -INF;\n\n let maxD = maxDimension(abs(rayDir));\n let shear = getShear(rayDir, maxD);\n var tt: f32;\n\n tt = intersectTriangle(\n rayOrg, rayDir,\n Triangle(pC, pB, pA), maxD, shear, INF\n ).t;\n if (tt > 0.0) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n tt = intersectTriangle(\n rayOrg, rayDir,\n Triangle(pD, pE, pF), maxD, shear, INF\n ).t;\n if (tt > 0.0) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pA, pB, pD, pE,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pB, pC, pE, pF,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pC, pA, pF, pD,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n\n *hitDistMin = max(*hitDistMin, distMin);\n *hitDistMax = min(*hitDistMax, distMax);\n\n return *hitDistMin <= *hitDistMax && *hitDistMax > 0.0;\n}\n";
|
|
2
|
+
declare const _default: "\n\n\n\n\nstruct MicroTriangleIntersect {\n barycentric: vec3f,\n t: f32,\n normal: vec3f,\n\n}\n\nfn findVT(\n uu: f32,\n pARel: vec3f, pBRel: vec3f,\n eAC: vec3f, eBD: vec3f,\n rayDir: vec3f,\n distMin: f32,\n hitDist: ptr<function, f32>\n) -> bool {\n if (uu >= 0.0 && uu <= 1.0) {\n let pAB = mix(pARel, pBRel, uu);\n let pCD = mix(eAC, eBD, uu);\n var n = cross(rayDir, pCD);\n let recDet = 1.0 / dot(n, n);\n n = cross(n, pAB);\n let tt = dot(n, pCD) * recDet;\n let vv = dot(n, rayDir) * recDet;\n if (vv >= 0.0 && vv <= 1.0 && tt > distMin && tt < *hitDist) {\n *hitDist = tt;\n return true;\n }\n }\n return false;\n}\n\nfn testRayVsBilinearPatch(\n rayOrg: vec3f, rayDir: vec3f, distMin: f32, distMax: f32,\n pA: vec3f, pB: vec3f, pC: vec3f, pD: vec3f,\n hitDist: ptr<function, f32>\n) -> bool {\n let eAB = pB - pA;\n let eAC = pC - pA;\n let eBD = pD - pB;\n let eCD = pD - pC;\n let pARel = pA - rayOrg;\n let pBRel = pB - rayOrg;\n\n var u1: f32;\n var u2: f32;\n {\n let qN = cross(eAB, -eCD);\n let a = dot(qN, rayDir);\n var b = dot(cross(pBRel, rayDir), eBD);\n let c = dot(cross(pARel, rayDir), eAC);\n b -= a + c;\n\n let det = b * b - 4.0 * a * c;\n if (det < 0.0) {\n return false;\n }\n\n if (a == 0.0) {\n u1 = -c / b;\n u2 = -1.0;\n } else {\n let sqrtDet = sqrt(det);\n let temp = -0.5 * (b + sign(b) * sqrtDet);\n u1 = temp / a;\n u2 = c / temp;\n }\n }\n\n *hitDist = distMax;\n\n var hit = false;\n\n hit = findVT(u1, pARel, pBRel, eAC, eBD, rayDir, distMin, hitDist) || \n findVT(u2, pARel, pBRel, eAC, eBD, rayDir, distMin, hitDist);\n if (!hit) {\n return false;\n }\n\n return true;\n}\n\nfn intersectPrism(\n rayOrg: vec3f, rayDir: vec3f, distMin: f32, distMax: f32,\n pA: vec3f, pB: vec3f, pC: vec3f,\n pD: vec3f, pE: vec3f, pF: vec3f,\n\n hitDistMin: ptr<function, f32>,\n hitDistMax: ptr<function, f32>\n) -> bool {\n *hitDistMin = INF;\n *hitDistMax = -INF;\n\n let maxD = maxDimension(abs(rayDir));\n let shear = getShear(rayDir, maxD);\n var tt: f32;\n\n tt = intersectTriangle(\n rayOrg, rayDir,\n Triangle(pC, pB, pA), maxD, shear, INF\n ).t;\n if (tt > 0.0) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n tt = intersectTriangle(\n rayOrg, rayDir,\n Triangle(pD, pE, pF), maxD, shear, INF\n ).t;\n if (tt > 0.0) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pA, pB, pD, pE,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pB, pC, pE, pF,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pC, pA, pF, pD,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n\n *hitDistMin = max(*hitDistMin, distMin);\n *hitDistMax = min(*hitDistMax, distMax);\n\n return *hitDistMin <= *hitDistMax && *hitDistMax > 0.0;\n}\n\n\nfn triangleBarycentric(p: vec3f, p0: vec3f, p1: vec3f, p2: vec3f) -> vec3f {\n let v0 = p1 - p0;\n let v1 = p2 - p0;\n let v2 = p - p0;\n\n let d00 = dot(v0, v0);\n let d01 = dot(v0, v1);\n let d11 = dot(v1, v1);\n let d20 = dot(v2, v0);\n let d21 = dot(v2, v1);\n\n let invDenom = 1.0 / (d00 * d11 - d01 * d01);\n let v = clamp((d11 * d20 - d01 * d21) * invDenom, 0.0, 1.0);\n let w = clamp((d00 * d21 - d01 * d20) * invDenom, 0.0, 1.0);\n let u = 1.0 - v - w;\n\n return vec3f(u, v, w);\n}\n\nfn wrapUv(uv: vec2f) -> vec2f {\n return (uv % 1.0 + 1.0) % 1.0;\n}\n\n\nfn intersectDisplacement(\n _rayOrigin: vec3f, _rayDir: vec3f, _tMax: f32,\n _pA: vec3f, _pB: vec3f, _pC: vec3f,\n _nA: vec3f, _nB: vec3f, _nC: vec3f,\n _tcA: vec2f, _tcB: vec2f, _tcC: vec2f,\n\n heightMapIndex: i32,\n heightMapSize: vec2f,\n\n _minH: f32, _maxH: f32,\n hScale: f32,\n stepSize: f32,\n uvProjection: i32,\n uvScale: vec2f,\n isShadowHit: bool,\n isRefraction: bool\n) -> MicroTriangleIntersect {\n\n let DT = stepSize;\n let dt = DT / length(_rayDir);\n let dbx = 0.001;\n let dby = 0.001;\n\n var result: MicroTriangleIntersect;\n result.t = INF;\n\n var hitDistMin = INF;\n var hitDistMax = -INF;\n\n let hSign = sign(hScale);\n let hScaleAbs = abs(hScale);\n // Face normal.\n let faceN = hSign * normalize(cross(_pB - _pA, _pC - _pA));\n\n // dA, dB, dC are negative if hScale is negative\n let dA = dot(_nA, faceN);\n let dB = dot(_nB, faceN);\n let dC = dot(_nC, faceN);\n\n var minH = _minH * hScale * min(min(dA, dB), dC);\n var maxH = _maxH * hScale * max(max(dA, dB), dC);\n\n // Add gap\n // 1. Avoid too small height cause ray marching miss.\n // 2. Make sure the ray start beyond the displaced surface when surface height is same with prism height.\n let prismHeight = abs(maxH) - abs(minH);\n minH = sign(minH) * max(abs(minH) - dt * 2.0, 0.0);\n if (prismHeight < dt * 2.0) {\n maxH = sign(maxH) * min(abs(maxH) + dt * 2.0, abs(hScale));\n }\n\n let pA = _pA + _nA * minH / dA;\n let pB = _pB + _nB * minH / dB;\n let pC = _pC + _nC * minH / dC;\n\n let pD = _pA + _nA * maxH / dA;\n let pE = _pB + _nB * maxH / dB;\n let pF = _pC + _nC * maxH / dC;\n\n if (!intersectPrism(\n _rayOrigin, _rayDir, 0.0, INF,\n pA, pB, pC,\n pD, pE, pF,\n \n &hitDistMin, &hitDistMax\n )) {\n return result;\n }\n\n var testFlag = false;\n // Ray is inside the prism\n if (hitDistMax == hitDistMin) {\n hitDistMin = 0.0;\n }\n\n var t = hitDistMin + dt * hashedSample(2u);\n var s = _rayOrigin + _rayDir * t;\n var hRay = dot(s - _pA, faceN);\n var hSurf = select(0.0, INF, hSign < 0.0);\n // initial scanning triangle\n var c0 = _pA + _nA * hRay / dA;\n var c1 = _pB + _nB * hRay / dB;\n var c2 = _pC + _nC * hRay / dC;\n\n var projPos: vec3f;\n\n hRay = abs(hRay);\n\n var hDiff = hRay - hSurf;\n var hDiffPrev = hDiff;\n var step = 0;\n\n while (true) {\n // TODO Avoid too long loop\n let b = triangleBarycentric(s, c0, c1, c2);\n // Projected point on base triangle\n projPos = _pA * b.x + _pB * b.y + _pC * b.z;\n // Height at projected point\n hRay = distance(projPos, s);\n // Update scanning point\n var uv: vec2f;\n if (uvProjection > 0) {\n let n = normalize(_nA * b.x + _nB * b.y + _nC * b.z);\n uv = wrapUv(projectUV(uvProjection, projPos, n) * uvScale);\n }\n else {\n uv = wrapUv(_tcA * b.x + _tcB * b.y + _tcC * b.z);\n }\n let h = sampleMap(heightMapIndex, uv).x;\n // height < dt will be ignored in ray marching\n hSurf = max(hScaleAbs * h, dt);\n\n // Advance scanning triangle\n let dh = dot(faceN, s - c0);\n c0 = c0 + _nA * dh / dA;\n c1 = c1 + _nB * dh / dB;\n c2 = c2 + _nC * dh / dC;\n\n hDiffPrev = hDiff;\n hDiff = hRay - hSurf;\n\n if (!(select(hDiff * hSign, hDiff * hDiffPrev, isRefraction) > 0.0\n && t < hitDistMax + dt) \n // Ignore first step\n && step > 0) {\n break;\n }\n\n step++;\n t = t + dt;\n s = s + _rayDir * dt;\n }\n\n if (select(hDiff * hSign, hDiff * hDiffPrev, isRefraction) <= 0.0) {\n let dtt = dt * (abs(hDiff) / (abs(hDiffPrev) + abs(hDiff) + EPS));\n t = t - dtt;\n // t = interpolateCrossing(_rayOrigin, _rayDir, projPos, t, dt, hSurf);\n let pHit = _rayOrigin + _rayDir * t;\n let b = triangleBarycentric(pHit, c0, c1, c2);\n\n let N = normalize(_nA * b.x + _nB * b.y + _nC * b.z);\n\n let p_a = _pA * b.x + _pB * b.y + _pC * b.z;\n let p_b = _pA * (b.x + dbx) + _pB * b.y + _pC * (b.z - dbx);\n let p_c = _pA * b.x + _pB * (b.y + dby) + _pC * (b.z - dby);\n\n var uv_a: vec2f;\n var uv_b: vec2f;\n var uv_c: vec2f;\n\n if (uvProjection > 0) {\n let NA = normalize(_nA * b.x + _nB * b.y + _nC * b.z);\n let NB = normalize(_nA * (b.x + dbx) + _nB * b.y + _nC * (b.z - dbx));\n let NC = normalize(_nA * b.x + _nB * (b.y + dby) + _nC * (b.z - dby)); \n uv_a = projectUV(uvProjection, p_a, NA) * uvScale;\n uv_b = projectUV(uvProjection, p_b, NB) * uvScale;\n uv_c = projectUV(uvProjection, p_c, NC) * uvScale;\n }\n else {\n uv_a = _tcA * b.x + _tcB * b.y + _tcC * b.z;\n uv_b = _tcA * (b.x + dbx) + _tcB * b.y + _tcC * (b.z - dbx);\n uv_c = _tcA * b.x + _tcB * (b.y + dby) + _tcC * (b.z - dby);\n }\n\n let s_a = p_a + hSign * N * sampleMap(heightMapIndex, wrapUv(uv_a)).x * hScale;\n let s_b = p_b + hSign * N * sampleMap(heightMapIndex, wrapUv(uv_b)).x * hScale;\n let s_c = p_c + hSign * N * sampleMap(heightMapIndex, wrapUv(uv_c)).x * hScale;\n\n let N_s = -hSign * normalize(cross(s_c - s_a, s_b - s_a));\n\n result.t = t;\n result.barycentric = b;\n result.normal = normalize(N_s - faceN + hSign * N);\n }\n\n return result;\n\n}\n";
|
|
3
|
+
export default _default;
|
|
4
|
+
export { displacementCommon };
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
const displacementCommon = /*wgsl*/ `
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
struct jv {
|
|
5
|
+
barycentric: vec3f,
|
|
6
|
+
t: f32,
|
|
7
|
+
normal: vec3f,
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fn uJ(
|
|
12
|
+
uu: f32,
|
|
13
|
+
tL: vec3f, tM: vec3f,
|
|
14
|
+
eAC: vec3f, eBD: vec3f,
|
|
15
|
+
iI: vec3f,
|
|
16
|
+
pL: f32,
|
|
17
|
+
pN: ptr<function, f32>
|
|
18
|
+
) -> bool {
|
|
19
|
+
if (uu >= 0.0 && uu <= 1.0) {
|
|
20
|
+
let pAB = mix(tL, tM, uu);
|
|
21
|
+
let pCD = mix(eAC, eBD, uu);
|
|
22
|
+
var n = cross(iI, pCD);
|
|
23
|
+
let vj = 1.0 / dot(n, n);
|
|
24
|
+
n = cross(n, pAB);
|
|
25
|
+
let tt = dot(n, pCD) * vj;
|
|
26
|
+
let vv = dot(n, iI) * vj;
|
|
27
|
+
if (vv >= 0.0 && vv <= 1.0 && tt > pL && tt < *pN) {
|
|
28
|
+
*pN = tt;
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn hd(
|
|
36
|
+
pt: vec3f, iI: vec3f, pL: f32, ta: f32,
|
|
37
|
+
pA: vec3f, pB: vec3f, pC: vec3f, pD: vec3f,
|
|
38
|
+
pN: ptr<function, f32>
|
|
39
|
+
) -> bool {
|
|
40
|
+
let eAB = pB - pA;
|
|
41
|
+
let eAC = pC - pA;
|
|
42
|
+
let eBD = pD - pB;
|
|
43
|
+
let eCD = pD - pC;
|
|
44
|
+
let tL = pA - pt;
|
|
45
|
+
let tM = pB - pt;
|
|
46
|
+
|
|
47
|
+
var u1: f32;
|
|
48
|
+
var u2: f32;
|
|
49
|
+
{
|
|
50
|
+
let qN = cross(eAB, -eCD);
|
|
51
|
+
let a = dot(qN, iI);
|
|
52
|
+
var b = dot(cross(tM, iI), eBD);
|
|
53
|
+
let c = dot(cross(tL, iI), eAC);
|
|
54
|
+
b -= a + c;
|
|
55
|
+
|
|
56
|
+
let det = b * b - 4.0 * a * c;
|
|
57
|
+
if (det < 0.0) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (a == 0.0) {
|
|
62
|
+
u1 = -c / b;
|
|
63
|
+
u2 = -1.0;
|
|
64
|
+
} else {
|
|
65
|
+
let vD = sqrt(det);
|
|
66
|
+
let wu = -0.5 * (b + sign(b) * vD);
|
|
67
|
+
u1 = wu / a;
|
|
68
|
+
u2 = c / wu;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
*pN = ta;
|
|
73
|
+
|
|
74
|
+
var hit = false;
|
|
75
|
+
|
|
76
|
+
hit = uJ(u1, tL, tM, eAC, eBD, iI, pL, pN) ||
|
|
77
|
+
uJ(u2, tL, tM, eAC, eBD, iI, pL, pN);
|
|
78
|
+
if (!hit) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fn sf(
|
|
86
|
+
pt: vec3f, iI: vec3f, pL: f32, ta: f32,
|
|
87
|
+
pA: vec3f, pB: vec3f, pC: vec3f,
|
|
88
|
+
pD: vec3f, pE: vec3f, pF: vec3f,
|
|
89
|
+
|
|
90
|
+
bT: ptr<function, f32>,
|
|
91
|
+
bS: ptr<function, f32>
|
|
92
|
+
) -> bool {
|
|
93
|
+
*bT = INF;
|
|
94
|
+
*bS = -INF;
|
|
95
|
+
|
|
96
|
+
let vQ = maxDimension(abs(iI));
|
|
97
|
+
let gJ = mg(iI, vQ);
|
|
98
|
+
var tt: f32;
|
|
99
|
+
|
|
100
|
+
tt = fI(
|
|
101
|
+
pt, iI,
|
|
102
|
+
fu(pC, pB, pA), vQ, gJ, INF
|
|
103
|
+
).t;
|
|
104
|
+
if (tt > 0.0) {
|
|
105
|
+
*bT = min(*bT, tt);
|
|
106
|
+
*bS = max(*bS, tt);
|
|
107
|
+
}
|
|
108
|
+
tt = fI(
|
|
109
|
+
pt, iI,
|
|
110
|
+
fu(pD, pE, pF), vQ, gJ, INF
|
|
111
|
+
).t;
|
|
112
|
+
if (tt > 0.0) {
|
|
113
|
+
*bT = min(*bT, tt);
|
|
114
|
+
*bS = max(*bS, tt);
|
|
115
|
+
}
|
|
116
|
+
if (hd(
|
|
117
|
+
pt, iI, -INF, INF,
|
|
118
|
+
pA, pB, pD, pE,
|
|
119
|
+
&tt)) {
|
|
120
|
+
*bT = min(*bT, tt);
|
|
121
|
+
*bS = max(*bS, tt);
|
|
122
|
+
}
|
|
123
|
+
if (hd(
|
|
124
|
+
pt, iI, -INF, INF,
|
|
125
|
+
pB, pC, pE, pF,
|
|
126
|
+
&tt)) {
|
|
127
|
+
*bT = min(*bT, tt);
|
|
128
|
+
*bS = max(*bS, tt);
|
|
129
|
+
}
|
|
130
|
+
if (hd(
|
|
131
|
+
pt, iI, -INF, INF,
|
|
132
|
+
pC, pA, pF, pD,
|
|
133
|
+
&tt)) {
|
|
134
|
+
*bT = min(*bT, tt);
|
|
135
|
+
*bS = max(*bS, tt);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
*bT = max(*bT, pL);
|
|
139
|
+
*bS = min(*bS, ta);
|
|
140
|
+
|
|
141
|
+
return *bT <= *bS && *bS > 0.0;
|
|
142
|
+
}
|
|
143
|
+
`;
|
|
144
|
+
export default /* wgsl */ `
|
|
145
|
+
|
|
146
|
+
${displacementCommon}
|
|
147
|
+
|
|
148
|
+
fn lD(p: vec3f, p0: vec3f, p1: vec3f, p2: vec3f) -> vec3f {
|
|
149
|
+
let v0 = p1 - p0;
|
|
150
|
+
let v1 = p2 - p0;
|
|
151
|
+
let v2 = p - p0;
|
|
152
|
+
|
|
153
|
+
let d00 = dot(v0, v0);
|
|
154
|
+
let d01 = dot(v0, v1);
|
|
155
|
+
let d11 = dot(v1, v1);
|
|
156
|
+
let d20 = dot(v2, v0);
|
|
157
|
+
let d21 = dot(v2, v1);
|
|
158
|
+
|
|
159
|
+
let tH = 1.0 / (d00 * d11 - d01 * d01);
|
|
160
|
+
let v = clamp((d11 * d20 - d01 * d21) * tH, 0.0, 1.0);
|
|
161
|
+
let w = clamp((d00 * d21 - d01 * d20) * tH, 0.0, 1.0);
|
|
162
|
+
let u = 1.0 - v - w;
|
|
163
|
+
|
|
164
|
+
return vec3f(u, v, w);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
fn sJ(uv: vec2f) -> vec2f {
|
|
168
|
+
return (uv % 1.0 + 1.0) % 1.0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
fn oP(
|
|
173
|
+
qf: vec3f, qA: vec3f, wB: f32,
|
|
174
|
+
_pA: vec3f, _pB: vec3f, _pC: vec3f,
|
|
175
|
+
_nA: vec3f, _nB: vec3f, _nC: vec3f,
|
|
176
|
+
vq: vec2f, vs: vec2f, vt: vec2f,
|
|
177
|
+
|
|
178
|
+
jH: i32,
|
|
179
|
+
vp: vec2f,
|
|
180
|
+
|
|
181
|
+
vW: f32, vV: f32,
|
|
182
|
+
hScale: f32,
|
|
183
|
+
vm: f32,
|
|
184
|
+
uvProjection: i32,
|
|
185
|
+
uvScale: vec2f,
|
|
186
|
+
vI: bool,
|
|
187
|
+
qQ: bool
|
|
188
|
+
) -> jv {
|
|
189
|
+
|
|
190
|
+
let DT = vm;
|
|
191
|
+
let dt = DT / length(qA);
|
|
192
|
+
let dbx = 0.001;
|
|
193
|
+
let dby = 0.001;
|
|
194
|
+
|
|
195
|
+
var result: jv;
|
|
196
|
+
result.t = INF;
|
|
197
|
+
|
|
198
|
+
var bT = INF;
|
|
199
|
+
var bS = -INF;
|
|
200
|
+
|
|
201
|
+
let qO = sign(hScale);
|
|
202
|
+
let uB = abs(hScale);
|
|
203
|
+
|
|
204
|
+
let sS = qO * normalize(cross(_pB - _pA, _pC - _pA));
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
let dA = dot(_nA, sS);
|
|
208
|
+
let dB = dot(_nB, sS);
|
|
209
|
+
let dC = dot(_nC, sS);
|
|
210
|
+
|
|
211
|
+
var minH = vW * hScale * min(min(dA, dB), dC);
|
|
212
|
+
var maxH = vV * hScale * max(max(dA, dB), dC);
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
let tN = abs(maxH) - abs(minH);
|
|
218
|
+
minH = sign(minH) * max(abs(minH) - dt * 2.0, 0.0);
|
|
219
|
+
if (tN < dt * 2.0) {
|
|
220
|
+
maxH = sign(maxH) * min(abs(maxH) + dt * 2.0, abs(hScale));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let pA = _pA + _nA * minH / dA;
|
|
224
|
+
let pB = _pB + _nB * minH / dB;
|
|
225
|
+
let pC = _pC + _nC * minH / dC;
|
|
226
|
+
|
|
227
|
+
let pD = _pA + _nA * maxH / dA;
|
|
228
|
+
let pE = _pB + _nB * maxH / dB;
|
|
229
|
+
let pF = _pC + _nC * maxH / dC;
|
|
230
|
+
|
|
231
|
+
if (!sf(
|
|
232
|
+
qf, qA, 0.0, INF,
|
|
233
|
+
pA, pB, pC,
|
|
234
|
+
pD, pE, pF,
|
|
235
|
+
|
|
236
|
+
&bT, &bS
|
|
237
|
+
)) {
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
var wv = false;
|
|
242
|
+
|
|
243
|
+
if (bS == bT) {
|
|
244
|
+
bT = 0.0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
var t = bT + dt * eo(2u);
|
|
248
|
+
var s = qf + qA * t;
|
|
249
|
+
var tG = dot(s - _pA, sS);
|
|
250
|
+
var uP = select(0.0, INF, qO < 0.0);
|
|
251
|
+
|
|
252
|
+
var c0 = _pA + _nA * tG / dA;
|
|
253
|
+
var c1 = _pB + _nB * tG / dB;
|
|
254
|
+
var c2 = _pC + _nC * tG / dC;
|
|
255
|
+
|
|
256
|
+
var tn: vec3f;
|
|
257
|
+
|
|
258
|
+
tG = abs(tG);
|
|
259
|
+
|
|
260
|
+
var qM = tG - uP;
|
|
261
|
+
var pM = qM;
|
|
262
|
+
var step = 0;
|
|
263
|
+
|
|
264
|
+
while (true) {
|
|
265
|
+
|
|
266
|
+
let b = lD(s, c0, c1, c2);
|
|
267
|
+
|
|
268
|
+
tn = _pA * b.x + _pB * b.y + _pC * b.z;
|
|
269
|
+
|
|
270
|
+
tG = distance(tn, s);
|
|
271
|
+
|
|
272
|
+
var uv: vec2f;
|
|
273
|
+
if (uvProjection > 0) {
|
|
274
|
+
let n = normalize(_nA * b.x + _nB * b.y + _nC * b.z);
|
|
275
|
+
uv = sJ(gz(uvProjection, tn, n) * uvScale);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
uv = sJ(vq * b.x + vs * b.y + vt * b.z);
|
|
279
|
+
}
|
|
280
|
+
let h = sampleMap(jH, uv).x;
|
|
281
|
+
|
|
282
|
+
uP = max(uB * h, dt);
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
let dh = dot(sS, s - c0);
|
|
286
|
+
c0 = c0 + _nA * dh / dA;
|
|
287
|
+
c1 = c1 + _nB * dh / dB;
|
|
288
|
+
c2 = c2 + _nC * dh / dC;
|
|
289
|
+
|
|
290
|
+
pM = qM;
|
|
291
|
+
qM = tG - uP;
|
|
292
|
+
|
|
293
|
+
if (!(select(qM * qO, qM * pM, qQ) > 0.0
|
|
294
|
+
&& t < bS + dt)
|
|
295
|
+
|
|
296
|
+
&& step > 0) {
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
step++;
|
|
301
|
+
t = t + dt;
|
|
302
|
+
s = s + qA * dt;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (select(qM * qO, qM * pM, qQ) <= 0.0) {
|
|
306
|
+
let dtt = dt * (abs(qM) / (abs(pM) + abs(qM) + EPS));
|
|
307
|
+
t = t - dtt;
|
|
308
|
+
|
|
309
|
+
let wx = qf + qA * t;
|
|
310
|
+
let b = lD(wx, c0, c1, c2);
|
|
311
|
+
|
|
312
|
+
let N = normalize(_nA * b.x + _nB * b.y + _nC * b.z);
|
|
313
|
+
|
|
314
|
+
let p_a = _pA * b.x + _pB * b.y + _pC * b.z;
|
|
315
|
+
let p_b = _pA * (b.x + dbx) + _pB * b.y + _pC * (b.z - dbx);
|
|
316
|
+
let p_c = _pA * b.x + _pB * (b.y + dby) + _pC * (b.z - dby);
|
|
317
|
+
|
|
318
|
+
var vS: vec2f;
|
|
319
|
+
var vT: vec2f;
|
|
320
|
+
var vU: vec2f;
|
|
321
|
+
|
|
322
|
+
if (uvProjection > 0) {
|
|
323
|
+
let NA = normalize(_nA * b.x + _nB * b.y + _nC * b.z);
|
|
324
|
+
let NB = normalize(_nA * (b.x + dbx) + _nB * b.y + _nC * (b.z - dbx));
|
|
325
|
+
let NC = normalize(_nA * b.x + _nB * (b.y + dby) + _nC * (b.z - dby));
|
|
326
|
+
vS = gz(uvProjection, p_a, NA) * uvScale;
|
|
327
|
+
vT = gz(uvProjection, p_b, NB) * uvScale;
|
|
328
|
+
vU = gz(uvProjection, p_c, NC) * uvScale;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
vS = vq * b.x + vs * b.y + vt * b.z;
|
|
332
|
+
vT = vq * (b.x + dbx) + vs * b.y + vt * (b.z - dbx);
|
|
333
|
+
vU = vq * b.x + vs * (b.y + dby) + vt * (b.z - dby);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
let s_a = p_a + qO * N * sampleMap(jH, sJ(vS)).x * hScale;
|
|
337
|
+
let s_b = p_b + qO * N * sampleMap(jH, sJ(vT)).x * hScale;
|
|
338
|
+
let s_c = p_c + qO * N * sampleMap(jH, sJ(vU)).x * hScale;
|
|
339
|
+
|
|
340
|
+
let N_s = -qO * normalize(cross(s_c - s_a, s_b - s_a));
|
|
341
|
+
|
|
342
|
+
result.t = t;
|
|
343
|
+
result.barycentric = b;
|
|
344
|
+
result.normal = normalize(N_s - sS + qO * N);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return result;
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
`;
|
|
351
|
+
export { displacementCommon };
|
|
352
|
+
//# sourceMappingURL=pdm_displacement.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdm_displacement.wgsl.js","sourceRoot":"","sources":["../../../../src/renderer/wgsl/chunks/pdm_displacement.wgsl.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8InC,CAAC;AAEF,eAAe,UAAU,CAAC;;EAExB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4MnB,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC","sourcesContent":["const displacementCommon = /*wgsl*/ `\n\n\nstruct MicroTriangleIntersect {\n barycentric: vec3f,\n t: f32,\n normal: vec3f,\n\n}\n\nfn findVT(\n uu: f32,\n pARel: vec3f, pBRel: vec3f,\n eAC: vec3f, eBD: vec3f,\n rayDir: vec3f,\n distMin: f32,\n hitDist: ptr<function, f32>\n) -> bool {\n if (uu >= 0.0 && uu <= 1.0) {\n let pAB = mix(pARel, pBRel, uu);\n let pCD = mix(eAC, eBD, uu);\n var n = cross(rayDir, pCD);\n let recDet = 1.0 / dot(n, n);\n n = cross(n, pAB);\n let tt = dot(n, pCD) * recDet;\n let vv = dot(n, rayDir) * recDet;\n if (vv >= 0.0 && vv <= 1.0 && tt > distMin && tt < *hitDist) {\n *hitDist = tt;\n return true;\n }\n }\n return false;\n}\n\nfn testRayVsBilinearPatch(\n rayOrg: vec3f, rayDir: vec3f, distMin: f32, distMax: f32,\n pA: vec3f, pB: vec3f, pC: vec3f, pD: vec3f,\n hitDist: ptr<function, f32>\n) -> bool {\n let eAB = pB - pA;\n let eAC = pC - pA;\n let eBD = pD - pB;\n let eCD = pD - pC;\n let pARel = pA - rayOrg;\n let pBRel = pB - rayOrg;\n\n var u1: f32;\n var u2: f32;\n {\n let qN = cross(eAB, -eCD);\n let a = dot(qN, rayDir);\n var b = dot(cross(pBRel, rayDir), eBD);\n let c = dot(cross(pARel, rayDir), eAC);\n b -= a + c;\n\n let det = b * b - 4.0 * a * c;\n if (det < 0.0) {\n return false;\n }\n\n if (a == 0.0) {\n u1 = -c / b;\n u2 = -1.0;\n } else {\n let sqrtDet = sqrt(det);\n let temp = -0.5 * (b + sign(b) * sqrtDet);\n u1 = temp / a;\n u2 = c / temp;\n }\n }\n\n *hitDist = distMax;\n\n var hit = false;\n\n hit = findVT(u1, pARel, pBRel, eAC, eBD, rayDir, distMin, hitDist) || \n findVT(u2, pARel, pBRel, eAC, eBD, rayDir, distMin, hitDist);\n if (!hit) {\n return false;\n }\n\n return true;\n}\n\nfn intersectPrism(\n rayOrg: vec3f, rayDir: vec3f, distMin: f32, distMax: f32,\n pA: vec3f, pB: vec3f, pC: vec3f,\n pD: vec3f, pE: vec3f, pF: vec3f,\n\n hitDistMin: ptr<function, f32>,\n hitDistMax: ptr<function, f32>\n) -> bool {\n *hitDistMin = INF;\n *hitDistMax = -INF;\n\n let maxD = maxDimension(abs(rayDir));\n let shear = getShear(rayDir, maxD);\n var tt: f32;\n\n tt = intersectTriangle(\n rayOrg, rayDir,\n Triangle(pC, pB, pA), maxD, shear, INF\n ).t;\n if (tt > 0.0) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n tt = intersectTriangle(\n rayOrg, rayDir,\n Triangle(pD, pE, pF), maxD, shear, INF\n ).t;\n if (tt > 0.0) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pA, pB, pD, pE,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pB, pC, pE, pF,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n if (testRayVsBilinearPatch(\n rayOrg, rayDir, -INF, INF,\n pC, pA, pF, pD,\n &tt)) {\n *hitDistMin = min(*hitDistMin, tt);\n *hitDistMax = max(*hitDistMax, tt);\n }\n\n *hitDistMin = max(*hitDistMin, distMin);\n *hitDistMax = min(*hitDistMax, distMax);\n\n return *hitDistMin <= *hitDistMax && *hitDistMax > 0.0;\n}\n`;\n\nexport default /* wgsl */ `\n\n${displacementCommon}\n\nfn triangleBarycentric(p: vec3f, p0: vec3f, p1: vec3f, p2: vec3f) -> vec3f {\n let v0 = p1 - p0;\n let v1 = p2 - p0;\n let v2 = p - p0;\n\n let d00 = dot(v0, v0);\n let d01 = dot(v0, v1);\n let d11 = dot(v1, v1);\n let d20 = dot(v2, v0);\n let d21 = dot(v2, v1);\n\n let invDenom = 1.0 / (d00 * d11 - d01 * d01);\n let v = clamp((d11 * d20 - d01 * d21) * invDenom, 0.0, 1.0);\n let w = clamp((d00 * d21 - d01 * d20) * invDenom, 0.0, 1.0);\n let u = 1.0 - v - w;\n\n return vec3f(u, v, w);\n}\n\nfn wrapUv(uv: vec2f) -> vec2f {\n return (uv % 1.0 + 1.0) % 1.0;\n}\n\n\nfn intersectDisplacement(\n _rayOrigin: vec3f, _rayDir: vec3f, _tMax: f32,\n _pA: vec3f, _pB: vec3f, _pC: vec3f,\n _nA: vec3f, _nB: vec3f, _nC: vec3f,\n _tcA: vec2f, _tcB: vec2f, _tcC: vec2f,\n\n heightMapIndex: i32,\n heightMapSize: vec2f,\n\n _minH: f32, _maxH: f32,\n hScale: f32,\n stepSize: f32,\n uvProjection: i32,\n uvScale: vec2f,\n isShadowHit: bool,\n isRefraction: bool\n) -> MicroTriangleIntersect {\n\n let DT = stepSize;\n let dt = DT / length(_rayDir);\n let dbx = 0.001;\n let dby = 0.001;\n\n var result: MicroTriangleIntersect;\n result.t = INF;\n\n var hitDistMin = INF;\n var hitDistMax = -INF;\n\n let hSign = sign(hScale);\n let hScaleAbs = abs(hScale);\n // Face normal.\n let faceN = hSign * normalize(cross(_pB - _pA, _pC - _pA));\n\n // dA, dB, dC are negative if hScale is negative\n let dA = dot(_nA, faceN);\n let dB = dot(_nB, faceN);\n let dC = dot(_nC, faceN);\n\n var minH = _minH * hScale * min(min(dA, dB), dC);\n var maxH = _maxH * hScale * max(max(dA, dB), dC);\n\n // Add gap\n // 1. Avoid too small height cause ray marching miss.\n // 2. Make sure the ray start beyond the displaced surface when surface height is same with prism height.\n let prismHeight = abs(maxH) - abs(minH);\n minH = sign(minH) * max(abs(minH) - dt * 2.0, 0.0);\n if (prismHeight < dt * 2.0) {\n maxH = sign(maxH) * min(abs(maxH) + dt * 2.0, abs(hScale));\n }\n\n let pA = _pA + _nA * minH / dA;\n let pB = _pB + _nB * minH / dB;\n let pC = _pC + _nC * minH / dC;\n\n let pD = _pA + _nA * maxH / dA;\n let pE = _pB + _nB * maxH / dB;\n let pF = _pC + _nC * maxH / dC;\n\n if (!intersectPrism(\n _rayOrigin, _rayDir, 0.0, INF,\n pA, pB, pC,\n pD, pE, pF,\n \n &hitDistMin, &hitDistMax\n )) {\n return result;\n }\n\n var testFlag = false;\n // Ray is inside the prism\n if (hitDistMax == hitDistMin) {\n hitDistMin = 0.0;\n }\n\n var t = hitDistMin + dt * hashedSample(2u);\n var s = _rayOrigin + _rayDir * t;\n var hRay = dot(s - _pA, faceN);\n var hSurf = select(0.0, INF, hSign < 0.0);\n // initial scanning triangle\n var c0 = _pA + _nA * hRay / dA;\n var c1 = _pB + _nB * hRay / dB;\n var c2 = _pC + _nC * hRay / dC;\n\n var projPos: vec3f;\n\n hRay = abs(hRay);\n\n var hDiff = hRay - hSurf;\n var hDiffPrev = hDiff;\n var step = 0;\n\n while (true) {\n // TODO Avoid too long loop\n let b = triangleBarycentric(s, c0, c1, c2);\n // Projected point on base triangle\n projPos = _pA * b.x + _pB * b.y + _pC * b.z;\n // Height at projected point\n hRay = distance(projPos, s);\n // Update scanning point\n var uv: vec2f;\n if (uvProjection > 0) {\n let n = normalize(_nA * b.x + _nB * b.y + _nC * b.z);\n uv = wrapUv(projectUV(uvProjection, projPos, n) * uvScale);\n }\n else {\n uv = wrapUv(_tcA * b.x + _tcB * b.y + _tcC * b.z);\n }\n let h = sampleMap(heightMapIndex, uv).x;\n // height < dt will be ignored in ray marching\n hSurf = max(hScaleAbs * h, dt);\n\n // Advance scanning triangle\n let dh = dot(faceN, s - c0);\n c0 = c0 + _nA * dh / dA;\n c1 = c1 + _nB * dh / dB;\n c2 = c2 + _nC * dh / dC;\n\n hDiffPrev = hDiff;\n hDiff = hRay - hSurf;\n\n if (!(select(hDiff * hSign, hDiff * hDiffPrev, isRefraction) > 0.0\n && t < hitDistMax + dt) \n // Ignore first step\n && step > 0) {\n break;\n }\n\n step++;\n t = t + dt;\n s = s + _rayDir * dt;\n }\n\n if (select(hDiff * hSign, hDiff * hDiffPrev, isRefraction) <= 0.0) {\n let dtt = dt * (abs(hDiff) / (abs(hDiffPrev) + abs(hDiff) + EPS));\n t = t - dtt;\n // t = interpolateCrossing(_rayOrigin, _rayDir, projPos, t, dt, hSurf);\n let pHit = _rayOrigin + _rayDir * t;\n let b = triangleBarycentric(pHit, c0, c1, c2);\n\n let N = normalize(_nA * b.x + _nB * b.y + _nC * b.z);\n\n let p_a = _pA * b.x + _pB * b.y + _pC * b.z;\n let p_b = _pA * (b.x + dbx) + _pB * b.y + _pC * (b.z - dbx);\n let p_c = _pA * b.x + _pB * (b.y + dby) + _pC * (b.z - dby);\n\n var uv_a: vec2f;\n var uv_b: vec2f;\n var uv_c: vec2f;\n\n if (uvProjection > 0) {\n let NA = normalize(_nA * b.x + _nB * b.y + _nC * b.z);\n let NB = normalize(_nA * (b.x + dbx) + _nB * b.y + _nC * (b.z - dbx));\n let NC = normalize(_nA * b.x + _nB * (b.y + dby) + _nC * (b.z - dby)); \n uv_a = projectUV(uvProjection, p_a, NA) * uvScale;\n uv_b = projectUV(uvProjection, p_b, NB) * uvScale;\n uv_c = projectUV(uvProjection, p_c, NC) * uvScale;\n }\n else {\n uv_a = _tcA * b.x + _tcB * b.y + _tcC * b.z;\n uv_b = _tcA * (b.x + dbx) + _tcB * b.y + _tcC * (b.z - dbx);\n uv_c = _tcA * b.x + _tcB * (b.y + dby) + _tcC * (b.z - dby);\n }\n\n let s_a = p_a + hSign * N * sampleMap(heightMapIndex, wrapUv(uv_a)).x * hScale;\n let s_b = p_b + hSign * N * sampleMap(heightMapIndex, wrapUv(uv_b)).x * hScale;\n let s_c = p_c + hSign * N * sampleMap(heightMapIndex, wrapUv(uv_c)).x * hScale;\n\n let N_s = -hSign * normalize(cross(s_c - s_a, s_b - s_a));\n\n result.t = t;\n result.barycentric = b;\n result.normal = normalize(N_s - faceN + hSign * N);\n }\n\n return result;\n\n}\n`;\n\nexport { displacementCommon };\n"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: "\nvar<private> s0: vec4u;\n\nfn rng_initialize(p: vec2u, frame: i32) {\n //white noise seed\n s0 = vec4u(p, u32(frame), u32(p.x) + u32(p.y));\n}\n\n// https://www.pcg-random.org/\nfn pcg4d() {\n\ts0 = s0 * 1664525u + 1013904223u;\n s0.x += s0.y*s0.w; s0.y += s0.z*s0.x; s0.z += s0.x*s0.y; s0.w += s0.y*s0.z;\n s0 = s0 ^ (s0>>vec4(16u));\n s0.x += s0.y*s0.w; s0.y += s0.z*s0.x; s0.z += s0.x*s0.y; s0.w += s0.y*s0.z;\n}\n\nfn rand() -> f32 {\n pcg4d(); return f32(s0.x)/f32(0xffffffffu);\n}\n\n";
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// RNG adapted from GLSL-PathTracer (https://github.com/knightcrawler25/GLSL-PathTracer),
|
|
2
|
+
// Copyright (c) 2019 Asif Ali, MIT license, which credits Moroz Mykhailo
|
|
3
|
+
// (https://www.shadertoy.com/view/wltcRS).
|
|
4
|
+
export default /* wgsl */ `
|
|
5
|
+
var<private> s0: vec4u;
|
|
6
|
+
|
|
7
|
+
fn jY(p: vec2u, frame: i32) {
|
|
8
|
+
|
|
9
|
+
s0 = vec4u(p, u32(frame), u32(p.x) + u32(p.y));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
fn vg() {
|
|
14
|
+
s0 = s0 * 1664525u + 1013904223u;
|
|
15
|
+
s0.x += s0.y*s0.w; s0.y += s0.z*s0.x; s0.z += s0.x*s0.y; s0.w += s0.y*s0.z;
|
|
16
|
+
s0 = s0 ^ (s0>>vec4(16u));
|
|
17
|
+
s0.x += s0.y*s0.w; s0.y += s0.z*s0.x; s0.z += s0.x*s0.y; s0.w += s0.y*s0.z;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fn rand() -> f32 {
|
|
21
|
+
vg(); return f32(s0.x)/f32(0xffffffffu);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
`;
|
|
25
|
+
//# sourceMappingURL=rand.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rand.wgsl.js","sourceRoot":"","sources":["../../../../src/renderer/wgsl/chunks/rand.wgsl.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,yEAAyE;AACzE,2CAA2C;AAE3C,eAAe,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;CAoBzB,CAAC","sourcesContent":["// RNG adapted from GLSL-PathTracer (https://github.com/knightcrawler25/GLSL-PathTracer),\n// Copyright (c) 2019 Asif Ali, MIT license, which credits Moroz Mykhailo\n// (https://www.shadertoy.com/view/wltcRS).\n\nexport default /* wgsl */ `\nvar<private> s0: vec4u;\n\nfn rng_initialize(p: vec2u, frame: i32) {\n //white noise seed\n s0 = vec4u(p, u32(frame), u32(p.x) + u32(p.y));\n}\n\n// https://www.pcg-random.org/\nfn pcg4d() {\n\ts0 = s0 * 1664525u + 1013904223u;\n s0.x += s0.y*s0.w; s0.y += s0.z*s0.x; s0.z += s0.x*s0.y; s0.w += s0.y*s0.z;\n s0 = s0 ^ (s0>>vec4(16u));\n s0.x += s0.y*s0.w; s0.y += s0.z*s0.x; s0.z += s0.x*s0.y; s0.w += s0.y*s0.z;\n}\n\nfn rand() -> f32 {\n pcg4d(); return f32(s0.x)/f32(0xffffffffu);\n}\n\n`;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './sobol.wgsl.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random.wgsl.js","sourceRoot":"","sources":["../../../../src/renderer/wgsl/chunks/random.wgsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["export { default } from './sobol.wgsl.js';\n"]}
|