@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,60 @@
|
|
|
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
|
+
/** How many levels a pyramid over this size has, down to a single texel. */
|
|
18
|
+
export declare function hzbMipCount(width: number, height: number): number;
|
|
19
|
+
/** Dimensions of the level below one of this size: halved, never below one. */
|
|
20
|
+
export declare function hzbMipSize(width: number, height: number): {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Reduce one level into the next, taking the furthest depth of each group.
|
|
26
|
+
*
|
|
27
|
+
* `out` must hold `hzbMipSize(width, height)` texels. Returns the size written.
|
|
28
|
+
*/
|
|
29
|
+
export declare function hzbReduce(src: Float32Array, width: number, height: number, out: Float32Array): {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* A light's pyramid's base: half its shadow map, each texel the furthest of the group under it,
|
|
35
|
+
* **turned over into the camera's convention.**
|
|
36
|
+
*
|
|
37
|
+
* A shadow map's depth is conventional — near is zero — because the lookup both pipelines share
|
|
38
|
+
* reads it so, and `depthConvention.ts` leaves shadow maps alone. Everything downstream of a
|
|
39
|
+
* pyramid is written for reversed-Z, so this stores `1 - depth`, where the furthest of a group is
|
|
40
|
+
* the smallest value, and from here the light's pyramid is the camera's: `hzbReduce` builds the
|
|
41
|
+
* rest, and the cull reads it through a matrix whose depth is turned over to match. The groups are
|
|
42
|
+
* `hzbReduce`'s, an odd map's extra row and column folded in, and so is the answer — it is
|
|
43
|
+
* `hzbReduce` of the turned-over map, exactly.
|
|
44
|
+
*
|
|
45
|
+
* **Half the map rather than all of it**, because the base level is the one that costs: a whole
|
|
46
|
+
* 2048 map's pyramid would be 22 MB beside the 16 MB of the map itself. `out` holds
|
|
47
|
+
* `hzbMipSize(width, height)` texels; returns that size.
|
|
48
|
+
*/
|
|
49
|
+
export declare function shadowPyramidBase(depth: Float32Array, width: number, height: number, out: Float32Array): {
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Whether a sphere is hidden behind the depth already in the pyramid.
|
|
55
|
+
*
|
|
56
|
+
* `sphereDepth` is the **nearest** clip depth of the sphere, which under reversed-Z is its
|
|
57
|
+
* *largest* value. It is hidden when even that is further away than the occluder depth — again a
|
|
58
|
+
* smaller number here.
|
|
59
|
+
*/
|
|
60
|
+
export declare function hzbOccluded(sphereNearestDepth: number, occluderFurthestDepth: number): boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
/** How many levels a pyramid over this size has, down to a single texel. */
|
|
18
|
+
export function hzbMipCount(width, height) {
|
|
19
|
+
return Math.floor(Math.log2(Math.max(1, Math.max(width, height)))) + 1;
|
|
20
|
+
}
|
|
21
|
+
/** Dimensions of the level below one of this size: halved, never below one. */
|
|
22
|
+
export function hzbMipSize(width, height) {
|
|
23
|
+
return { width: Math.max(1, width >> 1), height: Math.max(1, height >> 1) };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Reduce one level into the next, taking the furthest depth of each group.
|
|
27
|
+
*
|
|
28
|
+
* `out` must hold `hzbMipSize(width, height)` texels. Returns the size written.
|
|
29
|
+
*/
|
|
30
|
+
export function hzbReduce(src, width, height, out) {
|
|
31
|
+
const size = hzbMipSize(width, height);
|
|
32
|
+
for (let y = 0; y < size.height; y += 1) {
|
|
33
|
+
for (let x = 0; x < size.width; x += 1) {
|
|
34
|
+
const x0 = x * 2;
|
|
35
|
+
const y0 = y * 2;
|
|
36
|
+
/* The extra row and column of an odd level are folded into the last group. See the header. */
|
|
37
|
+
const x1 = Math.min(width - 1, x0 + 1);
|
|
38
|
+
const y1 = Math.min(height - 1, y0 + 1);
|
|
39
|
+
const lastX = x === size.width - 1 ? width - 1 : x1;
|
|
40
|
+
const lastY = y === size.height - 1 ? height - 1 : y1;
|
|
41
|
+
let furthest = Infinity;
|
|
42
|
+
for (let sy = y0; sy <= lastY; sy += 1) {
|
|
43
|
+
for (let sx = x0; sx <= lastX; sx += 1) {
|
|
44
|
+
/* Minimum, because reversed-Z puts the far plane at zero. */
|
|
45
|
+
furthest = Math.min(furthest, src[sy * width + sx]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
out[y * size.width + x] = furthest;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return size;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A light's pyramid's base: half its shadow map, each texel the furthest of the group under it,
|
|
55
|
+
* **turned over into the camera's convention.**
|
|
56
|
+
*
|
|
57
|
+
* A shadow map's depth is conventional — near is zero — because the lookup both pipelines share
|
|
58
|
+
* reads it so, and `depthConvention.ts` leaves shadow maps alone. Everything downstream of a
|
|
59
|
+
* pyramid is written for reversed-Z, so this stores `1 - depth`, where the furthest of a group is
|
|
60
|
+
* the smallest value, and from here the light's pyramid is the camera's: `hzbReduce` builds the
|
|
61
|
+
* rest, and the cull reads it through a matrix whose depth is turned over to match. The groups are
|
|
62
|
+
* `hzbReduce`'s, an odd map's extra row and column folded in, and so is the answer — it is
|
|
63
|
+
* `hzbReduce` of the turned-over map, exactly.
|
|
64
|
+
*
|
|
65
|
+
* **Half the map rather than all of it**, because the base level is the one that costs: a whole
|
|
66
|
+
* 2048 map's pyramid would be 22 MB beside the 16 MB of the map itself. `out` holds
|
|
67
|
+
* `hzbMipSize(width, height)` texels; returns that size.
|
|
68
|
+
*/
|
|
69
|
+
export function shadowPyramidBase(depth, width, height, out) {
|
|
70
|
+
const size = hzbMipSize(width, height);
|
|
71
|
+
for (let y = 0; y < size.height; y += 1) {
|
|
72
|
+
for (let x = 0; x < size.width; x += 1) {
|
|
73
|
+
const x0 = x * 2;
|
|
74
|
+
const y0 = y * 2;
|
|
75
|
+
const lastX = x === size.width - 1 ? width - 1 : Math.min(width - 1, x0 + 1);
|
|
76
|
+
const lastY = y === size.height - 1 ? height - 1 : Math.min(height - 1, y0 + 1);
|
|
77
|
+
let deepest = -Infinity;
|
|
78
|
+
for (let sy = y0; sy <= lastY; sy += 1) {
|
|
79
|
+
for (let sx = x0; sx <= lastX; sx += 1) {
|
|
80
|
+
deepest = Math.max(deepest, depth[sy * width + sx]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
out[y * size.width + x] = 1 - deepest;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return size;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Whether a sphere is hidden behind the depth already in the pyramid.
|
|
90
|
+
*
|
|
91
|
+
* `sphereDepth` is the **nearest** clip depth of the sphere, which under reversed-Z is its
|
|
92
|
+
* *largest* value. It is hidden when even that is further away than the occluder depth — again a
|
|
93
|
+
* smaller number here.
|
|
94
|
+
*/
|
|
95
|
+
export function hzbOccluded(sphereNearestDepth, occluderFurthestDepth) {
|
|
96
|
+
return sphereNearestDepth < occluderFurthestDepth;
|
|
97
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** The split sum's second half, in TypeScript, so the second pipeline's copy has a reference. */
|
|
2
|
+
/**
|
|
3
|
+
* **`flat/lobes.ts` in TypeScript: how much of an environment a surface returns.**
|
|
4
|
+
*
|
|
5
|
+
* The convolution decides *what* a surface reflects — a rougher one reads a blurrier level of the
|
|
6
|
+
* prefiltered chain — and this decides *how much*. Both halves are a fit and an algebraic
|
|
7
|
+
* compensation, which is to say both are arithmetic nobody can check by looking at a frame: the
|
|
8
|
+
* failure they exist to prevent was reported twice from consumers as *metals reading opaque*, and
|
|
9
|
+
* traced to a term that asserts a perfect mirror absorbs 55% of the light once it is roughened.
|
|
10
|
+
*
|
|
11
|
+
* **Metalness is a per-material scalar here, not an ORM map.** `flat/main.ts` reads it per texel
|
|
12
|
+
* from the blue channel of an occlusion-roughness-metallic image, which is a thing this pipeline
|
|
13
|
+
* has no textures to read; a GPU-driven material carries one number instead. That is a *subset* and
|
|
14
|
+
* not a second opinion: everywhere a texel could vary, a material is constant, and every expression
|
|
15
|
+
* below is the forward path's with a uniform standing in for a fetch.
|
|
16
|
+
*
|
|
17
|
+
* **What stays collapsed is the environment gain.** `flat/main.ts` scales what a metal reflects by
|
|
18
|
+
* `uEnvironmentGain`, which exists because a metal has no diffuse behind its reflection and a probe
|
|
19
|
+
* that under-reports the room leaves it with no other way to be lit. `PassEnvironment` carries no
|
|
20
|
+
* such control, so the gain is 1 and `mix(1, gain, metal)` is exactly 1 at every metalness — a
|
|
21
|
+
* collapse that is exact rather than approximate, which is the standard every term here is held to.
|
|
22
|
+
*/
|
|
23
|
+
/** A dielectric's normal-incidence reflectance, which is what a material with no metalness is. */
|
|
24
|
+
export declare const DIELECTRIC_F0 = 0.04;
|
|
25
|
+
/**
|
|
26
|
+
* A surface's normal-incidence reflectance, from its metalness.
|
|
27
|
+
*
|
|
28
|
+
* **A metal's Fresnel base is close to its albedo and a dielectric's is four per cent**, and
|
|
29
|
+
* `flat/main.ts` records what leaving it at 0.04 costs: a smooth metal seen head-on takes a four
|
|
30
|
+
* per cent reflection and reads as dark paint. The chromatic half of that — a metal's `f0` being
|
|
31
|
+
* its own colour rather than white — is in `lit.ts`, where the albedo is; this is the scalar the
|
|
32
|
+
* split sum takes.
|
|
33
|
+
*/
|
|
34
|
+
export declare function surfaceF0(metalness: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* The split sum's second half, as a two-term fit: `dfg.x` scales `f0` and `dfg.y` is added on top.
|
|
37
|
+
*
|
|
38
|
+
* **Karis's analytic fit rather than the tabulated integral**, which is a texture this pipeline
|
|
39
|
+
* would otherwise have to carry and bind. Its published error is around one per cent of the
|
|
40
|
+
* tabulated term, far below what an eight-bit frame can show. **What would make it wrong** is a
|
|
41
|
+
* material model with a second lobe — a clearcoat or a sheen carries its own BRDF and its own
|
|
42
|
+
* integral, and this is Trowbridge-Reitz with Smith masking and nothing else.
|
|
43
|
+
*/
|
|
44
|
+
export declare function envBrdfApprox(ndv: number, roughness: number, out: Float32Array): Float32Array;
|
|
45
|
+
/**
|
|
46
|
+
* The same, with the light that bounces more than once inside the microsurface put back.
|
|
47
|
+
*
|
|
48
|
+
* **The split sum integrates a *single* scattering event**, so it silently discards every ray that
|
|
49
|
+
* strikes one microfacet, bounces, and leaves. Roughness scatters light; it does not absorb it, so
|
|
50
|
+
* a surface with `f0` 1 has to return everything at every roughness — and the bare sum returns
|
|
51
|
+
* about `1 - 0.55 * roughness`, which is a 44% loss at roughness 0.8.
|
|
52
|
+
*
|
|
53
|
+
* Fdez-Agüera's compensation: the missing energy, returned at the surface's average Fresnel over
|
|
54
|
+
* the hemisphere, summed as a geometric series over repeated bounces. **At `f0` 1 it comes back to
|
|
55
|
+
* exactly 1.0 at every roughness** — `average` is 1, `multi` is `energy / energy`, and the sum
|
|
56
|
+
* telescopes — which is the invariant the test beside this file asserts across the whole range.
|
|
57
|
+
*
|
|
58
|
+
* **No divide guard, because the denominator cannot reach zero.** `missing` is at most 0.55 and
|
|
59
|
+
* `average` at most 1, so `1 - missing * average` bottoms out at 0.45 — the worst case in both
|
|
60
|
+
* variables at once.
|
|
61
|
+
*/
|
|
62
|
+
export declare function envSpecularEnergy(f0: number, dfgX: number, dfgY: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* How much of what the surface sees in the mirror direction reaches the frame.
|
|
65
|
+
*
|
|
66
|
+
* **Two expressions and a selector, because they answer different questions.** `prefiltered` is 1
|
|
67
|
+
* where the radiance came from a GGX-convolved chain, and there the split sum is the correct share
|
|
68
|
+
* of that integral — it carries the angular dependence itself, so it replaces the Fresnel sweep
|
|
69
|
+
* rather than multiplying it. Where the radiance is anything else, applying it would assert an
|
|
70
|
+
* integral that was never performed: `flat/main.ts` measured that mistake as the grazing-to-head-on
|
|
71
|
+
* ratio falling from about 15 to 1 down to 5 to 1, reported twice as a metal going opaque.
|
|
72
|
+
*
|
|
73
|
+
* So without a chain this is the engine's own long-standing weight — Schlick's Fresnel times
|
|
74
|
+
* `reflectivity * (1 - roughness)` — and with one it is the integral. The two are deliberately not
|
|
75
|
+
* blended into a single formula; a selector that is exactly 0 or exactly 1 is what makes a scene
|
|
76
|
+
* with no environment arithmetically identical to the frame it already rendered.
|
|
77
|
+
*
|
|
78
|
+
* `ndv` is `dot(n, toEye)` clamped at zero, as the caller's own facing term already computes.
|
|
79
|
+
*/
|
|
80
|
+
export declare function environmentWeight(ndv: number, roughness: number, reflectivity: number, prefiltered: number,
|
|
81
|
+
/**
|
|
82
|
+
* 0 is a dielectric and 1 is a metal. **Defaults to 0**, so every caller written before this
|
|
83
|
+
* argument existed gets the arithmetic it had.
|
|
84
|
+
*/
|
|
85
|
+
metalness?: number): number;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** The split sum's second half, in TypeScript, so the second pipeline's copy has a reference. */
|
|
2
|
+
/**
|
|
3
|
+
* **`flat/lobes.ts` in TypeScript: how much of an environment a surface returns.**
|
|
4
|
+
*
|
|
5
|
+
* The convolution decides *what* a surface reflects — a rougher one reads a blurrier level of the
|
|
6
|
+
* prefiltered chain — and this decides *how much*. Both halves are a fit and an algebraic
|
|
7
|
+
* compensation, which is to say both are arithmetic nobody can check by looking at a frame: the
|
|
8
|
+
* failure they exist to prevent was reported twice from consumers as *metals reading opaque*, and
|
|
9
|
+
* traced to a term that asserts a perfect mirror absorbs 55% of the light once it is roughened.
|
|
10
|
+
*
|
|
11
|
+
* **Metalness is a per-material scalar here, not an ORM map.** `flat/main.ts` reads it per texel
|
|
12
|
+
* from the blue channel of an occlusion-roughness-metallic image, which is a thing this pipeline
|
|
13
|
+
* has no textures to read; a GPU-driven material carries one number instead. That is a *subset* and
|
|
14
|
+
* not a second opinion: everywhere a texel could vary, a material is constant, and every expression
|
|
15
|
+
* below is the forward path's with a uniform standing in for a fetch.
|
|
16
|
+
*
|
|
17
|
+
* **What stays collapsed is the environment gain.** `flat/main.ts` scales what a metal reflects by
|
|
18
|
+
* `uEnvironmentGain`, which exists because a metal has no diffuse behind its reflection and a probe
|
|
19
|
+
* that under-reports the room leaves it with no other way to be lit. `PassEnvironment` carries no
|
|
20
|
+
* such control, so the gain is 1 and `mix(1, gain, metal)` is exactly 1 at every metalness — a
|
|
21
|
+
* collapse that is exact rather than approximate, which is the standard every term here is held to.
|
|
22
|
+
*/
|
|
23
|
+
/** A dielectric's normal-incidence reflectance, which is what a material with no metalness is. */
|
|
24
|
+
export const DIELECTRIC_F0 = 0.04;
|
|
25
|
+
/**
|
|
26
|
+
* A surface's normal-incidence reflectance, from its metalness.
|
|
27
|
+
*
|
|
28
|
+
* **A metal's Fresnel base is close to its albedo and a dielectric's is four per cent**, and
|
|
29
|
+
* `flat/main.ts` records what leaving it at 0.04 costs: a smooth metal seen head-on takes a four
|
|
30
|
+
* per cent reflection and reads as dark paint. The chromatic half of that — a metal's `f0` being
|
|
31
|
+
* its own colour rather than white — is in `lit.ts`, where the albedo is; this is the scalar the
|
|
32
|
+
* split sum takes.
|
|
33
|
+
*/
|
|
34
|
+
export function surfaceF0(metalness) {
|
|
35
|
+
return DIELECTRIC_F0 + (1 - DIELECTRIC_F0) * metalness;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The split sum's second half, as a two-term fit: `dfg.x` scales `f0` and `dfg.y` is added on top.
|
|
39
|
+
*
|
|
40
|
+
* **Karis's analytic fit rather than the tabulated integral**, which is a texture this pipeline
|
|
41
|
+
* would otherwise have to carry and bind. Its published error is around one per cent of the
|
|
42
|
+
* tabulated term, far below what an eight-bit frame can show. **What would make it wrong** is a
|
|
43
|
+
* material model with a second lobe — a clearcoat or a sheen carries its own BRDF and its own
|
|
44
|
+
* integral, and this is Trowbridge-Reitz with Smith masking and nothing else.
|
|
45
|
+
*/
|
|
46
|
+
export function envBrdfApprox(ndv, roughness, out) {
|
|
47
|
+
const c0 = [-1, -0.0275, -0.572, 0.022];
|
|
48
|
+
const c1 = [1, 0.0425, 1.04, -0.04];
|
|
49
|
+
const rx = roughness * c0[0] + c1[0];
|
|
50
|
+
const ry = roughness * c0[1] + c1[1];
|
|
51
|
+
const rz = roughness * c0[2] + c1[2];
|
|
52
|
+
const rw = roughness * c0[3] + c1[3];
|
|
53
|
+
const a004 = Math.min(rx * rx, Math.pow(2, -9.28 * ndv)) * rx + ry;
|
|
54
|
+
out[0] = -1.04 * a004 + rz;
|
|
55
|
+
out[1] = 1.04 * a004 + rw;
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The same, with the light that bounces more than once inside the microsurface put back.
|
|
60
|
+
*
|
|
61
|
+
* **The split sum integrates a *single* scattering event**, so it silently discards every ray that
|
|
62
|
+
* strikes one microfacet, bounces, and leaves. Roughness scatters light; it does not absorb it, so
|
|
63
|
+
* a surface with `f0` 1 has to return everything at every roughness — and the bare sum returns
|
|
64
|
+
* about `1 - 0.55 * roughness`, which is a 44% loss at roughness 0.8.
|
|
65
|
+
*
|
|
66
|
+
* Fdez-Agüera's compensation: the missing energy, returned at the surface's average Fresnel over
|
|
67
|
+
* the hemisphere, summed as a geometric series over repeated bounces. **At `f0` 1 it comes back to
|
|
68
|
+
* exactly 1.0 at every roughness** — `average` is 1, `multi` is `energy / energy`, and the sum
|
|
69
|
+
* telescopes — which is the invariant the test beside this file asserts across the whole range.
|
|
70
|
+
*
|
|
71
|
+
* **No divide guard, because the denominator cannot reach zero.** `missing` is at most 0.55 and
|
|
72
|
+
* `average` at most 1, so `1 - missing * average` bottoms out at 0.45 — the worst case in both
|
|
73
|
+
* variables at once.
|
|
74
|
+
*/
|
|
75
|
+
export function envSpecularEnergy(f0, dfgX, dfgY) {
|
|
76
|
+
const single = f0 * dfgX + dfgY;
|
|
77
|
+
const energy = dfgX + dfgY;
|
|
78
|
+
const missing = 1 - energy;
|
|
79
|
+
const average = f0 + (1 - f0) / 21;
|
|
80
|
+
const multi = (single * average) / (1 - missing * average);
|
|
81
|
+
return single + multi * missing;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* How much of what the surface sees in the mirror direction reaches the frame.
|
|
85
|
+
*
|
|
86
|
+
* **Two expressions and a selector, because they answer different questions.** `prefiltered` is 1
|
|
87
|
+
* where the radiance came from a GGX-convolved chain, and there the split sum is the correct share
|
|
88
|
+
* of that integral — it carries the angular dependence itself, so it replaces the Fresnel sweep
|
|
89
|
+
* rather than multiplying it. Where the radiance is anything else, applying it would assert an
|
|
90
|
+
* integral that was never performed: `flat/main.ts` measured that mistake as the grazing-to-head-on
|
|
91
|
+
* ratio falling from about 15 to 1 down to 5 to 1, reported twice as a metal going opaque.
|
|
92
|
+
*
|
|
93
|
+
* So without a chain this is the engine's own long-standing weight — Schlick's Fresnel times
|
|
94
|
+
* `reflectivity * (1 - roughness)` — and with one it is the integral. The two are deliberately not
|
|
95
|
+
* blended into a single formula; a selector that is exactly 0 or exactly 1 is what makes a scene
|
|
96
|
+
* with no environment arithmetically identical to the frame it already rendered.
|
|
97
|
+
*
|
|
98
|
+
* `ndv` is `dot(n, toEye)` clamped at zero, as the caller's own facing term already computes.
|
|
99
|
+
*/
|
|
100
|
+
export function environmentWeight(ndv, roughness, reflectivity, prefiltered,
|
|
101
|
+
/**
|
|
102
|
+
* 0 is a dielectric and 1 is a metal. **Defaults to 0**, so every caller written before this
|
|
103
|
+
* argument existed gets the arithmetic it had.
|
|
104
|
+
*/
|
|
105
|
+
metalness = 0) {
|
|
106
|
+
const f0 = surfaceF0(metalness);
|
|
107
|
+
const facing = 1 - ndv;
|
|
108
|
+
const fresnel = f0 + (1 - f0) * (facing * facing * facing * facing * facing);
|
|
109
|
+
/*
|
|
110
|
+
* **`max(reflectivity * (1 - roughness), metal)`, and both halves of that are repairs.**
|
|
111
|
+
*
|
|
112
|
+
* `reflectivity` is a per-material control, and it is zero for exactly the surfaces that carry
|
|
113
|
+
* their metalness some other way — `flat/main.ts` measured reading it alone as a chromed subject
|
|
114
|
+
* coming out near black with a baked probe sitting unread, because the whole block was skipped.
|
|
115
|
+
* So a metal reflects whether or not the material asked for reflections.
|
|
116
|
+
*
|
|
117
|
+
* And the `1 - roughness` thinning does not reach the metal. It stands for a polish that
|
|
118
|
+
* scatters a dielectric's reflection into no image at all; a metal has no diffuse to fall back
|
|
119
|
+
* on, so scaling it throws away 40% of everything a surface at roughness 0.4 shows and replaces
|
|
120
|
+
* it with a dark constant. It is also double counting — the level the sample comes from already
|
|
121
|
+
* *is* the roughness.
|
|
122
|
+
*/
|
|
123
|
+
const amount = Math.max(reflectivity * (1 - roughness), metalness);
|
|
124
|
+
const sweep = Math.min(Math.max(fresnel * amount, 0), 1);
|
|
125
|
+
const dfg = new Float32Array(2);
|
|
126
|
+
envBrdfApprox(ndv, roughness, dfg);
|
|
127
|
+
const integrated = Math.min(Math.max(envSpecularEnergy(f0, dfg[0], dfg[1]) * Math.max(reflectivity, metalness), 0), 1);
|
|
128
|
+
return sweep + (integrated - sweep) * prefiltered;
|
|
129
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arguments a culled frame hands the rasteriser, written by the device and read by it.
|
|
3
|
+
*
|
|
4
|
+
* **The whole pipeline exists so that the processor never learns how much there is to draw.** A
|
|
5
|
+
* cull dispatch writes the count into a buffer and the draw reads it from the same buffer; the
|
|
6
|
+
* frame is submitted before either number exists. So these are layouts rather than calls: what a
|
|
7
|
+
* block holds, in what order, and what a caller must have cleared before the dispatch runs.
|
|
8
|
+
*
|
|
9
|
+
* **One draw for the whole frame, not one per cluster.** Every surviving cluster is an *instance*
|
|
10
|
+
* of a fixed 128-triangle draw, which is what `VIS_MAX_TRIANGLES` is for: the index count is the
|
|
11
|
+
* same for all of them, so there is one block instead of thousands and no multi-draw extension is
|
|
12
|
+
* needed. A cluster with fewer triangles emits degenerate ones for the remainder — see
|
|
13
|
+
* `clusterVertexCluster` — and a degenerate triangle covers no pixel, so the picture is unchanged
|
|
14
|
+
* and the cost is the vertex stage running on indices that produce nothing.
|
|
15
|
+
*
|
|
16
|
+
* **What that costs, stated rather than hidden**: a scene whose clusters average 64 triangles runs
|
|
17
|
+
* the vertex stage twice for every triangle it draws. The alternative is a block per cluster and a
|
|
18
|
+
* loop of indirect draws on the processor, which is the draw-call bound this pipeline exists to
|
|
19
|
+
* remove. If a consumer's clusters are persistently half full, the fix is in the *baker* — see
|
|
20
|
+
* `assets/src/bake/cluster.ts`, whose target is the full 128.
|
|
21
|
+
*/
|
|
22
|
+
/** Words in a `drawIndexedIndirect` block: index count, instances, first index, base vertex, first instance. */
|
|
23
|
+
export declare const INDIRECT_DRAW_WORDS = 5;
|
|
24
|
+
/** Words in a `dispatchWorkgroups` block: three group counts. */
|
|
25
|
+
export declare const INDIRECT_DISPATCH_WORDS = 3;
|
|
26
|
+
/** Indices a cluster draw always issues, whatever the cluster actually holds. */
|
|
27
|
+
export declare const CLUSTER_INDEX_CAP: number;
|
|
28
|
+
/**
|
|
29
|
+
* The draw block for a frame that kept `clusters` of them.
|
|
30
|
+
*
|
|
31
|
+
* `firstInstance` is zero and the *instance index* is the slot in the kept list rather than the
|
|
32
|
+
* cluster identifier: the list is compacted, so slot and identifier differ, and the shader reads
|
|
33
|
+
* the identifier out of the list. Putting the identifier here instead would need a block per
|
|
34
|
+
* cluster, which is the thing this avoids.
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeClusterDrawArgs(out: Uint32Array, at: number, clusters: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* The dispatch block for `count` items at `groupSize` a group.
|
|
39
|
+
*
|
|
40
|
+
* **Rounded up, and zero items is zero groups rather than one.** A group that runs with nothing to
|
|
41
|
+
* do is harmless in this pipeline — every entry point range-checks its own invocation — but a
|
|
42
|
+
* dispatch of one group over an empty list still reads a buffer that a caller may not have bound,
|
|
43
|
+
* and "nothing to do" is the case a frame hits before anything has streamed in.
|
|
44
|
+
*
|
|
45
|
+
* **Zero falls out of the division rather than out of a special case**, and the special case that
|
|
46
|
+
* stood here is gone because a perturbation survived it: `ceil(0 / n)` is already 0, so the branch
|
|
47
|
+
* changed no answer and was a second statement of the rule to keep in step. The behaviour is still
|
|
48
|
+
* held by a test — what is gone is the code that was not doing the holding.
|
|
49
|
+
*/
|
|
50
|
+
export declare function writeDispatchArgs(out: Uint32Array, at: number, count: number, groupSize: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* Which slot of the kept list a vertex belongs to, and which triangle of that cluster.
|
|
53
|
+
*
|
|
54
|
+
* The vertex stage's whole addressing, on the processor so a test can read it. `vertex` is
|
|
55
|
+
* `@builtin(vertex_index)` and runs to `CLUSTER_INDEX_CAP`; `instance` is
|
|
56
|
+
* `@builtin(instance_index)` and is the slot.
|
|
57
|
+
*
|
|
58
|
+
* **A triangle past the cluster's own count is reported rather than clamped.** Clamping draws the
|
|
59
|
+
* last triangle of the cluster over and over, which is a visible sliver on every cluster that is
|
|
60
|
+
* not exactly full; reporting it lets the shader emit a degenerate triangle, which covers nothing.
|
|
61
|
+
*/
|
|
62
|
+
export declare function clusterVertexCluster(vertex: number, instance: number, triangleCount: number): {
|
|
63
|
+
slot: number;
|
|
64
|
+
triangle: number;
|
|
65
|
+
corner: number;
|
|
66
|
+
degenerate: boolean;
|
|
67
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arguments a culled frame hands the rasteriser, written by the device and read by it.
|
|
3
|
+
*
|
|
4
|
+
* **The whole pipeline exists so that the processor never learns how much there is to draw.** A
|
|
5
|
+
* cull dispatch writes the count into a buffer and the draw reads it from the same buffer; the
|
|
6
|
+
* frame is submitted before either number exists. So these are layouts rather than calls: what a
|
|
7
|
+
* block holds, in what order, and what a caller must have cleared before the dispatch runs.
|
|
8
|
+
*
|
|
9
|
+
* **One draw for the whole frame, not one per cluster.** Every surviving cluster is an *instance*
|
|
10
|
+
* of a fixed 128-triangle draw, which is what `VIS_MAX_TRIANGLES` is for: the index count is the
|
|
11
|
+
* same for all of them, so there is one block instead of thousands and no multi-draw extension is
|
|
12
|
+
* needed. A cluster with fewer triangles emits degenerate ones for the remainder — see
|
|
13
|
+
* `clusterVertexCluster` — and a degenerate triangle covers no pixel, so the picture is unchanged
|
|
14
|
+
* and the cost is the vertex stage running on indices that produce nothing.
|
|
15
|
+
*
|
|
16
|
+
* **What that costs, stated rather than hidden**: a scene whose clusters average 64 triangles runs
|
|
17
|
+
* the vertex stage twice for every triangle it draws. The alternative is a block per cluster and a
|
|
18
|
+
* loop of indirect draws on the processor, which is the draw-call bound this pipeline exists to
|
|
19
|
+
* remove. If a consumer's clusters are persistently half full, the fix is in the *baker* — see
|
|
20
|
+
* `assets/src/bake/cluster.ts`, whose target is the full 128.
|
|
21
|
+
*/
|
|
22
|
+
import { VIS_MAX_TRIANGLES } from './visbuffer.js';
|
|
23
|
+
/** Words in a `drawIndexedIndirect` block: index count, instances, first index, base vertex, first instance. */
|
|
24
|
+
export const INDIRECT_DRAW_WORDS = 5;
|
|
25
|
+
/** Words in a `dispatchWorkgroups` block: three group counts. */
|
|
26
|
+
export const INDIRECT_DISPATCH_WORDS = 3;
|
|
27
|
+
/** Indices a cluster draw always issues, whatever the cluster actually holds. */
|
|
28
|
+
export const CLUSTER_INDEX_CAP = VIS_MAX_TRIANGLES * 3;
|
|
29
|
+
/**
|
|
30
|
+
* The draw block for a frame that kept `clusters` of them.
|
|
31
|
+
*
|
|
32
|
+
* `firstInstance` is zero and the *instance index* is the slot in the kept list rather than the
|
|
33
|
+
* cluster identifier: the list is compacted, so slot and identifier differ, and the shader reads
|
|
34
|
+
* the identifier out of the list. Putting the identifier here instead would need a block per
|
|
35
|
+
* cluster, which is the thing this avoids.
|
|
36
|
+
*/
|
|
37
|
+
export function writeClusterDrawArgs(out, at, clusters) {
|
|
38
|
+
out[at] = CLUSTER_INDEX_CAP;
|
|
39
|
+
out[at + 1] = Math.max(0, clusters);
|
|
40
|
+
out[at + 2] = 0;
|
|
41
|
+
out[at + 3] = 0;
|
|
42
|
+
out[at + 4] = 0;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The dispatch block for `count` items at `groupSize` a group.
|
|
46
|
+
*
|
|
47
|
+
* **Rounded up, and zero items is zero groups rather than one.** A group that runs with nothing to
|
|
48
|
+
* do is harmless in this pipeline — every entry point range-checks its own invocation — but a
|
|
49
|
+
* dispatch of one group over an empty list still reads a buffer that a caller may not have bound,
|
|
50
|
+
* and "nothing to do" is the case a frame hits before anything has streamed in.
|
|
51
|
+
*
|
|
52
|
+
* **Zero falls out of the division rather than out of a special case**, and the special case that
|
|
53
|
+
* stood here is gone because a perturbation survived it: `ceil(0 / n)` is already 0, so the branch
|
|
54
|
+
* changed no answer and was a second statement of the rule to keep in step. The behaviour is still
|
|
55
|
+
* held by a test — what is gone is the code that was not doing the holding.
|
|
56
|
+
*/
|
|
57
|
+
export function writeDispatchArgs(out, at, count, groupSize) {
|
|
58
|
+
const groups = Math.ceil(Math.max(0, count) / Math.max(1, groupSize));
|
|
59
|
+
out[at] = groups;
|
|
60
|
+
out[at + 1] = 1;
|
|
61
|
+
out[at + 2] = 1;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Which slot of the kept list a vertex belongs to, and which triangle of that cluster.
|
|
65
|
+
*
|
|
66
|
+
* The vertex stage's whole addressing, on the processor so a test can read it. `vertex` is
|
|
67
|
+
* `@builtin(vertex_index)` and runs to `CLUSTER_INDEX_CAP`; `instance` is
|
|
68
|
+
* `@builtin(instance_index)` and is the slot.
|
|
69
|
+
*
|
|
70
|
+
* **A triangle past the cluster's own count is reported rather than clamped.** Clamping draws the
|
|
71
|
+
* last triangle of the cluster over and over, which is a visible sliver on every cluster that is
|
|
72
|
+
* not exactly full; reporting it lets the shader emit a degenerate triangle, which covers nothing.
|
|
73
|
+
*/
|
|
74
|
+
export function clusterVertexCluster(vertex, instance, triangleCount) {
|
|
75
|
+
const triangle = Math.floor(vertex / 3);
|
|
76
|
+
return { slot: instance, triangle, corner: vertex % 3, degenerate: triangle >= triangleCount };
|
|
77
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Four floats a mesh: world centre and radius. `CULL_INSTANCES_WGSL` reads this stride. */
|
|
2
|
+
export declare const INSTANCE_FLOATS = 4;
|
|
3
|
+
/** What the instance cull writes for a mesh wholly outside the view. Zero is everything else. */
|
|
4
|
+
export declare const INSTANCE_HIDDEN = 1;
|
|
5
|
+
/** Four words a cluster in the uploaded meta: index offset, index count, identifier, mesh. */
|
|
6
|
+
export declare const CLUSTER_META_WORDS = 4;
|
|
7
|
+
/**
|
|
8
|
+
* Each mesh's world bounding sphere, from the world spheres of its clusters.
|
|
9
|
+
*
|
|
10
|
+
* **Held to the numbers the device reads.** The centre is the middle of the clusters' box, stored
|
|
11
|
+
* in single precision first; the radius is then measured from the *stored* centre and rounded up,
|
|
12
|
+
* never to nearest — a sphere rounded the wrong way is a few parts in ten million short of a
|
|
13
|
+
* cluster's far edge, and a cull that is not conservative is a hole in the picture.
|
|
14
|
+
*
|
|
15
|
+
* A mesh no cluster names is a point at the origin, which draws nothing whatever the cull says. A
|
|
16
|
+
* cluster naming a mesh past `meshCount` is refused: it would be bounded by nothing and drawn by a
|
|
17
|
+
* transform that does not exist.
|
|
18
|
+
*/
|
|
19
|
+
export declare function instanceBounds(cull: Float32Array, meshOf: Uint32Array, count: number, meshCount: number): Float32Array;
|
|
20
|
+
/**
|
|
21
|
+
* One mesh's bounding sphere, from a contiguous run of its clusters' world bounds.
|
|
22
|
+
*
|
|
23
|
+
* **A run rather than a `meshOf` scan, because a streamed mesh's clusters are contiguous by
|
|
24
|
+
* construction** — the allocator hands out a range — so the scan `instanceBounds` does is work a
|
|
25
|
+
* streaming caller has already done.
|
|
26
|
+
*
|
|
27
|
+
* **A mesh with no clusters gets a sphere of zero radius rather than an empty box's arithmetic.**
|
|
28
|
+
* `Infinity - (-Infinity)` is `-Infinity`, and every comparison against `NaN` is false, which
|
|
29
|
+
* reads as a mesh that is never culled rather than one that is never drawn.
|
|
30
|
+
*
|
|
31
|
+
* The two forms must agree, and `instances.test.ts` is what holds them to it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function instanceSphereInto(cull: Float32Array, from: number, count: number, out: Float32Array, at: number): void;
|
|
34
|
+
/**
|
|
35
|
+
* One flag a mesh: `INSTANCE_HIDDEN` where its sphere is wholly outside the view. Returns how many
|
|
36
|
+
* are. Mirrors `CULL_INSTANCES_WGSL`, which `gpu-parity.mjs` holds to `sphereOutsideFrustum`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function cullInstances(planes: Float32Array, spheres: Float32Array, count: number, out: Uint32Array): number;
|
|
39
|
+
/**
|
|
40
|
+
* The cut, over every cluster, with the instance flags applied first: one flag a cluster, and how
|
|
41
|
+
* many were selected. Mirrors `LOD_CUT_WGSL`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function selectClusters(lod: Float32Array, meta: Uint32Array, hidden: Uint32Array, screenHeight: number, fovY: number, thresholdPixels: number, eyeX: number, eyeY: number, eyeZ: number, out: Uint32Array): number;
|