@driftengine/core 3.62.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 +122 -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 +70 -4
- package/dist/index.js +123 -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 +47 -14
- package/dist/render/backend/webgpu/surfaceTexturePass.js +128 -80
- 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 +261 -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 +158 -88
- 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,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DriftTR's resolve: a jittered frame at the render size into a picture at the output size.
|
|
3
|
+
*
|
|
4
|
+
* **This is the reference the compute shader is held to**, operation for operation, and it is built
|
|
5
|
+
* from the pieces before it: the jitter taken out of where the current frame was observed
|
|
6
|
+
* (`motionVectors.ts`), the history read bicubically where the surface was (`reproject.ts`), clipped
|
|
7
|
+
* to the render neighbourhood's variance box in YCoCg (`clamp.ts`), weighted by whether it is the
|
|
8
|
+
* same surface (`disocclusion.ts`), accumulated, and then sharpened into the picture that is shown.
|
|
9
|
+
*
|
|
10
|
+
* **Per output pixel, in this order:**
|
|
11
|
+
*
|
|
12
|
+
* 1. The render texels around where this frame observed the output pixel each land, unjittered, some
|
|
13
|
+
* distance from its centre. **Each contributes by that distance** — a Gaussian over output pixels —
|
|
14
|
+
* and the sum of their weights is how much this frame knows about the pixel. This is what makes the
|
|
15
|
+
* accumulation converge on the output-size picture rather than on the render's own, blurred to its
|
|
16
|
+
* texel size: an interpolated read of the render, averaged over every jitter, is exactly that blur.
|
|
17
|
+
* 2. The same texels bound the history, and give the **nearest depth**, whose texel's motion is the one
|
|
18
|
+
* taken — the dilation every temporal upscaler uses, because an edge's own motion belongs to the
|
|
19
|
+
* nearer of the two surfaces meeting there. The centre texel wins a tie.
|
|
20
|
+
* 3. That texel's motion is a drawn object's where the motion target flags one, carrying the object's
|
|
21
|
+
* previous view depth in its third channel; otherwise it is the camera's, through the surface's
|
|
22
|
+
* world position.
|
|
23
|
+
* 4. Where the surface was is read from the history — its colour and the weight it had gathered — and
|
|
24
|
+
* last frame's depth there says whether it is the same surface; the two frames' normals, from their
|
|
25
|
+
* depths, catch thin geometry. The disocclusion scales the history's weight.
|
|
26
|
+
* 5. The history is clipped to the box, its weight capped so a tenth of each frame is always new, and
|
|
27
|
+
* the two are mixed by their weights. Where the pixel has gathered less than one sample's worth,
|
|
28
|
+
* the render read bicubically fills the gap. The history keeps colour and weight; the picture shown
|
|
29
|
+
* is it sharpened.
|
|
30
|
+
*
|
|
31
|
+
* **Conventions.** Images are rows from `v = 0` upward. Depths are clip depths in the matrices'
|
|
32
|
+
* convention, OpenGL's here — the nearest is the smallest — and the renderer converts its reversed
|
|
33
|
+
* buffer before a sample reaches this arithmetic, as the temporal resolve already does.
|
|
34
|
+
*/
|
|
35
|
+
import { clipToBox, rgbToYCoCg, varianceBox, yCoCgToRgb } from './clamp.ts';
|
|
36
|
+
import { disocclusionWeight, normalFromPositions, worldPositionFromDepth } from './disocclusion.ts';
|
|
37
|
+
import type { DisocclusionParams } from './disocclusion.ts';
|
|
38
|
+
import { sampleBilinear, sampleHistoryBicubic5 } from './reproject.ts';
|
|
39
|
+
|
|
40
|
+
/** What a reconstruction is asked for. */
|
|
41
|
+
export interface ReconQuality {
|
|
42
|
+
/** Output size over render size, each axis. 1.3 to 2; 0 is off. */
|
|
43
|
+
readonly ratio: number;
|
|
44
|
+
/** The current frame's share of a fully trusted accumulation. */
|
|
45
|
+
readonly alpha: number;
|
|
46
|
+
/** How far the shown picture is sharpened, 0 to 1. */
|
|
47
|
+
readonly sharpen: number;
|
|
48
|
+
/** Standard deviations the neighbourhood box extends either side of its mean. */
|
|
49
|
+
readonly clampGamma: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A tenth of each frame kept, as the temporal resolve keeps; a box of a standard deviation and a
|
|
54
|
+
* quarter; a light sharpen. At two thirds of the output a side.
|
|
55
|
+
*/
|
|
56
|
+
export const DEFAULT_RECON_QUALITY: ReconQuality = {
|
|
57
|
+
ratio: 1.5,
|
|
58
|
+
alpha: 0.1,
|
|
59
|
+
sharpen: 0.25,
|
|
60
|
+
clampGamma: 1.25,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The current colour and the clipped history mixed: the history's share is `weight × (1 − alpha)`.
|
|
65
|
+
*
|
|
66
|
+
* A weight of zero is the current colour exactly — no history — and a weight of one with an alpha of
|
|
67
|
+
* zero is the history exactly. A convex mixture, so repeated accumulation of one colour converges to
|
|
68
|
+
* it and never overshoots.
|
|
69
|
+
*/
|
|
70
|
+
export function accumulate(
|
|
71
|
+
out: Float32Array | Float64Array,
|
|
72
|
+
current: ArrayLike<number>,
|
|
73
|
+
history: ArrayLike<number>,
|
|
74
|
+
weight: number,
|
|
75
|
+
alpha: number,
|
|
76
|
+
): void {
|
|
77
|
+
const kept = Math.min(1, Math.max(0, weight)) * (1 - Math.min(1, Math.max(0, alpha)));
|
|
78
|
+
for (let c = 0; c < 3; c += 1) {
|
|
79
|
+
out[c] = (current[c] as number) * (1 - kept) + (history[c] as number) * kept;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The centre pushed away from its four neighbours' mean by `amount`, and **held inside the range of
|
|
85
|
+
* the five** — the halo a plain unsharp mask draws beside every edge is a value outside that range.
|
|
86
|
+
* A flat region has no difference to push, so it is unchanged.
|
|
87
|
+
*/
|
|
88
|
+
export function sharpen(
|
|
89
|
+
out: Float32Array | Float64Array,
|
|
90
|
+
centre: ArrayLike<number>,
|
|
91
|
+
neighbours: ArrayLike<number>,
|
|
92
|
+
amount: number,
|
|
93
|
+
): void {
|
|
94
|
+
for (let c = 0; c < 3; c += 1) {
|
|
95
|
+
const middle = centre[c] as number;
|
|
96
|
+
let low = middle;
|
|
97
|
+
let high = middle;
|
|
98
|
+
let sum = 0;
|
|
99
|
+
for (let n = 0; n < 4; n += 1) {
|
|
100
|
+
const value = neighbours[n * 3 + c] as number;
|
|
101
|
+
sum += value;
|
|
102
|
+
low = Math.min(low, value);
|
|
103
|
+
high = Math.max(high, value);
|
|
104
|
+
}
|
|
105
|
+
const pushed = middle + amount * (middle - sum / 4);
|
|
106
|
+
out[c] = Math.min(high, Math.max(low, pushed));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Everything one resolve reads. Images are rows from `v = 0` upward. */
|
|
111
|
+
export interface ResolveFrame {
|
|
112
|
+
readonly renderWidth: number;
|
|
113
|
+
readonly renderHeight: number;
|
|
114
|
+
readonly outputWidth: number;
|
|
115
|
+
readonly outputHeight: number;
|
|
116
|
+
/** Render size, three floats a texel, linear. */
|
|
117
|
+
readonly scene: ArrayLike<number>;
|
|
118
|
+
/** Render size, one clip depth a texel. */
|
|
119
|
+
readonly depth: ArrayLike<number>;
|
|
120
|
+
/**
|
|
121
|
+
* Render size, four floats a texel: a drawn object's motion in uv, its previous view depth, and a
|
|
122
|
+
* flag above one half where a draw wrote them.
|
|
123
|
+
*/
|
|
124
|
+
readonly motion: ArrayLike<number>;
|
|
125
|
+
/** Last frame's `depth`. */
|
|
126
|
+
readonly previousDepth: ArrayLike<number>;
|
|
127
|
+
/** Output size, four floats a texel: last frame's unsharpened colour, and the weight it gathered. */
|
|
128
|
+
readonly history: ArrayLike<number>;
|
|
129
|
+
/** False on the first frame, after a resize and after a cut. */
|
|
130
|
+
readonly hasHistory: boolean;
|
|
131
|
+
/** This frame's inverse view-projection, unjittered. */
|
|
132
|
+
readonly inverseViewProj: ArrayLike<number>;
|
|
133
|
+
/** Last frame's view-projection and its inverse, unjittered. */
|
|
134
|
+
readonly previousViewProj: ArrayLike<number>;
|
|
135
|
+
readonly previousInverseViewProj: ArrayLike<number>;
|
|
136
|
+
readonly eye: ArrayLike<number>;
|
|
137
|
+
readonly previousEye: ArrayLike<number>;
|
|
138
|
+
/** This frame's and last frame's jitter, in render pixels. */
|
|
139
|
+
readonly jitter: ArrayLike<number>;
|
|
140
|
+
readonly previousJitter: ArrayLike<number>;
|
|
141
|
+
readonly quality: ReconQuality;
|
|
142
|
+
readonly disocclusion: DisocclusionParams;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* How far a render sample's contribution reaches, in output pixels: a Gaussian's standard deviation.
|
|
147
|
+
*
|
|
148
|
+
* Just under half a pixel, so a sample on a pixel's centre counts fully and one a pixel away counts a
|
|
149
|
+
* tenth — the width a reconstruction filter needs to avoid both aliasing and a soft picture.
|
|
150
|
+
*/
|
|
151
|
+
export const SAMPLE_SPREAD = 0.47;
|
|
152
|
+
|
|
153
|
+
/** A render sample's weight at `(dx, dy)` output pixels from an output pixel's centre. */
|
|
154
|
+
export function reconstructionWeight(dx: number, dy: number): number {
|
|
155
|
+
return Math.exp(-(dx * dx + dy * dy) / (2 * SAMPLE_SPREAD * SAMPLE_SPREAD));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* How much gathered weight counts as knowing a pixel. Below it, the render's bicubic read fills in —
|
|
160
|
+
* which is every pixel on the first frame at a large ratio, where the nearest sample can be most of a
|
|
161
|
+
* pixel away.
|
|
162
|
+
*/
|
|
163
|
+
export const CONFIDENT_WEIGHT = 1;
|
|
164
|
+
|
|
165
|
+
const SAMPLE = new Float32Array(3);
|
|
166
|
+
const GATHERED = new Float64Array(3);
|
|
167
|
+
const HISTORY = new Float32Array(4);
|
|
168
|
+
const NEIGHBOURS = new Float64Array(27);
|
|
169
|
+
const LOW = new Float64Array(3);
|
|
170
|
+
const HIGH = new Float64Array(3);
|
|
171
|
+
const YCOCG = new Float64Array(3);
|
|
172
|
+
const CLIPPED = new Float64Array(3);
|
|
173
|
+
const MIXED = new Float64Array(3);
|
|
174
|
+
const WORLD = new Float64Array(3);
|
|
175
|
+
const RIGHT = new Float64Array(3);
|
|
176
|
+
const UP = new Float64Array(3);
|
|
177
|
+
const NORMAL = new Float64Array(3);
|
|
178
|
+
const PREVIOUS_NORMAL = new Float64Array(3);
|
|
179
|
+
const CLIP = new Float64Array(4);
|
|
180
|
+
|
|
181
|
+
function clampTexel(value: number, size: number): number {
|
|
182
|
+
return value < 0 ? 0 : value >= size ? size - 1 : value;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** A texel's world position from a depth image, at its unjittered uv. Returns the view depth, or 0. */
|
|
186
|
+
function worldAt(
|
|
187
|
+
depths: ArrayLike<number>,
|
|
188
|
+
inverse: ArrayLike<number>,
|
|
189
|
+
jitter: ArrayLike<number>,
|
|
190
|
+
width: number,
|
|
191
|
+
height: number,
|
|
192
|
+
x: number,
|
|
193
|
+
y: number,
|
|
194
|
+
out: Float64Array,
|
|
195
|
+
): number {
|
|
196
|
+
const tx = clampTexel(x, width);
|
|
197
|
+
const ty = clampTexel(y, height);
|
|
198
|
+
const u = (tx + 0.5 - (jitter[0] as number)) / width;
|
|
199
|
+
const v = (ty + 0.5 - (jitter[1] as number)) / height;
|
|
200
|
+
const z = depths[ty * width + tx] as number;
|
|
201
|
+
if (!worldPositionFromDepth(inverse, u, v, z, out)) return 0;
|
|
202
|
+
/* The view depth is the clip w, which the inverse's w is the reciprocal of. */
|
|
203
|
+
const m = inverse;
|
|
204
|
+
const w =
|
|
205
|
+
(m[3] as number) * (u * 2 - 1) +
|
|
206
|
+
(m[7] as number) * (v * 2 - 1) +
|
|
207
|
+
(m[11] as number) * z +
|
|
208
|
+
(m[15] as number);
|
|
209
|
+
return 1 / w;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** The world normal at a texel, from its depth and its right and upper neighbours'. */
|
|
213
|
+
function normalAt(
|
|
214
|
+
depths: ArrayLike<number>,
|
|
215
|
+
inverse: ArrayLike<number>,
|
|
216
|
+
jitter: ArrayLike<number>,
|
|
217
|
+
eye: ArrayLike<number>,
|
|
218
|
+
width: number,
|
|
219
|
+
height: number,
|
|
220
|
+
x: number,
|
|
221
|
+
y: number,
|
|
222
|
+
out: Float64Array,
|
|
223
|
+
): boolean {
|
|
224
|
+
if (worldAt(depths, inverse, jitter, width, height, x, y, WORLD) <= 0) return false;
|
|
225
|
+
/* The neighbour on the inside of the border, so the edge texels have a normal too. */
|
|
226
|
+
const dx = x + 1 < width ? 1 : -1;
|
|
227
|
+
const dy = y + 1 < height ? 1 : -1;
|
|
228
|
+
if (worldAt(depths, inverse, jitter, width, height, x + dx, y, RIGHT) <= 0) return false;
|
|
229
|
+
if (worldAt(depths, inverse, jitter, width, height, x, y + dy, UP) <= 0) return false;
|
|
230
|
+
return normalFromPositions(WORLD, RIGHT, UP, eye, out);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The weight a pixel's history still deserves this frame: none on the first frame, where the surface
|
|
235
|
+
* was behind last frame's eye or off its picture, and otherwise what it gathered, scaled by whether it
|
|
236
|
+
* is the same surface. Reads `HISTORY`; writes the history's colour there.
|
|
237
|
+
*/
|
|
238
|
+
function historyWeight(frame: ResolveFrame, u: number, v: number, dx: number, dy: number): number {
|
|
239
|
+
if (!frame.hasHistory) return 0;
|
|
240
|
+
const rw = frame.renderWidth;
|
|
241
|
+
const rh = frame.renderHeight;
|
|
242
|
+
const flagAt = (dy * rw + dx) * 4;
|
|
243
|
+
let mu: number;
|
|
244
|
+
let mv: number;
|
|
245
|
+
let expected: number;
|
|
246
|
+
if ((frame.motion[flagAt + 3] as number) > 0.5) {
|
|
247
|
+
mu = frame.motion[flagAt] as number;
|
|
248
|
+
mv = frame.motion[flagAt + 1] as number;
|
|
249
|
+
expected = frame.motion[flagAt + 2] as number;
|
|
250
|
+
} else {
|
|
251
|
+
if (worldAt(frame.depth, frame.inverseViewProj, frame.jitter, rw, rh, dx, dy, WORLD) <= 0) {
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
const m = frame.previousViewProj;
|
|
255
|
+
for (let r = 0; r < 4; r += 1) {
|
|
256
|
+
CLIP[r] =
|
|
257
|
+
(m[r] as number) * (WORLD[0] as number) +
|
|
258
|
+
(m[4 + r] as number) * (WORLD[1] as number) +
|
|
259
|
+
(m[8 + r] as number) * (WORLD[2] as number) +
|
|
260
|
+
(m[12 + r] as number);
|
|
261
|
+
}
|
|
262
|
+
/*
|
|
263
|
+
* A surface behind last frame's eye has a w that is not positive: the disocclusion trusts no
|
|
264
|
+
* such depth, so it needs no refusal of its own here.
|
|
265
|
+
*/
|
|
266
|
+
expected = CLIP[3] as number;
|
|
267
|
+
const du = (dx + 0.5 - (frame.jitter[0] as number)) / rw;
|
|
268
|
+
const dv = (dy + 0.5 - (frame.jitter[1] as number)) / rh;
|
|
269
|
+
mu = ((CLIP[0] as number) / expected) * 0.5 + 0.5 - du;
|
|
270
|
+
mv = ((CLIP[1] as number) / expected) * 0.5 + 0.5 - dv;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const pu = u + mu;
|
|
274
|
+
const pv = v + mv;
|
|
275
|
+
if (!(pu >= 0 && pu <= 1 && pv >= 0 && pv <= 1)) return 0;
|
|
276
|
+
sampleHistoryBicubic5(
|
|
277
|
+
frame.history,
|
|
278
|
+
pu * frame.outputWidth - 0.5,
|
|
279
|
+
pv * frame.outputHeight - 0.5,
|
|
280
|
+
frame.outputWidth,
|
|
281
|
+
frame.outputHeight,
|
|
282
|
+
4,
|
|
283
|
+
HISTORY,
|
|
284
|
+
);
|
|
285
|
+
const px = clampTexel(Math.round(pu * rw + (frame.previousJitter[0] as number) - 0.5), rw);
|
|
286
|
+
const py = clampTexel(Math.round(pv * rh + (frame.previousJitter[1] as number) - 0.5), rh);
|
|
287
|
+
const held = worldAt(
|
|
288
|
+
frame.previousDepth,
|
|
289
|
+
frame.previousInverseViewProj,
|
|
290
|
+
frame.previousJitter,
|
|
291
|
+
rw,
|
|
292
|
+
rh,
|
|
293
|
+
px,
|
|
294
|
+
py,
|
|
295
|
+
RIGHT,
|
|
296
|
+
);
|
|
297
|
+
let normalDot = 1;
|
|
298
|
+
if (
|
|
299
|
+
normalAt(frame.depth, frame.inverseViewProj, frame.jitter, frame.eye, rw, rh, dx, dy, NORMAL) &&
|
|
300
|
+
normalAt(
|
|
301
|
+
frame.previousDepth,
|
|
302
|
+
frame.previousInverseViewProj,
|
|
303
|
+
frame.previousJitter,
|
|
304
|
+
frame.previousEye,
|
|
305
|
+
rw,
|
|
306
|
+
rh,
|
|
307
|
+
px,
|
|
308
|
+
py,
|
|
309
|
+
PREVIOUS_NORMAL,
|
|
310
|
+
)
|
|
311
|
+
) {
|
|
312
|
+
normalDot =
|
|
313
|
+
(NORMAL[0] as number) * (PREVIOUS_NORMAL[0] as number) +
|
|
314
|
+
(NORMAL[1] as number) * (PREVIOUS_NORMAL[1] as number) +
|
|
315
|
+
(NORMAL[2] as number) * (PREVIOUS_NORMAL[2] as number);
|
|
316
|
+
}
|
|
317
|
+
const trust = disocclusionWeight(
|
|
318
|
+
expected,
|
|
319
|
+
held,
|
|
320
|
+
Math.hypot(mu, mv),
|
|
321
|
+
normalDot,
|
|
322
|
+
frame.disocclusion,
|
|
323
|
+
);
|
|
324
|
+
return (HISTORY[3] as number) * trust;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* One output pixel: the history's next colour, before sharpening, and the weight it has gathered —
|
|
329
|
+
* four values into `out`.
|
|
330
|
+
*/
|
|
331
|
+
export function resolvePixel(frame: ResolveFrame, ox: number, oy: number, out: Float32Array): void {
|
|
332
|
+
const rw = frame.renderWidth;
|
|
333
|
+
const rh = frame.renderHeight;
|
|
334
|
+
const ow = frame.outputWidth;
|
|
335
|
+
const oh = frame.outputHeight;
|
|
336
|
+
const u = (ox + 0.5) / ow;
|
|
337
|
+
const v = (oy + 0.5) / oh;
|
|
338
|
+
const jx = frame.jitter[0] as number;
|
|
339
|
+
const jy = frame.jitter[1] as number;
|
|
340
|
+
|
|
341
|
+
/* Where this frame observed the pixel, and the render read there for the gaps. */
|
|
342
|
+
const rx = u * rw + jx - 0.5;
|
|
343
|
+
const ry = v * rh + jy - 0.5;
|
|
344
|
+
sampleHistoryBicubic5(frame.scene, rx, ry, rw, rh, 3, SAMPLE);
|
|
345
|
+
const nx = clampTexel(Math.round(rx), rw);
|
|
346
|
+
const ny = clampTexel(Math.round(ry), rh);
|
|
347
|
+
|
|
348
|
+
/* 1 and 2. Each texel around: its weight, its colour in the box, and its depth. */
|
|
349
|
+
let nearest = frame.depth[ny * rw + nx] as number;
|
|
350
|
+
let dx = nx;
|
|
351
|
+
let dy = ny;
|
|
352
|
+
let gathered = 0;
|
|
353
|
+
GATHERED.fill(0);
|
|
354
|
+
for (let j = -1; j <= 1; j += 1) {
|
|
355
|
+
for (let i = -1; i <= 1; i += 1) {
|
|
356
|
+
const tx = clampTexel(nx + i, rw);
|
|
357
|
+
const ty = clampTexel(ny + j, rh);
|
|
358
|
+
const at = (ty * rw + tx) * 3;
|
|
359
|
+
const r = frame.scene[at] as number;
|
|
360
|
+
const g = frame.scene[at + 1] as number;
|
|
361
|
+
const b = frame.scene[at + 2] as number;
|
|
362
|
+
const weight = reconstructionWeight(
|
|
363
|
+
((tx + 0.5 - jx) / rw) * ow - (ox + 0.5),
|
|
364
|
+
((ty + 0.5 - jy) / rh) * oh - (oy + 0.5),
|
|
365
|
+
);
|
|
366
|
+
gathered += weight;
|
|
367
|
+
GATHERED[0] = (GATHERED[0] as number) + r * weight;
|
|
368
|
+
GATHERED[1] = (GATHERED[1] as number) + g * weight;
|
|
369
|
+
GATHERED[2] = (GATHERED[2] as number) + b * weight;
|
|
370
|
+
rgbToYCoCg(YCOCG, r, g, b);
|
|
371
|
+
NEIGHBOURS.set(YCOCG, ((j + 1) * 3 + (i + 1)) * 3);
|
|
372
|
+
const z = frame.depth[ty * rw + tx] as number;
|
|
373
|
+
if (z < nearest) {
|
|
374
|
+
nearest = z;
|
|
375
|
+
dx = tx;
|
|
376
|
+
dy = ty;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
varianceBox(NEIGHBOURS, 9, frame.quality.clampGamma, LOW, HIGH);
|
|
381
|
+
for (let c = 0; c < 3; c += 1) GATHERED[c] = (GATHERED[c] as number) / gathered;
|
|
382
|
+
|
|
383
|
+
/* 3 and 4. The history, and the weight it still deserves. */
|
|
384
|
+
const cap = (1 - frame.quality.alpha) / frame.quality.alpha;
|
|
385
|
+
const kept = Math.min(cap, historyWeight(frame, u, v, dx, dy));
|
|
386
|
+
|
|
387
|
+
/* 5. Clipped, mixed by weight, and the gaps filled from the render. */
|
|
388
|
+
const total = kept + gathered;
|
|
389
|
+
if (kept > 0) {
|
|
390
|
+
rgbToYCoCg(YCOCG, HISTORY[0] as number, HISTORY[1] as number, HISTORY[2] as number);
|
|
391
|
+
clipToBox(CLIPPED, YCOCG, LOW, HIGH);
|
|
392
|
+
yCoCgToRgb(YCOCG, CLIPPED[0] as number, CLIPPED[1] as number, CLIPPED[2] as number);
|
|
393
|
+
accumulate(MIXED, GATHERED, YCOCG, 1, gathered / total);
|
|
394
|
+
} else {
|
|
395
|
+
MIXED.set(GATHERED);
|
|
396
|
+
}
|
|
397
|
+
const known = Math.min(1, total / CONFIDENT_WEIGHT);
|
|
398
|
+
for (let c = 0; c < 3; c += 1) {
|
|
399
|
+
out[c] = (SAMPLE[c] as number) * (1 - known) + (MIXED[c] as number) * known;
|
|
400
|
+
}
|
|
401
|
+
out[3] = total;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const TAP = new Float32Array(4);
|
|
405
|
+
const CENTRE = new Float32Array(4);
|
|
406
|
+
const AROUND = new Float32Array(12);
|
|
407
|
+
const SHOWN = new Float32Array(3);
|
|
408
|
+
const OFFSETS: readonly (readonly [number, number])[] = [
|
|
409
|
+
[-1, 0],
|
|
410
|
+
[1, 0],
|
|
411
|
+
[0, -1],
|
|
412
|
+
[0, 1],
|
|
413
|
+
];
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* The whole frame: the next history into `history`, four floats a pixel, and the picture shown into
|
|
417
|
+
* `shown`, three — the history sharpened against the four direct neighbours it has just been given.
|
|
418
|
+
*/
|
|
419
|
+
export function resolveFrame(
|
|
420
|
+
frame: ResolveFrame,
|
|
421
|
+
history: Float32Array,
|
|
422
|
+
shown: Float32Array,
|
|
423
|
+
): void {
|
|
424
|
+
const ow = frame.outputWidth;
|
|
425
|
+
const oh = frame.outputHeight;
|
|
426
|
+
for (let y = 0; y < oh; y += 1) {
|
|
427
|
+
for (let x = 0; x < ow; x += 1) {
|
|
428
|
+
resolvePixel(frame, x, y, TAP);
|
|
429
|
+
history.set(TAP, (y * ow + x) * 4);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
for (let y = 0; y < oh; y += 1) {
|
|
433
|
+
for (let x = 0; x < ow; x += 1) {
|
|
434
|
+
sampleBilinear(history, x, y, ow, oh, 4, CENTRE);
|
|
435
|
+
for (let n = 0; n < 4; n += 1) {
|
|
436
|
+
const offset = OFFSETS[n] as readonly [number, number];
|
|
437
|
+
sampleBilinear(history, x + offset[0], y + offset[1], ow, oh, 4, TAP);
|
|
438
|
+
AROUND.set(TAP.subarray(0, 3), n * 3);
|
|
439
|
+
}
|
|
440
|
+
sharpen(SHOWN, CENTRE, AROUND, frame.quality.sharpen);
|
|
441
|
+
shown.set(SHOWN, (y * ow + x) * 3);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which reconstruction tier a request gets.
|
|
3
|
+
*
|
|
4
|
+
* **Tier 0, DriftTR, is analytic** and runs wherever compute does. **Tier 2, DriftFG**, generates
|
|
5
|
+
* frames between rendered ones, over tier 0.
|
|
6
|
+
*
|
|
7
|
+
* **Tier 1, DriftNeural, was withdrawn before 4.0.0 by the spec's own stop condition**, and a request
|
|
8
|
+
* for it is tier 0 on every device. Measured (the plan's Tasks 8 and 9): a network refining the
|
|
9
|
+
* finished frame averaged +0.01 dB on scenes it had not seen, and lost the one clear difference in a
|
|
10
|
+
* blind comparison. The analytic tier was designed to stand without it, so this is the degradation
|
|
11
|
+
* the design was built around rather than a gap in it.
|
|
12
|
+
*
|
|
13
|
+
* **Tier 2 used to fall to tier 0 wherever tier 1 could not run**, so that a device lacking half
|
|
14
|
+
* precision could not choose frame generation over the analytic tier for a consumer who had asked
|
|
15
|
+
* for the learned base. With no learned base there is nothing to choose between, and a request for
|
|
16
|
+
* tier 2 is a request for exactly that. **What would make this wrong** is a learned tier that
|
|
17
|
+
* measures better — a network inside the resolve rather than after it — which brings the rule back.
|
|
18
|
+
*/
|
|
19
|
+
import type { GpuCapabilities } from '../deviceFeatures.ts';
|
|
20
|
+
|
|
21
|
+
export type ReconTier = 0 | 1 | 2;
|
|
22
|
+
|
|
23
|
+
/** Whether this device can reconstruct at all: the tiers are compute dispatches. */
|
|
24
|
+
export function reconstructionSupported(caps: GpuCapabilities): boolean {
|
|
25
|
+
return caps.indirect;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The tier a request gets, wherever `reconstructionSupported` says reconstruction runs at all. */
|
|
29
|
+
export function selectTier(requested: ReconTier): ReconTier {
|
|
30
|
+
return requested === 1 ? 0 : requested;
|
|
31
|
+
}
|
|
@@ -4,6 +4,40 @@ import type { Vec3 } from '../math/color.ts';
|
|
|
4
4
|
import { Camera } from './camera.ts';
|
|
5
5
|
import { roughnessForLevel } from './prefilterEnvMap.ts';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* The same view-projection with clip y negated, which is what rendering into a cube face wants.
|
|
9
|
+
*
|
|
10
|
+
* **A cubemap face's rows run downward and a GL framebuffer's run upward.** `framebufferTexture2D`
|
|
11
|
+
* on `TEXTURE_CUBE_MAP_POSITIVE_X + face` makes framebuffer row 0 the face's texel row 0, and the
|
|
12
|
+
* face's own direction mapping — the specification's `sc`, `tc`, `ma` table — says texel row 0 is
|
|
13
|
+
* the +Y end. A camera aimed along the face with its up at +Y puts +Y at the top of the render
|
|
14
|
+
* area, which in GL is the *last* row, so the face is stored upside down and every reflection and
|
|
15
|
+
* every irradiance sample taken from it has up and down the wrong way round.
|
|
16
|
+
*
|
|
17
|
+
* **Almost nothing can see it**, which is why it stood until 2026-09-16. A face that is flat, or
|
|
18
|
+
* chequered, or bright across its whole width is symmetric under a vertical flip, and so was every
|
|
19
|
+
* room this repository could bake into a probe. `showroom` is not: its walls are a lit cove and
|
|
20
|
+
* ceiling above and a dark floor below, and its ceiling came out 22 levels of 255 from what the
|
|
21
|
+
* other backend drew, with its floor 7 the other way and its walls exactly equal — a difference
|
|
22
|
+
* that reverses between a surface facing up and one facing down and leaves a horizontal one alone
|
|
23
|
+
* is a probe with its rows the wrong way up. `demo/dev/ibl.html?band=1` is the room that shows it
|
|
24
|
+
* directly: four side walls bright above and dark below, and without this correction the spheres
|
|
25
|
+
* in it are lit from underneath.
|
|
26
|
+
*
|
|
27
|
+
* **The winding goes with it.** Negating one clip axis mirrors every triangle, so a caller has to
|
|
28
|
+
* flip the front face for the duration or the room turns inside out — `bakeProbe` does.
|
|
29
|
+
*
|
|
30
|
+
* Writing into the source is allowed: each output element reads only the element at its own index.
|
|
31
|
+
*/
|
|
32
|
+
export function cubeFaceProjection(out: Float32Array, viewProj: ArrayLike<number>): Float32Array {
|
|
33
|
+
for (let i = 0; i < 16; i++) {
|
|
34
|
+
const value = viewProj[i] as number;
|
|
35
|
+
/* Row one of a column-major 4x4 is indices 1, 5, 9, 13 — the row that produces clip y. */
|
|
36
|
+
out[i] = i % 4 === 1 ? -value : value;
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
7
41
|
/**
|
|
8
42
|
* What a bake is for, and specifically whether it also replaces the scene's diffuse ambient.
|
|
9
43
|
*
|
|
@@ -327,6 +327,23 @@ export interface RenderQuality {
|
|
|
327
327
|
* rather than to a release. `?graph=0` turns it off in one reload.
|
|
328
328
|
*/
|
|
329
329
|
readonly frameGraph: boolean;
|
|
330
|
+
/**
|
|
331
|
+
* Schedule each flush through the identifier graph rather than through masks. WebGPU only.
|
|
332
|
+
*
|
|
333
|
+
* **Off, and nothing a consumer can see changes with it on.** The graph `frameGraph` records is
|
|
334
|
+
* the same either way; this chooses which scheduler groups it into passes and derives what each
|
|
335
|
+
* attachment loads and stores. The mask scheduler is exactly right for a frame whose composition
|
|
336
|
+
* is fixed, and the identifier graph is what can also express a frame whose composition is not —
|
|
337
|
+
* the second pipeline's — so this is the switch that says the second is a generalisation of the
|
|
338
|
+
* first: the eighteen scenes the harness walks are pixel-identical with it on, measured
|
|
339
|
+
* 2026-09-17 — `showroom` in six captures a side, because it varies between runs of one build
|
|
340
|
+
* whatever this says. `frame/flushGraph.ts` says where the two can part, and why no flush the
|
|
341
|
+
* renderer makes reaches it.
|
|
342
|
+
*
|
|
343
|
+
* Ignored where `frameGraph` is off, which records nothing to schedule, and on WebGL2, which has no
|
|
344
|
+
* verb-level graph. `?idgraph=1` turns it on in one reload.
|
|
345
|
+
*/
|
|
346
|
+
readonly identifierGraph: boolean;
|
|
330
347
|
/**
|
|
331
348
|
* Light the world from a froxel table rather than from a fixed set of uniform-array slots.
|
|
332
349
|
*
|
|
@@ -493,6 +510,53 @@ export interface RenderQuality {
|
|
|
493
510
|
* it be identical on both backends and asserted without one.
|
|
494
511
|
*/
|
|
495
512
|
readonly occlusionCulling: number;
|
|
513
|
+
/**
|
|
514
|
+
* Reconstruction: how many output pixels the renderer draws for each render pixel, each axis.
|
|
515
|
+
* **0 is off and is the default.**
|
|
516
|
+
*
|
|
517
|
+
* On, the scene and everything that reads it before the resolve are drawn at
|
|
518
|
+
* `ceil(output / ratio)` and a compute dispatch reconstructs the output-size picture from this
|
|
519
|
+
* frame and the accumulated history — DriftTR, `render/recon/`. What it saves is `1 - 1/r²` of
|
|
520
|
+
* the scene's fragment work, which at 1.5 is 56%; what it costs is one motion target and one
|
|
521
|
+
* previous depth at render size, two output-size histories and one dispatch.
|
|
522
|
+
*
|
|
523
|
+
* **Off is byte-for-byte what the renderer does today**, which is what the published scenes are
|
|
524
|
+
* gated at. WebGPU only: WebGL2 has no compute stage, and it keeps the temporal resolve at native
|
|
525
|
+
* size, which is what it does now.
|
|
526
|
+
*
|
|
527
|
+
* **Zero is off rather than one, because one is a thing somebody might mean** — the resolve at
|
|
528
|
+
* the output size with no upscaling, which is a temporal antialiaser with a better neighbourhood
|
|
529
|
+
* rule than `temporalAa`'s. A sentinel that collided with it would make that unaskable.
|
|
530
|
+
*
|
|
531
|
+
* The range is 1.3 to 2 and a value inside it is clamped to the end it is nearest. Below 1.3 the
|
|
532
|
+
* render saves less than a third of the fragment work and the resolve's own cost eats it; above 2
|
|
533
|
+
* the render is a quarter of the output and no reconstruction holds an edge through that. A
|
|
534
|
+
* negative number is off, not a clamp to the bottom: it cannot mean "a little".
|
|
535
|
+
*
|
|
536
|
+
* `?recon=` is how it gets A/B'd in one reload.
|
|
537
|
+
*/
|
|
538
|
+
readonly reconstruction: number;
|
|
539
|
+
/**
|
|
540
|
+
* Light a scene from what bounces, rather than from what was baked. **Off by default.**
|
|
541
|
+
*
|
|
542
|
+
* On, the probe grid the shading already samples is filled by tracing `render/gi/`'s three-level
|
|
543
|
+
* chain — the world distance field, and behind it the probes themselves, which is what makes the
|
|
544
|
+
* solution converge on several bounces over a few refreshes. Off, the probes hold one bounce of
|
|
545
|
+
* the rasterised scene, which is what this engine has always baked.
|
|
546
|
+
*
|
|
547
|
+
* **A switch rather than a strength.** Half an indirect bounce is not a thing to ask for: a probe
|
|
548
|
+
* either holds what the chain traced or it holds what the cube held, and mixing them is two
|
|
549
|
+
* solutions averaged rather than one at a lower quality. What is adjustable is how many probes
|
|
550
|
+
* refresh a frame, and that belongs to the grid.
|
|
551
|
+
*
|
|
552
|
+
* **WebGPU only**, and refused in words elsewhere — `INDIRECT_LIGHT_WEBGL2_REFUSAL`. A probe is a
|
|
553
|
+
* few hundred rays and that is a compute dispatch; WebGL2 has no stage for one, and the
|
|
554
|
+
* alternative — the two backends lighting one scene differently — is the disagreement the
|
|
555
|
+
* published pixel gate exists to prevent.
|
|
556
|
+
*
|
|
557
|
+
* `?indirect=1` turns it on in one reload.
|
|
558
|
+
*/
|
|
559
|
+
readonly indirectLight: boolean;
|
|
496
560
|
/**
|
|
497
561
|
* Ambient occlusion, 0 to 1. Off by default.
|
|
498
562
|
*
|
|
@@ -774,6 +838,8 @@ export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
|
|
|
774
838
|
temporalAa: false,
|
|
775
839
|
orderIndependent: false,
|
|
776
840
|
depthOfField: 0,
|
|
841
|
+
reconstruction: 0,
|
|
842
|
+
indirectLight: false,
|
|
777
843
|
occlusionCulling: 0,
|
|
778
844
|
ambientOcclusion: 0,
|
|
779
845
|
nightEmissive: false,
|
|
@@ -851,6 +917,7 @@ export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
|
|
|
851
917
|
discardResolvedAttachments: true,
|
|
852
918
|
deferFramePass: true,
|
|
853
919
|
frameGraph: true,
|
|
920
|
+
identifierGraph: false,
|
|
854
921
|
clusteredLights: false,
|
|
855
922
|
cullDraws: false,
|
|
856
923
|
/*
|
|
@@ -862,6 +929,22 @@ export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
|
|
|
862
929
|
});
|
|
863
930
|
|
|
864
931
|
/** Resolve and validate once at renderer construction, never in a hot path. */
|
|
932
|
+
/** The narrowest and widest ratio a reconstruction runs at; outside them a caller means the end. */
|
|
933
|
+
export const RECONSTRUCTION_RANGE = { least: 1.3, most: 2 } as const;
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Off, or a ratio inside the range.
|
|
937
|
+
*
|
|
938
|
+
* Anything that is not a positive number is off, which covers the default, a negative, and a
|
|
939
|
+
* `NaN` arriving from a query string somebody spelled wrong — none of those can mean "a little
|
|
940
|
+
* reconstruction", and a renderer that guessed one would be drawing at a size nobody asked for.
|
|
941
|
+
*/
|
|
942
|
+
function resolveReconstruction(asked: number | undefined): number {
|
|
943
|
+
const value = asked ?? DEFAULT_RENDER_QUALITY.reconstruction;
|
|
944
|
+
if (!(value > 0)) return 0;
|
|
945
|
+
return Math.min(RECONSTRUCTION_RANGE.most, Math.max(RECONSTRUCTION_RANGE.least, value));
|
|
946
|
+
}
|
|
947
|
+
|
|
865
948
|
export function resolveRenderQuality(options: RenderQualityOptions = {}): Readonly<RenderQuality> {
|
|
866
949
|
const quality: RenderQuality = {
|
|
867
950
|
outputTransform: options.outputTransform ?? DEFAULT_RENDER_QUALITY.outputTransform,
|
|
@@ -914,6 +997,9 @@ export function resolveRenderQuality(options: RenderQualityOptions = {}): Readon
|
|
|
914
997
|
),
|
|
915
998
|
temporalAa: options.temporalAa ?? DEFAULT_RENDER_QUALITY.temporalAa,
|
|
916
999
|
orderIndependent: options.orderIndependent ?? DEFAULT_RENDER_QUALITY.orderIndependent,
|
|
1000
|
+
/* Off, or a ratio at least 1.3 and at most 2 — never a number between zero and the range. */
|
|
1001
|
+
reconstruction: resolveReconstruction(options.reconstruction),
|
|
1002
|
+
indirectLight: options.indirectLight ?? DEFAULT_RENDER_QUALITY.indirectLight,
|
|
917
1003
|
depthOfField: Math.min(
|
|
918
1004
|
1,
|
|
919
1005
|
Math.max(0, options.depthOfField ?? DEFAULT_RENDER_QUALITY.depthOfField),
|
|
@@ -969,6 +1055,7 @@ export function resolveRenderQuality(options: RenderQualityOptions = {}): Readon
|
|
|
969
1055
|
options.discardResolvedAttachments ?? DEFAULT_RENDER_QUALITY.discardResolvedAttachments,
|
|
970
1056
|
deferFramePass: options.deferFramePass ?? DEFAULT_RENDER_QUALITY.deferFramePass,
|
|
971
1057
|
frameGraph: options.frameGraph ?? DEFAULT_RENDER_QUALITY.frameGraph,
|
|
1058
|
+
identifierGraph: options.identifierGraph ?? DEFAULT_RENDER_QUALITY.identifierGraph,
|
|
972
1059
|
clusteredLights: options.clusteredLights ?? DEFAULT_RENDER_QUALITY.clusteredLights,
|
|
973
1060
|
cullDraws: options.cullDraws ?? DEFAULT_RENDER_QUALITY.cullDraws,
|
|
974
1061
|
waterReflectionFilterTaps:
|