@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,322 @@
|
|
|
1
|
+
/** The directional shadow lookup for the device, as the text both consumers include. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SHADOW_DEPTH_BIAS,
|
|
5
|
+
SHADOW_DEPTH_FADE,
|
|
6
|
+
SHADOW_PCF_OFFSETS,
|
|
7
|
+
SHADOW_SLOPE_TEXELS,
|
|
8
|
+
SHADOW_TERMINATOR_BAND,
|
|
9
|
+
SHADOW_TEXEL_SCALE,
|
|
10
|
+
} from '../../gpudriven/shadow.ts';
|
|
11
|
+
import { DIRECTIONAL_SHADOW_FADE_START, POINT_SHADOW_FADE_START } from '../../renderQuality.ts';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* **`gpudriven/shadow.ts` for the device, term for term, with `gpu-parity.mjs` running both.**
|
|
15
|
+
*
|
|
16
|
+
* The lesson is a week old and this is the first term written with it in hand: a shading term that
|
|
17
|
+
* exists only as a shader is a term nothing can disagree with. The lit expression had no reference
|
|
18
|
+
* until the highlight went in; this one had a reference before it had a shader.
|
|
19
|
+
*
|
|
20
|
+
* **The map is read through a function the *including* module defines**, `shadowDepthAt(u, v)`.
|
|
21
|
+
* The parity entry point reads a storage buffer, because that is what `gpuCompute.mjs` can hand a
|
|
22
|
+
* check; the shading pass reads a depth texture. What must not differ between them is the
|
|
23
|
+
* arithmetic around the read, so the arithmetic is here and the read is not.
|
|
24
|
+
*
|
|
25
|
+
* Every constant is interpolated from the reference rather than restated. A texel scale that is
|
|
26
|
+
* 1.35 here and 1.3 there is a shadow with a different softness on each path, and nothing on screen
|
|
27
|
+
* says which one is the engine's.
|
|
28
|
+
*/
|
|
29
|
+
export const SHADE_SHADOW_WGSL = /* wgsl */ `
|
|
30
|
+
struct ShadowSettings {
|
|
31
|
+
strength: f32,
|
|
32
|
+
mapSize: f32,
|
|
33
|
+
depthSpan: f32,
|
|
34
|
+
maxDistance: f32,
|
|
35
|
+
maxSlope: f32,
|
|
36
|
+
taps: f32,
|
|
37
|
+
padA: f32,
|
|
38
|
+
padB: f32,
|
|
39
|
+
lightDir: vec4<f32>,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const SHADOW_TAPS: array<vec2<f32>, ${SHADOW_PCF_OFFSETS.length}> = array<vec2<f32>, ${SHADOW_PCF_OFFSETS.length}>(
|
|
43
|
+
${SHADOW_PCF_OFFSETS.map(([x, y]) => ` vec2<f32>(${x.toFixed(3)}, ${y.toFixed(3)})`).join(',\n')}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* The receiver plane, from the two derivatives of the light-space position.
|
|
48
|
+
*
|
|
49
|
+
* Takes them rather than computing them: a fragment shader has dFdx and dFdy and a compute
|
|
50
|
+
* invocation has neither, so the forward path would pass what the hardware gave it and the second
|
|
51
|
+
* pipeline passes what it derives from the barycentric gradients it already has. Refused where the
|
|
52
|
+
* two-by-two system is ill-conditioned — see gpudriven/shadow.ts, which carries the argument.
|
|
53
|
+
*/
|
|
54
|
+
fn receiverPlaneDepthGradient(dx: vec3<f32>, dy: vec3<f32>) -> vec2<f32> {
|
|
55
|
+
let determinant = dx.x * dy.y - dx.y * dy.x;
|
|
56
|
+
let conditioning = length(dx.xy) * length(dy.xy);
|
|
57
|
+
if (abs(determinant) < 1e-4 * conditioning) {
|
|
58
|
+
return vec2<f32>(0.0, 0.0);
|
|
59
|
+
}
|
|
60
|
+
return vec2<f32>(
|
|
61
|
+
(dx.z * dy.y - dx.y * dy.z) / determinant,
|
|
62
|
+
(dx.x * dy.z - dx.z * dy.x) / determinant,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* The receiver plane from the barycentric gradients the shading pass already has.
|
|
68
|
+
*
|
|
69
|
+
* gpudriven/shadow.ts is the twin and carries the argument: a light-space position is a linear
|
|
70
|
+
* combination of the three corners, so its derivative is the same combination of the weight
|
|
71
|
+
* gradients. Exact because a directional light's projection is orthographic.
|
|
72
|
+
*
|
|
73
|
+
* The halving on x and y is the remap into the map's 0-to-1 coordinates. Depth is not halved,
|
|
74
|
+
* because this pipeline's light matrix already emits z in 0..1.
|
|
75
|
+
*/
|
|
76
|
+
fn receiverPlaneFromWeights(
|
|
77
|
+
l0: vec3<f32>,
|
|
78
|
+
l1: vec3<f32>,
|
|
79
|
+
l2: vec3<f32>,
|
|
80
|
+
gx: vec3<f32>,
|
|
81
|
+
gy: vec3<f32>,
|
|
82
|
+
) -> vec2<f32> {
|
|
83
|
+
let dx = vec3<f32>(
|
|
84
|
+
(gx.x * l0.x + gx.y * l1.x + gx.z * l2.x) * 0.5,
|
|
85
|
+
(gx.x * l0.y + gx.y * l1.y + gx.z * l2.y) * 0.5,
|
|
86
|
+
gx.x * l0.z + gx.y * l1.z + gx.z * l2.z,
|
|
87
|
+
);
|
|
88
|
+
let dy = vec3<f32>(
|
|
89
|
+
(gy.x * l0.x + gy.y * l1.x + gy.z * l2.x) * 0.5,
|
|
90
|
+
(gy.x * l0.y + gy.y * l1.y + gy.z * l2.y) * 0.5,
|
|
91
|
+
gy.x * l0.z + gy.y * l1.z + gy.z * l2.z,
|
|
92
|
+
);
|
|
93
|
+
return receiverPlaneDepthGradient(dx, dy);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* How much of a shadow survives having been cast this far along the ground. */
|
|
97
|
+
fn shadowReach(distance: f32, maxDistance: f32) -> f32 {
|
|
98
|
+
return 1.0 - smoothstep(maxDistance * ${POINT_SHADOW_FADE_START.toFixed(2)}, maxDistance, distance);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fn directionalVisibility(
|
|
102
|
+
receiverDepth: f32,
|
|
103
|
+
compareDepth: f32,
|
|
104
|
+
storedDepth: f32,
|
|
105
|
+
settings: ShadowSettings,
|
|
106
|
+
) -> f32 {
|
|
107
|
+
if (compareDepth <= storedDepth) {
|
|
108
|
+
return 1.0;
|
|
109
|
+
}
|
|
110
|
+
let rayDistance = max(receiverDepth - storedDepth, 0.0) * settings.depthSpan;
|
|
111
|
+
let ground = rayDistance * length(settings.lightDir.xz);
|
|
112
|
+
return 1.0 - shadowReach(ground, settings.maxDistance);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
* How much light reaches a receiver: 0 in full shadow, 1 in full light.
|
|
117
|
+
*
|
|
118
|
+
* Four early-outs, and the reference records that every one is a cost rather than a correctness
|
|
119
|
+
* guard — the result is a mix by the product of all four fades, so a fade at zero returns one
|
|
120
|
+
* whether or not the return fires. They stay because each skips twelve reads. The bounds check has
|
|
121
|
+
* a second job: without it the taps read outside the map.
|
|
122
|
+
*/
|
|
123
|
+
fn shadowFactor(
|
|
124
|
+
lightPos: vec4<f32>,
|
|
125
|
+
depthGradient: vec2<f32>,
|
|
126
|
+
ndl: f32,
|
|
127
|
+
settings: ShadowSettings,
|
|
128
|
+
) -> f32 {
|
|
129
|
+
if (settings.strength <= 0.0) {
|
|
130
|
+
return 1.0;
|
|
131
|
+
}
|
|
132
|
+
if (lightPos.w == 0.0) {
|
|
133
|
+
return 1.0;
|
|
134
|
+
}
|
|
135
|
+
/*
|
|
136
|
+
* x and y are remapped and z is not: WebGPU clips z to 0..1 already, where the GLSL this is
|
|
137
|
+
* transcribed from clips it to -1..1. See gpudriven/shadow.ts, which carries the argument.
|
|
138
|
+
*/
|
|
139
|
+
let ndc = lightPos.xyz / lightPos.w;
|
|
140
|
+
let p = vec3<f32>(ndc.x * 0.5 + 0.5, ndc.y * 0.5 + 0.5, ndc.z);
|
|
141
|
+
|
|
142
|
+
let receiverFade = smoothstep(${SHADOW_TERMINATOR_BAND[0].toFixed(2)}, ${SHADOW_TERMINATOR_BAND[1].toFixed(2)}, ndl);
|
|
143
|
+
if (receiverFade <= 0.0) {
|
|
144
|
+
return 1.0;
|
|
145
|
+
}
|
|
146
|
+
if (p.z > 1.0 || p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0) {
|
|
147
|
+
return 1.0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let fromCentre = max(abs(p.x - 0.5) * 2.0, abs(p.y - 0.5) * 2.0);
|
|
151
|
+
let edgeFade = (1.0 - smoothstep(0.72, 0.98, fromCentre)) * (1.0 - smoothstep(${SHADOW_DEPTH_FADE[0].toFixed(2)}, ${SHADOW_DEPTH_FADE[1].toFixed(2)}, p.z));
|
|
152
|
+
if (edgeFade <= 0.0) {
|
|
153
|
+
return 1.0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let slope = length(settings.lightDir.xz) / max(settings.lightDir.y, 0.001);
|
|
157
|
+
let lowElevationFade =
|
|
158
|
+
1.0 - smoothstep(settings.maxSlope * ${DIRECTIONAL_SHADOW_FADE_START.toFixed(2)}, settings.maxSlope, slope);
|
|
159
|
+
if (lowElevationFade <= 0.0) {
|
|
160
|
+
return 1.0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let texel = ${SHADOW_TEXEL_SCALE.toFixed(2)} / settings.mapSize;
|
|
164
|
+
let slopeLimit = ${SHADOW_SLOPE_TEXELS.toFixed(1)} / settings.mapSize;
|
|
165
|
+
let taps = u32(clamp(settings.taps, 1.0, ${SHADOW_PCF_OFFSETS.length}.0));
|
|
166
|
+
|
|
167
|
+
var lit = 0.0;
|
|
168
|
+
for (var tap = 0u; tap < taps; tap = tap + 1u) {
|
|
169
|
+
let offset = SHADOW_TAPS[tap] * texel;
|
|
170
|
+
let u = p.x + offset.x;
|
|
171
|
+
let v = p.y + offset.y;
|
|
172
|
+
/*
|
|
173
|
+
* The fetched depth belongs to the centre of the containing texel, not to the continuous
|
|
174
|
+
* coordinate — so the plane compensation is measured to that centre. Following the continuous
|
|
175
|
+
* one leaves half a texel of uncompensated slope, which is the repeating ribs a grazing face
|
|
176
|
+
* shows.
|
|
177
|
+
*/
|
|
178
|
+
let centreU = (floor(u * settings.mapSize) + 0.5) / settings.mapSize;
|
|
179
|
+
let centreV = (floor(v * settings.mapSize) + 0.5) / settings.mapSize;
|
|
180
|
+
let raw = depthGradient.x * (centreU - p.x) + depthGradient.y * (centreV - p.y);
|
|
181
|
+
let slopeOffset = clamp(raw, -slopeLimit, slopeLimit);
|
|
182
|
+
let receiverDepth = p.z + slopeOffset;
|
|
183
|
+
let compare = receiverDepth - ${SHADOW_DEPTH_BIAS.toFixed(2)} / settings.depthSpan;
|
|
184
|
+
lit = lit + directionalVisibility(receiverDepth, compare, shadowDepthAt(u, v), settings);
|
|
185
|
+
}
|
|
186
|
+
lit = lit / f32(taps);
|
|
187
|
+
|
|
188
|
+
let amount = settings.strength * edgeFade * lowElevationFade * receiverFade;
|
|
189
|
+
return 1.0 + (lit - 1.0) * amount;
|
|
190
|
+
}
|
|
191
|
+
`;
|
|
192
|
+
|
|
193
|
+
/** Floats the parity entry point's settings block holds. Matches `ShadowSettings`. */
|
|
194
|
+
export const SHADOW_SETTINGS_FLOATS = 12;
|
|
195
|
+
|
|
196
|
+
/** Floats a receiver: the light-space clip position, the depth gradient and `n · l`. */
|
|
197
|
+
export const SHADOW_RECEIVER_FLOATS = 8;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* An entry point that does nothing but look a shadow up, so `gpu-parity.mjs` can compare the
|
|
201
|
+
* function above with `gpudriven/shadow.ts` directly.
|
|
202
|
+
*
|
|
203
|
+
* It defines `shadowDepthAt` over a storage buffer, which is what a compute harness can be handed;
|
|
204
|
+
* the shading pass will define it over a depth texture. Nearest, which is what the comparison
|
|
205
|
+
* assumes — the arithmetic above measures its compensation to the texel centre.
|
|
206
|
+
*/
|
|
207
|
+
export const SHADOW_PARITY_WGSL = /* wgsl */ `
|
|
208
|
+
@group(0) @binding(0) var<storage, read> params: array<f32>;
|
|
209
|
+
@group(0) @binding(1) var<storage, read> settingsBuffer: array<f32>;
|
|
210
|
+
@group(0) @binding(2) var<storage, read> receivers: array<f32>;
|
|
211
|
+
@group(0) @binding(3) var<storage, read> shadowMap: array<f32>;
|
|
212
|
+
@group(0) @binding(4) var<storage, read> gradients: array<f32>;
|
|
213
|
+
@group(0) @binding(5) var<storage, read_write> factors: array<f32>;
|
|
214
|
+
|
|
215
|
+
fn shadowDepthAt(u: f32, v: f32) -> f32 {
|
|
216
|
+
let size = settingsBuffer[1];
|
|
217
|
+
let x = clamp(floor(u * size), 0.0, size - 1.0);
|
|
218
|
+
let y = clamp(floor(v * size), 0.0, size - 1.0);
|
|
219
|
+
return shadowMap[u32(y) * u32(size) + u32(x)];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
${SHADE_SHADOW_WGSL}
|
|
223
|
+
|
|
224
|
+
@compute @workgroup_size(64)
|
|
225
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
226
|
+
if (id.x >= u32(params[0])) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
var settings: ShadowSettings;
|
|
230
|
+
settings.strength = settingsBuffer[0];
|
|
231
|
+
settings.mapSize = settingsBuffer[1];
|
|
232
|
+
settings.depthSpan = settingsBuffer[2];
|
|
233
|
+
settings.maxDistance = settingsBuffer[3];
|
|
234
|
+
settings.maxSlope = settingsBuffer[4];
|
|
235
|
+
settings.taps = settingsBuffer[5];
|
|
236
|
+
settings.lightDir = vec4<f32>(settingsBuffer[8], settingsBuffer[9], settingsBuffer[10], 0.0);
|
|
237
|
+
|
|
238
|
+
let at = id.x * ${SHADOW_RECEIVER_FLOATS}u;
|
|
239
|
+
/*
|
|
240
|
+
* The gradient is solved here rather than passed, so the solve is checked too — the corpus feeds
|
|
241
|
+
* the two derivative vectors and the reference runs the same two-by-two.
|
|
242
|
+
*/
|
|
243
|
+
let gradient = receiverPlaneDepthGradient(
|
|
244
|
+
vec3<f32>(gradients[id.x * 6u], gradients[id.x * 6u + 1u], gradients[id.x * 6u + 2u]),
|
|
245
|
+
vec3<f32>(gradients[id.x * 6u + 3u], gradients[id.x * 6u + 4u], gradients[id.x * 6u + 5u]),
|
|
246
|
+
);
|
|
247
|
+
factors[id.x] = shadowFactor(
|
|
248
|
+
vec4<f32>(receivers[at], receivers[at + 1u], receivers[at + 2u], receivers[at + 3u]),
|
|
249
|
+
gradient,
|
|
250
|
+
receivers[at + 6u],
|
|
251
|
+
settings,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
`;
|
|
255
|
+
|
|
256
|
+
/** Floats a case of the receiver-plane check: three corners and the two weight gradients. */
|
|
257
|
+
export const RECEIVER_PLANE_FLOATS = 15;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The gradient assembly alone, as a dispatch, because it is the one piece of the shadow the
|
|
261
|
+
* shading pass computes for itself.
|
|
262
|
+
*
|
|
263
|
+
* The eleventh check hands the solve two derivative vectors. This is the step *before* that one:
|
|
264
|
+
* turning three light-space corners and two barycentric gradients into those vectors, which is
|
|
265
|
+
* where a factor of two or a transposed weight lives. Both are invisible in a picture — a gradient
|
|
266
|
+
* off by two compensates a tap by half of what it should, which is acne on grazing surfaces and
|
|
267
|
+
* looks like a bias that wants tuning.
|
|
268
|
+
*/
|
|
269
|
+
export const RECEIVER_PLANE_PARITY_WGSL = /* wgsl */ `
|
|
270
|
+
@group(0) @binding(0) var<storage, read> params: array<f32>;
|
|
271
|
+
@group(0) @binding(1) var<storage, read> cases: array<f32>;
|
|
272
|
+
@group(0) @binding(2) var<storage, read_write> planes: array<f32>;
|
|
273
|
+
|
|
274
|
+
fn receiverPlaneDepthGradient(dx: vec3<f32>, dy: vec3<f32>) -> vec2<f32> {
|
|
275
|
+
let determinant = dx.x * dy.y - dx.y * dy.x;
|
|
276
|
+
let conditioning = length(dx.xy) * length(dy.xy);
|
|
277
|
+
if (abs(determinant) < 1e-4 * conditioning) {
|
|
278
|
+
return vec2<f32>(0.0, 0.0);
|
|
279
|
+
}
|
|
280
|
+
return vec2<f32>(
|
|
281
|
+
(dx.z * dy.y - dx.y * dy.z) / determinant,
|
|
282
|
+
(dx.x * dy.z - dx.z * dy.x) / determinant,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
fn receiverPlaneFromWeights(
|
|
287
|
+
l0: vec3<f32>,
|
|
288
|
+
l1: vec3<f32>,
|
|
289
|
+
l2: vec3<f32>,
|
|
290
|
+
gx: vec3<f32>,
|
|
291
|
+
gy: vec3<f32>,
|
|
292
|
+
) -> vec2<f32> {
|
|
293
|
+
let dx = vec3<f32>(
|
|
294
|
+
(gx.x * l0.x + gx.y * l1.x + gx.z * l2.x) * 0.5,
|
|
295
|
+
(gx.x * l0.y + gx.y * l1.y + gx.z * l2.y) * 0.5,
|
|
296
|
+
gx.x * l0.z + gx.y * l1.z + gx.z * l2.z,
|
|
297
|
+
);
|
|
298
|
+
let dy = vec3<f32>(
|
|
299
|
+
(gy.x * l0.x + gy.y * l1.x + gy.z * l2.x) * 0.5,
|
|
300
|
+
(gy.x * l0.y + gy.y * l1.y + gy.z * l2.y) * 0.5,
|
|
301
|
+
gy.x * l0.z + gy.y * l1.z + gy.z * l2.z,
|
|
302
|
+
);
|
|
303
|
+
return receiverPlaneDepthGradient(dx, dy);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@compute @workgroup_size(64)
|
|
307
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
308
|
+
if (id.x >= u32(params[0])) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
let at = id.x * ${RECEIVER_PLANE_FLOATS}u;
|
|
312
|
+
let plane = receiverPlaneFromWeights(
|
|
313
|
+
vec3<f32>(cases[at], cases[at + 1u], cases[at + 2u]),
|
|
314
|
+
vec3<f32>(cases[at + 3u], cases[at + 4u], cases[at + 5u]),
|
|
315
|
+
vec3<f32>(cases[at + 6u], cases[at + 7u], cases[at + 8u]),
|
|
316
|
+
vec3<f32>(cases[at + 9u], cases[at + 10u], cases[at + 11u]),
|
|
317
|
+
vec3<f32>(cases[at + 12u], cases[at + 13u], cases[at + 14u]),
|
|
318
|
+
);
|
|
319
|
+
planes[id.x * 2u] = plane.x;
|
|
320
|
+
planes[id.x * 2u + 1u] = plane.y;
|
|
321
|
+
}
|
|
322
|
+
`;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { GPU_DRIVEN_VERTEX_FLOATS } from '../../gpudriven/sceneUpload.ts';
|
|
2
|
+
import { DECODE_WGSL, decodeResourcesWgsl } from './decode.wgsl.ts';
|
|
3
|
+
import { MATERIAL_SLOTS, MATERIAL_TABLE_WGSL } from './materialTable.wgsl.ts';
|
|
4
|
+
import { MESH_TRANSFORM_WGSL } from './meshTransform.wgsl.ts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The hardware path: one indirect draw that fills the visibility buffer for the whole frame.
|
|
8
|
+
*
|
|
9
|
+
* **Hand-written WGSL, for the reason `cull.wgsl.ts` gives at length**: WebGL2 has no compute
|
|
10
|
+
* stage and no indirect draw, so there is no GLSL original to generate this from and nothing it
|
|
11
|
+
* can break by being wrong. What keeps it honest is `scripts/gpu-parity.mjs`, which runs the
|
|
12
|
+
* packing below against `gpudriven/visbuffer.ts` on a real device.
|
|
13
|
+
*
|
|
14
|
+
* **Every surviving cluster is an instance of a fixed 128-triangle draw.** `indirect.ts` carries
|
|
15
|
+
* the argument layout and the reason: one block for the frame rather than thousands, and a cluster
|
|
16
|
+
* with fewer triangles emitting degenerate ones for the remainder. The degenerate case is a real
|
|
17
|
+
* branch here rather than a clamp — clamping draws a cluster's last triangle once per unused slot,
|
|
18
|
+
* which is a sliver along the edge of every cluster that is not exactly full.
|
|
19
|
+
*
|
|
20
|
+
* **The fragment writes an identifier, not a colour.** Depth is the hardware's; what lands in the
|
|
21
|
+
* target is which triangle of which cluster covered the pixel, and the shading reads it later —
|
|
22
|
+
* which is the whole point of a visibility buffer. `VIS_EMPTY` is what a caller clears the target
|
|
23
|
+
* to, because zero is a legal identifier.
|
|
24
|
+
*
|
|
25
|
+
* **It binds a material anyway, and only for the alpha test.** That is the one decision a pixel
|
|
26
|
+
* cannot defer: a cutout leaf that is discarded in the shading pass has already written its
|
|
27
|
+
* identifier here, so what stood behind it was never rastered and there is nothing left to shade.
|
|
28
|
+
* So this stage carries the material table and the whole decode machinery to answer one question —
|
|
29
|
+
* is this texel solid enough to own the pixel — and **a material whose cutoff is zero asks none of
|
|
30
|
+
* it**, which is what keeps an opaque scene paying nothing. A cluster carries one material, so the
|
|
31
|
+
* branch is coherent across every fragment of a draw rather than divergent within one.
|
|
32
|
+
*
|
|
33
|
+
* **The shadow pass shares this module's vertex stage and has no fragment stage at all**, so a
|
|
34
|
+
* cutout surface casts the shadow of its whole quad. That is a real limitation rather than an
|
|
35
|
+
* oversight: giving the depth-only pass a fragment stage would give it the material table and the
|
|
36
|
+
* decode tables too, and the map is drawn every frame over the whole scene. `docs/IMPROVEMENTS.md`
|
|
37
|
+
* carries the row.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The cutout rule, which is `gpudriven/alphaTest.ts`'s `alphaKept` and must stay it.
|
|
42
|
+
*
|
|
43
|
+
* **`>=` rather than `>`** is the boundary every alpha test gets wrong, and getting it wrong shows
|
|
44
|
+
* as a one-texel seam around every leaf rather than as anything failing. **The guard is a separate
|
|
45
|
+
* return rather than arithmetic** because a NaN alpha must be discarded when a test was asked for
|
|
46
|
+
* and kept when it was not, and **it is a negated `>` rather than a `<=`** because a device may
|
|
47
|
+
* assume NaN never arrives and this is where the reference had to move to meet it. The reference's
|
|
48
|
+
* header carries both, and `scripts/gpu-parity.mjs` holds the two to each other on a device.
|
|
49
|
+
*/
|
|
50
|
+
const ALPHA_TEST_WGSL = /* wgsl */ `
|
|
51
|
+
fn alphaKept(alpha: f32, cutoff: f32) -> bool {
|
|
52
|
+
if (!(cutoff > 0.0)) { return true; }
|
|
53
|
+
return alpha >= cutoff;
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The footprint-to-level expression, which is `shade.wgsl.ts`'s `surfaceLod` and must stay it.
|
|
59
|
+
*
|
|
60
|
+
* **Two stages choose a mip level for one texel now**, and they choose it from different evidence:
|
|
61
|
+
* this one differences its neighbours, and the shading pass differences barycentric gradients
|
|
62
|
+
* because a compute invocation has no neighbours. What they must not differ about is what a
|
|
63
|
+
* footprint means once measured, which is this.
|
|
64
|
+
*/
|
|
65
|
+
const SURFACE_LOD_WGSL = /* wgsl */ `
|
|
66
|
+
fn surfaceLod(gradX: vec2<f32>, gradY: vec2<f32>, size: f32) -> f32 {
|
|
67
|
+
let footprint = max(length(gradX), length(gradY)) * size;
|
|
68
|
+
return max(log2(max(footprint, 1e-30)), 0.0);
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The raster pass.
|
|
74
|
+
*
|
|
75
|
+
* `clusterList` is the compacted output of the cull, `clusterMeta` is four words a cluster — index
|
|
76
|
+
* offset, index count, cluster identifier, mesh — and `transforms` is sixteen floats a mesh. A
|
|
77
|
+
* cluster reaches its transform through its mesh rather than carrying one, because a mesh drawn
|
|
78
|
+
* twice is two instances of one cluster set and a transform per cluster would store it twice.
|
|
79
|
+
*/
|
|
80
|
+
export const VISBUFFER_RASTER_WGSL = /* wgsl */ `
|
|
81
|
+
struct Varying {
|
|
82
|
+
@builtin(position) position: vec4<f32>,
|
|
83
|
+
@location(0) @interpolate(flat) visibility: u32,
|
|
84
|
+
/** The cluster's material and this vertex's texture coordinate, for the alpha test. */
|
|
85
|
+
@location(1) @interpolate(flat) material: u32,
|
|
86
|
+
@location(2) uv: vec2<f32>,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The two numbers the decode machinery needs that nothing else here carries. */
|
|
90
|
+
struct RasterParams {
|
|
91
|
+
/** x is the simulation time, y the latent layer's edge in texels, and two spare. */
|
|
92
|
+
values: vec4<f32>,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
${MATERIAL_TABLE_WGSL}
|
|
96
|
+
@group(0) @binding(0) var<storage, read> viewProj: array<f32, 16>;
|
|
97
|
+
@group(0) @binding(1) var<storage, read> clusterList: array<u32>;
|
|
98
|
+
@group(0) @binding(2) var<storage, read> clusterMeta: array<u32>;
|
|
99
|
+
@group(0) @binding(3) var<storage, read> indices: array<u32>;
|
|
100
|
+
/** Eleven floats a vertex: position, normal, colour, uv. One buffer, for the shading pass's
|
|
101
|
+
storage budget — see shade.wgsl.ts. This stage reads the position and the uv. */
|
|
102
|
+
@group(0) @binding(4) var<storage, read> vertices: array<f32>;
|
|
103
|
+
@group(0) @binding(5) var<storage, read> transforms: array<f32>;
|
|
104
|
+
/** One material a cluster, read in the vertex stage and carried flat. */
|
|
105
|
+
@group(0) @binding(6) var<storage, read> materialOf: array<u32>;
|
|
106
|
+
@group(0) @binding(7) var<uniform> materials: array<Material, ${MATERIAL_SLOTS}>;
|
|
107
|
+
@group(0) @binding(8) var<uniform> rasterParams: RasterParams;
|
|
108
|
+
${decodeResourcesWgsl({ group: 0, latents: 9, clampSampler: 10, repeatSampler: 11, nodes: 12, weights: 13 })}
|
|
109
|
+
fn decodeLatentSize() -> f32 {
|
|
110
|
+
return rasterParams.values.y;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
${DECODE_WGSL}
|
|
114
|
+
${SURFACE_LOD_WGSL}
|
|
115
|
+
${ALPHA_TEST_WGSL}
|
|
116
|
+
|
|
117
|
+
const VIS_TRIANGLE_BITS: u32 = 7u;
|
|
118
|
+
const VIS_MAX_TRIANGLES: u32 = 128u;
|
|
119
|
+
|
|
120
|
+
/* The same expression as packVisibility in gpudriven/visbuffer.ts, checked against it on the
|
|
121
|
+
device by scripts/gpu-parity.mjs. Seven bits of triangle, twenty-five of cluster. */
|
|
122
|
+
fn packVisibility(cluster: u32, triangle: u32) -> u32 {
|
|
123
|
+
return (cluster << VIS_TRIANGLE_BITS) | (triangle & (VIS_MAX_TRIANGLES - 1u));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
${MESH_TRANSFORM_WGSL}
|
|
127
|
+
|
|
128
|
+
@vertex
|
|
129
|
+
fn vertexMain(
|
|
130
|
+
@builtin(vertex_index) vertex: u32,
|
|
131
|
+
@builtin(instance_index) slot: u32,
|
|
132
|
+
) -> Varying {
|
|
133
|
+
var out: Varying;
|
|
134
|
+
let cluster = clusterList[slot];
|
|
135
|
+
/* metaAt, because meta is a reserved word in WGSL. A backtick cannot appear in this comment
|
|
136
|
+
either: it would close the template literal the shader is written in. This shader was
|
|
137
|
+
committed and read by a generator check for a day before anything compiled it. */
|
|
138
|
+
let metaAt = cluster * 4u;
|
|
139
|
+
let indexOffset = clusterMeta[metaAt];
|
|
140
|
+
let indexCount = clusterMeta[metaAt + 1u];
|
|
141
|
+
let clusterId = clusterMeta[metaAt + 2u];
|
|
142
|
+
let mesh = clusterMeta[metaAt + 3u];
|
|
143
|
+
|
|
144
|
+
let triangle = vertex / 3u;
|
|
145
|
+
/* Past this cluster's own triangles: collapse to a point, which covers no pixel. See the
|
|
146
|
+
header for why this is not a clamp onto the last real triangle. */
|
|
147
|
+
if (triangle * 3u >= indexCount) {
|
|
148
|
+
out.position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
|
|
149
|
+
out.visibility = 0u;
|
|
150
|
+
out.material = 0u;
|
|
151
|
+
out.uv = vec2<f32>(0.0);
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let index = indices[indexOffset + vertex];
|
|
156
|
+
let at = index * ${GPU_DRIVEN_VERTEX_FLOATS}u;
|
|
157
|
+
let local = vec3<f32>(vertices[at], vertices[at + 1u], vertices[at + 2u]);
|
|
158
|
+
let world = worldOf(mesh, local);
|
|
159
|
+
|
|
160
|
+
out.position = vec4<f32>(
|
|
161
|
+
viewProj[0] * world.x + viewProj[4] * world.y + viewProj[8] * world.z + viewProj[12],
|
|
162
|
+
viewProj[1] * world.x + viewProj[5] * world.y + viewProj[9] * world.z + viewProj[13],
|
|
163
|
+
viewProj[2] * world.x + viewProj[6] * world.y + viewProj[10] * world.z + viewProj[14],
|
|
164
|
+
viewProj[3] * world.x + viewProj[7] * world.y + viewProj[11] * world.z + viewProj[15],
|
|
165
|
+
);
|
|
166
|
+
out.visibility = packVisibility(clusterId, triangle);
|
|
167
|
+
/* By the cluster's own record rather than the mesh's, which is where materialOf is indexed. */
|
|
168
|
+
out.material = materialOf[cluster];
|
|
169
|
+
out.uv = vec2<f32>(vertices[at + 9u], vertices[at + 10u]);
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@fragment
|
|
174
|
+
fn fragmentMain(in: Varying) -> @location(0) u32 {
|
|
175
|
+
let entry = materials[min(in.material, ${MATERIAL_SLOTS - 1}u)];
|
|
176
|
+
let cutoff = entry.orm.z;
|
|
177
|
+
/*
|
|
178
|
+
* **A cutoff of zero skips the fetch outright**, and with it the whole decode interpreter. That
|
|
179
|
+
* branch is on a value read from a uniform by a flat-interpolated index that is constant across
|
|
180
|
+
* the draw, so it is coherent — every fragment of a cluster takes the same side of it.
|
|
181
|
+
*
|
|
182
|
+
* **The derivatives are taken before the branch**, because a texture level derived inside
|
|
183
|
+
* non-uniform control flow is what the language forbids and a discard below makes the rest of
|
|
184
|
+
* this function non-uniform anyway. shade.wgsl.ts computes the same footprint from barycentric
|
|
185
|
+
* gradients instead, having no neighbouring invocations to difference against.
|
|
186
|
+
*/
|
|
187
|
+
let uv = in.uv * entry.maps.xy;
|
|
188
|
+
let lod = surfaceLod(dpdx(uv), dpdy(uv), rasterParams.values.y);
|
|
189
|
+
/*
|
|
190
|
+
* **This branch duplicates alphaKept's own guard and is not redundant**: alphaKept answers what
|
|
191
|
+
* the picture is and this decides what the frame pays. A material with no cutout skips the
|
|
192
|
+
* decode interpreter entirely, which is the whole of why the raster can carry it at all.
|
|
193
|
+
*/
|
|
194
|
+
if (cutoff > 0.0 && entry.programs.x != NO_PROGRAM) {
|
|
195
|
+
let alpha = decodeProgram(entry.programs.x, uv, lod, rasterParams.values.x).w;
|
|
196
|
+
if (!alphaKept(alpha, cutoff)) { discard; }
|
|
197
|
+
}
|
|
198
|
+
return in.visibility;
|
|
199
|
+
}
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The packing alone, as a dispatch, so the layout above can be checked against the reference.
|
|
204
|
+
*
|
|
205
|
+
* **A raster pass cannot be compared to a processor-side model and a bit layout can.** What goes
|
|
206
|
+
* wrong in a visibility buffer is almost never the rasterisation — the hardware does that — it is
|
|
207
|
+
* one field overflowing into the next, silently, on the one asset whose clusters are full. So the
|
|
208
|
+
* expression is lifted out and run over generated pairs until it agrees with `packVisibility` and
|
|
209
|
+
* `unpackVisibility` for every one of them.
|
|
210
|
+
*/
|
|
211
|
+
export const VISBUFFER_PACK_WGSL = `
|
|
212
|
+
@group(0) @binding(0) var<storage, read> clusters: array<u32>;
|
|
213
|
+
@group(0) @binding(1) var<storage, read> triangles: array<u32>;
|
|
214
|
+
@group(0) @binding(2) var<storage, read_write> packed: array<u32>;
|
|
215
|
+
@group(0) @binding(3) var<storage, read_write> roundTrip: array<u32>;
|
|
216
|
+
|
|
217
|
+
const VIS_TRIANGLE_BITS: u32 = 7u;
|
|
218
|
+
const VIS_MAX_TRIANGLES: u32 = 128u;
|
|
219
|
+
|
|
220
|
+
@compute @workgroup_size(64)
|
|
221
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
222
|
+
if (id.x >= arrayLength(&clusters)) { return; }
|
|
223
|
+
let value = (clusters[id.x] << VIS_TRIANGLE_BITS) | (triangles[id.x] & (VIS_MAX_TRIANGLES - 1u));
|
|
224
|
+
packed[id.x] = value;
|
|
225
|
+
/* Unpacked and re-packed, so a layout that packs consistently and unpacks wrongly is caught
|
|
226
|
+
as well as one that packs wrongly at all. */
|
|
227
|
+
let cluster = value >> VIS_TRIANGLE_BITS;
|
|
228
|
+
let triangle = value & (VIS_MAX_TRIANGLES - 1u);
|
|
229
|
+
roundTrip[id.x] = select(0u, 1u, cluster == clusters[id.x] && triangle == triangles[id.x]);
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The cutout rule alone, as a dispatch, so it can be checked against `gpudriven/alphaTest.ts`.
|
|
235
|
+
*
|
|
236
|
+
* **The same function the raster calls, included rather than copied.** A second spelling of a
|
|
237
|
+
* four-line comparison is exactly the kind of thing that stays right for a year and then does not,
|
|
238
|
+
* and the failure it produces — a seam one texel wide around every cutout surface — reads as a
|
|
239
|
+
* mipmap problem. This shares the declaration, so breaking the rule breaks the check.
|
|
240
|
+
*/
|
|
241
|
+
export const VISBUFFER_ALPHA_WGSL = /* wgsl */ `
|
|
242
|
+
@group(0) @binding(0) var<storage, read> alphas: array<f32>;
|
|
243
|
+
@group(0) @binding(1) var<storage, read> cutoffs: array<f32>;
|
|
244
|
+
@group(0) @binding(2) var<storage, read_write> kept: array<f32>;
|
|
245
|
+
${ALPHA_TEST_WGSL}
|
|
246
|
+
@compute @workgroup_size(64)
|
|
247
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
248
|
+
if (id.x >= arrayLength(&alphas)) { return; }
|
|
249
|
+
kept[id.x] = select(0.0, 1.0, alphaKept(alphas[id.x], cutoffs[id.x]));
|
|
250
|
+
}
|
|
251
|
+
`;
|