@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,332 @@
|
|
|
1
|
+
/** Every material's decode programs, flattened into what the shading pass binds. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DECODE_ADDRESS_MODES,
|
|
5
|
+
DECODE_CONSTANT_CAPACITY,
|
|
6
|
+
DECODE_FBM_OCTAVES,
|
|
7
|
+
DECODE_NETWORK_CAPACITY,
|
|
8
|
+
DECODE_NETWORK_HIDDEN_LAYERS,
|
|
9
|
+
DECODE_NETWORK_INPUTS,
|
|
10
|
+
DECODE_NETWORK_OUTPUTS,
|
|
11
|
+
DECODE_NETWORK_WIDTH,
|
|
12
|
+
DECODE_NODE_CAPACITY,
|
|
13
|
+
DECODE_NODES_BYTES,
|
|
14
|
+
DECODE_OPS,
|
|
15
|
+
DECODE_PROGRAM_CAPACITY,
|
|
16
|
+
DECODE_REGISTERS,
|
|
17
|
+
DECODE_WEIGHT_BLOCKS,
|
|
18
|
+
DECODE_WEIGHTS_BYTES,
|
|
19
|
+
} from '../shaders/gpudriven/decode.wgsl.ts';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* **A program is `DecodeResources` with bytes rather than floats**, because bytes are what the
|
|
23
|
+
* device array holds. The types are structural: core does not import `@driftengine/texture`, and
|
|
24
|
+
* what `encodeMaterial` returns satisfies `programFromEncoded` as it stands.
|
|
25
|
+
*
|
|
26
|
+
* **Every slot a graph names is program-local and is rewritten here to a global one** — a layer, a
|
|
27
|
+
* network, a constant — so the interpreter needs no per-program indirection table. The graph a
|
|
28
|
+
* caller handed in is not modified; the rewritten copy lives only in the table.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export interface GpuDrivenLatent {
|
|
32
|
+
readonly width: number;
|
|
33
|
+
readonly height: number;
|
|
34
|
+
/** One to four. The lanes past them read zero, and alpha reads one, as `decodeCpu` does. */
|
|
35
|
+
readonly components: number;
|
|
36
|
+
/** Level 0 first, each half the last, down to one texel. `components` bytes a texel. */
|
|
37
|
+
readonly levels: readonly Uint8Array[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface GpuDrivenNetwork {
|
|
41
|
+
readonly shape: {
|
|
42
|
+
readonly inputs: number;
|
|
43
|
+
readonly hidden: readonly number[];
|
|
44
|
+
readonly outputs: number;
|
|
45
|
+
};
|
|
46
|
+
readonly weights: Float32Array;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface GpuDrivenProgram {
|
|
50
|
+
readonly graph: {
|
|
51
|
+
readonly nodes: Uint32Array;
|
|
52
|
+
readonly count: number;
|
|
53
|
+
readonly result: number;
|
|
54
|
+
readonly addressMode: number;
|
|
55
|
+
};
|
|
56
|
+
readonly latents: readonly GpuDrivenLatent[];
|
|
57
|
+
readonly blocks?: readonly GpuDrivenLatent[];
|
|
58
|
+
readonly networks: readonly GpuDrivenNetwork[];
|
|
59
|
+
/** Four floats a slot, for `CONSTANT`. */
|
|
60
|
+
readonly constants?: Float32Array;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface DecodeTables {
|
|
64
|
+
readonly nodes: Uint32Array;
|
|
65
|
+
readonly weights: Float32Array;
|
|
66
|
+
/** One array a mip level: every layer's RGBA bytes, layer after layer. */
|
|
67
|
+
readonly levels: readonly Uint8Array[];
|
|
68
|
+
/** At least one, because a texture array of no layers cannot be created. */
|
|
69
|
+
readonly layerCount: number;
|
|
70
|
+
/** Level 0's edge in texels. One when nothing is sampled. */
|
|
71
|
+
readonly layerSize: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** What `encodeMaterial` returns, as far as this needs it. */
|
|
75
|
+
export interface EncodedProgramShape {
|
|
76
|
+
readonly latentWidth: number;
|
|
77
|
+
readonly latentHeight: number;
|
|
78
|
+
readonly components: number;
|
|
79
|
+
readonly weights: Float32Array;
|
|
80
|
+
readonly shape: GpuDrivenNetwork['shape'];
|
|
81
|
+
readonly graph: GpuDrivenProgram['graph'];
|
|
82
|
+
/** Level 0 first — `encodeMaterial` puts the latent itself there. */
|
|
83
|
+
readonly mips: readonly { readonly data: Uint8Array }[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function programFromEncoded(encoded: EncodedProgramShape): GpuDrivenProgram {
|
|
87
|
+
return {
|
|
88
|
+
graph: encoded.graph,
|
|
89
|
+
latents: [
|
|
90
|
+
{
|
|
91
|
+
width: encoded.latentWidth,
|
|
92
|
+
height: encoded.latentHeight,
|
|
93
|
+
components: encoded.components,
|
|
94
|
+
levels: encoded.mips.map((level) => level.data),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
networks: [{ shape: encoded.shape, weights: encoded.weights }],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const NETWORK_AT = DECODE_PROGRAM_CAPACITY * 4;
|
|
102
|
+
const NODE_AT = NETWORK_AT + DECODE_NETWORK_CAPACITY * 8;
|
|
103
|
+
const CONSTANT_AT = DECODE_WEIGHT_BLOCKS * 4;
|
|
104
|
+
|
|
105
|
+
/** Whether an operation's `a` and `b` name registers. `decodeGraph.ts`'s `OP_ARGS`, again. */
|
|
106
|
+
const REGISTER_ARGS: Readonly<Record<number, readonly [boolean, boolean]>> = {
|
|
107
|
+
[DECODE_OPS.SAMPLE_LATENT]: [false, false],
|
|
108
|
+
[DECODE_OPS.EVAL_NETWORK]: [true, false],
|
|
109
|
+
[DECODE_OPS.SAMPLE_BLOCK]: [false, false],
|
|
110
|
+
[DECODE_OPS.PROCEDURAL_FBM]: [false, false],
|
|
111
|
+
[DECODE_OPS.FLIPBOOK_INDEX]: [false, false],
|
|
112
|
+
[DECODE_OPS.LATENT_LERP]: [true, true],
|
|
113
|
+
[DECODE_OPS.REMAP_CHANNEL]: [true, false],
|
|
114
|
+
[DECODE_OPS.COMPOSITE]: [true, true],
|
|
115
|
+
[DECODE_OPS.CONSTANT]: [false, false],
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
function refuse(message: string): never {
|
|
119
|
+
throw new Error(`[driftengine] ${message}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** `networkWeightCount`, again, for the same reason `REGISTER_ARGS` is. */
|
|
123
|
+
function weightCount(shape: GpuDrivenNetwork['shape']): number {
|
|
124
|
+
let total = 0;
|
|
125
|
+
let previous = shape.inputs;
|
|
126
|
+
for (const width of shape.hidden) {
|
|
127
|
+
total += previous * width + width;
|
|
128
|
+
previous = width;
|
|
129
|
+
}
|
|
130
|
+
return total + previous * shape.outputs + shape.outputs;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function packDecodeTables(programs: readonly GpuDrivenProgram[]): DecodeTables {
|
|
134
|
+
if (programs.length > DECODE_PROGRAM_CAPACITY) {
|
|
135
|
+
refuse(`${programs.length} programs, past the ${DECODE_PROGRAM_CAPACITY} the table holds`);
|
|
136
|
+
}
|
|
137
|
+
const nodes = new Uint32Array(DECODE_NODES_BYTES / 4);
|
|
138
|
+
const weights = new Float32Array(DECODE_WEIGHTS_BYTES / 4);
|
|
139
|
+
|
|
140
|
+
const first = programs.flatMap((p) => [...p.latents, ...(p.blocks ?? [])])[0];
|
|
141
|
+
const layerSize = first?.width ?? 1;
|
|
142
|
+
if (!(layerSize > 0 && (layerSize & (layerSize - 1)) === 0)) {
|
|
143
|
+
refuse(`a latent is ${layerSize} texels across, and a layer's edge has to be a power of two`);
|
|
144
|
+
}
|
|
145
|
+
const levelCount = Math.log2(layerSize) + 1;
|
|
146
|
+
const chunks: Uint8Array[][] = Array.from({ length: levelCount }, () => []);
|
|
147
|
+
|
|
148
|
+
let layers = 0;
|
|
149
|
+
let networkCount = 0;
|
|
150
|
+
let nodeCount = 0;
|
|
151
|
+
let weightAt = 0;
|
|
152
|
+
let constantCount = 0;
|
|
153
|
+
|
|
154
|
+
const addLatent = (latent: GpuDrivenLatent): number => {
|
|
155
|
+
if (latent.width !== layerSize || latent.height !== layerSize) {
|
|
156
|
+
refuse(
|
|
157
|
+
`a latent is ${latent.width} by ${latent.height}, and every latent in one pass is ` +
|
|
158
|
+
`${layerSize} by ${layerSize}`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
if (latent.components < 1 || latent.components > 4) {
|
|
162
|
+
refuse(`a latent has ${latent.components} components, not one to four`);
|
|
163
|
+
}
|
|
164
|
+
if (latent.levels.length !== levelCount) {
|
|
165
|
+
refuse(
|
|
166
|
+
`a latent carries ${latent.levels.length} level${latent.levels.length === 1 ? '' : 's'}, ` +
|
|
167
|
+
`and a ${layerSize}-texel layer has ${levelCount}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
for (let level = 0; level < levelCount; level += 1) {
|
|
171
|
+
const edge = Math.max(1, layerSize >> level);
|
|
172
|
+
const source = latent.levels[level] as Uint8Array;
|
|
173
|
+
if (source.length !== edge * edge * latent.components) {
|
|
174
|
+
refuse(
|
|
175
|
+
`level ${level} of a latent holds ${source.length} bytes, not ${edge * edge * latent.components}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const rgba = new Uint8Array(edge * edge * 4);
|
|
179
|
+
for (let texel = 0; texel < edge * edge; texel += 1) {
|
|
180
|
+
for (let c = 0; c < 4; c += 1) {
|
|
181
|
+
rgba[texel * 4 + c] =
|
|
182
|
+
c < latent.components
|
|
183
|
+
? (source[texel * latent.components + c] as number)
|
|
184
|
+
: c === 3
|
|
185
|
+
? 255
|
|
186
|
+
: 0;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
(chunks[level] as Uint8Array[]).push(rgba);
|
|
190
|
+
}
|
|
191
|
+
layers += 1;
|
|
192
|
+
return layers - 1;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
programs.forEach((program, p) => {
|
|
196
|
+
const graph = program.graph;
|
|
197
|
+
if (graph.addressMode >= DECODE_ADDRESS_MODES) {
|
|
198
|
+
refuse(
|
|
199
|
+
`program ${p} asks for address mode ${graph.addressMode}; the interpreter knows 0 to ${DECODE_ADDRESS_MODES - 1}`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
if (graph.result >= DECODE_REGISTERS) {
|
|
203
|
+
refuse(`program ${p} returns register ${graph.result}, past the ${DECODE_REGISTERS} it has`);
|
|
204
|
+
}
|
|
205
|
+
const latentLayer = program.latents.map(addLatent);
|
|
206
|
+
const blockLayer = (program.blocks ?? []).map(addLatent);
|
|
207
|
+
|
|
208
|
+
const networkIndex = program.networks.map((network) => {
|
|
209
|
+
const { shape } = network;
|
|
210
|
+
if (shape.inputs < 1 || shape.inputs > DECODE_NETWORK_INPUTS) {
|
|
211
|
+
refuse(`a network takes ${shape.inputs} inputs; a register holds ${DECODE_NETWORK_INPUTS}`);
|
|
212
|
+
}
|
|
213
|
+
if (shape.outputs < 1 || shape.outputs > DECODE_NETWORK_OUTPUTS) {
|
|
214
|
+
refuse(
|
|
215
|
+
`a network gives ${shape.outputs} outputs; a register holds ${DECODE_NETWORK_OUTPUTS}`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
if (shape.hidden.length > DECODE_NETWORK_HIDDEN_LAYERS) {
|
|
219
|
+
refuse(
|
|
220
|
+
`a network has ${shape.hidden.length} hidden layers, past ${DECODE_NETWORK_HIDDEN_LAYERS}`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
for (const width of shape.hidden) {
|
|
224
|
+
if (width < 1 || width > DECODE_NETWORK_WIDTH) {
|
|
225
|
+
refuse(`a hidden layer is ${width} wide, past ${DECODE_NETWORK_WIDTH}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (network.weights.length !== weightCount(shape)) {
|
|
229
|
+
refuse(
|
|
230
|
+
`a network carries ${network.weights.length} weights and its shape needs ${weightCount(shape)}`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
if (networkCount >= DECODE_NETWORK_CAPACITY) {
|
|
234
|
+
refuse(`more than ${DECODE_NETWORK_CAPACITY} networks`);
|
|
235
|
+
}
|
|
236
|
+
if (weightAt + network.weights.length > DECODE_WEIGHT_BLOCKS * 4) {
|
|
237
|
+
refuse(
|
|
238
|
+
`the networks need more than the ${DECODE_WEIGHT_BLOCKS * 4} weights a ` +
|
|
239
|
+
`${DECODE_WEIGHTS_BYTES}-byte uniform holds`,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
const at = NETWORK_AT + networkCount * 8;
|
|
243
|
+
nodes[at] = weightAt;
|
|
244
|
+
nodes[at + 1] = shape.inputs;
|
|
245
|
+
nodes[at + 2] = shape.outputs;
|
|
246
|
+
nodes[at + 3] = shape.hidden.length;
|
|
247
|
+
shape.hidden.forEach((width, k) => {
|
|
248
|
+
nodes[at + 4 + k] = width;
|
|
249
|
+
});
|
|
250
|
+
weights.set(network.weights, weightAt);
|
|
251
|
+
weightAt += network.weights.length;
|
|
252
|
+
networkCount += 1;
|
|
253
|
+
return networkCount - 1;
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const constants = program.constants ?? new Float32Array(0);
|
|
257
|
+
const constantIndex: number[] = [];
|
|
258
|
+
for (let k = 0; k * 4 < constants.length; k += 1) {
|
|
259
|
+
if (constantCount >= DECODE_CONSTANT_CAPACITY) {
|
|
260
|
+
refuse(`more than ${DECODE_CONSTANT_CAPACITY} constants`);
|
|
261
|
+
}
|
|
262
|
+
for (let c = 0; c < 4; c += 1) {
|
|
263
|
+
weights[CONSTANT_AT + constantCount * 4 + c] = constants[k * 4 + c] ?? 0;
|
|
264
|
+
}
|
|
265
|
+
constantIndex.push(constantCount);
|
|
266
|
+
constantCount += 1;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (nodeCount + graph.count > DECODE_NODE_CAPACITY) {
|
|
270
|
+
refuse(`more than ${DECODE_NODE_CAPACITY} decode nodes`);
|
|
271
|
+
}
|
|
272
|
+
const header = p * 4;
|
|
273
|
+
nodes[header] = nodeCount;
|
|
274
|
+
nodes[header + 1] = graph.count;
|
|
275
|
+
nodes[header + 2] = graph.result;
|
|
276
|
+
nodes[header + 3] = graph.addressMode;
|
|
277
|
+
|
|
278
|
+
for (let i = 0; i < graph.count; i += 1) {
|
|
279
|
+
const op = graph.nodes[i * 4] as number;
|
|
280
|
+
let a = graph.nodes[i * 4 + 1] as number;
|
|
281
|
+
let b = graph.nodes[i * 4 + 2] as number;
|
|
282
|
+
const dst = graph.nodes[i * 4 + 3] as number;
|
|
283
|
+
const args = REGISTER_ARGS[op];
|
|
284
|
+
if (args === undefined) {
|
|
285
|
+
refuse(`program ${p} node ${i} has opcode ${op}, which the interpreter does not have`);
|
|
286
|
+
}
|
|
287
|
+
if (
|
|
288
|
+
dst >= DECODE_REGISTERS ||
|
|
289
|
+
(args[0] && a >= DECODE_REGISTERS) ||
|
|
290
|
+
(args[1] && b >= DECODE_REGISTERS)
|
|
291
|
+
) {
|
|
292
|
+
refuse(
|
|
293
|
+
`program ${p} node ${i} names a register past ${DECODE_REGISTERS - 1}: ${a}, ${b}, ${dst}`,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
if (op === DECODE_OPS.SAMPLE_LATENT) {
|
|
297
|
+
a =
|
|
298
|
+
latentLayer[a] ??
|
|
299
|
+
refuse(`program ${p} node ${i} samples latent ${a}, which it does not carry`);
|
|
300
|
+
} else if (op === DECODE_OPS.SAMPLE_BLOCK) {
|
|
301
|
+
a =
|
|
302
|
+
blockLayer[a] ??
|
|
303
|
+
refuse(`program ${p} node ${i} samples block ${a}, which it does not carry`);
|
|
304
|
+
} else if (op === DECODE_OPS.EVAL_NETWORK) {
|
|
305
|
+
b =
|
|
306
|
+
networkIndex[b] ??
|
|
307
|
+
refuse(`program ${p} node ${i} runs network ${b}, which it does not carry`);
|
|
308
|
+
} else if (op === DECODE_OPS.CONSTANT) {
|
|
309
|
+
a =
|
|
310
|
+
constantIndex[a] ??
|
|
311
|
+
refuse(`program ${p} node ${i} reads constant ${a}, which it does not carry`);
|
|
312
|
+
} else if (op === DECODE_OPS.PROCEDURAL_FBM && b > DECODE_FBM_OCTAVES) {
|
|
313
|
+
refuse(`program ${p} node ${i} asks for ${b} octaves, past ${DECODE_FBM_OCTAVES}`);
|
|
314
|
+
}
|
|
315
|
+
const at = NODE_AT + nodeCount * 4;
|
|
316
|
+
nodes[at] = op;
|
|
317
|
+
nodes[at + 1] = a;
|
|
318
|
+
nodes[at + 2] = b;
|
|
319
|
+
nodes[at + 3] = dst;
|
|
320
|
+
nodeCount += 1;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const layerCount = Math.max(1, layers);
|
|
325
|
+
const levels = chunks.map((parts, level) => {
|
|
326
|
+
const edge = Math.max(1, layerSize >> level);
|
|
327
|
+
const bytes = new Uint8Array(layerCount * edge * edge * 4);
|
|
328
|
+
parts.forEach((part, layer) => bytes.set(part, layer * edge * edge * 4));
|
|
329
|
+
return bytes;
|
|
330
|
+
});
|
|
331
|
+
return { nodes, weights, levels, layerCount, layerSize };
|
|
332
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frustum planes from a view-projection matrix, and the sphere test against them.
|
|
3
|
+
*
|
|
4
|
+
* **The reference implementation, and that is its job.** The culling arithmetic is written twice —
|
|
5
|
+
* here for the processor and in WGSL for the device — and a test asserts the two agree over
|
|
6
|
+
* generated input. `splats` already establishes that discipline for shaders authored once and
|
|
7
|
+
* generated to two backends; this is the same rule where the second copy cannot be generated.
|
|
8
|
+
*
|
|
9
|
+
* **Reversed-Z does not change the planes, only their names.** `depthConvention.ts` maps near to 1
|
|
10
|
+
* and far to 0, but the two depth planes are still "clip z at or above 0" and "clip z at or below
|
|
11
|
+
* w" — the mapping swaps which physical plane each one is, and a sphere satisfying both is inside
|
|
12
|
+
* either way. Nothing here has to know which way depth runs, which is why nothing here asks.
|
|
13
|
+
*
|
|
14
|
+
* Column-major throughout, matching the matrices the renderer already passes around.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Six planes, four floats each: a, b, c, d with the normal pointing inward. */
|
|
18
|
+
export const FRUSTUM_FLOATS = 24;
|
|
19
|
+
|
|
20
|
+
function setPlane(out: Float32Array, at: number, a: number, b: number, c: number, d: number): void {
|
|
21
|
+
/* Normalised so the plane test is a true signed distance and can be compared against a radius. */
|
|
22
|
+
const length = Math.hypot(a, b, c);
|
|
23
|
+
const k = length > 0 ? 1 / length : 0;
|
|
24
|
+
out[at] = a * k;
|
|
25
|
+
out[at + 1] = b * k;
|
|
26
|
+
out[at + 2] = c * k;
|
|
27
|
+
out[at + 3] = d * k;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function frustumPlanes(viewProj: Float32Array, out: Float32Array): void {
|
|
31
|
+
const m = viewProj;
|
|
32
|
+
/* Rows of a column-major matrix: row i is m[i], m[4+i], m[8+i], m[12+i]. */
|
|
33
|
+
const r0 = [m[0] as number, m[4] as number, m[8] as number, m[12] as number];
|
|
34
|
+
const r1 = [m[1] as number, m[5] as number, m[9] as number, m[13] as number];
|
|
35
|
+
const r2 = [m[2] as number, m[6] as number, m[10] as number, m[14] as number];
|
|
36
|
+
const r3 = [m[3] as number, m[7] as number, m[11] as number, m[15] as number];
|
|
37
|
+
|
|
38
|
+
setPlane(out, 0, r3[0] + r0[0], r3[1] + r0[1], r3[2] + r0[2], r3[3] + r0[3]);
|
|
39
|
+
setPlane(out, 4, r3[0] - r0[0], r3[1] - r0[1], r3[2] - r0[2], r3[3] - r0[3]);
|
|
40
|
+
setPlane(out, 8, r3[0] + r1[0], r3[1] + r1[1], r3[2] + r1[2], r3[3] + r1[3]);
|
|
41
|
+
setPlane(out, 12, r3[0] - r1[0], r3[1] - r1[1], r3[2] - r1[2], r3[3] - r1[3]);
|
|
42
|
+
/* The two depth planes, in clip terms rather than near/far terms. See the header. */
|
|
43
|
+
setPlane(out, 16, r2[0], r2[1], r2[2], r2[3]);
|
|
44
|
+
setPlane(out, 20, r3[0] - r2[0], r3[1] - r2[1], r3[2] - r2[2], r3[3] - r2[3]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Whether a bounding sphere is entirely outside the frustum.
|
|
49
|
+
*
|
|
50
|
+
* **Conservative in one direction only.** A sphere straddling a plane survives, because culling
|
|
51
|
+
* something visible is a hole in the picture and keeping something invisible is a wasted draw.
|
|
52
|
+
*/
|
|
53
|
+
export function sphereOutsideFrustum(
|
|
54
|
+
planes: Float32Array,
|
|
55
|
+
cx: number,
|
|
56
|
+
cy: number,
|
|
57
|
+
cz: number,
|
|
58
|
+
radius: number,
|
|
59
|
+
): boolean {
|
|
60
|
+
for (let p = 0; p < 6; p += 1) {
|
|
61
|
+
const at = p * 4;
|
|
62
|
+
const distance =
|
|
63
|
+
(planes[at] as number) * cx +
|
|
64
|
+
(planes[at + 1] as number) * cy +
|
|
65
|
+
(planes[at + 2] as number) * cz +
|
|
66
|
+
(planes[at + 3] as number);
|
|
67
|
+
if (distance < -radius) return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A sink that keeps what a streaming scene writes, for tests that read its geometry back.
|
|
3
|
+
*
|
|
4
|
+
* **Not a `.test.ts` file**, for the reason `rendererHarness.ts` gives: Vitest registers a test
|
|
5
|
+
* when the file declaring it is imported, so a helper living beside tests would re-run them in
|
|
6
|
+
* every file that imported it.
|
|
7
|
+
*
|
|
8
|
+
* **The scene keeps no copy of its vertices and indices** — they go to the device of the pass
|
|
9
|
+
* that draws them, through a `GeometrySink` — so a test that wants to read them attaches one of
|
|
10
|
+
* these where the pass would have attached itself, and reads the mirror.
|
|
11
|
+
*/
|
|
12
|
+
import { GPU_DRIVEN_VERTEX_FLOATS } from './sceneUpload.ts';
|
|
13
|
+
|
|
14
|
+
import type { GeometrySink, StreamCapacity } from './streamScene.ts';
|
|
15
|
+
|
|
16
|
+
export interface MirrorWrite {
|
|
17
|
+
readonly kind: 'vertices' | 'indices';
|
|
18
|
+
readonly first: number;
|
|
19
|
+
readonly count: number;
|
|
20
|
+
/** The array the scene handed over, kept so a test can ask whether it was the same one. */
|
|
21
|
+
readonly source: Float32Array | Uint32Array;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface MirrorSink extends GeometrySink {
|
|
25
|
+
readonly vertices: Float32Array;
|
|
26
|
+
readonly indices: Uint32Array;
|
|
27
|
+
readonly writes: MirrorWrite[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** A mirror as large as the capacity: what the pass's two buffers would hold. */
|
|
31
|
+
export function mirrorSink(capacity: StreamCapacity): MirrorSink {
|
|
32
|
+
const vertices = new Float32Array(capacity.vertices * GPU_DRIVEN_VERTEX_FLOATS);
|
|
33
|
+
const indices = new Uint32Array(capacity.indices);
|
|
34
|
+
const writes: MirrorWrite[] = [];
|
|
35
|
+
return {
|
|
36
|
+
vertices,
|
|
37
|
+
indices,
|
|
38
|
+
writes,
|
|
39
|
+
writeVertices(first, rows, count) {
|
|
40
|
+
vertices.set(
|
|
41
|
+
rows.subarray(0, count * GPU_DRIVEN_VERTEX_FLOATS),
|
|
42
|
+
first * GPU_DRIVEN_VERTEX_FLOATS,
|
|
43
|
+
);
|
|
44
|
+
writes.push({ kind: 'vertices', first, count, source: rows });
|
|
45
|
+
},
|
|
46
|
+
writeIndices(first, values, count) {
|
|
47
|
+
indices.set(values.subarray(0, count), first);
|
|
48
|
+
writes.push({ kind: 'indices', first, count, source: values });
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hierarchical depth buffer, and the one decision in it that is easy to get backwards.
|
|
3
|
+
*
|
|
4
|
+
* A texel of level *n+1* must hold the depth **furthest from the camera** of the four it covers.
|
|
5
|
+
* Taking the nearest culls geometry that is visible, which appears as holes that come and go with
|
|
6
|
+
* camera motion and is diagnosed as almost anything else first.
|
|
7
|
+
*
|
|
8
|
+
* **Under reversed-Z, furthest is the minimum value, not the maximum.** `depthConvention.ts` maps
|
|
9
|
+
* the near plane to 1 and the far plane to 0, so the conventional `max` reduction every published
|
|
10
|
+
* description gives is exactly wrong for this engine. That inversion is the reason this module
|
|
11
|
+
* exists as its own file with this paragraph in it rather than as four lines inside a pass.
|
|
12
|
+
*
|
|
13
|
+
* **An odd level includes its extra row and column rather than dropping them.** Dropping them
|
|
14
|
+
* loses the depth of a strip one texel wide along two edges, and a strip of missing occluder is a
|
|
15
|
+
* strip of geometry culled against nothing — conservative in the wrong direction.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** How many levels a pyramid over this size has, down to a single texel. */
|
|
19
|
+
export function hzbMipCount(width: number, height: number): number {
|
|
20
|
+
return Math.floor(Math.log2(Math.max(1, Math.max(width, height)))) + 1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Dimensions of the level below one of this size: halved, never below one. */
|
|
24
|
+
export function hzbMipSize(width: number, height: number): { width: number; height: number } {
|
|
25
|
+
return { width: Math.max(1, width >> 1), height: Math.max(1, height >> 1) };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reduce one level into the next, taking the furthest depth of each group.
|
|
30
|
+
*
|
|
31
|
+
* `out` must hold `hzbMipSize(width, height)` texels. Returns the size written.
|
|
32
|
+
*/
|
|
33
|
+
export function hzbReduce(
|
|
34
|
+
src: Float32Array,
|
|
35
|
+
width: number,
|
|
36
|
+
height: number,
|
|
37
|
+
out: Float32Array,
|
|
38
|
+
): { width: number; height: number } {
|
|
39
|
+
const size = hzbMipSize(width, height);
|
|
40
|
+
for (let y = 0; y < size.height; y += 1) {
|
|
41
|
+
for (let x = 0; x < size.width; x += 1) {
|
|
42
|
+
const x0 = x * 2;
|
|
43
|
+
const y0 = y * 2;
|
|
44
|
+
/* The extra row and column of an odd level are folded into the last group. See the header. */
|
|
45
|
+
const x1 = Math.min(width - 1, x0 + 1);
|
|
46
|
+
const y1 = Math.min(height - 1, y0 + 1);
|
|
47
|
+
const lastX = x === size.width - 1 ? width - 1 : x1;
|
|
48
|
+
const lastY = y === size.height - 1 ? height - 1 : y1;
|
|
49
|
+
|
|
50
|
+
let furthest = Infinity;
|
|
51
|
+
for (let sy = y0; sy <= lastY; sy += 1) {
|
|
52
|
+
for (let sx = x0; sx <= lastX; sx += 1) {
|
|
53
|
+
/* Minimum, because reversed-Z puts the far plane at zero. */
|
|
54
|
+
furthest = Math.min(furthest, src[sy * width + sx] as number);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
out[y * size.width + x] = furthest;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return size;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A light's pyramid's base: half its shadow map, each texel the furthest of the group under it,
|
|
65
|
+
* **turned over into the camera's convention.**
|
|
66
|
+
*
|
|
67
|
+
* A shadow map's depth is conventional — near is zero — because the lookup both pipelines share
|
|
68
|
+
* reads it so, and `depthConvention.ts` leaves shadow maps alone. Everything downstream of a
|
|
69
|
+
* pyramid is written for reversed-Z, so this stores `1 - depth`, where the furthest of a group is
|
|
70
|
+
* the smallest value, and from here the light's pyramid is the camera's: `hzbReduce` builds the
|
|
71
|
+
* rest, and the cull reads it through a matrix whose depth is turned over to match. The groups are
|
|
72
|
+
* `hzbReduce`'s, an odd map's extra row and column folded in, and so is the answer — it is
|
|
73
|
+
* `hzbReduce` of the turned-over map, exactly.
|
|
74
|
+
*
|
|
75
|
+
* **Half the map rather than all of it**, because the base level is the one that costs: a whole
|
|
76
|
+
* 2048 map's pyramid would be 22 MB beside the 16 MB of the map itself. `out` holds
|
|
77
|
+
* `hzbMipSize(width, height)` texels; returns that size.
|
|
78
|
+
*/
|
|
79
|
+
export function shadowPyramidBase(
|
|
80
|
+
depth: Float32Array,
|
|
81
|
+
width: number,
|
|
82
|
+
height: number,
|
|
83
|
+
out: Float32Array,
|
|
84
|
+
): { width: number; height: number } {
|
|
85
|
+
const size = hzbMipSize(width, height);
|
|
86
|
+
for (let y = 0; y < size.height; y += 1) {
|
|
87
|
+
for (let x = 0; x < size.width; x += 1) {
|
|
88
|
+
const x0 = x * 2;
|
|
89
|
+
const y0 = y * 2;
|
|
90
|
+
const lastX = x === size.width - 1 ? width - 1 : Math.min(width - 1, x0 + 1);
|
|
91
|
+
const lastY = y === size.height - 1 ? height - 1 : Math.min(height - 1, y0 + 1);
|
|
92
|
+
let deepest = -Infinity;
|
|
93
|
+
for (let sy = y0; sy <= lastY; sy += 1) {
|
|
94
|
+
for (let sx = x0; sx <= lastX; sx += 1) {
|
|
95
|
+
deepest = Math.max(deepest, depth[sy * width + sx] as number);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
out[y * size.width + x] = 1 - deepest;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return size;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Whether a sphere is hidden behind the depth already in the pyramid.
|
|
106
|
+
*
|
|
107
|
+
* `sphereDepth` is the **nearest** clip depth of the sphere, which under reversed-Z is its
|
|
108
|
+
* *largest* value. It is hidden when even that is further away than the occluder depth — again a
|
|
109
|
+
* smaller number here.
|
|
110
|
+
*/
|
|
111
|
+
export function hzbOccluded(sphereNearestDepth: number, occluderFurthestDepth: number): boolean {
|
|
112
|
+
return sphereNearestDepth < occluderFurthestDepth;
|
|
113
|
+
}
|