@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,329 @@
|
|
|
1
|
+
/** What the second pipeline's shading pass computes, in TypeScript, so something can disagree. */
|
|
2
|
+
|
|
3
|
+
import { EMISSIVE_SHADOW_SHARE, MIN_LOBE_ALPHA } from '../shaders/flat/lobes.ts';
|
|
4
|
+
import { environmentWeight } from './ibl.ts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* **The lit expression had no reference until 2026-09-16, and that was a gap rather than a policy.**
|
|
8
|
+
*
|
|
9
|
+
* `shadeBins.ts` is the reference for the *reconstruction* — screen vertices, perspective-correct
|
|
10
|
+
* weights, their gradients — and `gpu-parity.mjs` runs it against `SHADE_SURFACE_WGSL` over
|
|
11
|
+
* generated triangles. The shading pass's header gives the reason and it is a good one: the
|
|
12
|
+
* interpolation is the only part that differs between the two pipelines, so it is the only part
|
|
13
|
+
* that can drift.
|
|
14
|
+
*
|
|
15
|
+
* That argument holds for a lit expression of four lines. It stops holding the moment the
|
|
16
|
+
* expression grows a term, and it was never an argument for having *no* reference: nothing in the
|
|
17
|
+
* tree computed what the shader computed, so nothing could disagree with it. The forward path's own
|
|
18
|
+
* expression is GLSL and cannot be compared to WGSL by reading them side by side.
|
|
19
|
+
*
|
|
20
|
+
* **This is the twin, and it is deliberately not the forward path's whole material.** What the
|
|
21
|
+
* second pipeline draws is still a subset — no texture, so every property a texel could vary is a
|
|
22
|
+
* per-material constant — and every term that *is* here matches `flat/main.ts` exactly. Stating
|
|
23
|
+
* the subset is the point; discovering it from a capture is what this repository keeps refusing.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** A surface, after the visibility buffer has been turned back into one. */
|
|
27
|
+
export interface LitSurface {
|
|
28
|
+
/** Vertex colour times the material's tint. */
|
|
29
|
+
readonly albedo: readonly [number, number, number];
|
|
30
|
+
/** Unit length, in world space. */
|
|
31
|
+
readonly normal: readonly [number, number, number];
|
|
32
|
+
/** Unit length, from the surface toward the eye. */
|
|
33
|
+
readonly toEye: readonly [number, number, number];
|
|
34
|
+
/** 0 is a mirror, 1 is fully rough. */
|
|
35
|
+
readonly roughness: number;
|
|
36
|
+
/** How much of the light the surface returns as a highlight. Zero for a matte one. */
|
|
37
|
+
readonly specular: number;
|
|
38
|
+
/** Added as `emissiveColour * emissive`, which is `albedo * emissive` where no map says otherwise. */
|
|
39
|
+
readonly emissive: number;
|
|
40
|
+
/**
|
|
41
|
+
* What the glow is coloured by: flat/main.ts's `emissiveTint * emissiveMapped`, the albedo times
|
|
42
|
+
* an emissive map. **Defaults to the albedo**, so a surface with no map glows exactly as it did —
|
|
43
|
+
* and it reaches the glow and nothing else, because a map says where light is emitted rather than
|
|
44
|
+
* what the surface is made of.
|
|
45
|
+
*/
|
|
46
|
+
readonly emissiveColour?: readonly [number, number, number];
|
|
47
|
+
/**
|
|
48
|
+
* How much of the environment the surface returns, before the angle and the roughness are
|
|
49
|
+
* accounted for. **Defaults to 0**, so a material that says nothing reflects nothing.
|
|
50
|
+
*/
|
|
51
|
+
readonly reflectivity?: number;
|
|
52
|
+
/**
|
|
53
|
+
* How much of the directional source reaches this surface: 0 in full shadow, 1 in full light.
|
|
54
|
+
*
|
|
55
|
+
* **Applied to the diffuse term and the highlight, and to nothing else**, which is where
|
|
56
|
+
* `flat/main.ts` puts its own `sunShade`. Its comment records what applying it more widely costs:
|
|
57
|
+
* scale the ambient too and an enclosed face is darkened once for having no sun and again for the
|
|
58
|
+
* light it should still have received, which a consumer answered by raising a floor constant and
|
|
59
|
+
* losing the contrast permanently.
|
|
60
|
+
*
|
|
61
|
+
* **Defaults to 1**, so a caller that says nothing about occlusion renders exactly the frame this
|
|
62
|
+
* pipeline rendered before it had a shadow map — the same promise `roughness` and `specular`
|
|
63
|
+
* make.
|
|
64
|
+
*/
|
|
65
|
+
readonly shade?: number;
|
|
66
|
+
/**
|
|
67
|
+
* 0 is a dielectric and 1 is a metal. **Defaults to 0.**
|
|
68
|
+
*
|
|
69
|
+
* `flat/main.ts` reads this per texel from the blue channel of an occlusion-roughness-metallic
|
|
70
|
+
* image; this pipeline has no textures, so it is one number a material. That is the whole of the
|
|
71
|
+
* difference — every expression it enters is the forward path's with a constant standing in for
|
|
72
|
+
* a fetch — and it is four of them: the direct diffuse it removes, the colour it gives the
|
|
73
|
+
* highlight, the side of the environment blend the highlight is added on, and the `f0` and the
|
|
74
|
+
* amount `ibl.ts` builds the weight from.
|
|
75
|
+
*/
|
|
76
|
+
readonly metalness?: number;
|
|
77
|
+
/**
|
|
78
|
+
* How much of the surface's light a crevice leaves, from an ORM map's red channel. **Defaults
|
|
79
|
+
* to 1.**
|
|
80
|
+
*
|
|
81
|
+
* **It multiplies the whole result**, highlight, reflection and emissive included, because that
|
|
82
|
+
* is what `flat/main.ts` does — `lit *= ormOcclusion` — and its comment records the narrower
|
|
83
|
+
* reading as considered and not taken, with the double count against a cast shadow as the
|
|
84
|
+
* stated cost.
|
|
85
|
+
*/
|
|
86
|
+
readonly occlusion?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The frame's one directional light and its hemispheric fill. */
|
|
90
|
+
export interface LitEnvironment {
|
|
91
|
+
/** Toward the light, unit length, as `Environment.directionalDir` is. */
|
|
92
|
+
readonly lightDir: readonly [number, number, number];
|
|
93
|
+
readonly lightColour: readonly [number, number, number];
|
|
94
|
+
readonly sky: readonly [number, number, number];
|
|
95
|
+
readonly ground: readonly [number, number, number];
|
|
96
|
+
/**
|
|
97
|
+
* The room's diffuse light in the surface's own direction, from a cosine-convolved level.
|
|
98
|
+
*
|
|
99
|
+
* **It replaces the hemispheric gradient rather than lifting it**, by `irradianceAmount`, which
|
|
100
|
+
* is what `flat/main.ts` does and what its own comment records the alternative costing: a mix
|
|
101
|
+
* *toward* a coarse box-filtered level is a sample of the room rather than an integral over it,
|
|
102
|
+
* and it rendered a night courtyard black.
|
|
103
|
+
*/
|
|
104
|
+
readonly irradiance?: readonly [number, number, number];
|
|
105
|
+
/** How much of the gradient the irradiance replaces. **Defaults to 0**, which keeps it. */
|
|
106
|
+
readonly irradianceAmount?: number;
|
|
107
|
+
/**
|
|
108
|
+
* What the surface sees in the mirror direction, from the chain at its own roughness.
|
|
109
|
+
*
|
|
110
|
+
* **It replaces a hemispheric gradient rather than standing alone**, by `radianceAmount`, and the
|
|
111
|
+
* default matters more here than anywhere else in this interface: a metal's environment weight is
|
|
112
|
+
* exactly 1 at every angle and every roughness, so a metal with nothing to reflect is **black**.
|
|
113
|
+
* The gradient is what `flat/main.ts` reflects where a scene has no probe, and computing it here
|
|
114
|
+
* rather than in the caller is what stops that being something a caller can forget.
|
|
115
|
+
*/
|
|
116
|
+
readonly radiance?: readonly [number, number, number];
|
|
117
|
+
/**
|
|
118
|
+
* How much of the gradient the radiance replaces. **Defaults to 0**, which keeps the gradient —
|
|
119
|
+
* the same shape and the same default as `irradianceAmount`.
|
|
120
|
+
*/
|
|
121
|
+
readonly radianceAmount?: number;
|
|
122
|
+
/**
|
|
123
|
+
* Whether that radiance came from a GGX-convolved chain. **Defaults to 0.**
|
|
124
|
+
*
|
|
125
|
+
* The split sum is the correct share of a *prefiltered* environment and asserts an integral that
|
|
126
|
+
* was never performed over anything else — `ibl.ts` carries what ignoring that costs.
|
|
127
|
+
*/
|
|
128
|
+
readonly prefiltered?: number;
|
|
129
|
+
/**
|
|
130
|
+
* The frame's emissive gain times its night factor. **Defaults to 1.**
|
|
131
|
+
*
|
|
132
|
+
* `flat/main.ts` scales every glow by `uEmissiveGain * uNightFactor`, so a scene whose clock says
|
|
133
|
+
* it is day has nothing glowing on the forward path. This pipeline added `albedo * emissive` and
|
|
134
|
+
* nothing else until 2026-09-17, which is a rig that glowed on one pipeline and not the other.
|
|
135
|
+
*/
|
|
136
|
+
readonly emission?: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* How much of the sky a normal sees, against how much of the ground.
|
|
141
|
+
*
|
|
142
|
+
* `n.y * 0.5 + 0.5`, which is `flat/main.ts`'s own. Named rather than inlined because two
|
|
143
|
+
* pipelines disagreeing about it is two pipelines lighting one scene differently, with nothing on
|
|
144
|
+
* screen to say which is right.
|
|
145
|
+
*/
|
|
146
|
+
export function HEMISPHERIC(ny: number): number {
|
|
147
|
+
return ny * 0.5 + 0.5;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The normalised GGX distribution, transcribed from `flat/lobes.ts`.
|
|
152
|
+
*
|
|
153
|
+
* **It peaks at one whatever the roughness**, and that is what makes a widened lobe broader rather
|
|
154
|
+
* than brighter — `lobes.ts` records paying for the version that did not. The floor on `a` is what
|
|
155
|
+
* keeps a mirror from dividing by nothing.
|
|
156
|
+
*/
|
|
157
|
+
/*
|
|
158
|
+
* **Two floors, and only one of them can be seen in the output.** The denominator's is what keeps
|
|
159
|
+
* a near-mirror's peak finite, and deleting it is worth 256 times the highlight at roughness 0.05 —
|
|
160
|
+
* `gpu-parity.mjs` catches that, now that a fifth of its corpus sits on the peak. The floor on `a`
|
|
161
|
+
* cannot be caught, because the denominator's already prevents the division by zero it guards
|
|
162
|
+
* against: at roughness zero the whole term is a ten-thousandth with it and zero without, and both
|
|
163
|
+
* round to nothing beside a lit surface. It is kept because it is what `flat/lobes.ts` has, and two
|
|
164
|
+
* spellings of one lobe differing by a guard is the drift this pair exists to prevent.
|
|
165
|
+
*/
|
|
166
|
+
export function specularLobe(ndh: number, roughness: number): number {
|
|
167
|
+
const a = Math.max(roughness * roughness, MIN_LOBE_ALPHA);
|
|
168
|
+
const a2 = a * a;
|
|
169
|
+
const d = ndh * ndh * (a2 - 1) + 1;
|
|
170
|
+
return (a2 * a2) / Math.max(d * d, 1e-8);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function newLitColour(): Float32Array {
|
|
174
|
+
return new Float32Array(3);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Scratch, because this is per pixel in the reference as well as on the device. */
|
|
178
|
+
const HALFWAY = new Float32Array(3);
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The colour the second pipeline writes for one reconstructed surface.
|
|
182
|
+
*
|
|
183
|
+
* **The highlight is added on both sides of the environment blend, and which side carries how much
|
|
184
|
+
* is metalness.** `flat/main.ts` writes it as two lines with the blend between them, and its
|
|
185
|
+
* comments carry what each is for. The dielectric's share goes in *underneath*, where the blend
|
|
186
|
+
* dims it by the surface's own reflectance — moving it out "takes a lobe that was correctly dimmed
|
|
187
|
+
* and puts it back at full strength", which on a near-black glass lens carrying `specular` 1 is a
|
|
188
|
+
* white blob where there was none. The metal's share goes *over the top*, because on a metal the
|
|
189
|
+
* blend reaches 1 and a highlight left underneath is multiplied by exactly zero: the surface with
|
|
190
|
+
* the most reason to show a specular streak is the one guaranteed not to.
|
|
191
|
+
*
|
|
192
|
+
* **This file had both shares on the outside until 2026-09-17** and cited the metal argument for
|
|
193
|
+
* it. Nothing caught it: no material in any rig carries a `specular` and a `reflectivity` at once,
|
|
194
|
+
* so the two orders had never been asked to differ.
|
|
195
|
+
*/
|
|
196
|
+
export function litColour(
|
|
197
|
+
surface: LitSurface,
|
|
198
|
+
environment: LitEnvironment,
|
|
199
|
+
out: Float32Array,
|
|
200
|
+
): Float32Array {
|
|
201
|
+
const [nx, ny, nz] = surface.normal;
|
|
202
|
+
const [lx, ly, lz] = environment.lightDir;
|
|
203
|
+
|
|
204
|
+
const ndl = Math.max(nx * lx + ny * ly + nz * lz, 0);
|
|
205
|
+
const fill = HEMISPHERIC(ny);
|
|
206
|
+
|
|
207
|
+
/* The half vector between the light and the eye, which is where a highlight is brightest. */
|
|
208
|
+
HALFWAY[0] = lx + (surface.toEye[0] as number);
|
|
209
|
+
HALFWAY[1] = ly + (surface.toEye[1] as number);
|
|
210
|
+
HALFWAY[2] = lz + (surface.toEye[2] as number);
|
|
211
|
+
const length = Math.hypot(HALFWAY[0] as number, HALFWAY[1] as number, HALFWAY[2] as number);
|
|
212
|
+
let ndh = 0;
|
|
213
|
+
let voh = 0;
|
|
214
|
+
if (length > 0) {
|
|
215
|
+
ndh = Math.max(
|
|
216
|
+
(nx * (HALFWAY[0] as number) + ny * (HALFWAY[1] as number) + nz * (HALFWAY[2] as number)) /
|
|
217
|
+
length,
|
|
218
|
+
0,
|
|
219
|
+
);
|
|
220
|
+
voh = Math.max(
|
|
221
|
+
((surface.toEye[0] as number) * (HALFWAY[0] as number) +
|
|
222
|
+
(surface.toEye[1] as number) * (HALFWAY[1] as number) +
|
|
223
|
+
(surface.toEye[2] as number) * (HALFWAY[2] as number)) /
|
|
224
|
+
length,
|
|
225
|
+
0,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
/*
|
|
229
|
+
* **Computed whether or not the surface is shiny, and multiplied by zero where it is not.** A
|
|
230
|
+
* branch on a material's specular would be a branch on a value read from a table, which is what
|
|
231
|
+
* the shading pass's own header refuses for the same reason the forward path does: it is not
|
|
232
|
+
* provably uniform control flow.
|
|
233
|
+
*/
|
|
234
|
+
const lobe = specularLobe(ndh, surface.roughness);
|
|
235
|
+
/* One number for both direct terms: the sun being occluded is one fact about one source. */
|
|
236
|
+
const shade = surface.shade ?? 1;
|
|
237
|
+
const metal = surface.metalness ?? 0;
|
|
238
|
+
const occlusion = surface.occlusion ?? 1;
|
|
239
|
+
/*
|
|
240
|
+
* **A glow is scaled by the frame and dimmed by a share of the sun's shadow**, which is
|
|
241
|
+
* flat/main.ts's `mix(1, min(lightShade, sunShade), EMISSIVE_SHADOW_SHARE)` with no lamps: a lit
|
|
242
|
+
* inlay in a deck that is itself in shade, rather than a lamp head blacked out by a passer-by.
|
|
243
|
+
*/
|
|
244
|
+
const glow =
|
|
245
|
+
surface.emissive * (environment.emission ?? 1) * (1 + (shade - 1) * EMISSIVE_SHADOW_SHARE);
|
|
246
|
+
/*
|
|
247
|
+
* **A metal's highlight goes white at a grazing angle, and that is most of what reads as
|
|
248
|
+
* polished.** Schlick's reflectance climbs to 1 at the edge whatever the material is, so a red
|
|
249
|
+
* metal shows a red highlight face-on and a white one along every panel edge. Scaled by
|
|
250
|
+
* metalness, so `specColour + (1 - specColour) * 0` is `specColour` exactly on a dielectric.
|
|
251
|
+
*/
|
|
252
|
+
const facing = 1 - voh;
|
|
253
|
+
const edge = facing * facing * facing * facing * facing * metal;
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* **How much of the room the surface returns, computed once rather than per channel.** It is a
|
|
257
|
+
* function of the angle, the roughness and the material alone — `ibl.ts` carries both halves of
|
|
258
|
+
* the split sum and why the selector between them is exactly 0 or exactly 1.
|
|
259
|
+
*/
|
|
260
|
+
const nv =
|
|
261
|
+
nx * (surface.toEye[0] as number) +
|
|
262
|
+
ny * (surface.toEye[1] as number) +
|
|
263
|
+
nz * (surface.toEye[2] as number);
|
|
264
|
+
const ndv = Math.max(nv, 0);
|
|
265
|
+
const weight = environmentWeight(
|
|
266
|
+
ndv,
|
|
267
|
+
surface.roughness,
|
|
268
|
+
surface.reflectivity ?? 0,
|
|
269
|
+
environment.prefiltered ?? 0,
|
|
270
|
+
metal,
|
|
271
|
+
);
|
|
272
|
+
const irradianceAmount = environment.irradianceAmount ?? 0;
|
|
273
|
+
const radianceAmount = environment.radianceAmount ?? 0;
|
|
274
|
+
/*
|
|
275
|
+
* **The mirror direction, and what a surface sees along it with no probe bound.** `reflect(-v, n)`
|
|
276
|
+
* written out: the two-colour gradient the ambient comes from, sampled in the direction the
|
|
277
|
+
* surface is reflecting rather than the one it faces. That distinction is the whole of what makes
|
|
278
|
+
* a curved dielectric read as curved with no environment in the scene at all.
|
|
279
|
+
*
|
|
280
|
+
* **The unclamped dot, not `ndv`.** `reflect` takes the facing term as it is; clamping it at zero
|
|
281
|
+
* would fold the mirror direction back on itself for a surface seen from behind — which happens
|
|
282
|
+
* on every silhouette where interpolated normals turn past the eye — and reflect the sky where
|
|
283
|
+
* the ground belongs. The weight below clamps because a negative Fresnel is not a reflectance;
|
|
284
|
+
* the two uses are different questions about one dot product.
|
|
285
|
+
*/
|
|
286
|
+
const mirroredY = 2 * nv * ny - (surface.toEye[1] as number);
|
|
287
|
+
|
|
288
|
+
for (let channel = 0; channel < 3; channel += 1) {
|
|
289
|
+
const albedo = surface.albedo[channel] as number;
|
|
290
|
+
const hemispheric =
|
|
291
|
+
(environment.ground[channel] as number) +
|
|
292
|
+
((environment.sky[channel] as number) - (environment.ground[channel] as number)) * fill;
|
|
293
|
+
const room = environment.irradiance?.[channel] ?? 0;
|
|
294
|
+
const ambient = hemispheric + (room - hemispheric) * irradianceAmount;
|
|
295
|
+
/*
|
|
296
|
+
* **A metal's highlight takes its own colour and a dielectric's takes the light's**, which is
|
|
297
|
+
* why gold under a white lamp reads as gold rather than as beige plastic with a white dot on
|
|
298
|
+
* it. `specular` is this engine's dielectric reflectance — a look control rather than an `f0` —
|
|
299
|
+
* so the blend runs from it to the albedo rather than from 0.04.
|
|
300
|
+
*/
|
|
301
|
+
const specColour = surface.specular + (albedo - surface.specular) * metal;
|
|
302
|
+
const sunSpec = specColour + (1 - specColour) * edge;
|
|
303
|
+
const highlight = (environment.lightColour[channel] as number) * lobe * sunSpec * shade;
|
|
304
|
+
/*
|
|
305
|
+
* **A metal keeps its ambient and loses its direct diffuse**, written as one term because the
|
|
306
|
+
* honest two cancel: a metal's reduced diffuse plus the ambient floor that stops a rough one
|
|
307
|
+
* going black once its diffuse is gone sum to `albedo * ambient` exactly.
|
|
308
|
+
*/
|
|
309
|
+
const base =
|
|
310
|
+
albedo *
|
|
311
|
+
(ambient + (environment.lightColour[channel] as number) * ndl * shade * (1 - metal)) +
|
|
312
|
+
highlight * (1 - metal);
|
|
313
|
+
/*
|
|
314
|
+
* **What a metal reflects is the room through itself**, which is the other half of "a metal is
|
|
315
|
+
* nothing but its reflection". `mix(1, albedo, 0)` is exactly 1, so a dielectric reflects the
|
|
316
|
+
* room's own colour as it always did.
|
|
317
|
+
*/
|
|
318
|
+
const gradient =
|
|
319
|
+
(environment.ground[channel] as number) +
|
|
320
|
+
((environment.sky[channel] as number) - (environment.ground[channel] as number)) *
|
|
321
|
+
HEMISPHERIC(mirroredY);
|
|
322
|
+
const seen = gradient + ((environment.radiance?.[channel] ?? 0) - gradient) * radianceAmount;
|
|
323
|
+
const reflected = seen * (1 + (albedo - 1) * metal);
|
|
324
|
+
const glowColour = surface.emissiveColour?.[channel] ?? albedo;
|
|
325
|
+
out[channel] =
|
|
326
|
+
(base + (reflected - base) * weight + highlight * metal + glowColour * glow) * occlusion;
|
|
327
|
+
}
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Choosing which level of the cluster graph to draw, per cluster, independently.
|
|
3
|
+
*
|
|
4
|
+
* **Independently is the whole point.** A cluster asks only about its own error and its parent's,
|
|
5
|
+
* never about its neighbours — and the graph's monotonic-error guarantee is what makes the result
|
|
6
|
+
* crack-free anyway. That is why this can run per cluster on the device with no communication.
|
|
7
|
+
*
|
|
8
|
+
* **Both halves of the rule are needed.** "Draw it if its own error is small enough" alone draws
|
|
9
|
+
* every ancestor as well; "draw it if its parent's error is too large" alone draws nothing at the
|
|
10
|
+
* root, where the parent error is infinite and therefore always too large — which is exactly the
|
|
11
|
+
* case that makes the coarsest level appear and never disappear.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* How large a geometric error appears on screen, in pixels.
|
|
16
|
+
*
|
|
17
|
+
* Distance is clamped below by the cluster's own radius, so a cluster the camera is inside reports
|
|
18
|
+
* an enormous error rather than dividing by something near zero — which is the difference between
|
|
19
|
+
* "always use the finest level here" and a non-finite number reaching a comparison.
|
|
20
|
+
*/
|
|
21
|
+
export function projectedError(
|
|
22
|
+
error: number,
|
|
23
|
+
distance: number,
|
|
24
|
+
radius: number,
|
|
25
|
+
screenHeight: number,
|
|
26
|
+
fovY: number,
|
|
27
|
+
): number {
|
|
28
|
+
const safe = Math.max(distance, radius, 1e-4);
|
|
29
|
+
const scale = screenHeight / (2 * Math.tan(fovY / 2));
|
|
30
|
+
return (error * scale) / safe;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function distanceTo(
|
|
34
|
+
cx: number,
|
|
35
|
+
cy: number,
|
|
36
|
+
cz: number,
|
|
37
|
+
ex: number,
|
|
38
|
+
ey: number,
|
|
39
|
+
ez: number,
|
|
40
|
+
): number {
|
|
41
|
+
return Math.hypot(cx - ex, cy - ey, cz - ez);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Whether this cluster is the one to draw.
|
|
46
|
+
*
|
|
47
|
+
* True when its own error is acceptable and its parent's is not — see the header for why both
|
|
48
|
+
* halves are required.
|
|
49
|
+
*/
|
|
50
|
+
export function clusterSelected(
|
|
51
|
+
ownError: number,
|
|
52
|
+
parentError: number,
|
|
53
|
+
distance: number,
|
|
54
|
+
radius: number,
|
|
55
|
+
screenHeight: number,
|
|
56
|
+
fovY: number,
|
|
57
|
+
thresholdPixels: number,
|
|
58
|
+
): boolean {
|
|
59
|
+
const own = projectedError(ownError, distance, radius, screenHeight, fovY);
|
|
60
|
+
const parent = projectedError(parentError, distance, radius, screenHeight, fovY);
|
|
61
|
+
return own <= thresholdPixels && parent > thresholdPixels;
|
|
62
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grouping the frame's pixels by the material that has to shade them.
|
|
3
|
+
*
|
|
4
|
+
* **A visibility buffer defers the shading and does not organise it.** Neighbouring pixels can
|
|
5
|
+
* hold triangles from different meshes with different materials, so shading it in place means
|
|
6
|
+
* every invocation branching on a material it cannot know until it has read the buffer — which on
|
|
7
|
+
* a wide machine is every lane in a group taking every branch. Binning first turns that into one
|
|
8
|
+
* dispatch per material, each of which shades pixels that all want the same code.
|
|
9
|
+
*
|
|
10
|
+
* **A material with no pixels gets a zero-length bin and a zero-workgroup dispatch, never an
|
|
11
|
+
* absent one.** The arguments are indexed by material identifier, so dropping an empty one shifts
|
|
12
|
+
* every later material's block and the scene shades with the wrong code — a picture that is
|
|
13
|
+
* plausible, entirely wrong, and correlates with nothing a consumer changed. `binsPresent` is the
|
|
14
|
+
* separate question of how many materials actually appear, which is a number to report rather
|
|
15
|
+
* than a length to index by.
|
|
16
|
+
*
|
|
17
|
+
* **Offsets are a prefix sum and the cursors are a copy of it.** The scatter needs somewhere to
|
|
18
|
+
* count from that is not the offsets themselves, or the second pixel of a bin overwrites the
|
|
19
|
+
* first's offset and every later bin starts in the wrong place.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { INDIRECT_DISPATCH_WORDS, writeDispatchArgs } from './indirect.ts';
|
|
23
|
+
import { VIS_TRIANGLE_BITS, visibilityCovered } from './visbuffer.ts';
|
|
24
|
+
|
|
25
|
+
/** Invocations a shading group covers. One pixel each; the bins are lists, not rectangles. */
|
|
26
|
+
export const BIN_GROUP_SIZE = 64;
|
|
27
|
+
|
|
28
|
+
/** Words in one material's dispatch block, so a caller can size the buffer. */
|
|
29
|
+
export const BIN_DISPATCH_WORDS = INDIRECT_DISPATCH_WORDS;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Which material a pixel wants, or -1 where nothing covered it.
|
|
33
|
+
*
|
|
34
|
+
* **The sentinel test survives perturbation and is kept**, which is worth the sentence because it
|
|
35
|
+
* looks like the load-bearing line and is not. `VIS_EMPTY` is `0xffffffff`, so its cluster field
|
|
36
|
+
* reads as 33,554,431 — and the range test one line down refuses any cluster past the table, which
|
|
37
|
+
* every real table is far smaller than. Deleting either check alone therefore changes no answer
|
|
38
|
+
* this repository can produce. What the sentinel test decides is a table sized to the full
|
|
39
|
+
* twenty-five bits, which is 134 MB and nothing allocates; what the range test decides is a
|
|
40
|
+
* visibility buffer left over from a frame with more geometry in it, which is a real case and is
|
|
41
|
+
* the one `gpu-parity.mjs` generates. Both are kept because they answer different questions and
|
|
42
|
+
* one of them is cheap insurance against the other's assumption.
|
|
43
|
+
*/
|
|
44
|
+
export function materialAt(
|
|
45
|
+
visibility: Uint32Array,
|
|
46
|
+
materialOf: Uint32Array,
|
|
47
|
+
pixel: number,
|
|
48
|
+
): number {
|
|
49
|
+
const packed = visibility[pixel] as number;
|
|
50
|
+
if (!visibilityCovered(packed)) return -1;
|
|
51
|
+
const cluster = packed >>> VIS_TRIANGLE_BITS;
|
|
52
|
+
const material = materialOf[cluster];
|
|
53
|
+
return material === undefined ? -1 : material;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* How many pixels each material owns, and how many pixels were covered at all.
|
|
58
|
+
*
|
|
59
|
+
* `counts` is cleared here rather than by the caller, because a count buffer reused across frames
|
|
60
|
+
* without clearing grows without bound and the bins then run off the end of the pixel list —
|
|
61
|
+
* which appears as the shading reading a neighbouring bin's pixels.
|
|
62
|
+
*/
|
|
63
|
+
export function countBins(
|
|
64
|
+
visibility: Uint32Array,
|
|
65
|
+
materialOf: Uint32Array,
|
|
66
|
+
counts: Uint32Array,
|
|
67
|
+
): number {
|
|
68
|
+
counts.fill(0);
|
|
69
|
+
let covered = 0;
|
|
70
|
+
for (let pixel = 0; pixel < visibility.length; pixel += 1) {
|
|
71
|
+
const material = materialAt(visibility, materialOf, pixel);
|
|
72
|
+
if (material < 0 || material >= counts.length) continue;
|
|
73
|
+
counts[material] = (counts[material] as number) + 1;
|
|
74
|
+
covered += 1;
|
|
75
|
+
}
|
|
76
|
+
return covered;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Where each material's pixels begin: the exclusive prefix sum of the counts. */
|
|
80
|
+
export function binOffsets(counts: Uint32Array, offsets: Uint32Array): number {
|
|
81
|
+
let running = 0;
|
|
82
|
+
for (let material = 0; material < counts.length; material += 1) {
|
|
83
|
+
offsets[material] = running;
|
|
84
|
+
running += counts[material] as number;
|
|
85
|
+
}
|
|
86
|
+
return running;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Write every covered pixel's index into its material's slice of `pixels`.
|
|
91
|
+
*
|
|
92
|
+
* `cursors` starts as a copy of `offsets` and is advanced as the scatter runs, so `offsets` stays
|
|
93
|
+
* readable afterwards — which the shading dispatch needs, because it is what tells a group where
|
|
94
|
+
* its material's list starts.
|
|
95
|
+
*/
|
|
96
|
+
export function fillBins(
|
|
97
|
+
visibility: Uint32Array,
|
|
98
|
+
materialOf: Uint32Array,
|
|
99
|
+
offsets: Uint32Array,
|
|
100
|
+
cursors: Uint32Array,
|
|
101
|
+
pixels: Uint32Array,
|
|
102
|
+
): void {
|
|
103
|
+
cursors.set(offsets);
|
|
104
|
+
for (let pixel = 0; pixel < visibility.length; pixel += 1) {
|
|
105
|
+
const material = materialAt(visibility, materialOf, pixel);
|
|
106
|
+
if (material < 0 || material >= offsets.length) continue;
|
|
107
|
+
const at = cursors[material] as number;
|
|
108
|
+
pixels[at] = pixel;
|
|
109
|
+
cursors[material] = at + 1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** One dispatch block per **declared** material, zero groups where the bin is empty. */
|
|
114
|
+
export function binDispatchArgs(
|
|
115
|
+
counts: Uint32Array,
|
|
116
|
+
out: Uint32Array,
|
|
117
|
+
groupSize: number = BIN_GROUP_SIZE,
|
|
118
|
+
): void {
|
|
119
|
+
for (let material = 0; material < counts.length; material += 1) {
|
|
120
|
+
writeDispatchArgs(out, material * BIN_DISPATCH_WORDS, counts[material] as number, groupSize);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** How many materials the frame actually contains, which is not how many it declares. */
|
|
125
|
+
export function binsPresent(counts: Uint32Array): number {
|
|
126
|
+
let present = 0;
|
|
127
|
+
for (let material = 0; material < counts.length; material += 1) {
|
|
128
|
+
if ((counts[material] as number) > 0) present += 1;
|
|
129
|
+
}
|
|
130
|
+
return present;
|
|
131
|
+
}
|