@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,56 @@
|
|
|
1
|
+
/** Composing the world's distance field, on the device, because 707 ms is not a frame. */
|
|
2
|
+
/**
|
|
3
|
+
* **This is the only version of `composeGlobalField` that can run in a frame.**
|
|
4
|
+
*
|
|
5
|
+
* The TypeScript in `gi/globalField.ts` is the reference and says so in its own header: it visits
|
|
6
|
+
* every sample of every cascade for every instance it cannot cull outright, deliberately, because
|
|
7
|
+
* a reference that was already accelerated would be a second thing to be wrong rather than the
|
|
8
|
+
* thing the first is checked by. Measured by `scripts/gi-schemes.mjs`, that costs **707 ms a
|
|
9
|
+
* frame** for 32 instances over four cascades of 65 cubed — 35 million inverse transforms and
|
|
10
|
+
* trilinear reads, which is exactly the shape a GPU is for and exactly the shape a CPU is not.
|
|
11
|
+
*
|
|
12
|
+
* **One invocation a sample, and no culling at all.** The reference culls an instance further from
|
|
13
|
+
* a cascade than that cascade's reach, and the measurement that justified it there — 19.4 ms
|
|
14
|
+
* against 150.2 — is a statement about a serial loop. Here every sample is already parallel, so
|
|
15
|
+
* what the cull would save is a branch per instance per thread and what it would cost is a
|
|
16
|
+
* divergent one. It is left out, and `scripts/gi-parity.mjs` is what proves that changes no answer:
|
|
17
|
+
* the cull cannot change a result, only the time taken to reach it, because a culled instance is
|
|
18
|
+
* one whose contribution the minimum would have discarded.
|
|
19
|
+
*
|
|
20
|
+
* **The layouts are the reference's, restated rather than shared, and that is the hazard.** A
|
|
21
|
+
* shader and a TypeScript function cannot import a struct from each other, so the eight-corner
|
|
22
|
+
* blend below and `read()` in `globalField.ts` are two spellings of one decision. `gi-parity.mjs`
|
|
23
|
+
* runs both over generated input and compares every sample, which is the arrangement
|
|
24
|
+
* `gpu-parity.mjs` established for exactly this reason.
|
|
25
|
+
*/
|
|
26
|
+
/** Floats per instance in the `instances` buffer. See `INSTANCE_*` below for what they are. */
|
|
27
|
+
export declare const COMPOSE_INSTANCE_FLOATS = 32;
|
|
28
|
+
/** Where each field of an instance record starts, in floats. */
|
|
29
|
+
export declare const INSTANCE_INVERSE = 0;
|
|
30
|
+
export declare const INSTANCE_SCALE = 16;
|
|
31
|
+
export declare const INSTANCE_BOUNDS = 17;
|
|
32
|
+
export declare const INSTANCE_DIMS = 23;
|
|
33
|
+
export declare const INSTANCE_OFFSET = 26;
|
|
34
|
+
/** The instance's own colour, three floats. White where a consumer declared none. */
|
|
35
|
+
export declare const INSTANCE_ALBEDO = 28;
|
|
36
|
+
/**
|
|
37
|
+
* Floats in the `params` buffer: cascade origin, step, dims, reach, instance count, output base.
|
|
38
|
+
*
|
|
39
|
+
* **Every cascade has its own copy, at its own 256-byte-aligned offset.** `queue.writeBuffer` is a
|
|
40
|
+
* queue operation and is not ordered against the commands of an encoder, so rewriting one params
|
|
41
|
+
* buffer between dispatches gives every dispatch the *last* write — three cascades composed with
|
|
42
|
+
* the outermost one's origin and step, which looks like a field that is simply wrong everywhere.
|
|
43
|
+
*/
|
|
44
|
+
export declare const COMPOSE_PARAM_FLOATS = 12;
|
|
45
|
+
/** Where a cascade's samples start in the shared output, in floats. `params[9]`. */
|
|
46
|
+
export declare const COMPOSE_OUTPUT_BASE = 9;
|
|
47
|
+
/**
|
|
48
|
+
* Bytes between one cascade's params and the next.
|
|
49
|
+
*
|
|
50
|
+
* A storage binding's offset must be a multiple of `minStorageBufferOffsetAlignment`, which is 256
|
|
51
|
+
* on every device this targets — the same limit the GPU-driven pyramid's levels are padded to.
|
|
52
|
+
*/
|
|
53
|
+
export declare const COMPOSE_PARAM_STRIDE = 256;
|
|
54
|
+
/** Invocations a workgroup. 64 is this backend's default everywhere else. */
|
|
55
|
+
export declare const COMPOSE_WORKGROUP = 64;
|
|
56
|
+
export declare const COMPOSE_FIELD_WGSL = "\nstruct Params {\n originX: f32,\n originY: f32,\n originZ: f32,\n step: f32,\n countX: f32,\n countY: f32,\n countZ: f32,\n reach: f32,\n instances: f32,\n padA: f32,\n padB: f32,\n padC: f32,\n};\n\n@group(0) @binding(0) var<storage, read> params: array<f32>;\n@group(0) @binding(1) var<storage, read> instances: array<f32>;\n@group(0) @binding(2) var<storage, read> sources: array<f32>;\n@group(0) @binding(3) var<storage, read_write> field: array<f32>;\n/* The colour of whatever won the union at each sample, three floats. See GlobalFieldCascade. */\n@group(0) @binding(4) var<storage, read_write> albedo: array<f32>;\n\n/*\n * The eight-corner blend of one object's field, at a point already in that object's space.\n *\n * Clamped at the grid's edge, exactly as the reference is: a sample past the last plane takes that\n * plane rather than extrapolating, and the index stops one short so the pair it interpolates\n * between is always inside.\n */\nfn sourceAt(base: u32, bounds0: vec3<f32>, bounds1: vec3<f32>, dims: vec3<f32>, p: vec3<f32>) -> f32 {\n /* One step for all three axes, because an object's voxels are cubic. bakeObjectSdf is why. */\n let step = (bounds1.x - bounds0.x) / (dims.x - 1.0);\n\n var low = vec3<f32>(0.0, 0.0, 0.0);\n var frac = vec3<f32>(0.0, 0.0, 0.0);\n for (var axis = 0u; axis < 3u; axis = axis + 1u) {\n let count = dims[axis];\n let local = (p[axis] - bounds0[axis]) / step;\n let clamped = clamp(local, 0.0, count - 1.0);\n let index = min(floor(clamped), count - 2.0);\n low[axis] = index;\n frac[axis] = clamped - index;\n }\n\n let nx = u32(dims.x);\n let ny = u32(dims.y);\n let lx = u32(low.x);\n let ly = u32(low.y);\n let lz = u32(low.z);\n\n var total = 0.0;\n for (var cz = 0u; cz < 2u; cz = cz + 1u) {\n let wz = select(1.0 - frac.z, frac.z, cz == 1u);\n for (var cy = 0u; cy < 2u; cy = cy + 1u) {\n let wy = select(1.0 - frac.y, frac.y, cy == 1u);\n for (var cx = 0u; cx < 2u; cx = cx + 1u) {\n let wx = select(1.0 - frac.x, frac.x, cx == 1u);\n let at = lx + cx + nx * (ly + cy + ny * (lz + cz));\n total = total + sources[base + at] * wx * wy * wz;\n }\n }\n }\n return total;\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n let countX = u32(params[4]);\n let countY = u32(params[5]);\n let countZ = u32(params[6]);\n let total = countX * countY * countZ;\n let index = id.x;\n if (index >= total) {\n return;\n }\n\n let ix = index % countX;\n let iy = (index / countX) % countY;\n let iz = index / (countX * countY);\n let step = params[3];\n let world = vec3<f32>(\n params[0] + f32(ix) * step,\n params[1] + f32(iy) * step,\n params[2] + f32(iz) * step,\n );\n\n /* The reach, which is both the initial value and a bound on what any instance can lower it to. */\n var best = params[7];\n /* White, so a sample no instance reached is neutral rather than a light that vanishes. */\n var bestAlbedo = vec3<f32>(1.0, 1.0, 1.0);\n let instanceCount = u32(params[8]);\n\n for (var i = 0u; i < instanceCount; i = i + 1u) {\n let base = i * 32u;\n\n /*\n * The world point carried into the object's space through the **inverse**. Column-major, the\n * order gl-matrix stores a matrix in, which is the order the reference reads it in too.\n */\n let object = vec3<f32>(\n instances[base + 0u] * world.x + instances[base + 4u] * world.y + instances[base + 8u] * world.z + instances[base + 12u],\n instances[base + 1u] * world.x + instances[base + 5u] * world.y + instances[base + 9u] * world.z + instances[base + 13u],\n instances[base + 2u] * world.x + instances[base + 6u] * world.y + instances[base + 10u] * world.z + instances[base + 14u],\n );\n\n let scale = instances[base + 16u];\n let bounds0 = vec3<f32>(\n instances[base + 17u],\n instances[base + 17u + 1u],\n instances[base + 17u + 2u],\n );\n let bounds1 = vec3<f32>(\n instances[base + 17u + 3u],\n instances[base + 17u + 4u],\n instances[base + 17u + 5u],\n );\n\n /*\n * **Outside the source's box, bounded two ways and the larger taken.** The distance to the box\n * alone is a true bound and a useless one: just outside it says zero, so a sphere trace stops\n * on a phantom shell around every instance. d(q) >= d(c) - |q - c| by the triangle\n * inequality, against the field's own value at the nearest point of the box, is the bound that\n * reports the real clearance. See sampleInstance in globalField.ts.\n */\n let clamped = clamp(object, bounds0, bounds1);\n let outside = length(object - clamped);\n\n var distance = 0.0;\n if (outside > 0.0) {\n let dims = vec3<f32>(\n instances[base + 23u],\n instances[base + 23u + 1u],\n instances[base + 23u + 2u],\n );\n let sourceBase = u32(instances[base + 26u]);\n let atBox = sourceAt(sourceBase, bounds0, bounds1, dims, clamped);\n distance = max(outside, atBox - outside) * scale;\n } else {\n let dims = vec3<f32>(\n instances[base + 23u],\n instances[base + 23u + 1u],\n instances[base + 23u + 2u],\n );\n let sourceBase = u32(instances[base + 26u]);\n distance = sourceAt(sourceBase, bounds0, bounds1, dims, object) * scale;\n }\n\n /*\n * **The minimum, because the union of two solids is the nearer surface** \u2014 and the colour goes\n * with it rather than beside it. Writing the albedo unconditionally would paint every sample\n * with whichever instance happened to come last, which is a field of the right shape in the\n * wrong colours and looks like a lighting bug rather than a composition one.\n */\n if (distance < best) {\n best = distance;\n bestAlbedo = vec3<f32>(\n instances[base + 28u],\n instances[base + 28u + 1u],\n instances[base + 28u + 2u],\n );\n }\n }\n\n /*\n * **Into this cascade's own region of one shared buffer.** Without the base every cascade writes\n * the same samples and the last one wins, which reads as a field that has only its outermost\n * level \u2014 the innermost detail simply absent, at the resolution a viewer is closest to.\n */\n field[u32(params[9]) + index] = best;\n let colourAt = (u32(params[9]) + index) * 3u;\n albedo[colourAt] = bestAlbedo.x;\n albedo[colourAt + 1u] = bestAlbedo.y;\n albedo[colourAt + 2u] = bestAlbedo.z;\n}\n";
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/** Composing the world's distance field, on the device, because 707 ms is not a frame. */
|
|
2
|
+
/**
|
|
3
|
+
* **This is the only version of `composeGlobalField` that can run in a frame.**
|
|
4
|
+
*
|
|
5
|
+
* The TypeScript in `gi/globalField.ts` is the reference and says so in its own header: it visits
|
|
6
|
+
* every sample of every cascade for every instance it cannot cull outright, deliberately, because
|
|
7
|
+
* a reference that was already accelerated would be a second thing to be wrong rather than the
|
|
8
|
+
* thing the first is checked by. Measured by `scripts/gi-schemes.mjs`, that costs **707 ms a
|
|
9
|
+
* frame** for 32 instances over four cascades of 65 cubed — 35 million inverse transforms and
|
|
10
|
+
* trilinear reads, which is exactly the shape a GPU is for and exactly the shape a CPU is not.
|
|
11
|
+
*
|
|
12
|
+
* **One invocation a sample, and no culling at all.** The reference culls an instance further from
|
|
13
|
+
* a cascade than that cascade's reach, and the measurement that justified it there — 19.4 ms
|
|
14
|
+
* against 150.2 — is a statement about a serial loop. Here every sample is already parallel, so
|
|
15
|
+
* what the cull would save is a branch per instance per thread and what it would cost is a
|
|
16
|
+
* divergent one. It is left out, and `scripts/gi-parity.mjs` is what proves that changes no answer:
|
|
17
|
+
* the cull cannot change a result, only the time taken to reach it, because a culled instance is
|
|
18
|
+
* one whose contribution the minimum would have discarded.
|
|
19
|
+
*
|
|
20
|
+
* **The layouts are the reference's, restated rather than shared, and that is the hazard.** A
|
|
21
|
+
* shader and a TypeScript function cannot import a struct from each other, so the eight-corner
|
|
22
|
+
* blend below and `read()` in `globalField.ts` are two spellings of one decision. `gi-parity.mjs`
|
|
23
|
+
* runs both over generated input and compares every sample, which is the arrangement
|
|
24
|
+
* `gpu-parity.mjs` established for exactly this reason.
|
|
25
|
+
*/
|
|
26
|
+
/** Floats per instance in the `instances` buffer. See `INSTANCE_*` below for what they are. */
|
|
27
|
+
export const COMPOSE_INSTANCE_FLOATS = 32;
|
|
28
|
+
/** Where each field of an instance record starts, in floats. */
|
|
29
|
+
export const INSTANCE_INVERSE = 0;
|
|
30
|
+
export const INSTANCE_SCALE = 16;
|
|
31
|
+
export const INSTANCE_BOUNDS = 17;
|
|
32
|
+
export const INSTANCE_DIMS = 23;
|
|
33
|
+
export const INSTANCE_OFFSET = 26;
|
|
34
|
+
/** The instance's own colour, three floats. White where a consumer declared none. */
|
|
35
|
+
export const INSTANCE_ALBEDO = 28;
|
|
36
|
+
/**
|
|
37
|
+
* Floats in the `params` buffer: cascade origin, step, dims, reach, instance count, output base.
|
|
38
|
+
*
|
|
39
|
+
* **Every cascade has its own copy, at its own 256-byte-aligned offset.** `queue.writeBuffer` is a
|
|
40
|
+
* queue operation and is not ordered against the commands of an encoder, so rewriting one params
|
|
41
|
+
* buffer between dispatches gives every dispatch the *last* write — three cascades composed with
|
|
42
|
+
* the outermost one's origin and step, which looks like a field that is simply wrong everywhere.
|
|
43
|
+
*/
|
|
44
|
+
export const COMPOSE_PARAM_FLOATS = 12;
|
|
45
|
+
/** Where a cascade's samples start in the shared output, in floats. `params[9]`. */
|
|
46
|
+
export const COMPOSE_OUTPUT_BASE = 9;
|
|
47
|
+
/**
|
|
48
|
+
* Bytes between one cascade's params and the next.
|
|
49
|
+
*
|
|
50
|
+
* A storage binding's offset must be a multiple of `minStorageBufferOffsetAlignment`, which is 256
|
|
51
|
+
* on every device this targets — the same limit the GPU-driven pyramid's levels are padded to.
|
|
52
|
+
*/
|
|
53
|
+
export const COMPOSE_PARAM_STRIDE = 256;
|
|
54
|
+
/** Invocations a workgroup. 64 is this backend's default everywhere else. */
|
|
55
|
+
export const COMPOSE_WORKGROUP = 64;
|
|
56
|
+
export const COMPOSE_FIELD_WGSL = /* wgsl */ `
|
|
57
|
+
struct Params {
|
|
58
|
+
originX: f32,
|
|
59
|
+
originY: f32,
|
|
60
|
+
originZ: f32,
|
|
61
|
+
step: f32,
|
|
62
|
+
countX: f32,
|
|
63
|
+
countY: f32,
|
|
64
|
+
countZ: f32,
|
|
65
|
+
reach: f32,
|
|
66
|
+
instances: f32,
|
|
67
|
+
padA: f32,
|
|
68
|
+
padB: f32,
|
|
69
|
+
padC: f32,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
@group(0) @binding(0) var<storage, read> params: array<f32>;
|
|
73
|
+
@group(0) @binding(1) var<storage, read> instances: array<f32>;
|
|
74
|
+
@group(0) @binding(2) var<storage, read> sources: array<f32>;
|
|
75
|
+
@group(0) @binding(3) var<storage, read_write> field: array<f32>;
|
|
76
|
+
/* The colour of whatever won the union at each sample, three floats. See GlobalFieldCascade. */
|
|
77
|
+
@group(0) @binding(4) var<storage, read_write> albedo: array<f32>;
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* The eight-corner blend of one object's field, at a point already in that object's space.
|
|
81
|
+
*
|
|
82
|
+
* Clamped at the grid's edge, exactly as the reference is: a sample past the last plane takes that
|
|
83
|
+
* plane rather than extrapolating, and the index stops one short so the pair it interpolates
|
|
84
|
+
* between is always inside.
|
|
85
|
+
*/
|
|
86
|
+
fn sourceAt(base: u32, bounds0: vec3<f32>, bounds1: vec3<f32>, dims: vec3<f32>, p: vec3<f32>) -> f32 {
|
|
87
|
+
/* One step for all three axes, because an object's voxels are cubic. bakeObjectSdf is why. */
|
|
88
|
+
let step = (bounds1.x - bounds0.x) / (dims.x - 1.0);
|
|
89
|
+
|
|
90
|
+
var low = vec3<f32>(0.0, 0.0, 0.0);
|
|
91
|
+
var frac = vec3<f32>(0.0, 0.0, 0.0);
|
|
92
|
+
for (var axis = 0u; axis < 3u; axis = axis + 1u) {
|
|
93
|
+
let count = dims[axis];
|
|
94
|
+
let local = (p[axis] - bounds0[axis]) / step;
|
|
95
|
+
let clamped = clamp(local, 0.0, count - 1.0);
|
|
96
|
+
let index = min(floor(clamped), count - 2.0);
|
|
97
|
+
low[axis] = index;
|
|
98
|
+
frac[axis] = clamped - index;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let nx = u32(dims.x);
|
|
102
|
+
let ny = u32(dims.y);
|
|
103
|
+
let lx = u32(low.x);
|
|
104
|
+
let ly = u32(low.y);
|
|
105
|
+
let lz = u32(low.z);
|
|
106
|
+
|
|
107
|
+
var total = 0.0;
|
|
108
|
+
for (var cz = 0u; cz < 2u; cz = cz + 1u) {
|
|
109
|
+
let wz = select(1.0 - frac.z, frac.z, cz == 1u);
|
|
110
|
+
for (var cy = 0u; cy < 2u; cy = cy + 1u) {
|
|
111
|
+
let wy = select(1.0 - frac.y, frac.y, cy == 1u);
|
|
112
|
+
for (var cx = 0u; cx < 2u; cx = cx + 1u) {
|
|
113
|
+
let wx = select(1.0 - frac.x, frac.x, cx == 1u);
|
|
114
|
+
let at = lx + cx + nx * (ly + cy + ny * (lz + cz));
|
|
115
|
+
total = total + sources[base + at] * wx * wy * wz;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return total;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@compute @workgroup_size(${COMPOSE_WORKGROUP})
|
|
123
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
124
|
+
let countX = u32(params[4]);
|
|
125
|
+
let countY = u32(params[5]);
|
|
126
|
+
let countZ = u32(params[6]);
|
|
127
|
+
let total = countX * countY * countZ;
|
|
128
|
+
let index = id.x;
|
|
129
|
+
if (index >= total) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let ix = index % countX;
|
|
134
|
+
let iy = (index / countX) % countY;
|
|
135
|
+
let iz = index / (countX * countY);
|
|
136
|
+
let step = params[3];
|
|
137
|
+
let world = vec3<f32>(
|
|
138
|
+
params[0] + f32(ix) * step,
|
|
139
|
+
params[1] + f32(iy) * step,
|
|
140
|
+
params[2] + f32(iz) * step,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
/* The reach, which is both the initial value and a bound on what any instance can lower it to. */
|
|
144
|
+
var best = params[7];
|
|
145
|
+
/* White, so a sample no instance reached is neutral rather than a light that vanishes. */
|
|
146
|
+
var bestAlbedo = vec3<f32>(1.0, 1.0, 1.0);
|
|
147
|
+
let instanceCount = u32(params[8]);
|
|
148
|
+
|
|
149
|
+
for (var i = 0u; i < instanceCount; i = i + 1u) {
|
|
150
|
+
let base = i * ${COMPOSE_INSTANCE_FLOATS}u;
|
|
151
|
+
|
|
152
|
+
/*
|
|
153
|
+
* The world point carried into the object's space through the **inverse**. Column-major, the
|
|
154
|
+
* order gl-matrix stores a matrix in, which is the order the reference reads it in too.
|
|
155
|
+
*/
|
|
156
|
+
let object = vec3<f32>(
|
|
157
|
+
instances[base + 0u] * world.x + instances[base + 4u] * world.y + instances[base + 8u] * world.z + instances[base + 12u],
|
|
158
|
+
instances[base + 1u] * world.x + instances[base + 5u] * world.y + instances[base + 9u] * world.z + instances[base + 13u],
|
|
159
|
+
instances[base + 2u] * world.x + instances[base + 6u] * world.y + instances[base + 10u] * world.z + instances[base + 14u],
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
let scale = instances[base + ${INSTANCE_SCALE}u];
|
|
163
|
+
let bounds0 = vec3<f32>(
|
|
164
|
+
instances[base + ${INSTANCE_BOUNDS}u],
|
|
165
|
+
instances[base + ${INSTANCE_BOUNDS}u + 1u],
|
|
166
|
+
instances[base + ${INSTANCE_BOUNDS}u + 2u],
|
|
167
|
+
);
|
|
168
|
+
let bounds1 = vec3<f32>(
|
|
169
|
+
instances[base + ${INSTANCE_BOUNDS}u + 3u],
|
|
170
|
+
instances[base + ${INSTANCE_BOUNDS}u + 4u],
|
|
171
|
+
instances[base + ${INSTANCE_BOUNDS}u + 5u],
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
/*
|
|
175
|
+
* **Outside the source's box, bounded two ways and the larger taken.** The distance to the box
|
|
176
|
+
* alone is a true bound and a useless one: just outside it says zero, so a sphere trace stops
|
|
177
|
+
* on a phantom shell around every instance. d(q) >= d(c) - |q - c| by the triangle
|
|
178
|
+
* inequality, against the field's own value at the nearest point of the box, is the bound that
|
|
179
|
+
* reports the real clearance. See sampleInstance in globalField.ts.
|
|
180
|
+
*/
|
|
181
|
+
let clamped = clamp(object, bounds0, bounds1);
|
|
182
|
+
let outside = length(object - clamped);
|
|
183
|
+
|
|
184
|
+
var distance = 0.0;
|
|
185
|
+
if (outside > 0.0) {
|
|
186
|
+
let dims = vec3<f32>(
|
|
187
|
+
instances[base + 23u],
|
|
188
|
+
instances[base + 23u + 1u],
|
|
189
|
+
instances[base + 23u + 2u],
|
|
190
|
+
);
|
|
191
|
+
let sourceBase = u32(instances[base + 26u]);
|
|
192
|
+
let atBox = sourceAt(sourceBase, bounds0, bounds1, dims, clamped);
|
|
193
|
+
distance = max(outside, atBox - outside) * scale;
|
|
194
|
+
} else {
|
|
195
|
+
let dims = vec3<f32>(
|
|
196
|
+
instances[base + ${INSTANCE_DIMS}u],
|
|
197
|
+
instances[base + ${INSTANCE_DIMS}u + 1u],
|
|
198
|
+
instances[base + ${INSTANCE_DIMS}u + 2u],
|
|
199
|
+
);
|
|
200
|
+
let sourceBase = u32(instances[base + ${INSTANCE_OFFSET}u]);
|
|
201
|
+
distance = sourceAt(sourceBase, bounds0, bounds1, dims, object) * scale;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/*
|
|
205
|
+
* **The minimum, because the union of two solids is the nearer surface** — and the colour goes
|
|
206
|
+
* with it rather than beside it. Writing the albedo unconditionally would paint every sample
|
|
207
|
+
* with whichever instance happened to come last, which is a field of the right shape in the
|
|
208
|
+
* wrong colours and looks like a lighting bug rather than a composition one.
|
|
209
|
+
*/
|
|
210
|
+
if (distance < best) {
|
|
211
|
+
best = distance;
|
|
212
|
+
bestAlbedo = vec3<f32>(
|
|
213
|
+
instances[base + ${INSTANCE_ALBEDO}u],
|
|
214
|
+
instances[base + ${INSTANCE_ALBEDO}u + 1u],
|
|
215
|
+
instances[base + ${INSTANCE_ALBEDO}u + 2u],
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/*
|
|
221
|
+
* **Into this cascade's own region of one shared buffer.** Without the base every cascade writes
|
|
222
|
+
* the same samples and the last one wins, which reads as a field that has only its outermost
|
|
223
|
+
* level — the innermost detail simply absent, at the resolution a viewer is closest to.
|
|
224
|
+
*/
|
|
225
|
+
field[u32(params[9]) + index] = best;
|
|
226
|
+
let colourAt = (u32(params[9]) + index) * 3u;
|
|
227
|
+
albedo[colourAt] = bestAlbedo.x;
|
|
228
|
+
albedo[colourAt + 1u] = bestAlbedo.y;
|
|
229
|
+
albedo[colourAt + 2u] = bestAlbedo.z;
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** The composed field, drawn — so a pass that fills one can be looked at rather than trusted. */
|
|
2
|
+
/**
|
|
3
|
+
* **A visualisation, and it is the honest first consumer of the field.**
|
|
4
|
+
*
|
|
5
|
+
* What Wave 4A's chain is eventually for is indirect light in the shading path, and that is a far
|
|
6
|
+
* larger integration than a pass. What a pass can do now is prove the composition runs on a device
|
|
7
|
+
* and say what it costs — and a distance field is a thing you can *see*, by sphere-tracing it from
|
|
8
|
+
* the camera. If the geometry in the picture is the geometry in the scene, in the right places and
|
|
9
|
+
* the right sizes, the composition is right; if a cascade boundary shows as a seam, the fade is
|
|
10
|
+
* wrong. Neither is available from a number.
|
|
11
|
+
*
|
|
12
|
+
* That is what `DRAFT_SCENES` is for, and it is the same shape the GPU-driven pipeline's three rigs
|
|
13
|
+
* took: a second path drawn beside the first, measured, and kept out of the published set until
|
|
14
|
+
* what it draws is the whole material.
|
|
15
|
+
*
|
|
16
|
+
* **The march is `traceField.ts`'s, minus the cone.** Step by the field's own value, which is a
|
|
17
|
+
* distance nothing can be nearer than; stop where it falls under an epsilon; give up where the ray
|
|
18
|
+
* leaves the outermost cascade, because past that there is no information and stepping on a clamped
|
|
19
|
+
* value converges on the boundary and reports a surface made of nothing.
|
|
20
|
+
*/
|
|
21
|
+
/** Floats in the march's params: the inverse view-projection, the eye, and four scalars. */
|
|
22
|
+
export declare const MARCH_PARAM_FLOATS = 24;
|
|
23
|
+
/** Where each field starts. `INV_VIEW_PROJ` is column-major, as `gl-matrix` stores it. */
|
|
24
|
+
export declare const MARCH_INV_VIEW_PROJ = 0;
|
|
25
|
+
export declare const MARCH_EYE = 16;
|
|
26
|
+
export declare const MARCH_LEVELS = 20;
|
|
27
|
+
export declare const MARCH_SIDE = 21;
|
|
28
|
+
export declare const MARCH_STEPS = 22;
|
|
29
|
+
export declare const MARCH_EPSILON = 23;
|
|
30
|
+
export declare const MARCH_FIELD_WGSL: string;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/** The composed field, drawn — so a pass that fills one can be looked at rather than trusted. */
|
|
2
|
+
import { SAMPLE_FIELD_WGSL } from './sampleField.wgsl.js';
|
|
3
|
+
/**
|
|
4
|
+
* **A visualisation, and it is the honest first consumer of the field.**
|
|
5
|
+
*
|
|
6
|
+
* What Wave 4A's chain is eventually for is indirect light in the shading path, and that is a far
|
|
7
|
+
* larger integration than a pass. What a pass can do now is prove the composition runs on a device
|
|
8
|
+
* and say what it costs — and a distance field is a thing you can *see*, by sphere-tracing it from
|
|
9
|
+
* the camera. If the geometry in the picture is the geometry in the scene, in the right places and
|
|
10
|
+
* the right sizes, the composition is right; if a cascade boundary shows as a seam, the fade is
|
|
11
|
+
* wrong. Neither is available from a number.
|
|
12
|
+
*
|
|
13
|
+
* That is what `DRAFT_SCENES` is for, and it is the same shape the GPU-driven pipeline's three rigs
|
|
14
|
+
* took: a second path drawn beside the first, measured, and kept out of the published set until
|
|
15
|
+
* what it draws is the whole material.
|
|
16
|
+
*
|
|
17
|
+
* **The march is `traceField.ts`'s, minus the cone.** Step by the field's own value, which is a
|
|
18
|
+
* distance nothing can be nearer than; stop where it falls under an epsilon; give up where the ray
|
|
19
|
+
* leaves the outermost cascade, because past that there is no information and stepping on a clamped
|
|
20
|
+
* value converges on the boundary and reports a surface made of nothing.
|
|
21
|
+
*/
|
|
22
|
+
/** Floats in the march's params: the inverse view-projection, the eye, and four scalars. */
|
|
23
|
+
export const MARCH_PARAM_FLOATS = 24;
|
|
24
|
+
/** Where each field starts. `INV_VIEW_PROJ` is column-major, as `gl-matrix` stores it. */
|
|
25
|
+
export const MARCH_INV_VIEW_PROJ = 0;
|
|
26
|
+
export const MARCH_EYE = 16;
|
|
27
|
+
export const MARCH_LEVELS = 20;
|
|
28
|
+
export const MARCH_SIDE = 21;
|
|
29
|
+
export const MARCH_STEPS = 22;
|
|
30
|
+
export const MARCH_EPSILON = 23;
|
|
31
|
+
export const MARCH_FIELD_WGSL = /* wgsl */ `
|
|
32
|
+
@group(0) @binding(0) var<storage, read> params: array<f32>;
|
|
33
|
+
@group(0) @binding(1) var<storage, read> cascades: array<f32>;
|
|
34
|
+
@group(0) @binding(2) var<storage, read> fields: array<f32>;
|
|
35
|
+
|
|
36
|
+
${SAMPLE_FIELD_WGSL}
|
|
37
|
+
|
|
38
|
+
struct Varying {
|
|
39
|
+
@builtin(position) position: vec4<f32>,
|
|
40
|
+
@location(0) uv: vec2<f32>,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* One triangle covering the frame, which is one fewer than two and has no diagonal for a
|
|
45
|
+
* derivative to straddle. Clip y of +1 is the top of the image on both backends — see
|
|
46
|
+
* CLIP_CORRECTION's own note, which spent months saying otherwise — so uv.y counts down from it.
|
|
47
|
+
*/
|
|
48
|
+
@vertex
|
|
49
|
+
fn vertexMain(@builtin(vertex_index) index: u32) -> Varying {
|
|
50
|
+
var out: Varying;
|
|
51
|
+
let x = f32(i32(index) / 2) * 4.0 - 1.0;
|
|
52
|
+
let y = f32(i32(index) & 1) * 4.0 - 1.0;
|
|
53
|
+
out.position = vec4<f32>(x, y, 0.0, 1.0);
|
|
54
|
+
out.uv = vec2<f32>(x * 0.5 + 0.5, 0.5 - y * 0.5);
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fn unproject(ndc: vec2<f32>) -> vec3<f32> {
|
|
59
|
+
let m = ${MARCH_INV_VIEW_PROJ}u;
|
|
60
|
+
let clip = vec4<f32>(ndc.x, ndc.y, 0.5, 1.0);
|
|
61
|
+
/*
|
|
62
|
+
* Column-major, so column c is params[c * 4 .. c * 4 + 3]. Any depth gives the same ray from the
|
|
63
|
+
* eye, which is why the z above is a half rather than a near or a far plane — this is the one
|
|
64
|
+
* place the depth convention does not have to be known.
|
|
65
|
+
*/
|
|
66
|
+
var world = vec4<f32>(0.0, 0.0, 0.0, 0.0);
|
|
67
|
+
for (var row = 0u; row < 4u; row = row + 1u) {
|
|
68
|
+
world[row] =
|
|
69
|
+
params[m + row] * clip.x +
|
|
70
|
+
params[m + 4u + row] * clip.y +
|
|
71
|
+
params[m + 8u + row] * clip.z +
|
|
72
|
+
params[m + 12u + row] * clip.w;
|
|
73
|
+
}
|
|
74
|
+
return world.xyz / world.w;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The field's gradient, which for a distance field is the surface normal. */
|
|
78
|
+
fn normalAt(levels: u32, side: u32, p: vec3<f32>, h: f32) -> vec3<f32> {
|
|
79
|
+
let dx = sampleField(levels, side, p + vec3<f32>(h, 0.0, 0.0)) - sampleField(levels, side, p - vec3<f32>(h, 0.0, 0.0));
|
|
80
|
+
let dy = sampleField(levels, side, p + vec3<f32>(0.0, h, 0.0)) - sampleField(levels, side, p - vec3<f32>(0.0, h, 0.0));
|
|
81
|
+
let dz = sampleField(levels, side, p + vec3<f32>(0.0, 0.0, h)) - sampleField(levels, side, p - vec3<f32>(0.0, 0.0, h));
|
|
82
|
+
let g = vec3<f32>(dx, dy, dz);
|
|
83
|
+
let length2 = dot(g, g);
|
|
84
|
+
return select(vec3<f32>(0.0, 1.0, 0.0), g * inverseSqrt(length2), length2 > 1e-12);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Whether a point is still inside the outermost cascade, which is all the field knows about. */
|
|
88
|
+
fn withinField(levels: u32, p: vec3<f32>) -> bool {
|
|
89
|
+
let base = (levels - 1u) * 8u;
|
|
90
|
+
let low = vec3<f32>(cascades[base], cascades[base + 1u], cascades[base + 2u]);
|
|
91
|
+
let high = vec3<f32>(cascades[base + 3u], cascades[base + 4u], cascades[base + 5u]);
|
|
92
|
+
return all(p >= low) && all(p <= high);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@fragment
|
|
96
|
+
fn fragmentMain(vary: Varying) -> @location(0) vec4<f32> {
|
|
97
|
+
let levels = u32(params[${MARCH_LEVELS}]);
|
|
98
|
+
let side = u32(params[${MARCH_SIDE}]);
|
|
99
|
+
let steps = u32(params[${MARCH_STEPS}]);
|
|
100
|
+
let epsilon = params[${MARCH_EPSILON}];
|
|
101
|
+
let eye = vec3<f32>(
|
|
102
|
+
params[${MARCH_EYE}],
|
|
103
|
+
params[${MARCH_EYE} + 1u],
|
|
104
|
+
params[${MARCH_EYE} + 2u],
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
let ndc = vec2<f32>(vary.uv.x * 2.0 - 1.0, 1.0 - vary.uv.y * 2.0);
|
|
108
|
+
let direction = normalize(unproject(ndc) - eye);
|
|
109
|
+
|
|
110
|
+
/* The finest cascade's step, which is the smallest move worth making. */
|
|
111
|
+
let floorStep = cascades[6] * 0.25;
|
|
112
|
+
var travelled = 0.0;
|
|
113
|
+
var hit = false;
|
|
114
|
+
var at = eye;
|
|
115
|
+
for (var i = 0u; i < steps; i = i + 1u) {
|
|
116
|
+
at = eye + direction * travelled;
|
|
117
|
+
if (!withinField(levels, at)) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
let distance = sampleField(levels, side, at);
|
|
121
|
+
if (distance <= epsilon) {
|
|
122
|
+
hit = true;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
travelled = travelled + max(distance, floorStep);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!hit) {
|
|
129
|
+
/* Nothing here, so the frame keeps whatever drew before this. */
|
|
130
|
+
discard;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let normal = normalAt(levels, side, at, cascades[6] * 0.5);
|
|
134
|
+
let sun = normalize(vec3<f32>(0.4, 0.8, 0.45));
|
|
135
|
+
let lambert = max(dot(normal, sun), 0.0);
|
|
136
|
+
/* A hemispheric fill under it, so a face turned away is readable rather than black. */
|
|
137
|
+
let ambient = 0.18 + 0.12 * (normal.y * 0.5 + 0.5);
|
|
138
|
+
let shade = vec3<f32>(0.62, 0.66, 0.72) * (lambert * 0.85 + ambient);
|
|
139
|
+
return vec4<f32>(shade, 1.0);
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A probe's own bake, on the device: trace a sphere of rays, convolve them into an octahedral map.
|
|
3
|
+
*
|
|
4
|
+
* **Two dispatches rather than one, and the split is what makes it affordable.** A probe's texel
|
|
5
|
+
* is a cosine-weighted sum over every direction, so one invocation a texel that also traced would
|
|
6
|
+
* trace the same `PROBE_DIRECTIONS` rays once per texel — 256 rays becoming 256 × edge², which for
|
|
7
|
+
* an edge of 16 is sixty-five thousand marches for a probe that needs 256. So `traceMain` casts
|
|
8
|
+
* the rays once and writes them down, and `convolveMain` reads them back.
|
|
9
|
+
*
|
|
10
|
+
* **The octahedral mapping is a third spelling and that is a hazard this file states rather than
|
|
11
|
+
* hides.** `octahedral.ts` holds it in TypeScript and in GLSL; this is WGSL, because a hand-written
|
|
12
|
+
* compute shader cannot include the generated one. `scripts/probe-bake-parity.mjs` is what holds
|
|
13
|
+
* the three together, over the texels and the directions both.
|
|
14
|
+
*
|
|
15
|
+
* **A probe's normal is its ray's own direction, which is right here and wrong on a surface.**
|
|
16
|
+
* `probeTraceField` lifts the start along the normal to keep a ray from immediately hitting the
|
|
17
|
+
* surface it left, and its header says lifting along the ray as well double-counts — for a *surface*
|
|
18
|
+
* sample, where the normal and the ray are different things. A probe stands in open space and has
|
|
19
|
+
* no surface and no normal, so the only thing to lift along is the ray, and what it buys is a probe
|
|
20
|
+
* that has come to rest inside a wall casting rays that leave it rather than all reporting a hit at
|
|
21
|
+
* zero distance.
|
|
22
|
+
*
|
|
23
|
+
* The accessors an including module must define, before including the core, are `probeIndirect`'s
|
|
24
|
+
* — see `probeTrace.wgsl.ts` — plus `bake: ProbeBake` as a uniform.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Floats in the bake block, and where each field of it starts.
|
|
28
|
+
*
|
|
29
|
+
* **A `vec3<f32>` is sixteen-byte *aligned* and twelve bytes *long*, and an `f32` after one fills
|
|
30
|
+
* the gap rather than starting a new row.** So `counts` occupies floats 8 to 10 and `edge` is float
|
|
31
|
+
* **11**, not 12 — which cost an afternoon: written at 12, the shader read `edge` as `frame` and
|
|
32
|
+
* every direction came back rotated by the difference, at exactly the right radius. The radius
|
|
33
|
+
* matching is what said it was the angle and not the set.
|
|
34
|
+
*
|
|
35
|
+
* Exported as named offsets for that reason. A caller that counts rows gets this wrong; a caller
|
|
36
|
+
* that names the field cannot.
|
|
37
|
+
*/
|
|
38
|
+
export declare const BAKE_ORIGIN = 0;
|
|
39
|
+
export declare const BAKE_SPACING = 4;
|
|
40
|
+
export declare const BAKE_COUNTS = 8;
|
|
41
|
+
export declare const BAKE_EDGE = 11;
|
|
42
|
+
export declare const BAKE_FRAME = 12;
|
|
43
|
+
export declare const BAKE_SCHEDULED = 13;
|
|
44
|
+
/** The sun, which the trace evaluates itself so a light that moves changes the bounce. */
|
|
45
|
+
export declare const BAKE_SUN_DIR = 16;
|
|
46
|
+
export declare const BAKE_SUN_COLOUR = 20;
|
|
47
|
+
/** What a ray that left the world finds. The frame's ambient, so nothing rasterised is read. */
|
|
48
|
+
export declare const BAKE_SKY_COLOUR = 24;
|
|
49
|
+
/** Rounded up to the struct's own sixteen-byte alignment, with two vec3 rows for the sun. */
|
|
50
|
+
export declare const PROBE_BAKE_FLOATS = 28;
|
|
51
|
+
/** Invocations a workgroup, for both entry points. 64 is this backend's default everywhere. */
|
|
52
|
+
export declare const PROBE_BAKE_WORKGROUP = 64;
|
|
53
|
+
/** Floats a ray's radiance takes in the intermediate buffer. */
|
|
54
|
+
export declare const PROBE_RAY_FLOATS = 3;
|
|
55
|
+
/** Floats a baked texel takes. Three and not four: the alpha of an irradiance map means nothing. */
|
|
56
|
+
export declare const PROBE_TEXEL_FLOATS = 3;
|
|
57
|
+
export declare const PROBE_BAKE_STRUCT_WGSL = "\nstruct ProbeBake {\n /* Where the grid's first probe stands, and how far apart they are. */\n origin: vec3<f32>,\n spacing: vec3<f32>,\n /* How many probes along each axis. Whole numbers carried as floats, as every block here does. */\n counts: vec3<f32>,\n /* Texels across one probe's map, gutter included. */\n edge: f32,\n /* Which frame this is, which turns the direction set so a probe converges rather than repeats. */\n frame: f32,\n /* How many probes this dispatch bakes. The schedule says which. */\n scheduled: f32,\n pad: f32,\n /* Towards the sun, and what colour it is. The trace shades what it hits rather than reading a\n capture, which is what lets a bounce follow a light that moved. */\n sunDir: vec3<f32>,\n sunColour: vec3<f32>,\n /* And what is outside, for a ray that left. See probeDistantRadiance. */\n skyColour: vec3<f32>,\n}\n";
|
|
58
|
+
/**
|
|
59
|
+
* The octahedral mapping and the probe lattice, as text.
|
|
60
|
+
*
|
|
61
|
+
* Defines `bakeOctInsetDir(u, v, edge)` and `bakeProbePosition(layer)`.
|
|
62
|
+
*/
|
|
63
|
+
export declare const PROBE_BAKE_CORE_WGSL: string;
|
|
64
|
+
/**
|
|
65
|
+
* The parity module: the bake over plain buffers, with a radiance that is a function of position.
|
|
66
|
+
*
|
|
67
|
+
* **The radiance is positional for the reason `probeTraceParityWgsl` gives**: a march that landed a
|
|
68
|
+
* voxel from where the reference landed would return almost the right answer from a smooth field
|
|
69
|
+
* and exactly the right one from a constant, so a constant would check the convolution and nothing
|
|
70
|
+
* about the trace.
|
|
71
|
+
*
|
|
72
|
+
* What this check is *for*, over and above `indirect-parity.mjs`, is the three pieces of arithmetic
|
|
73
|
+
* that only exist in this file: the octahedral texel-to-direction fold, the layer-to-position
|
|
74
|
+
* lattice, and the Fibonacci direction set. Each is a second spelling of something `octahedral.ts`,
|
|
75
|
+
* `probeGrid.ts` and `probeTrace.ts` already hold, and a second spelling is what this repository
|
|
76
|
+
* has learned to check rather than trust.
|
|
77
|
+
*/
|
|
78
|
+
export declare function probeBakeParityWgsl(): string;
|
|
79
|
+
/**
|
|
80
|
+
* The production module: the same core, reading the renderer's composed field and probe array.
|
|
81
|
+
*
|
|
82
|
+
* **`probeRadianceAt` is the probe volume here and a sine of position in the parity module**, which
|
|
83
|
+
* is the whole reason the core takes it as an accessor. A probe traced against radiance that is
|
|
84
|
+
* itself probe radiance converges on several bounces over a few refreshes — the maintainer's answer
|
|
85
|
+
* of 2026-09-17 — and that is a property of what is bound rather than of the arithmetic.
|
|
86
|
+
*
|
|
87
|
+
* **The probe array is sampled while a later pass writes a mip of it, and that is legal.** WebGPU
|
|
88
|
+
* forbids a texture being read and written inside one pass, not across two on one encoder: the
|
|
89
|
+
* dispatches here read the array as it stood, and the blit that follows writes the levels the next
|
|
90
|
+
* frame's dispatches will read. What that costs is a frame of latency in the bounce, which is what
|
|
91
|
+
* a probe volume has anyway because it accumulates.
|
|
92
|
+
*/
|
|
93
|
+
export declare function probeBakeWgsl(): string;
|
|
94
|
+
/** Bytes between one blit's parameters and the next. A dynamic offset must be 256-aligned. */
|
|
95
|
+
export declare const PROBE_BLIT_STRIDE = 256;
|
|
96
|
+
/** Floats a blit's parameters hold: the slot, the map's edge, and the target level's edge. */
|
|
97
|
+
export declare const PROBE_BLIT_FLOATS = 4;
|
|
98
|
+
/**
|
|
99
|
+
* Carrying a baked map into the probe array the shading already samples.
|
|
100
|
+
*
|
|
101
|
+
* **A render pass rather than a storage write, because the probe array is not a storage texture.**
|
|
102
|
+
* It is created with `RENDER_ATTACHMENT | TEXTURE_BINDING` and its format is the surface's, which
|
|
103
|
+
* needs a device feature before it can be written from compute. Rendering into one mip of one layer
|
|
104
|
+
* needs neither, and the array already carries the usage for it.
|
|
105
|
+
*
|
|
106
|
+
* **The target edge is a parameter because not every level is the irradiance level.** A layer the
|
|
107
|
+
* scene has never rasterised holds undefined contents in its roughness chain, and a fragment
|
|
108
|
+
* sampling that is worse than a fragment sampling a flat colour. So a layer being filled for the
|
|
109
|
+
* first time has every level written from the same map — blocky at level 0, which is the honest
|
|
110
|
+
* thing a diffuse solution can say about a mirror — and every frame after that writes only the
|
|
111
|
+
* irradiance level.
|
|
112
|
+
*/
|
|
113
|
+
export declare const PROBE_BLIT_WGSL: string;
|