@driftengine/core 3.63.0 → 4.0.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/CHANGELOG.json +111 -0
- package/NOTICE +20 -0
- package/README.md +1 -1
- package/dist/core/loop.js +18 -2
- package/dist/core/storage.js +5 -0
- package/dist/geometry/meshBuilder.d.ts +1 -1
- package/dist/geometry/meshBuilder.js +6 -2
- package/dist/index.d.ts +69 -4
- package/dist/index.js +112 -2
- package/dist/input/input.js +6 -1
- package/dist/math/exact.d.ts +13 -3
- package/dist/math/exact.js +68 -3
- package/dist/math/frustum.d.ts +17 -2
- package/dist/math/frustum.js +24 -0
- package/dist/render/backend/api.d.ts +34 -1
- package/dist/render/backend/api.js +22 -1
- package/dist/render/backend/budget.d.ts +7 -6
- package/dist/render/backend/budget.js +7 -6
- package/dist/render/backend/createRenderer.d.ts +57 -0
- package/dist/render/backend/createRenderer.js +51 -2
- package/dist/render/backend/materialChanges.d.ts +41 -0
- package/dist/render/backend/materialChanges.js +38 -0
- package/dist/render/backend/select.js +8 -0
- package/dist/render/backend/webgl2/renderer.d.ts +80 -1
- package/dist/render/backend/webgl2/renderer.js +208 -10
- package/dist/render/backend/webgpu/buffers.d.ts +20 -1
- package/dist/render/backend/webgpu/buffers.js +116 -58
- package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
- package/dist/render/backend/webgpu/fieldCompose.js +396 -0
- package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
- package/dist/render/backend/webgpu/giFieldPass.js +137 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
- package/dist/render/backend/webgpu/linePass.d.ts +4 -14
- package/dist/render/backend/webgpu/linePass.js +4 -33
- package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
- package/dist/render/backend/webgpu/probeBake.js +493 -0
- package/dist/render/backend/webgpu/renderer.d.ts +379 -24
- package/dist/render/backend/webgpu/renderer.js +1369 -76
- package/dist/render/backend/webgpu/scatterPass.js +15 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
- package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
- package/dist/render/causticsRenderer.d.ts +3 -1
- package/dist/render/causticsRenderer.js +4 -1
- package/dist/render/depthConvention.d.ts +12 -0
- package/dist/render/depthConvention.js +14 -0
- package/dist/render/deviceFeatures.d.ts +32 -0
- package/dist/render/deviceFeatures.js +41 -0
- package/dist/render/fog.d.ts +79 -0
- package/dist/render/fog.js +138 -0
- package/dist/render/frame/alias.d.ts +30 -0
- package/dist/render/frame/alias.js +61 -0
- package/dist/render/frame/deps.d.ts +37 -0
- package/dist/render/frame/deps.js +122 -0
- package/dist/render/frame/flushGraph.d.ts +43 -0
- package/dist/render/frame/flushGraph.js +84 -0
- package/dist/render/frame/graphSchedule.d.ts +49 -0
- package/dist/render/frame/graphSchedule.js +120 -0
- package/dist/render/frame/index.d.ts +15 -0
- package/dist/render/frame/index.js +8 -0
- package/dist/render/frame/lifetime.d.ts +24 -0
- package/dist/render/frame/lifetime.js +36 -0
- package/dist/render/frame/passTimings.d.ts +42 -0
- package/dist/render/frame/passTimings.js +38 -0
- package/dist/render/frame/validate.d.ts +15 -0
- package/dist/render/frame/validate.js +22 -0
- package/dist/render/frame/virtual.d.ts +44 -0
- package/dist/render/frame/virtual.js +61 -0
- package/dist/render/gi/chain.d.ts +82 -0
- package/dist/render/gi/chain.js +135 -0
- package/dist/render/gi/denoise.d.ts +114 -0
- package/dist/render/gi/denoise.js +169 -0
- package/dist/render/gi/fieldScene.d.ts +125 -0
- package/dist/render/gi/fieldScene.js +219 -0
- package/dist/render/gi/globalField.d.ts +157 -0
- package/dist/render/gi/globalField.js +373 -0
- package/dist/render/gi/probeGridFit.d.ts +24 -0
- package/dist/render/gi/probeGridFit.js +71 -0
- package/dist/render/gi/probeTrace.d.ts +82 -0
- package/dist/render/gi/probeTrace.js +128 -0
- package/dist/render/gi/probeVolume.d.ts +136 -0
- package/dist/render/gi/probeVolume.js +191 -0
- package/dist/render/gi/reflection.d.ts +73 -0
- package/dist/render/gi/reflection.js +109 -0
- package/dist/render/gi/traceField.d.ts +91 -0
- package/dist/render/gi/traceField.js +129 -0
- package/dist/render/gi/traceScreen.d.ts +68 -0
- package/dist/render/gi/traceScreen.js +82 -0
- package/dist/render/gpuScene.d.ts +38 -0
- package/dist/render/gpuScene.js +41 -0
- package/dist/render/gpudriven/alphaTest.d.ts +28 -0
- package/dist/render/gpudriven/alphaTest.js +32 -0
- package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
- package/dist/render/gpudriven/clusterUpload.js +75 -0
- package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
- package/dist/render/gpudriven/clusterWorld.js +155 -0
- package/dist/render/gpudriven/compact.d.ts +51 -0
- package/dist/render/gpudriven/compact.js +68 -0
- package/dist/render/gpudriven/cullClusters.d.ts +129 -0
- package/dist/render/gpudriven/cullClusters.js +237 -0
- package/dist/render/gpudriven/decodeTables.d.ts +64 -0
- package/dist/render/gpudriven/decodeTables.js +219 -0
- package/dist/render/gpudriven/frustum.d.ts +25 -0
- package/dist/render/gpudriven/frustum.js +59 -0
- package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
- package/dist/render/gpudriven/geometryHarness.js +31 -0
- package/dist/render/gpudriven/hzb.d.ts +60 -0
- package/dist/render/gpudriven/hzb.js +97 -0
- package/dist/render/gpudriven/ibl.d.ts +85 -0
- package/dist/render/gpudriven/ibl.js +129 -0
- package/dist/render/gpudriven/indirect.d.ts +67 -0
- package/dist/render/gpudriven/indirect.js +77 -0
- package/dist/render/gpudriven/instances.d.ts +43 -0
- package/dist/render/gpudriven/instances.js +172 -0
- package/dist/render/gpudriven/lit.d.ts +165 -0
- package/dist/render/gpudriven/lit.js +165 -0
- package/dist/render/gpudriven/lodCut.d.ts +28 -0
- package/dist/render/gpudriven/lodCut.js +38 -0
- package/dist/render/gpudriven/materialBin.d.ts +60 -0
- package/dist/render/gpudriven/materialBin.js +108 -0
- package/dist/render/gpudriven/materialTable.d.ts +88 -0
- package/dist/render/gpudriven/materialTable.js +115 -0
- package/dist/render/gpudriven/pipeline.d.ts +135 -0
- package/dist/render/gpudriven/pipeline.js +237 -0
- package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
- package/dist/render/gpudriven/rangeAlloc.js +112 -0
- package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
- package/dist/render/gpudriven/sceneUpload.js +115 -0
- package/dist/render/gpudriven/shadeBins.d.ts +92 -0
- package/dist/render/gpudriven/shadeBins.js +182 -0
- package/dist/render/gpudriven/shadow.d.ts +136 -0
- package/dist/render/gpudriven/shadow.js +224 -0
- package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
- package/dist/render/gpudriven/shadowCamera.js +345 -0
- package/dist/render/gpudriven/streamScene.d.ts +194 -0
- package/dist/render/gpudriven/streamScene.js +459 -0
- package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
- package/dist/render/gpudriven/surfaceFrame.js +51 -0
- package/dist/render/gpudriven/twoPhase.d.ts +122 -0
- package/dist/render/gpudriven/twoPhase.js +160 -0
- package/dist/render/gpudriven/visbuffer.d.ts +25 -0
- package/dist/render/gpudriven/visbuffer.js +37 -0
- package/dist/render/halfFloat.d.ts +10 -0
- package/dist/render/halfFloat.js +23 -4
- package/dist/render/inference/attentionTiled.d.ts +27 -0
- package/dist/render/inference/attentionTiled.js +117 -0
- package/dist/render/inference/denseKernels.d.ts +29 -0
- package/dist/render/inference/denseKernels.js +312 -0
- package/dist/render/inference/device.d.ts +21 -0
- package/dist/render/inference/device.js +32 -0
- package/dist/render/inference/deviceGraph.d.ts +34 -0
- package/dist/render/inference/deviceGraph.js +17 -0
- package/dist/render/inference/fuse.d.ts +15 -0
- package/dist/render/inference/fuse.js +37 -0
- package/dist/render/inference/kernelKit.d.ts +52 -0
- package/dist/render/inference/kernelKit.js +70 -0
- package/dist/render/inference/kernels.d.ts +3 -0
- package/dist/render/inference/kernels.js +11 -0
- package/dist/render/inference/plan.d.ts +13 -0
- package/dist/render/inference/plan.js +18 -0
- package/dist/render/inference/reuse.d.ts +39 -0
- package/dist/render/inference/reuse.js +65 -0
- package/dist/render/inference/runner.d.ts +31 -0
- package/dist/render/inference/runner.js +175 -0
- package/dist/render/inference/schedule.d.ts +39 -0
- package/dist/render/inference/schedule.js +59 -0
- package/dist/render/inference/shapeKernels.d.ts +10 -0
- package/dist/render/inference/shapeKernels.js +80 -0
- package/dist/render/inference/spatialKernels.d.ts +21 -0
- package/dist/render/inference/spatialKernels.js +179 -0
- package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
- package/dist/render/inference/splatRaster.wgsl.js +337 -0
- package/dist/render/inference/splatTiles.d.ts +79 -0
- package/dist/render/inference/splatTiles.js +161 -0
- package/dist/render/lineBatch.d.ts +2 -5
- package/dist/render/lineBatch.js +4 -24
- package/dist/render/mesh.d.ts +4 -0
- package/dist/render/mesh.js +45 -1
- package/dist/render/pass.d.ts +145 -8
- package/dist/render/prefilterEnvMap.d.ts +22 -0
- package/dist/render/prefilterEnvMap.js +31 -0
- package/dist/render/readback.d.ts +30 -0
- package/dist/render/readback.js +47 -0
- package/dist/render/recon/clamp.d.ts +36 -0
- package/dist/render/recon/clamp.js +92 -0
- package/dist/render/recon/disocclusion.d.ts +60 -0
- package/dist/render/recon/disocclusion.js +109 -0
- package/dist/render/recon/frameGen.d.ts +81 -0
- package/dist/render/recon/frameGen.js +150 -0
- package/dist/render/recon/frameSizes.d.ts +34 -0
- package/dist/render/recon/frameSizes.js +58 -0
- package/dist/render/recon/jitter.d.ts +60 -0
- package/dist/render/recon/jitter.js +118 -0
- package/dist/render/recon/motionVectors.d.ts +55 -0
- package/dist/render/recon/motionVectors.js +107 -0
- package/dist/render/recon/reproject.d.ts +41 -0
- package/dist/render/recon/reproject.js +131 -0
- package/dist/render/recon/resolve.d.ts +90 -0
- package/dist/render/recon/resolve.js +313 -0
- package/dist/render/recon/tier.d.ts +24 -0
- package/dist/render/recon/tier.js +8 -0
- package/dist/render/reflectionProbe.d.ts +26 -0
- package/dist/render/reflectionProbe.js +33 -0
- package/dist/render/renderQuality.d.ts +69 -0
- package/dist/render/renderQuality.js +22 -0
- package/dist/render/screenSpaceReflection.d.ts +23 -0
- package/dist/render/screenSpaceReflection.js +22 -3
- package/dist/render/sdfFont.js +2 -0
- package/dist/render/segmentQuads.d.ts +13 -0
- package/dist/render/segmentQuads.js +32 -0
- package/dist/render/shaders/flat/lobes.d.ts +27 -0
- package/dist/render/shaders/flat/lobes.js +33 -3
- package/dist/render/shaders/flat/preamble.d.ts +7 -0
- package/dist/render/shaders/flat/preamble.js +24 -1
- package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
- package/dist/render/shaders/flat/probeGrid.js +71 -2
- package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
- package/dist/render/shaders/generated/flat.wgsl.js +64 -24
- package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
- package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
- package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
- package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
- package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
- package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
- package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
- package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
- package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
- package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
- package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
- package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
- package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
- package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
- package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
- package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
- package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
- package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
- package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
- package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
- package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
- package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
- package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
- package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
- package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
- package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
- package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
- package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
- package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
- package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
- package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
- package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
- package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
- package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
- package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
- package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
- package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
- package/dist/render/shaders/network.wgsl.d.ts +101 -0
- package/dist/render/shaders/network.wgsl.js +206 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
- package/dist/render/shaders/recon/motion.wgsl.js +96 -0
- package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
- package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
- package/dist/render/temporalAa.js +8 -33
- package/dist/render/textLayout.js +12 -6
- package/dist/render/textRenderer.d.ts +3 -1
- package/dist/render/textRenderer.js +4 -1
- package/dist/render/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +11 -0
- package/dist/render/windStreakRenderer.d.ts +2 -1
- package/dist/render/windStreakRenderer.js +3 -1
- package/dist/world/cell.d.ts +63 -0
- package/dist/world/cell.js +181 -0
- package/dist/world/cellStream.d.ts +103 -0
- package/dist/world/cellStream.js +198 -0
- package/dist/world/freeze.d.ts +81 -0
- package/dist/world/freeze.js +114 -0
- package/dist/world/rebase.d.ts +29 -0
- package/dist/world/rebase.js +41 -0
- package/package.json +8 -3
- package/scripts/frames.mjs +92 -0
- package/scripts/gpuCompute.mjs +323 -0
- package/scripts/png.d.mts +16 -0
- package/scripts/png.mjs +25 -0
- package/src/core/loop.ts +19 -2
- package/src/core/storage.ts +5 -0
- package/src/geometry/meshBuilder.ts +5 -1
- package/src/index.ts +246 -4
- package/src/input/input.ts +6 -1
- package/src/math/exact.ts +69 -3
- package/src/math/frustum.ts +52 -3
- package/src/render/backend/api.ts +42 -1
- package/src/render/backend/budget.ts +7 -6
- package/src/render/backend/createRenderer.ts +92 -3
- package/src/render/backend/materialChanges.ts +54 -0
- package/src/render/backend/select.ts +8 -0
- package/src/render/backend/webgl2/renderer.ts +211 -9
- package/src/render/backend/webgpu/buffers.ts +182 -69
- package/src/render/backend/webgpu/fieldCompose.ts +482 -0
- package/src/render/backend/webgpu/giFieldPass.ts +200 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
- package/src/render/backend/webgpu/linePass.ts +4 -39
- package/src/render/backend/webgpu/probeBake.ts +588 -0
- package/src/render/backend/webgpu/renderer.ts +1481 -76
- package/src/render/backend/webgpu/scatterPass.ts +15 -1
- package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
- package/src/render/causticsRenderer.ts +5 -2
- package/src/render/depthConvention.ts +15 -0
- package/src/render/deviceFeatures.ts +77 -0
- package/src/render/fog.ts +185 -0
- package/src/render/frame/alias.ts +97 -0
- package/src/render/frame/deps.ts +155 -0
- package/src/render/frame/flushGraph.ts +135 -0
- package/src/render/frame/graphSchedule.ts +170 -0
- package/src/render/frame/index.ts +52 -0
- package/src/render/frame/lifetime.ts +61 -0
- package/src/render/frame/passTimings.ts +69 -0
- package/src/render/frame/validate.ts +40 -0
- package/src/render/frame/virtual.ts +91 -0
- package/src/render/gi/chain.ts +225 -0
- package/src/render/gi/denoise.ts +276 -0
- package/src/render/gi/fieldScene.ts +264 -0
- package/src/render/gi/globalField.ts +543 -0
- package/src/render/gi/probeGridFit.ts +89 -0
- package/src/render/gi/probeTrace.ts +143 -0
- package/src/render/gi/probeVolume.ts +288 -0
- package/src/render/gi/reflection.ts +163 -0
- package/src/render/gi/traceField.ts +223 -0
- package/src/render/gi/traceScreen.ts +106 -0
- package/src/render/gpuScene.ts +80 -0
- package/src/render/gpudriven/alphaTest.ts +33 -0
- package/src/render/gpudriven/clusterUpload.ts +123 -0
- package/src/render/gpudriven/clusterWorld.ts +239 -0
- package/src/render/gpudriven/compact.ts +80 -0
- package/src/render/gpudriven/cullClusters.ts +333 -0
- package/src/render/gpudriven/decodeTables.ts +332 -0
- package/src/render/gpudriven/frustum.ts +70 -0
- package/src/render/gpudriven/geometryHarness.ts +51 -0
- package/src/render/gpudriven/hzb.ts +113 -0
- package/src/render/gpudriven/ibl.ts +147 -0
- package/src/render/gpudriven/indirect.ts +89 -0
- package/src/render/gpudriven/instances.ts +234 -0
- package/src/render/gpudriven/lit.ts +329 -0
- package/src/render/gpudriven/lodCut.ts +62 -0
- package/src/render/gpudriven/materialBin.ts +131 -0
- package/src/render/gpudriven/materialTable.ts +164 -0
- package/src/render/gpudriven/pipeline.ts +336 -0
- package/src/render/gpudriven/rangeAlloc.ts +122 -0
- package/src/render/gpudriven/sceneUpload.ts +173 -0
- package/src/render/gpudriven/shadeBins.ts +222 -0
- package/src/render/gpudriven/shadow.ts +285 -0
- package/src/render/gpudriven/shadowCamera.ts +406 -0
- package/src/render/gpudriven/streamScene.ts +575 -0
- package/src/render/gpudriven/surfaceFrame.ts +68 -0
- package/src/render/gpudriven/twoPhase.ts +214 -0
- package/src/render/gpudriven/visbuffer.ts +41 -0
- package/src/render/halfFloat.ts +22 -4
- package/src/render/inference/attentionTiled.ts +132 -0
- package/src/render/inference/denseKernels.ts +369 -0
- package/src/render/inference/device.ts +44 -0
- package/src/render/inference/deviceGraph.ts +39 -0
- package/src/render/inference/fuse.ts +47 -0
- package/src/render/inference/kernelKit.ts +120 -0
- package/src/render/inference/kernels.ts +18 -0
- package/src/render/inference/plan.ts +26 -0
- package/src/render/inference/reuse.ts +79 -0
- package/src/render/inference/runner.ts +204 -0
- package/src/render/inference/schedule.ts +80 -0
- package/src/render/inference/shapeKernels.ts +112 -0
- package/src/render/inference/spatialKernels.ts +220 -0
- package/src/render/inference/splatRaster.wgsl.ts +348 -0
- package/src/render/inference/splatTiles.ts +186 -0
- package/src/render/lineBatch.ts +4 -24
- package/src/render/mesh.ts +46 -1
- package/src/render/pass.ts +155 -10
- package/src/render/prefilterEnvMap.ts +33 -0
- package/src/render/readback.ts +73 -0
- package/src/render/recon/clamp.ts +113 -0
- package/src/render/recon/disocclusion.ts +143 -0
- package/src/render/recon/frameGen.ts +191 -0
- package/src/render/recon/frameSizes.ts +64 -0
- package/src/render/recon/jitter.ts +126 -0
- package/src/render/recon/motionVectors.ts +138 -0
- package/src/render/recon/reproject.ts +179 -0
- package/src/render/recon/resolve.ts +444 -0
- package/src/render/recon/tier.ts +31 -0
- package/src/render/reflectionProbe.ts +34 -0
- package/src/render/renderQuality.ts +87 -0
- package/src/render/screenSpaceReflection.ts +37 -3
- package/src/render/sdfFont.ts +2 -0
- package/src/render/segmentQuads.ts +39 -0
- package/src/render/shaders/flat/lobes.ts +35 -3
- package/src/render/shaders/flat/preamble.ts +25 -1
- package/src/render/shaders/flat/probeGrid.ts +77 -2
- package/src/render/shaders/generated/flat.wgsl.ts +64 -24
- package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
- package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
- package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
- package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
- package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
- package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
- package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
- package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
- package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
- package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
- package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
- package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
- package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
- package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
- package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
- package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
- package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
- package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
- package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
- package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
- package/src/render/shaders/network.wgsl.ts +238 -0
- package/src/render/shaders/recon/motion.wgsl.ts +101 -0
- package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
- package/src/render/temporalAa.ts +9 -33
- package/src/render/textLayout.ts +12 -6
- package/src/render/textRenderer.ts +5 -2
- package/src/render/translucentQueue.ts +11 -0
- package/src/render/windStreakRenderer.ts +4 -2
- package/src/world/cell.ts +231 -0
- package/src/world/cellStream.ts +278 -0
- package/src/world/freeze.ts +157 -0
- package/src/world/rebase.ts +56 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuilding a pixel's surface from the triangle it recorded.
|
|
3
|
+
*
|
|
4
|
+
* **This is the only part of the shading that differs between the two pipelines.** The forward
|
|
5
|
+
* path gets its surface attributes from the rasteriser's varyings; a visibility buffer has none,
|
|
6
|
+
* so every attribute has to be interpolated here from the three vertices of the triangle the pixel
|
|
7
|
+
* wrote down. The lighting itself is not this module's business and must not become a second copy
|
|
8
|
+
* of the forward path's — a pair of lighting expressions drifts, and the parity gate is then the
|
|
9
|
+
* only thing that notices.
|
|
10
|
+
*
|
|
11
|
+
* **Perspective correction is not optional and screen-space barycentrics are not enough.** A
|
|
12
|
+
* triangle seen at an angle covers pixels whose interpolated attributes are *not* linear in screen
|
|
13
|
+
* position: the correct weights are the screen-space ones divided by each vertex's clip `w` and
|
|
14
|
+
* renormalised. Skipping it is the classic affine-texturing look, and on a floor it is unmistakable.
|
|
15
|
+
*
|
|
16
|
+
* **The gradients are derived analytically, and this is the subtle one.** A fragment shader gets
|
|
17
|
+
* `dFdx` and `dFdy` for free because it runs in quads of four pixels; a compute invocation has no
|
|
18
|
+
* neighbours and no derivative at all. A texture read without one either picks a fixed level —
|
|
19
|
+
* which is a blurry picture everywhere, or an aliased one — or picks level zero, which sparkles.
|
|
20
|
+
* So the rate of change of every barycentric with respect to screen x and y is computed from the
|
|
21
|
+
* triangle's own edge functions, and an attribute's gradient is the same weighted sum its value
|
|
22
|
+
* is. `attributeGradients` is that, and `barycentricGradients` is what it rests on.
|
|
23
|
+
*
|
|
24
|
+
* Everything here takes plain numbers and fills arrays the caller owns, because the shader does the
|
|
25
|
+
* same arithmetic per pixel and the two have to be comparable term by term.
|
|
26
|
+
*/
|
|
27
|
+
/** Screen position and reciprocal clip w of one vertex: x, y, 1/w. */
|
|
28
|
+
export declare const SCREEN_VERTEX_FLOATS = 3;
|
|
29
|
+
/**
|
|
30
|
+
* Project one clip-space vertex into pixel coordinates.
|
|
31
|
+
*
|
|
32
|
+
* Fills `x, y, 1/w`. Answers **false behind the eye**, where the division has no meaning: a
|
|
33
|
+
* visibility buffer cannot record such a pixel in the first place — the rasteriser clipped the
|
|
34
|
+
* triangle before it was drawn — so reaching this with `w <= 0` means the identifier and the
|
|
35
|
+
* geometry have gone out of step, and a silent NaN would shade a plausible-looking wrong surface.
|
|
36
|
+
*/
|
|
37
|
+
export declare function screenVertex(clipX: number, clipY: number, clipW: number, width: number, height: number, out: Float32Array, at: number): boolean;
|
|
38
|
+
/** Twice the signed area of the screen triangle. Zero where it is degenerate. */
|
|
39
|
+
export declare function screenArea(screen: Float32Array): number;
|
|
40
|
+
/**
|
|
41
|
+
* The screen-space barycentric weights of a point, before perspective correction.
|
|
42
|
+
*
|
|
43
|
+
* Answers false for a degenerate triangle — one whose three screen positions are collinear, which
|
|
44
|
+
* covers no pixel and whose weights are a division by zero. A caller that reaches this has a
|
|
45
|
+
* visibility identifier for a triangle the rasteriser never drew.
|
|
46
|
+
*
|
|
47
|
+
* **A point outside the triangle gets a negative weight rather than a clamp.** Clamping is how a
|
|
48
|
+
* pixel on the far side of an edge ends up shaded as though it were on the triangle, which along a
|
|
49
|
+
* silhouette is a fringe of the wrong material.
|
|
50
|
+
*/
|
|
51
|
+
export declare function screenBarycentrics(screen: Float32Array, x: number, y: number, out: Float32Array): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The perspective-correct weights, from the screen-space ones and the vertices' reciprocal `w`.
|
|
54
|
+
*
|
|
55
|
+
* Each screen weight is scaled by its vertex's `1/w` and the three renormalised. At an orthographic
|
|
56
|
+
* projection every `1/w` is equal and this is the identity, which is why the affine version looks
|
|
57
|
+
* right on a test quad facing the camera and wrong on the floor beneath it.
|
|
58
|
+
*/
|
|
59
|
+
export declare function perspectiveBarycentrics(screen: Float32Array, lambda: Float32Array, out: Float32Array): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* How each perspective-correct weight changes with screen x and y, at one pixel.
|
|
62
|
+
*
|
|
63
|
+
* Fills six numbers: `d0/dx, d1/dx, d2/dx, d0/dy, d1/dy, d2/dy`.
|
|
64
|
+
*
|
|
65
|
+
* **Derived rather than differenced.** The screen weights are linear in `x` and `y`, so their
|
|
66
|
+
* gradients are constants of the triangle; the perspective-correct ones are a ratio of two linear
|
|
67
|
+
* functions, and the quotient rule gives the rest. What this buys over a finite difference is that
|
|
68
|
+
* it is exact at the pixel rather than an average over one, and that it costs no neighbours — a
|
|
69
|
+
* compute invocation has none.
|
|
70
|
+
*/
|
|
71
|
+
export declare function barycentricGradients(screen: Float32Array, lambda: Float32Array, out: Float32Array): boolean;
|
|
72
|
+
/** One attribute interpolated by the weights already computed. */
|
|
73
|
+
export declare function interpolate(a0: number, a1: number, a2: number, weights: Float32Array): number;
|
|
74
|
+
/**
|
|
75
|
+
* One attribute's rate of change with screen x and y, from the weight gradients.
|
|
76
|
+
*
|
|
77
|
+
* An attribute is a weighted sum of three constants, so its gradient is the same sum of the
|
|
78
|
+
* weights' gradients. This is what a texture fetch's level of detail is computed from.
|
|
79
|
+
*/
|
|
80
|
+
export declare function attributeGradients(a0: number, a1: number, a2: number, gradients: Float32Array): {
|
|
81
|
+
dx: number;
|
|
82
|
+
dy: number;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Which pixel a shading invocation is responsible for.
|
|
86
|
+
*
|
|
87
|
+
* A group covers `BIN_GROUP_SIZE` entries of one material's slice; an invocation past the end of
|
|
88
|
+
* the slice has no pixel, which is the ordinary case because the slice is not a multiple of the
|
|
89
|
+
* group size. Answers -1 there rather than the last pixel of the bin, which would shade it once
|
|
90
|
+
* per spare lane.
|
|
91
|
+
*/
|
|
92
|
+
export declare function binPixel(pixels: Uint32Array, offset: number, count: number, invocation: number): number;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuilding a pixel's surface from the triangle it recorded.
|
|
3
|
+
*
|
|
4
|
+
* **This is the only part of the shading that differs between the two pipelines.** The forward
|
|
5
|
+
* path gets its surface attributes from the rasteriser's varyings; a visibility buffer has none,
|
|
6
|
+
* so every attribute has to be interpolated here from the three vertices of the triangle the pixel
|
|
7
|
+
* wrote down. The lighting itself is not this module's business and must not become a second copy
|
|
8
|
+
* of the forward path's — a pair of lighting expressions drifts, and the parity gate is then the
|
|
9
|
+
* only thing that notices.
|
|
10
|
+
*
|
|
11
|
+
* **Perspective correction is not optional and screen-space barycentrics are not enough.** A
|
|
12
|
+
* triangle seen at an angle covers pixels whose interpolated attributes are *not* linear in screen
|
|
13
|
+
* position: the correct weights are the screen-space ones divided by each vertex's clip `w` and
|
|
14
|
+
* renormalised. Skipping it is the classic affine-texturing look, and on a floor it is unmistakable.
|
|
15
|
+
*
|
|
16
|
+
* **The gradients are derived analytically, and this is the subtle one.** A fragment shader gets
|
|
17
|
+
* `dFdx` and `dFdy` for free because it runs in quads of four pixels; a compute invocation has no
|
|
18
|
+
* neighbours and no derivative at all. A texture read without one either picks a fixed level —
|
|
19
|
+
* which is a blurry picture everywhere, or an aliased one — or picks level zero, which sparkles.
|
|
20
|
+
* So the rate of change of every barycentric with respect to screen x and y is computed from the
|
|
21
|
+
* triangle's own edge functions, and an attribute's gradient is the same weighted sum its value
|
|
22
|
+
* is. `attributeGradients` is that, and `barycentricGradients` is what it rests on.
|
|
23
|
+
*
|
|
24
|
+
* Everything here takes plain numbers and fills arrays the caller owns, because the shader does the
|
|
25
|
+
* same arithmetic per pixel and the two have to be comparable term by term.
|
|
26
|
+
*/
|
|
27
|
+
/** Screen position and reciprocal clip w of one vertex: x, y, 1/w. */
|
|
28
|
+
export const SCREEN_VERTEX_FLOATS = 3;
|
|
29
|
+
/**
|
|
30
|
+
* Project one clip-space vertex into pixel coordinates.
|
|
31
|
+
*
|
|
32
|
+
* Fills `x, y, 1/w`. Answers **false behind the eye**, where the division has no meaning: a
|
|
33
|
+
* visibility buffer cannot record such a pixel in the first place — the rasteriser clipped the
|
|
34
|
+
* triangle before it was drawn — so reaching this with `w <= 0` means the identifier and the
|
|
35
|
+
* geometry have gone out of step, and a silent NaN would shade a plausible-looking wrong surface.
|
|
36
|
+
*/
|
|
37
|
+
export function screenVertex(clipX, clipY, clipW, width, height, out, at) {
|
|
38
|
+
if (!(clipW > 1e-9))
|
|
39
|
+
return false;
|
|
40
|
+
const inverse = 1 / clipW;
|
|
41
|
+
out[at] = (clipX * inverse * 0.5 + 0.5) * width;
|
|
42
|
+
out[at + 1] = (clipY * inverse * 0.5 + 0.5) * height;
|
|
43
|
+
out[at + 2] = inverse;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/** Twice the signed area of the screen triangle. Zero where it is degenerate. */
|
|
47
|
+
export function screenArea(screen) {
|
|
48
|
+
const x0 = screen[0];
|
|
49
|
+
const y0 = screen[1];
|
|
50
|
+
const x1 = screen[3];
|
|
51
|
+
const y1 = screen[4];
|
|
52
|
+
const x2 = screen[6];
|
|
53
|
+
const y2 = screen[7];
|
|
54
|
+
return (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The screen-space barycentric weights of a point, before perspective correction.
|
|
58
|
+
*
|
|
59
|
+
* Answers false for a degenerate triangle — one whose three screen positions are collinear, which
|
|
60
|
+
* covers no pixel and whose weights are a division by zero. A caller that reaches this has a
|
|
61
|
+
* visibility identifier for a triangle the rasteriser never drew.
|
|
62
|
+
*
|
|
63
|
+
* **A point outside the triangle gets a negative weight rather than a clamp.** Clamping is how a
|
|
64
|
+
* pixel on the far side of an edge ends up shaded as though it were on the triangle, which along a
|
|
65
|
+
* silhouette is a fringe of the wrong material.
|
|
66
|
+
*/
|
|
67
|
+
export function screenBarycentrics(screen, x, y, out) {
|
|
68
|
+
const area = screenArea(screen);
|
|
69
|
+
if (Math.abs(area) < 1e-12)
|
|
70
|
+
return false;
|
|
71
|
+
const x0 = screen[0];
|
|
72
|
+
const y0 = screen[1];
|
|
73
|
+
const x1 = screen[3];
|
|
74
|
+
const y1 = screen[4];
|
|
75
|
+
const x2 = screen[6];
|
|
76
|
+
const y2 = screen[7];
|
|
77
|
+
const inverse = 1 / area;
|
|
78
|
+
out[1] = ((x - x0) * (y2 - y0) - (x2 - x0) * (y - y0)) * inverse;
|
|
79
|
+
out[2] = ((x1 - x0) * (y - y0) - (x - x0) * (y1 - y0)) * inverse;
|
|
80
|
+
out[0] = 1 - out[1] - out[2];
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The perspective-correct weights, from the screen-space ones and the vertices' reciprocal `w`.
|
|
85
|
+
*
|
|
86
|
+
* Each screen weight is scaled by its vertex's `1/w` and the three renormalised. At an orthographic
|
|
87
|
+
* projection every `1/w` is equal and this is the identity, which is why the affine version looks
|
|
88
|
+
* right on a test quad facing the camera and wrong on the floor beneath it.
|
|
89
|
+
*/
|
|
90
|
+
export function perspectiveBarycentrics(screen, lambda, out) {
|
|
91
|
+
const w0 = lambda[0] * screen[2];
|
|
92
|
+
const w1 = lambda[1] * screen[5];
|
|
93
|
+
const w2 = lambda[2] * screen[8];
|
|
94
|
+
const sum = w0 + w1 + w2;
|
|
95
|
+
if (Math.abs(sum) < 1e-20)
|
|
96
|
+
return false;
|
|
97
|
+
const inverse = 1 / sum;
|
|
98
|
+
out[0] = w0 * inverse;
|
|
99
|
+
out[1] = w1 * inverse;
|
|
100
|
+
out[2] = w2 * inverse;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* How each perspective-correct weight changes with screen x and y, at one pixel.
|
|
105
|
+
*
|
|
106
|
+
* Fills six numbers: `d0/dx, d1/dx, d2/dx, d0/dy, d1/dy, d2/dy`.
|
|
107
|
+
*
|
|
108
|
+
* **Derived rather than differenced.** The screen weights are linear in `x` and `y`, so their
|
|
109
|
+
* gradients are constants of the triangle; the perspective-correct ones are a ratio of two linear
|
|
110
|
+
* functions, and the quotient rule gives the rest. What this buys over a finite difference is that
|
|
111
|
+
* it is exact at the pixel rather than an average over one, and that it costs no neighbours — a
|
|
112
|
+
* compute invocation has none.
|
|
113
|
+
*/
|
|
114
|
+
export function barycentricGradients(screen, lambda, out) {
|
|
115
|
+
const area = screenArea(screen);
|
|
116
|
+
if (Math.abs(area) < 1e-12)
|
|
117
|
+
return false;
|
|
118
|
+
const inverse = 1 / area;
|
|
119
|
+
const x0 = screen[0];
|
|
120
|
+
const y0 = screen[1];
|
|
121
|
+
const x1 = screen[3];
|
|
122
|
+
const y1 = screen[4];
|
|
123
|
+
const x2 = screen[6];
|
|
124
|
+
const y2 = screen[7];
|
|
125
|
+
/* The screen weights' own gradients, which are constant over the triangle. */
|
|
126
|
+
const d1dx = (y2 - y0) * inverse;
|
|
127
|
+
const d1dy = (x0 - x2) * inverse;
|
|
128
|
+
const d2dx = (y0 - y1) * inverse;
|
|
129
|
+
const d2dy = (x1 - x0) * inverse;
|
|
130
|
+
const d0dx = -d1dx - d2dx;
|
|
131
|
+
const d0dy = -d1dy - d2dy;
|
|
132
|
+
const iw0 = screen[2];
|
|
133
|
+
const iw1 = screen[5];
|
|
134
|
+
const iw2 = screen[8];
|
|
135
|
+
const n0 = lambda[0] * iw0;
|
|
136
|
+
const n1 = lambda[1] * iw1;
|
|
137
|
+
const n2 = lambda[2] * iw2;
|
|
138
|
+
const sum = n0 + n1 + n2;
|
|
139
|
+
if (Math.abs(sum) < 1e-20)
|
|
140
|
+
return false;
|
|
141
|
+
const inverseSum = 1 / sum;
|
|
142
|
+
/* The denominator's own gradient: the same weighted sum of the reciprocal w values. */
|
|
143
|
+
const dSumDx = d0dx * iw0 + d1dx * iw1 + d2dx * iw2;
|
|
144
|
+
const dSumDy = d0dy * iw0 + d1dy * iw1 + d2dy * iw2;
|
|
145
|
+
/* Quotient rule, per weight, with the shared denominator factored out. */
|
|
146
|
+
out[0] = (d0dx * iw0 - n0 * inverseSum * dSumDx) * inverseSum;
|
|
147
|
+
out[1] = (d1dx * iw1 - n1 * inverseSum * dSumDx) * inverseSum;
|
|
148
|
+
out[2] = (d2dx * iw2 - n2 * inverseSum * dSumDx) * inverseSum;
|
|
149
|
+
out[3] = (d0dy * iw0 - n0 * inverseSum * dSumDy) * inverseSum;
|
|
150
|
+
out[4] = (d1dy * iw1 - n1 * inverseSum * dSumDy) * inverseSum;
|
|
151
|
+
out[5] = (d2dy * iw2 - n2 * inverseSum * dSumDy) * inverseSum;
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
/** One attribute interpolated by the weights already computed. */
|
|
155
|
+
export function interpolate(a0, a1, a2, weights) {
|
|
156
|
+
return a0 * weights[0] + a1 * weights[1] + a2 * weights[2];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* One attribute's rate of change with screen x and y, from the weight gradients.
|
|
160
|
+
*
|
|
161
|
+
* An attribute is a weighted sum of three constants, so its gradient is the same sum of the
|
|
162
|
+
* weights' gradients. This is what a texture fetch's level of detail is computed from.
|
|
163
|
+
*/
|
|
164
|
+
export function attributeGradients(a0, a1, a2, gradients) {
|
|
165
|
+
return {
|
|
166
|
+
dx: a0 * gradients[0] + a1 * gradients[1] + a2 * gradients[2],
|
|
167
|
+
dy: a0 * gradients[3] + a1 * gradients[4] + a2 * gradients[5],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Which pixel a shading invocation is responsible for.
|
|
172
|
+
*
|
|
173
|
+
* A group covers `BIN_GROUP_SIZE` entries of one material's slice; an invocation past the end of
|
|
174
|
+
* the slice has no pixel, which is the ordinary case because the slice is not a multiple of the
|
|
175
|
+
* group size. Answers -1 there rather than the last pixel of the bin, which would shade it once
|
|
176
|
+
* per spare lane.
|
|
177
|
+
*/
|
|
178
|
+
export function binPixel(pixels, offset, count, invocation) {
|
|
179
|
+
if (invocation < 0 || invocation >= count)
|
|
180
|
+
return -1;
|
|
181
|
+
return pixels[offset + invocation] ?? -1;
|
|
182
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/** The directional shadow lookup, in TypeScript, so the second pipeline's copy has a reference. */
|
|
2
|
+
/**
|
|
3
|
+
* **`flat/directionalShadow.ts` in TypeScript, for one depth layer.**
|
|
4
|
+
*
|
|
5
|
+
* The lesson of the lit expression was a week old when this was written: a term that exists only
|
|
6
|
+
* as a shader is a term nothing can disagree with. So the lookup was written here first, tested
|
|
7
|
+
* here, and `SHADE_SHADOW_WGSL` beside it is the same arithmetic for the device with
|
|
8
|
+
* `gpu-parity.mjs` running both — which is the order the map itself then followed.
|
|
9
|
+
*
|
|
10
|
+
* **One layer, where the forward path has three.** That path keeps a static map, a peeled one
|
|
11
|
+
* holding the second static occluder, and a dynamic one for movers, and multiplies their
|
|
12
|
+
* transmissions — an arrangement its own comments argue for at length and which exists because its
|
|
13
|
+
* shadow *pool* is shared between lights and rationed across frames. The second pipeline has no
|
|
14
|
+
* such pool: it owns its geometry, and a pass owns whatever target it renders in `prepare`. When
|
|
15
|
+
* there is one caster set there is one map, and stating that is better than pretending the shape
|
|
16
|
+
* is the same.
|
|
17
|
+
*
|
|
18
|
+
* **Everything else is term for term**, because the two pipelines drawing one scene must not
|
|
19
|
+
* disagree about where a shadow ends. Each fade below returns *fully lit*, which is the thing that
|
|
20
|
+
* makes them dangerous: a guard that fires when it should not removes a shadow, and a missing
|
|
21
|
+
* shadow reads as a scene that never had one.
|
|
22
|
+
*/
|
|
23
|
+
/** How much of a texel the filter reaches, which sets the softness of an edge. */
|
|
24
|
+
export declare const SHADOW_TEXEL_SCALE = 1.35;
|
|
25
|
+
/**
|
|
26
|
+
* The most depth the receiver-plane compensation may carry a tap, in texels.
|
|
27
|
+
*
|
|
28
|
+
* **A product of an unbounded gradient and a bounded offset**, and `directionalShadow.ts` records
|
|
29
|
+
* paying for the version where only the offset was bounded: a gradient that has blown up turns a
|
|
30
|
+
* fraction of a texel into a depth swing of whole map units, the comparison flips on alternate
|
|
31
|
+
* shadow texels, and what draws is hard straight stripes along the map's texel grid — oblique on
|
|
32
|
+
* screen, because that grid is turned by the sun rather than by the camera.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SHADOW_SLOPE_TEXELS = 9.1;
|
|
35
|
+
/** Subtracted from every comparison, in depth-span units. The contact bias. */
|
|
36
|
+
export declare const SHADOW_DEPTH_BIAS = 0.14;
|
|
37
|
+
/** The band of `n · l` over which the shadow modulation is given up. See `shadowFactor`. */
|
|
38
|
+
export declare const SHADOW_TERMINATOR_BAND: readonly [number, number];
|
|
39
|
+
/**
|
|
40
|
+
* The stretch of stored depth, 0 to 1, over which a shadow is given up at the map's far end.
|
|
41
|
+
*
|
|
42
|
+
* **A fit has to keep its receivers short of it**, and that is why it is a name rather than two
|
|
43
|
+
* literals: in the scene fit the far end is the scene's own rim, where nothing lies beyond, and a
|
|
44
|
+
* fit that followed the eye first put the whole of the eye's sphere inside it — `fitShadow` derives
|
|
45
|
+
* its least depth reach from the first of these two numbers.
|
|
46
|
+
*/
|
|
47
|
+
export declare const SHADOW_DEPTH_FADE: readonly [number, number];
|
|
48
|
+
/**
|
|
49
|
+
* The twelve taps, transcribed from `flat/pointShadow.ts`.
|
|
50
|
+
*
|
|
51
|
+
* A Poisson set rather than a grid: a grid filters along its own axes and bands across them, and
|
|
52
|
+
* the sun turns the map's grid relative to the screen, so the banding arrives at an angle nobody
|
|
53
|
+
* can attribute to anything.
|
|
54
|
+
*/
|
|
55
|
+
export declare const SHADOW_PCF_OFFSETS: readonly (readonly [number, number])[];
|
|
56
|
+
export interface ShadowSettings {
|
|
57
|
+
/** 0 turns the whole lookup off, and off is exact rather than nearly. */
|
|
58
|
+
readonly strength: number;
|
|
59
|
+
readonly mapSize: number;
|
|
60
|
+
/** Metres the map's depth range spans, which turns a stored depth into a distance. */
|
|
61
|
+
readonly depthSpan: number;
|
|
62
|
+
/** Metres a shadow may travel along the ground before it has faded out. */
|
|
63
|
+
readonly maxDistance: number;
|
|
64
|
+
/** The steepest `|light.xz| / light.y` that still casts. */
|
|
65
|
+
readonly maxSlope: number;
|
|
66
|
+
readonly taps: number;
|
|
67
|
+
/** Toward the light, unit length, as `Environment.directionalDir` is. */
|
|
68
|
+
readonly lightDir: readonly [number, number, number];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The receiver plane: how the light-space depth changes per unit of the light's own `u` and `v`.
|
|
72
|
+
*
|
|
73
|
+
* **A fragment shader gets `dFdx`/`dFdy` and a compute invocation has none**, having no neighbours
|
|
74
|
+
* to difference against — the same fact `SHADE_SURFACE_WGSL` exists for. So this takes the two
|
|
75
|
+
* derivatives rather than computing them: the forward path passes what the hardware gave it, and
|
|
76
|
+
* the second pipeline passes what it derives from the barycentric gradients it already has. The
|
|
77
|
+
* arithmetic between them is one function, which is the whole point.
|
|
78
|
+
*
|
|
79
|
+
* **It is a two-by-two solve and it is refused where the system is ill-conditioned.** A triangle
|
|
80
|
+
* seen almost edge-on in the light's projection has a determinant near zero, and dividing by it
|
|
81
|
+
* turns a fraction of a texel into a depth swing of whole map units — which the clamp downstream
|
|
82
|
+
* then has to catch. Refusing here is cheaper and says what happened: a plane whose slope cannot be
|
|
83
|
+
* measured gets no compensation rather than a wrong one.
|
|
84
|
+
*
|
|
85
|
+
* **Exact only where the light's projection is orthographic**, which a directional light's is: `w`
|
|
86
|
+
* is one, so the light-space position is linear in the world position and a barycentric
|
|
87
|
+
* interpolation of the three corners is the real thing rather than an approximation of it.
|
|
88
|
+
*/
|
|
89
|
+
export declare function receiverPlaneDepthGradient(dx: readonly [number, number, number], dy: readonly [number, number, number], out: Float32Array): Float32Array;
|
|
90
|
+
/**
|
|
91
|
+
* The receiver plane a shading invocation can actually get, from the two things it already has.
|
|
92
|
+
*
|
|
93
|
+
* **A compute invocation has no neighbours, so the derivative has to be built rather than taken.**
|
|
94
|
+
* `SHADE_SURFACE_WGSL` already computes how each barycentric weight changes per pixel of screen —
|
|
95
|
+
* that is what a visibility buffer's shading needs for texture gradients — and a light-space
|
|
96
|
+
* position is a linear combination of the three corners with exactly those weights. So the
|
|
97
|
+
* derivative of the light-space position is the same combination of the corners with the *weight
|
|
98
|
+
* gradients*, which is what this assembles before handing it to the solve above.
|
|
99
|
+
*
|
|
100
|
+
* **Exact rather than approximate, because a directional light's projection is orthographic.** `w`
|
|
101
|
+
* is one everywhere, so the light-space position is linear in the world position and no perspective
|
|
102
|
+
* divide stands between the weights and the answer. A spot light would need the quotient rule here
|
|
103
|
+
* and this function would be wrong for it, which is worth knowing before one arrives.
|
|
104
|
+
*
|
|
105
|
+
* **The halving is the remap.** The lookup addresses the map in 0-to-1 coordinates and clip `x` and
|
|
106
|
+
* `y` run -1 to 1, so a slope stated per clip unit is twice the slope per map unit. Depth is not
|
|
107
|
+
* halved: this pipeline's light matrix already emits `z` in 0..1, which is the same asymmetry
|
|
108
|
+
* `shadowFactor` carries and for the same reason.
|
|
109
|
+
*
|
|
110
|
+
* Each corner is a light-space clip position, `x`, `y` and `z`, with `w` taken as one.
|
|
111
|
+
*/
|
|
112
|
+
export declare function receiverPlaneFromWeights(l0: readonly [number, number, number], l1: readonly [number, number, number], l2: readonly [number, number, number], gx: readonly [number, number, number], gy: readonly [number, number, number], out: Float32Array): Float32Array;
|
|
113
|
+
/** How much of a shadow survives having been cast this far along the ground. */
|
|
114
|
+
export declare function shadowReach(distance: number, maxDistance: number): number;
|
|
115
|
+
/**
|
|
116
|
+
* Whether one tap is lit, and by how much.
|
|
117
|
+
*
|
|
118
|
+
* **A tap behind an occluder is not simply dark**: how far the shadow has travelled along the
|
|
119
|
+
* ground decides how much of it is left, which is what keeps one map's worth of geometry from
|
|
120
|
+
* shadowing the whole world.
|
|
121
|
+
*/
|
|
122
|
+
export declare function directionalVisibility(receiverDepth: number, compareDepth: number, storedDepth: number, settings: ShadowSettings): number;
|
|
123
|
+
/**
|
|
124
|
+
* How much light reaches a receiver, from 0 in full shadow to 1 in full light.
|
|
125
|
+
*
|
|
126
|
+
* `lightPos` is the receiver in the light's clip space, before the divide. `depthGradient` is how
|
|
127
|
+
* the light-space depth changes across a pixel of the map — the receiver plane — which a fragment
|
|
128
|
+
* shader gets from `dFdx`/`dFdy` and a **compute invocation cannot**, having no neighbours. The
|
|
129
|
+
* second pipeline derives it from the barycentric gradients `SHADE_SURFACE_WGSL` already computes,
|
|
130
|
+
* which is the same reason that file computes them: a derivative has to come from somewhere.
|
|
131
|
+
*
|
|
132
|
+
* `depthAt` reads the map with nearest filtering, which is what the comparison assumes: the fetched
|
|
133
|
+
* depth belongs to the centre of the containing texel, and following the continuous coordinate
|
|
134
|
+
* instead leaves half a texel of uncompensated slope — the repeating ribs a grazing face shows.
|
|
135
|
+
*/
|
|
136
|
+
export declare function shadowFactor(lightPos: readonly [number, number, number, number], depthGradient: readonly [number, number], ndl: number, settings: ShadowSettings, depthAt: (u: number, v: number) => number): number;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/** The directional shadow lookup, in TypeScript, so the second pipeline's copy has a reference. */
|
|
2
|
+
import { DIRECTIONAL_SHADOW_FADE_START, POINT_SHADOW_FADE_START } from '../renderQuality.js';
|
|
3
|
+
/**
|
|
4
|
+
* **`flat/directionalShadow.ts` in TypeScript, for one depth layer.**
|
|
5
|
+
*
|
|
6
|
+
* The lesson of the lit expression was a week old when this was written: a term that exists only
|
|
7
|
+
* as a shader is a term nothing can disagree with. So the lookup was written here first, tested
|
|
8
|
+
* here, and `SHADE_SHADOW_WGSL` beside it is the same arithmetic for the device with
|
|
9
|
+
* `gpu-parity.mjs` running both — which is the order the map itself then followed.
|
|
10
|
+
*
|
|
11
|
+
* **One layer, where the forward path has three.** That path keeps a static map, a peeled one
|
|
12
|
+
* holding the second static occluder, and a dynamic one for movers, and multiplies their
|
|
13
|
+
* transmissions — an arrangement its own comments argue for at length and which exists because its
|
|
14
|
+
* shadow *pool* is shared between lights and rationed across frames. The second pipeline has no
|
|
15
|
+
* such pool: it owns its geometry, and a pass owns whatever target it renders in `prepare`. When
|
|
16
|
+
* there is one caster set there is one map, and stating that is better than pretending the shape
|
|
17
|
+
* is the same.
|
|
18
|
+
*
|
|
19
|
+
* **Everything else is term for term**, because the two pipelines drawing one scene must not
|
|
20
|
+
* disagree about where a shadow ends. Each fade below returns *fully lit*, which is the thing that
|
|
21
|
+
* makes them dangerous: a guard that fires when it should not removes a shadow, and a missing
|
|
22
|
+
* shadow reads as a scene that never had one.
|
|
23
|
+
*/
|
|
24
|
+
/** How much of a texel the filter reaches, which sets the softness of an edge. */
|
|
25
|
+
export const SHADOW_TEXEL_SCALE = 1.35;
|
|
26
|
+
/**
|
|
27
|
+
* The most depth the receiver-plane compensation may carry a tap, in texels.
|
|
28
|
+
*
|
|
29
|
+
* **A product of an unbounded gradient and a bounded offset**, and `directionalShadow.ts` records
|
|
30
|
+
* paying for the version where only the offset was bounded: a gradient that has blown up turns a
|
|
31
|
+
* fraction of a texel into a depth swing of whole map units, the comparison flips on alternate
|
|
32
|
+
* shadow texels, and what draws is hard straight stripes along the map's texel grid — oblique on
|
|
33
|
+
* screen, because that grid is turned by the sun rather than by the camera.
|
|
34
|
+
*/
|
|
35
|
+
export const SHADOW_SLOPE_TEXELS = 9.1;
|
|
36
|
+
/** Subtracted from every comparison, in depth-span units. The contact bias. */
|
|
37
|
+
export const SHADOW_DEPTH_BIAS = 0.14;
|
|
38
|
+
/** The band of `n · l` over which the shadow modulation is given up. See `shadowFactor`. */
|
|
39
|
+
export const SHADOW_TERMINATOR_BAND = [0.08, 0.2];
|
|
40
|
+
/**
|
|
41
|
+
* The stretch of stored depth, 0 to 1, over which a shadow is given up at the map's far end.
|
|
42
|
+
*
|
|
43
|
+
* **A fit has to keep its receivers short of it**, and that is why it is a name rather than two
|
|
44
|
+
* literals: in the scene fit the far end is the scene's own rim, where nothing lies beyond, and a
|
|
45
|
+
* fit that followed the eye first put the whole of the eye's sphere inside it — `fitShadow` derives
|
|
46
|
+
* its least depth reach from the first of these two numbers.
|
|
47
|
+
*/
|
|
48
|
+
export const SHADOW_DEPTH_FADE = [0.9, 1];
|
|
49
|
+
/**
|
|
50
|
+
* The twelve taps, transcribed from `flat/pointShadow.ts`.
|
|
51
|
+
*
|
|
52
|
+
* A Poisson set rather than a grid: a grid filters along its own axes and bands across them, and
|
|
53
|
+
* the sun turns the map's grid relative to the screen, so the banding arrives at an angle nobody
|
|
54
|
+
* can attribute to anything.
|
|
55
|
+
*/
|
|
56
|
+
export const SHADOW_PCF_OFFSETS = [
|
|
57
|
+
[-0.326, -0.406],
|
|
58
|
+
[0.519, 0.767],
|
|
59
|
+
[0.962, -0.195],
|
|
60
|
+
[-0.696, 0.457],
|
|
61
|
+
[-0.84, -0.074],
|
|
62
|
+
[0.185, -0.893],
|
|
63
|
+
[0.896, 0.412],
|
|
64
|
+
[-0.203, 0.621],
|
|
65
|
+
[0.473, -0.48],
|
|
66
|
+
[0.507, 0.064],
|
|
67
|
+
[-0.322, -0.933],
|
|
68
|
+
[-0.792, -0.598],
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* The receiver plane: how the light-space depth changes per unit of the light's own `u` and `v`.
|
|
72
|
+
*
|
|
73
|
+
* **A fragment shader gets `dFdx`/`dFdy` and a compute invocation has none**, having no neighbours
|
|
74
|
+
* to difference against — the same fact `SHADE_SURFACE_WGSL` exists for. So this takes the two
|
|
75
|
+
* derivatives rather than computing them: the forward path passes what the hardware gave it, and
|
|
76
|
+
* the second pipeline passes what it derives from the barycentric gradients it already has. The
|
|
77
|
+
* arithmetic between them is one function, which is the whole point.
|
|
78
|
+
*
|
|
79
|
+
* **It is a two-by-two solve and it is refused where the system is ill-conditioned.** A triangle
|
|
80
|
+
* seen almost edge-on in the light's projection has a determinant near zero, and dividing by it
|
|
81
|
+
* turns a fraction of a texel into a depth swing of whole map units — which the clamp downstream
|
|
82
|
+
* then has to catch. Refusing here is cheaper and says what happened: a plane whose slope cannot be
|
|
83
|
+
* measured gets no compensation rather than a wrong one.
|
|
84
|
+
*
|
|
85
|
+
* **Exact only where the light's projection is orthographic**, which a directional light's is: `w`
|
|
86
|
+
* is one, so the light-space position is linear in the world position and a barycentric
|
|
87
|
+
* interpolation of the three corners is the real thing rather than an approximation of it.
|
|
88
|
+
*/
|
|
89
|
+
export function receiverPlaneDepthGradient(dx, dy, out) {
|
|
90
|
+
const determinant = dx[0] * dy[1] - dx[1] * dy[0];
|
|
91
|
+
const conditioning = Math.hypot(dx[0], dx[1]) * Math.hypot(dy[0], dy[1]);
|
|
92
|
+
if (Math.abs(determinant) < 1e-4 * conditioning) {
|
|
93
|
+
out[0] = 0;
|
|
94
|
+
out[1] = 0;
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
out[0] = (dx[2] * dy[1] - dx[1] * dy[2]) / determinant;
|
|
98
|
+
out[1] = (dx[0] * dy[2] - dx[2] * dy[0]) / determinant;
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The receiver plane a shading invocation can actually get, from the two things it already has.
|
|
103
|
+
*
|
|
104
|
+
* **A compute invocation has no neighbours, so the derivative has to be built rather than taken.**
|
|
105
|
+
* `SHADE_SURFACE_WGSL` already computes how each barycentric weight changes per pixel of screen —
|
|
106
|
+
* that is what a visibility buffer's shading needs for texture gradients — and a light-space
|
|
107
|
+
* position is a linear combination of the three corners with exactly those weights. So the
|
|
108
|
+
* derivative of the light-space position is the same combination of the corners with the *weight
|
|
109
|
+
* gradients*, which is what this assembles before handing it to the solve above.
|
|
110
|
+
*
|
|
111
|
+
* **Exact rather than approximate, because a directional light's projection is orthographic.** `w`
|
|
112
|
+
* is one everywhere, so the light-space position is linear in the world position and no perspective
|
|
113
|
+
* divide stands between the weights and the answer. A spot light would need the quotient rule here
|
|
114
|
+
* and this function would be wrong for it, which is worth knowing before one arrives.
|
|
115
|
+
*
|
|
116
|
+
* **The halving is the remap.** The lookup addresses the map in 0-to-1 coordinates and clip `x` and
|
|
117
|
+
* `y` run -1 to 1, so a slope stated per clip unit is twice the slope per map unit. Depth is not
|
|
118
|
+
* halved: this pipeline's light matrix already emits `z` in 0..1, which is the same asymmetry
|
|
119
|
+
* `shadowFactor` carries and for the same reason.
|
|
120
|
+
*
|
|
121
|
+
* Each corner is a light-space clip position, `x`, `y` and `z`, with `w` taken as one.
|
|
122
|
+
*/
|
|
123
|
+
export function receiverPlaneFromWeights(l0, l1, l2, gx, gy, out) {
|
|
124
|
+
const along = (g, axis) => g[0] * l0[axis] +
|
|
125
|
+
g[1] * l1[axis] +
|
|
126
|
+
g[2] * l2[axis];
|
|
127
|
+
return receiverPlaneDepthGradient([along(gx, 0) * 0.5, along(gx, 1) * 0.5, along(gx, 2)], [along(gy, 0) * 0.5, along(gy, 1) * 0.5, along(gy, 2)], out);
|
|
128
|
+
}
|
|
129
|
+
/** GLSL's `smoothstep`, which is not `Math`'s anything. */
|
|
130
|
+
function smoothstep(edge0, edge1, x) {
|
|
131
|
+
const t = Math.min(Math.max((x - edge0) / (edge1 - edge0), 0), 1);
|
|
132
|
+
return t * t * (3 - 2 * t);
|
|
133
|
+
}
|
|
134
|
+
/** How much of a shadow survives having been cast this far along the ground. */
|
|
135
|
+
export function shadowReach(distance, maxDistance) {
|
|
136
|
+
return 1 - smoothstep(maxDistance * POINT_SHADOW_FADE_START, maxDistance, distance);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Whether one tap is lit, and by how much.
|
|
140
|
+
*
|
|
141
|
+
* **A tap behind an occluder is not simply dark**: how far the shadow has travelled along the
|
|
142
|
+
* ground decides how much of it is left, which is what keeps one map's worth of geometry from
|
|
143
|
+
* shadowing the whole world.
|
|
144
|
+
*/
|
|
145
|
+
export function directionalVisibility(receiverDepth, compareDepth, storedDepth, settings) {
|
|
146
|
+
if (compareDepth <= storedDepth)
|
|
147
|
+
return 1;
|
|
148
|
+
const rayDistance = Math.max(receiverDepth - storedDepth, 0) * settings.depthSpan;
|
|
149
|
+
const ground = rayDistance * Math.hypot(settings.lightDir[0], settings.lightDir[2]);
|
|
150
|
+
return 1 - shadowReach(ground, settings.maxDistance);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* How much light reaches a receiver, from 0 in full shadow to 1 in full light.
|
|
154
|
+
*
|
|
155
|
+
* `lightPos` is the receiver in the light's clip space, before the divide. `depthGradient` is how
|
|
156
|
+
* the light-space depth changes across a pixel of the map — the receiver plane — which a fragment
|
|
157
|
+
* shader gets from `dFdx`/`dFdy` and a **compute invocation cannot**, having no neighbours. The
|
|
158
|
+
* second pipeline derives it from the barycentric gradients `SHADE_SURFACE_WGSL` already computes,
|
|
159
|
+
* which is the same reason that file computes them: a derivative has to come from somewhere.
|
|
160
|
+
*
|
|
161
|
+
* `depthAt` reads the map with nearest filtering, which is what the comparison assumes: the fetched
|
|
162
|
+
* depth belongs to the centre of the containing texel, and following the continuous coordinate
|
|
163
|
+
* instead leaves half a texel of uncompensated slope — the repeating ribs a grazing face shows.
|
|
164
|
+
*/
|
|
165
|
+
export function shadowFactor(lightPos, depthGradient, ndl, settings, depthAt) {
|
|
166
|
+
/*
|
|
167
|
+
* **Four early-outs below, and every one of them is a cost rather than a correctness guard.**
|
|
168
|
+
* The result is `1 + (lit - 1) * amount` and `amount` is the product of all four fades, so a fade
|
|
169
|
+
* at zero returns exactly one whether or not the return fires — perturbing any of them changes
|
|
170
|
+
* no answer, which is recorded here rather than papered over. They stay because each one skips a
|
|
171
|
+
* loop of twelve texture reads, which on a full screen is the difference between a lookup and a
|
|
172
|
+
* pass. The bounds check is the one with a second job: without it the taps read outside the map.
|
|
173
|
+
*/
|
|
174
|
+
if (settings.strength <= 0)
|
|
175
|
+
return 1;
|
|
176
|
+
const w = lightPos[3];
|
|
177
|
+
if (w === 0)
|
|
178
|
+
return 1;
|
|
179
|
+
/*
|
|
180
|
+
* **`x` and `y` are remapped and `z` is not, and that is a convention rather than an asymmetry.**
|
|
181
|
+
* WebGPU clips `z` to 0..1 already; OpenGL clips it to -1..1, which is why the GLSL this is
|
|
182
|
+
* transcribed from remaps all three. This module is the second pipeline's and the second pipeline
|
|
183
|
+
* is WebGPU only, so it takes WebGPU's convention — and a caller handing it a GL-style depth gets
|
|
184
|
+
* a shadow that is half as deep as it should be and biased by half the map, which reads as
|
|
185
|
+
* everything being lit. `CLIP_CORRECTION` records the same family of mistake one level up.
|
|
186
|
+
*/
|
|
187
|
+
const px = (lightPos[0] / w) * 0.5 + 0.5;
|
|
188
|
+
const py = (lightPos[1] / w) * 0.5 + 0.5;
|
|
189
|
+
const pz = lightPos[2] / w;
|
|
190
|
+
const receiverFade = smoothstep(SHADOW_TERMINATOR_BAND[0], SHADOW_TERMINATOR_BAND[1], ndl);
|
|
191
|
+
if (receiverFade <= 0)
|
|
192
|
+
return 1;
|
|
193
|
+
if (pz > 1 || px < 0 || px > 1 || py < 0 || py > 1)
|
|
194
|
+
return 1;
|
|
195
|
+
const fromCentre = Math.max(Math.abs(px - 0.5) * 2, Math.abs(py - 0.5) * 2);
|
|
196
|
+
const edgeFade = (1 - smoothstep(0.72, 0.98, fromCentre)) *
|
|
197
|
+
(1 - smoothstep(SHADOW_DEPTH_FADE[0], SHADOW_DEPTH_FADE[1], pz));
|
|
198
|
+
if (edgeFade <= 0)
|
|
199
|
+
return 1;
|
|
200
|
+
const slope = Math.hypot(settings.lightDir[0], settings.lightDir[2]) /
|
|
201
|
+
Math.max(settings.lightDir[1], 0.001);
|
|
202
|
+
const lowElevationFade = 1 - smoothstep(settings.maxSlope * DIRECTIONAL_SHADOW_FADE_START, settings.maxSlope, slope);
|
|
203
|
+
if (lowElevationFade <= 0)
|
|
204
|
+
return 1;
|
|
205
|
+
const texel = SHADOW_TEXEL_SCALE / settings.mapSize;
|
|
206
|
+
const slopeLimit = SHADOW_SLOPE_TEXELS / settings.mapSize;
|
|
207
|
+
const taps = Math.max(1, Math.min(Math.trunc(settings.taps), SHADOW_PCF_OFFSETS.length));
|
|
208
|
+
let lit = 0;
|
|
209
|
+
for (let tap = 0; tap < taps; tap += 1) {
|
|
210
|
+
const offset = SHADOW_PCF_OFFSETS[tap];
|
|
211
|
+
const u = px + offset[0] * texel;
|
|
212
|
+
const v = py + offset[1] * texel;
|
|
213
|
+
const centreU = (Math.floor(u * settings.mapSize) + 0.5) / settings.mapSize;
|
|
214
|
+
const centreV = (Math.floor(v * settings.mapSize) + 0.5) / settings.mapSize;
|
|
215
|
+
const raw = depthGradient[0] * (centreU - px) + depthGradient[1] * (centreV - py);
|
|
216
|
+
const slopeOffset = Math.min(Math.max(raw, -slopeLimit), slopeLimit);
|
|
217
|
+
const receiverDepth = pz + slopeOffset;
|
|
218
|
+
const compare = receiverDepth - SHADOW_DEPTH_BIAS / settings.depthSpan;
|
|
219
|
+
lit += directionalVisibility(receiverDepth, compare, depthAt(u, v), settings);
|
|
220
|
+
}
|
|
221
|
+
lit /= taps;
|
|
222
|
+
const amount = settings.strength * edgeFade * lowElevationFade * receiverFade;
|
|
223
|
+
return 1 + (lit - 1) * amount;
|
|
224
|
+
}
|