@forgeax/engine-render 0.1.33 → 0.1.34
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/README.md +1010 -124
- package/dist/assembly/backend-contract.d.ts +2 -0
- package/dist/assembly/backend-contract.d.ts.map +1 -1
- package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
- package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
- package/dist/assembly/canvas-draw-guard.d.ts +3 -0
- package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
- package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
- package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
- package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
- package/dist/assembly/factory.d.ts +1 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +3 -3
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
- package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
- package/dist/assembly/material-shader-policy.d.ts +16 -2
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
- package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/render-feature-post-processes.d.ts +6 -0
- package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
- package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-inspection.d.ts +11 -0
- package/dist/assembly/renderer-inspection.d.ts.map +1 -1
- package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
- package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +1 -1
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
- package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +1 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/barrel-distortion.d.ts +47 -0
- package/dist/barrel-distortion.d.ts.map +1 -0
- package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
- package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
- package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
- package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
- package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
- package/dist/chunk-MKDIT2EM.mjs.map +1 -0
- package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
- package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
- package/dist/chunk-ODZWR6JQ.mjs +4927 -0
- package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
- package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
- package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
- package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
- package/dist/chunk-UI5SFODX.mjs.map +1 -0
- package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
- package/dist/chunk-UINHLCZA.mjs.map +1 -0
- package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
- package/dist/chunk-WEX45HKH.mjs.map +1 -0
- package/dist/cloud/density.d.ts +55 -0
- package/dist/cloud/density.d.ts.map +1 -0
- package/dist/cloud/extract.d.ts +25 -0
- package/dist/cloud/extract.d.ts.map +1 -0
- package/dist/cloud/feature.d.ts +57 -0
- package/dist/cloud/feature.d.ts.map +1 -0
- package/dist/cloud/frame-context.d.ts +8 -0
- package/dist/cloud/frame-context.d.ts.map +1 -0
- package/dist/cloud/inspection.d.ts +59 -0
- package/dist/cloud/inspection.d.ts.map +1 -0
- package/dist/cloud/optics.d.ts +56 -0
- package/dist/cloud/optics.d.ts.map +1 -0
- package/dist/cloud/parameters.d.ts +73 -0
- package/dist/cloud/parameters.d.ts.map +1 -0
- package/dist/cloud/resources.d.ts +60 -0
- package/dist/cloud/resources.d.ts.map +1 -0
- package/dist/cloud/shadow.d.ts +42 -0
- package/dist/cloud/shadow.d.ts.map +1 -0
- package/dist/cloud/temporal.d.ts +74 -0
- package/dist/cloud/temporal.d.ts.map +1 -0
- package/dist/components/barrel-distortion.d.ts +13 -0
- package/dist/components/barrel-distortion.d.ts.map +1 -0
- package/dist/components/cloud-layer.d.ts +29 -0
- package/dist/components/cloud-layer.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/instances.d.ts +20 -6
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/construct-renderer.d.ts +1 -1
- package/dist/construct-renderer.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +6759 -2875
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/dynamic-geometry.d.ts +5 -1
- package/dist/dynamic-geometry.d.ts.map +1 -1
- package/dist/errors/cloud.d.ts +59 -0
- package/dist/errors/cloud.d.ts.map +1 -0
- package/dist/errors/render.d.ts +18 -4
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/examples/single-layer-medium-surface.d.ts +47 -0
- package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
- package/dist/extract/camera.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +5 -1
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/features/barrel-distortion.d.ts +29 -0
- package/dist/features/barrel-distortion.d.ts.map +1 -0
- package/dist/features/error-reporting.d.ts +6 -2
- package/dist/features/error-reporting.d.ts.map +1 -1
- package/dist/features/host.d.ts +10 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/plan.d.ts +8 -0
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/render-graph-contribution.d.ts +5 -0
- package/dist/features/render-graph-contribution.d.ts.map +1 -1
- package/dist/features/render-graph-raster.d.ts +1 -0
- package/dist/features/render-graph-raster.d.ts.map +1 -1
- package/dist/features/targets.d.ts +2 -0
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +44 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +15 -7
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-dirty-ranges.d.ts +11 -0
- package/dist/gpu-dirty-ranges.d.ts.map +1 -0
- package/dist/gpu-driven/batch-topology.d.ts +17 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/material-artifacts.d.ts +6 -0
- package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster-material.d.ts +178 -0
- package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +47 -3
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/resource-allocation.d.ts +31 -0
- package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
- package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
- package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
- package/dist/gpu-driven/view-gpu.d.ts +26 -2
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +5 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +2 -2
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +10 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +27 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +258 -8
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +135 -1
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instance-buffer-cache.d.ts +4 -4
- package/dist/instance-buffer-cache.d.ts.map +1 -1
- package/dist/instances.d.ts +48 -100
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +7 -7
- package/dist/pbr-pipeline.d.ts +19 -1
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
- package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
- package/dist/pipeline/standard-output/types.d.ts +4 -2
- package/dist/pipeline/standard-output/types.d.ts.map +1 -1
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +1 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
- package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
- package/dist/record/barrel-distortion-frame.d.ts +15 -0
- package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
- package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
- package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
- package/dist/record/fold-buckets.d.ts +95 -0
- package/dist/record/fold-buckets.d.ts.map +1 -0
- package/dist/record/fold-instance-buffer.d.ts +6 -0
- package/dist/record/fold-instance-buffer.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +1 -0
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +37 -3
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts +10 -61
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-draw-receipts.d.ts +11 -0
- package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +8 -0
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +21 -5
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +7 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +13 -2
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/motion-blur-receipt.d.ts +11 -0
- package/dist/record/motion-blur-receipt.d.ts.map +1 -0
- package/dist/record/probe-blend-buffer.d.ts +16 -0
- package/dist/record/probe-blend-buffer.d.ts.map +1 -0
- package/dist/record/recovery-pipeline.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +22 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +2 -0
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +22 -2
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +11 -3
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/record/volume-params.d.ts +9 -0
- package/dist/record/volume-params.d.ts.map +1 -0
- package/dist/recovery/render-system-candidate.d.ts +10 -0
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/reflection/record-owner.d.ts.map +1 -1
- package/dist/render-contract.d.ts +42 -4
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +103 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +3 -2
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +16 -9
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system-presentation.d.ts +23 -0
- package/dist/render-system-presentation.d.ts.map +1 -0
- package/dist/render-system-producer-roots.d.ts +10 -0
- package/dist/render-system-producer-roots.d.ts.map +1 -0
- package/dist/render-system-residency.d.ts +12 -0
- package/dist/render-system-residency.d.ts.map +1 -0
- package/dist/render-system.d.ts +19 -14
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/probe-blend.d.ts +27 -0
- package/dist/scene/probe-blend.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +12 -5
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +9 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/surface/dynamic-input.d.ts +133 -0
- package/dist/surface/dynamic-input.d.ts.map +1 -0
- package/dist/surface/gpu-driven.d.ts +41 -0
- package/dist/surface/gpu-driven.d.ts.map +1 -0
- package/dist/surface/submission-observation.d.ts +136 -0
- package/dist/surface/submission-observation.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/temporal/gpu.d.ts +13 -1
- package/dist/temporal/gpu.d.ts.map +1 -1
- package/dist/temporal/index.mjs +5 -5
- package/dist/temporal/inspection.d.ts.map +1 -1
- package/dist/temporal/standard-scene-data.d.ts.map +1 -1
- package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
- package/dist/transmission/single-layer-medium.d.ts +89 -0
- package/dist/transmission/single-layer-medium.d.ts.map +1 -0
- package/dist/typed-render-graph-primitives.d.ts +14 -2
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/component.d.ts +9 -4
- package/dist/volume/component.d.ts.map +1 -1
- package/dist/volume/extract.d.ts +1 -1
- package/dist/volume/extract.d.ts.map +1 -1
- package/dist/volume/inspection.d.ts +2 -0
- package/dist/volume/inspection.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +4 -1
- package/dist/volume/passes.d.ts.map +1 -1
- package/dist/volume/resources.d.ts.map +1 -1
- package/package.json +22 -21
- package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
- package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
- package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
- package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
- package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
- package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
- package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
- package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
- package/src/__tests__/factory-contract.integration.test.ts +295 -45
- package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
- package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
- package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
- package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
- package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
- package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
- package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
- package/src/__tests__/gpu-scene.unit.test.ts +119 -9
- package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
- package/src/__tests__/instances-culling.integration.test.ts +10 -36
- package/src/__tests__/instances-store.unit.test.ts +97 -305
- package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
- package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
- package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
- package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
- package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
- package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
- package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
- package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
- package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
- package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
- package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
- package/src/__tests__/probe-bindings.unit.test.ts +582 -1
- package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
- package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
- package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
- package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
- package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
- package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
- package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
- package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
- package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
- package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
- package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
- package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
- package/src/__tests__/resource-allocation.unit.test.ts +123 -0
- package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
- package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
- package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
- package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
- package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
- package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
- package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
- package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
- package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
- package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
- package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
- package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
- package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
- package/src/__tests__/temporal-performance.integration.test.ts +3 -3
- package/src/__tests__/visibility-instances.integration.test.ts +7 -19
- package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
- package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
- package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
- package/src/assembly/backend-contract.ts +30 -0
- package/src/assembly/barrel-distortion-inspection.ts +22 -0
- package/src/assembly/canvas-draw-guard.ts +11 -0
- package/src/assembly/cloud-shadow-entry.ts +22 -0
- package/src/assembly/dynamic-geometry-host.ts +65 -37
- package/src/assembly/dynamic-geometry-runtime.ts +7 -1
- package/src/assembly/factory.ts +2 -30
- package/src/assembly/host-contract.ts +3 -3
- package/src/assembly/material/assembly.ts +25 -13
- package/src/assembly/material/pipeline-helpers.ts +53 -12
- package/src/assembly/material-shader-policy.ts +55 -0
- package/src/assembly/material-shader-prewarm.ts +21 -10
- package/src/assembly/recovery/device-loss-fanout.ts +13 -0
- package/src/assembly/recovery/renderer-recover.ts +41 -18
- package/src/assembly/render-feature-post-processes.ts +54 -0
- package/src/assembly/renderer-facade.ts +4 -1
- package/src/assembly/renderer-feature-inspection.ts +8 -2
- package/src/assembly/renderer-frame-transaction.ts +23 -0
- package/src/assembly/renderer-inspection.ts +28 -0
- package/src/assembly/skin-palette-owner.ts +1 -1
- package/src/assembly/temporal-post-process-prewarm.ts +3 -3
- package/src/assembly/webgpu-pbr-ready.ts +9 -1
- package/src/assembly/webgpu-ready-per-pass.ts +104 -0
- package/src/assembly/webgpu-ready.ts +115 -61
- package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
- package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
- package/src/assembly/webgpu-renderer.ts +214 -252
- package/src/assembly/webgpu-vertex-layouts.ts +1 -1
- package/src/barrel-distortion.ts +247 -0
- package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
- package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
- package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
- package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
- package/src/cloud/density.ts +600 -0
- package/src/cloud/extract.ts +110 -0
- package/src/cloud/feature.ts +1810 -0
- package/src/cloud/frame-context.ts +42 -0
- package/src/cloud/inspection.ts +130 -0
- package/src/cloud/optics.ts +285 -0
- package/src/cloud/parameters.ts +255 -0
- package/src/cloud/resources.ts +122 -0
- package/src/cloud/shadow.ts +167 -0
- package/src/cloud/temporal.ts +226 -0
- package/src/components/barrel-distortion.ts +46 -0
- package/src/components/cloud-layer.ts +47 -0
- package/src/components/index.ts +2 -0
- package/src/components/instances.ts +18 -45
- package/src/components/sprite-instances.ts +1 -1
- package/src/construct-renderer.ts +1 -1
- package/src/dynamic-geometry.ts +12 -1
- package/src/errors/cloud.ts +103 -0
- package/src/errors/render.ts +44 -7
- package/src/examples/single-layer-medium-surface.ts +59 -0
- package/src/extract/camera.ts +15 -1
- package/src/extract/contracts.ts +5 -0
- package/src/features/barrel-distortion.ts +172 -0
- package/src/features/error-reporting.ts +26 -6
- package/src/features/host.ts +115 -14
- package/src/features/plan.ts +8 -0
- package/src/features/render-graph-contribution.ts +9 -0
- package/src/features/render-graph-raster.ts +45 -3
- package/src/features/targets.ts +66 -0
- package/src/features/types.ts +47 -0
- package/src/fullscreen-post-process-pass.ts +41 -9
- package/src/gpu-dirty-ranges.ts +48 -0
- package/src/gpu-driven/batch-topology.ts +53 -0
- package/src/gpu-driven/material-artifacts.ts +33 -25
- package/src/gpu-driven/prepared-draw.ts +12 -4
- package/src/gpu-driven/production-raster-material.ts +1894 -0
- package/src/gpu-driven/production-raster.ts +825 -784
- package/src/gpu-driven/resource-allocation.ts +142 -0
- package/src/gpu-driven/shadow-ownership.ts +71 -0
- package/src/gpu-driven/view-gpu.ts +164 -10
- package/src/gpu-scene.ts +75 -84
- package/src/hdrp-buffers.ts +4 -3
- package/src/ibl/skylight-bind-group.ts +49 -7
- package/src/index.ts +196 -9
- package/src/inspection-types.ts +162 -0
- package/src/instance-buffer-cache.ts +4 -4
- package/src/instances.ts +149 -569
- package/src/pbr-pipeline.ts +219 -13
- package/src/pipeline/single-layer-medium-passes.ts +267 -0
- package/src/pipeline/standard-forward-lane.ts +313 -57
- package/src/pipeline/standard-output/graph.ts +8 -2
- package/src/pipeline/standard-output/types.ts +12 -1
- package/src/pipeline/standard-pipeline.ts +291 -18
- package/src/pipeline/standard-post.ts +90 -24
- package/src/pipeline-builder.ts +1 -1
- package/src/plugin.ts +4 -0
- package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
- package/src/prepare/prepared-graphics-resolver.ts +2 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
- package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
- package/src/record/barrel-distortion-frame.ts +110 -0
- package/src/record/dynamic-geometry-consumption.ts +39 -9
- package/src/record/fold-buckets.ts +852 -0
- package/src/record/fold-instance-buffer.ts +51 -0
- package/src/record/frame-lighting.ts +36 -2
- package/src/record/frame-snapshot.ts +39 -3
- package/src/record/frame.ts +217 -1084
- package/src/record/gpu-draw-receipts.ts +38 -0
- package/src/record/gpu-timing.ts +48 -5
- package/src/record/main-pass-geometry.ts +251 -82
- package/src/record/main-pass-material.ts +66 -4
- package/src/record/main-pass-sprite-draws.ts +7 -65
- package/src/record/main-pass.ts +156 -20
- package/src/record/motion-blur-receipt.ts +91 -0
- package/src/record/probe-blend-buffer.ts +180 -0
- package/src/record/recovery-pipeline.ts +35 -3
- package/src/record/render-context.ts +39 -3
- package/src/record/shadow-pass.ts +30 -1
- package/src/record/skybox-post-pass.ts +28 -4
- package/src/record/typed-frame-graph.ts +770 -134
- package/src/record/view-ubo.ts +26 -3
- package/src/record/volume-params.ts +225 -0
- package/src/recovery/render-system-candidate.ts +235 -42
- package/src/reflection/record-owner.ts +7 -3
- package/src/render-contract.ts +48 -4
- package/src/render-graph-primitives.ts +7 -1
- package/src/render-pipeline.ts +130 -0
- package/src/render-system-extract-tail.ts +57 -61
- package/src/render-system-extract.ts +74 -76
- package/src/render-system-presentation.ts +56 -0
- package/src/render-system-producer-roots.ts +96 -0
- package/src/render-system-residency.ts +159 -0
- package/src/render-system.ts +347 -363
- package/src/scene/probe-blend.ts +96 -4
- package/src/scene/render-scene.ts +349 -280
- package/src/ssao-buffers.ts +95 -2
- package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
- package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
- package/src/surface/dynamic-input.ts +658 -0
- package/src/surface/gpu-driven.ts +147 -0
- package/src/surface/submission-observation.ts +517 -0
- package/src/systems/skin-palette-allocator.ts +4 -1
- package/src/temporal/gpu.ts +101 -17
- package/src/temporal/inspection.ts +7 -1
- package/src/temporal/standard-scene-data.ts +5 -0
- package/src/temporal/target-coverage-attachment.ts +4 -0
- package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
- package/src/transmission/single-layer-medium.ts +322 -0
- package/src/typed-render-graph-primitives.ts +70 -2
- package/src/volume/component.ts +10 -9
- package/src/volume/extract.ts +11 -5
- package/src/volume/inspection.ts +3 -0
- package/src/volume/passes.ts +87 -4
- package/src/volume/resources.ts +2 -1
- package/dist/chunk-3RTCJTH4.mjs.map +0 -1
- package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
- package/dist/chunk-NNQL7CB3.mjs +0 -1713
- package/dist/chunk-NNQL7CB3.mjs.map +0 -1
- package/dist/chunk-OO3DRYK7.mjs.map +0 -1
- package/dist/chunk-PA5DRJNI.mjs.map +0 -1
- package/dist/chunk-PLAXOOX5.mjs.map +0 -1
- package/dist/chunk-VOZWDM3L.mjs.map +0 -1
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
2
|
+
import {
|
|
3
|
+
type CloudLayerData,
|
|
4
|
+
type CloudQuality,
|
|
5
|
+
CloudQualityValue,
|
|
6
|
+
cloudQualityFromF32,
|
|
7
|
+
} from '../components/cloud-layer';
|
|
8
|
+
import { type CloudLayerError, CloudLayerInvalidParameterError } from '../errors/cloud';
|
|
9
|
+
|
|
10
|
+
export interface CloudLayerAuthoring {
|
|
11
|
+
readonly seed?: number;
|
|
12
|
+
readonly baseHeight?: number;
|
|
13
|
+
readonly thickness?: number;
|
|
14
|
+
readonly scale?: number;
|
|
15
|
+
readonly coverage?: number;
|
|
16
|
+
readonly density?: number;
|
|
17
|
+
readonly wind?: ArrayLike<number>;
|
|
18
|
+
readonly quality?: CloudQuality | number;
|
|
19
|
+
readonly shadowRange?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ValidatedCloudLayer {
|
|
23
|
+
readonly seed: number;
|
|
24
|
+
readonly baseHeight: number;
|
|
25
|
+
readonly thickness: number;
|
|
26
|
+
readonly scale: number;
|
|
27
|
+
readonly coverage: number;
|
|
28
|
+
readonly density: number;
|
|
29
|
+
readonly wind: readonly [number, number, number];
|
|
30
|
+
readonly quality: CloudQuality;
|
|
31
|
+
readonly shadowRange: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CloudQualityProfile {
|
|
35
|
+
readonly cacheResolution: number;
|
|
36
|
+
readonly viewSteps: number;
|
|
37
|
+
readonly shadowSteps: number;
|
|
38
|
+
readonly historyWeight: number;
|
|
39
|
+
/** Renderer-owned sky trace domain in world units; independent of Camera.far. */
|
|
40
|
+
readonly viewDistance: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Quality values are bounded in one place. The values are deliberately
|
|
45
|
+
* renderer policy, while the component stores only the closed quality code.
|
|
46
|
+
*/
|
|
47
|
+
export const CLOUD_QUALITY_PROFILES: Readonly<Record<CloudQuality, CloudQualityProfile>> =
|
|
48
|
+
Object.freeze({
|
|
49
|
+
low: Object.freeze({
|
|
50
|
+
// Preserve low-profile ray counts while keeping separate puffs from
|
|
51
|
+
// collapsing into one bilinear cache smear.
|
|
52
|
+
cacheResolution: 32,
|
|
53
|
+
viewSteps: 40,
|
|
54
|
+
shadowSteps: 12,
|
|
55
|
+
historyWeight: 0.82,
|
|
56
|
+
viewDistance: 1600,
|
|
57
|
+
}),
|
|
58
|
+
medium: Object.freeze({
|
|
59
|
+
cacheResolution: 40,
|
|
60
|
+
viewSteps: 64,
|
|
61
|
+
shadowSteps: 20,
|
|
62
|
+
historyWeight: 0.9,
|
|
63
|
+
viewDistance: 2400,
|
|
64
|
+
}),
|
|
65
|
+
high: Object.freeze({
|
|
66
|
+
cacheResolution: 64,
|
|
67
|
+
viewSteps: 64,
|
|
68
|
+
shadowSteps: 32,
|
|
69
|
+
historyWeight: 0.94,
|
|
70
|
+
viewDistance: 4000,
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The spatial cloud-shadow map is intentionally derived from the same quality
|
|
76
|
+
* profile everywhere: graph allocation, light-space projection and inspection
|
|
77
|
+
* must agree on one texel grid. Keep the multiplier here rather than letting
|
|
78
|
+
* each owner invent a resolution.
|
|
79
|
+
*/
|
|
80
|
+
export function cloudShadowResolutionForQuality(qualityValue: CloudQuality): number {
|
|
81
|
+
return CLOUD_QUALITY_PROFILES[qualityValue].cacheResolution * 4;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Cloud visibility is a sky-domain concern. It must not inherit the opaque
|
|
86
|
+
* geometry far plane or the finite receiver-shadow footprint: either value is
|
|
87
|
+
* commonly much shorter than a ground-view cloud trace and would turn the
|
|
88
|
+
* distant layer into a flat wall.
|
|
89
|
+
*/
|
|
90
|
+
export function cloudViewDistanceForQuality(qualityValue: CloudQuality): number {
|
|
91
|
+
return CLOUD_QUALITY_PROFILES[qualityValue].viewDistance;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** rgba16float is four 16-bit channels (8 bytes per texel). */
|
|
95
|
+
export const CLOUD_SHADOW_BYTES_PER_TEXEL = 8;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Authored density is a normalized formation value. Convert it to a bounded
|
|
99
|
+
* per-world-unit extinction coefficient only at integration time; otherwise a
|
|
100
|
+
* long horizon step would become opaque after its first sample and expose
|
|
101
|
+
* marching bands instead of a participating volume.
|
|
102
|
+
*/
|
|
103
|
+
export const CLOUD_EXTINCTION_COEFFICIENT = 0.03;
|
|
104
|
+
|
|
105
|
+
export const DEFAULT_CLOUD_LAYER: ValidatedCloudLayer = Object.freeze({
|
|
106
|
+
seed: 1337,
|
|
107
|
+
baseHeight: 120,
|
|
108
|
+
thickness: 80,
|
|
109
|
+
scale: 0.004,
|
|
110
|
+
coverage: 0.48,
|
|
111
|
+
density: 1,
|
|
112
|
+
wind: Object.freeze([8, 0, 2] as [number, number, number]),
|
|
113
|
+
quality: 'medium',
|
|
114
|
+
shadowRange: 512,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
function invalid(field: string, value: unknown, expected: string): Result<never, CloudLayerError> {
|
|
118
|
+
return err(new CloudLayerInvalidParameterError(field, value, expected));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function finiteRange(
|
|
122
|
+
field: string,
|
|
123
|
+
value: unknown,
|
|
124
|
+
min: number,
|
|
125
|
+
max = Number.POSITIVE_INFINITY,
|
|
126
|
+
): Result<number, CloudLayerError> {
|
|
127
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < min || value > max) {
|
|
128
|
+
const expected = Number.isFinite(max)
|
|
129
|
+
? `finite and in [${min}, ${max}]`
|
|
130
|
+
: `finite and >= ${min}`;
|
|
131
|
+
return invalid(field, value, expected);
|
|
132
|
+
}
|
|
133
|
+
return ok(value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function quality(value: unknown): Result<CloudQuality, CloudLayerError> {
|
|
137
|
+
if (typeof value === 'string' && (value === 'low' || value === 'medium' || value === 'high')) {
|
|
138
|
+
return ok(value);
|
|
139
|
+
}
|
|
140
|
+
if (typeof value === 'number') {
|
|
141
|
+
const resolved = cloudQualityFromF32(value);
|
|
142
|
+
if (resolved !== undefined) return ok(resolved);
|
|
143
|
+
}
|
|
144
|
+
return invalid(
|
|
145
|
+
'quality',
|
|
146
|
+
value,
|
|
147
|
+
`one of low, medium, high (codes ${CloudQualityValue.low}, ${CloudQualityValue.medium}, ${CloudQualityValue.high})`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function wind(value: unknown): Result<readonly [number, number, number], CloudLayerError> {
|
|
152
|
+
if (value === undefined || value === null || typeof value !== 'object') {
|
|
153
|
+
return invalid('wind', value, 'three finite world-space components');
|
|
154
|
+
}
|
|
155
|
+
const source = value as ArrayLike<number>;
|
|
156
|
+
if (source.length !== 3) return invalid('wind', value, 'three finite world-space components');
|
|
157
|
+
const result: [number, number, number] = [
|
|
158
|
+
source[0] ?? Number.NaN,
|
|
159
|
+
source[1] ?? Number.NaN,
|
|
160
|
+
source[2] ?? Number.NaN,
|
|
161
|
+
];
|
|
162
|
+
if (result.some((entry) => !Number.isFinite(entry) || Math.abs(entry) > 1000)) {
|
|
163
|
+
return invalid('wind', value, 'three finite components in [-1000, 1000]');
|
|
164
|
+
}
|
|
165
|
+
return ok(Object.freeze(result));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Validate one detached CloudLayer POD before deriving cache or graph state. */
|
|
169
|
+
export function validateCloudLayer(
|
|
170
|
+
input: CloudLayerAuthoring | Partial<CloudLayerData> | undefined,
|
|
171
|
+
): Result<ValidatedCloudLayer, CloudLayerError> {
|
|
172
|
+
const value = input ?? {};
|
|
173
|
+
const seed = value.seed ?? DEFAULT_CLOUD_LAYER.seed;
|
|
174
|
+
if (typeof seed !== 'number' || !Number.isInteger(seed) || seed < 0 || seed > 0xffffffff) {
|
|
175
|
+
return invalid('seed', seed, 'an integer in [0, 4294967295]');
|
|
176
|
+
}
|
|
177
|
+
const baseHeight = finiteRange(
|
|
178
|
+
'baseHeight',
|
|
179
|
+
value.baseHeight ?? DEFAULT_CLOUD_LAYER.baseHeight,
|
|
180
|
+
-100000,
|
|
181
|
+
1000000,
|
|
182
|
+
);
|
|
183
|
+
if (!baseHeight.ok) return baseHeight;
|
|
184
|
+
const thickness = finiteRange(
|
|
185
|
+
'thickness',
|
|
186
|
+
value.thickness ?? DEFAULT_CLOUD_LAYER.thickness,
|
|
187
|
+
0.001,
|
|
188
|
+
1000000,
|
|
189
|
+
);
|
|
190
|
+
if (!thickness.ok) return thickness;
|
|
191
|
+
const scale = finiteRange('scale', value.scale ?? DEFAULT_CLOUD_LAYER.scale, 0.000001, 10);
|
|
192
|
+
if (!scale.ok) return scale;
|
|
193
|
+
const coverage = finiteRange('coverage', value.coverage ?? DEFAULT_CLOUD_LAYER.coverage, 0, 1);
|
|
194
|
+
if (!coverage.ok) return coverage;
|
|
195
|
+
const density = finiteRange('density', value.density ?? DEFAULT_CLOUD_LAYER.density, 0, 32);
|
|
196
|
+
if (!density.ok) return density;
|
|
197
|
+
const resolvedWind = wind(value.wind ?? DEFAULT_CLOUD_LAYER.wind);
|
|
198
|
+
if (!resolvedWind.ok) return resolvedWind;
|
|
199
|
+
const resolvedQuality = quality(value.quality ?? DEFAULT_CLOUD_LAYER.quality);
|
|
200
|
+
if (!resolvedQuality.ok) return resolvedQuality;
|
|
201
|
+
const shadowRange = finiteRange(
|
|
202
|
+
'shadowRange',
|
|
203
|
+
value.shadowRange ?? DEFAULT_CLOUD_LAYER.shadowRange,
|
|
204
|
+
0.001,
|
|
205
|
+
10000000,
|
|
206
|
+
);
|
|
207
|
+
if (!shadowRange.ok) return shadowRange;
|
|
208
|
+
return ok(
|
|
209
|
+
Object.freeze({
|
|
210
|
+
seed,
|
|
211
|
+
baseHeight: baseHeight.value,
|
|
212
|
+
thickness: thickness.value,
|
|
213
|
+
scale: scale.value,
|
|
214
|
+
coverage: coverage.value,
|
|
215
|
+
density: density.value,
|
|
216
|
+
wind: resolvedWind.value,
|
|
217
|
+
quality: resolvedQuality.value,
|
|
218
|
+
shadowRange: shadowRange.value,
|
|
219
|
+
}),
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Stable source identity used by cache, history and recovery receipts. */
|
|
224
|
+
export function cloudLayerSourceKey(params: ValidatedCloudLayer): string {
|
|
225
|
+
return [
|
|
226
|
+
'cloud-layer-v1',
|
|
227
|
+
params.seed,
|
|
228
|
+
params.baseHeight,
|
|
229
|
+
params.thickness,
|
|
230
|
+
params.scale,
|
|
231
|
+
params.coverage,
|
|
232
|
+
params.density,
|
|
233
|
+
params.wind[0],
|
|
234
|
+
params.wind[1],
|
|
235
|
+
params.wind[2],
|
|
236
|
+
params.quality,
|
|
237
|
+
params.shadowRange,
|
|
238
|
+
].join(':');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Stable identity for the reusable formation bases. Coverage, density and
|
|
243
|
+
* wind are evaluation inputs and deliberately do not rebuild the weather,
|
|
244
|
+
* body or erosion cache when they change continuously.
|
|
245
|
+
*/
|
|
246
|
+
export function cloudLayerFormationKey(params: ValidatedCloudLayer): string {
|
|
247
|
+
return [
|
|
248
|
+
'cloud-formation-v5',
|
|
249
|
+
params.seed,
|
|
250
|
+
params.baseHeight,
|
|
251
|
+
params.thickness,
|
|
252
|
+
params.scale,
|
|
253
|
+
params.quality,
|
|
254
|
+
].join(':');
|
|
255
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { CloudDensityCache } from './density';
|
|
2
|
+
import type { CloudShadowProjection } from './shadow';
|
|
3
|
+
import type { CloudHistory } from './temporal';
|
|
4
|
+
|
|
5
|
+
/** Evidence level for bytes owned by the prepared GPU path. */
|
|
6
|
+
export type CloudGpuResourceEvidence = 'unavailable' | 'declared' | 'measured';
|
|
7
|
+
|
|
8
|
+
/** rgba16float is four 16-bit channels (8 bytes per texel). */
|
|
9
|
+
export const CLOUD_RGBA16FLOAT_BYTES_PER_TEXEL = 8;
|
|
10
|
+
/** Two ping-pong surfaces for each of radiance/transmittance/depth. */
|
|
11
|
+
export const CLOUD_HISTORY_SURFACE_COUNT = 6;
|
|
12
|
+
|
|
13
|
+
export interface CloudLayerResourceFacts {
|
|
14
|
+
readonly generation: number;
|
|
15
|
+
/** CPU-side packed formation payload; this is not GPU residency. */
|
|
16
|
+
readonly cacheBytes: number;
|
|
17
|
+
/** Measured GPU bytes, or zero when no prepared-owner receipt was supplied. */
|
|
18
|
+
readonly shadowBytes: number;
|
|
19
|
+
readonly historyBytes: number;
|
|
20
|
+
readonly inFlightBytes: number;
|
|
21
|
+
readonly residentBytes: number;
|
|
22
|
+
readonly resourceCount: number;
|
|
23
|
+
/** Whether the GPU byte fields are measured, only graph-declared, or unknown. */
|
|
24
|
+
readonly gpuEvidence: CloudGpuResourceEvidence;
|
|
25
|
+
/** Descriptor-derived allocation sizes, independent from physical residency. */
|
|
26
|
+
readonly declaredShadowBytes: number;
|
|
27
|
+
readonly declaredHistoryBytes: number;
|
|
28
|
+
readonly declaredResidentBytes: number;
|
|
29
|
+
readonly declaredResourceCount: number;
|
|
30
|
+
/** Measured GPU resource count, kept separate from logical declarations. */
|
|
31
|
+
readonly measuredGpuResourceCount: number;
|
|
32
|
+
readonly cacheResolution: number;
|
|
33
|
+
readonly shadowResolution: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface CloudLayerResourceInputs {
|
|
37
|
+
readonly generation: number;
|
|
38
|
+
readonly cache?: CloudDensityCache;
|
|
39
|
+
readonly shadow?: CloudShadowProjection;
|
|
40
|
+
readonly history?: CloudHistory;
|
|
41
|
+
/** Bytes reported by the prepared GPU owner; absent means unavailable. */
|
|
42
|
+
readonly shadowBytes?: number;
|
|
43
|
+
readonly historyBytes?: number;
|
|
44
|
+
readonly inFlightBytes?: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Derive one inspection receipt from the resources owned by the current generation. */
|
|
48
|
+
export function inspectCloudLayerResources(
|
|
49
|
+
input: CloudLayerResourceInputs,
|
|
50
|
+
): CloudLayerResourceFacts {
|
|
51
|
+
const cacheBytes = input.cache?.byteLength ?? 0;
|
|
52
|
+
const shadowResolution = input.shadow?.resolution ?? 0;
|
|
53
|
+
const declaredShadowBytes =
|
|
54
|
+
shadowResolution * shadowResolution * CLOUD_RGBA16FLOAT_BYTES_PER_TEXEL;
|
|
55
|
+
const historyWidth = input.history?.width ?? 0;
|
|
56
|
+
const historyHeight = input.history?.height ?? 0;
|
|
57
|
+
const declaredHistoryBytes =
|
|
58
|
+
historyWidth * historyHeight * CLOUD_HISTORY_SURFACE_COUNT * CLOUD_RGBA16FLOAT_BYTES_PER_TEXEL;
|
|
59
|
+
const shadowBytes = input.shadowBytes ?? 0;
|
|
60
|
+
const historyBytes = input.historyBytes ?? 0;
|
|
61
|
+
const inFlightBytes = Math.max(0, input.inFlightBytes ?? 0);
|
|
62
|
+
const residentBytes = cacheBytes + shadowBytes + historyBytes;
|
|
63
|
+
const measuredGpuResourceCount =
|
|
64
|
+
Number(input.shadowBytes !== undefined) + Number(input.historyBytes !== undefined);
|
|
65
|
+
const gpuEvidence: CloudGpuResourceEvidence =
|
|
66
|
+
measuredGpuResourceCount > 0 || input.inFlightBytes !== undefined
|
|
67
|
+
? 'measured'
|
|
68
|
+
: input.shadow !== undefined || input.history !== undefined
|
|
69
|
+
? 'declared'
|
|
70
|
+
: 'unavailable';
|
|
71
|
+
const resourceCount =
|
|
72
|
+
Number(input.cache !== undefined) +
|
|
73
|
+
Number(input.shadow !== undefined) +
|
|
74
|
+
Number(input.history !== undefined);
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
generation: input.generation,
|
|
77
|
+
cacheBytes,
|
|
78
|
+
shadowBytes,
|
|
79
|
+
historyBytes,
|
|
80
|
+
inFlightBytes,
|
|
81
|
+
residentBytes,
|
|
82
|
+
resourceCount,
|
|
83
|
+
gpuEvidence,
|
|
84
|
+
declaredShadowBytes,
|
|
85
|
+
declaredHistoryBytes,
|
|
86
|
+
declaredResidentBytes: cacheBytes + declaredShadowBytes + declaredHistoryBytes,
|
|
87
|
+
declaredResourceCount: resourceCount,
|
|
88
|
+
measuredGpuResourceCount,
|
|
89
|
+
cacheResolution: input.cache?.resolution ?? 0,
|
|
90
|
+
shadowResolution,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface CloudLayerGeneration {
|
|
95
|
+
readonly generation: number;
|
|
96
|
+
readonly sourceKey: string;
|
|
97
|
+
readonly resourceFacts: CloudLayerResourceFacts;
|
|
98
|
+
readonly status: 'candidate' | 'active' | 'lkg' | 'retiring';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Candidate -> active transition used by the renderer's existing graph owner. */
|
|
102
|
+
export function acceptCloudLayerGeneration(
|
|
103
|
+
candidate: CloudLayerGeneration,
|
|
104
|
+
previous: CloudLayerGeneration | undefined,
|
|
105
|
+
): { readonly active: CloudLayerGeneration; readonly lkg: CloudLayerGeneration | undefined } {
|
|
106
|
+
return Object.freeze({
|
|
107
|
+
active: Object.freeze({ ...candidate, status: 'active' as const }),
|
|
108
|
+
lkg:
|
|
109
|
+
previous === undefined ? undefined : Object.freeze({ ...previous, status: 'lkg' as const }),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** A failed candidate never replaces the LKG; retirement is fence-owned by Render. */
|
|
114
|
+
export function retainCloudLayerAfterFailure(
|
|
115
|
+
active: CloudLayerGeneration | undefined,
|
|
116
|
+
candidate: CloudLayerGeneration,
|
|
117
|
+
): { readonly active: CloudLayerGeneration | undefined; readonly retiring: CloudLayerGeneration } {
|
|
118
|
+
return Object.freeze({
|
|
119
|
+
active,
|
|
120
|
+
retiring: Object.freeze({ ...candidate, status: 'retiring' as const }),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { CloudDensityCache } from './density';
|
|
2
|
+
import { integrateCloudSolarColumn } from './optics';
|
|
3
|
+
import type { ValidatedCloudLayer } from './parameters';
|
|
4
|
+
|
|
5
|
+
export interface CloudShadowProjection {
|
|
6
|
+
readonly revision: number;
|
|
7
|
+
readonly resolution: number;
|
|
8
|
+
readonly range: number;
|
|
9
|
+
readonly texelSize: number;
|
|
10
|
+
readonly center: readonly [number, number, number];
|
|
11
|
+
readonly origin: readonly [number, number, number];
|
|
12
|
+
readonly right: readonly [number, number, number];
|
|
13
|
+
readonly up: readonly [number, number, number];
|
|
14
|
+
readonly sunDirection: readonly [number, number, number];
|
|
15
|
+
readonly lowSun: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CloudShadowSample {
|
|
19
|
+
readonly transmittance: number;
|
|
20
|
+
readonly uv: readonly [number, number] | undefined;
|
|
21
|
+
readonly valid: boolean;
|
|
22
|
+
readonly fallback: 'none' | 'low-sun' | 'outside-range' | 'empty-coverage';
|
|
23
|
+
readonly revision: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalize(vector: ArrayLike<number>): readonly [number, number, number] {
|
|
27
|
+
const x = vector[0] ?? 0;
|
|
28
|
+
const y = vector[1] ?? 0;
|
|
29
|
+
const z = vector[2] ?? 0;
|
|
30
|
+
const length = Math.hypot(x, y, z);
|
|
31
|
+
return length <= 1e-8 ? [0, 1, 0] : [x / length, y / length, z / length];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function cross(
|
|
35
|
+
a: readonly [number, number, number],
|
|
36
|
+
b: readonly [number, number, number],
|
|
37
|
+
): readonly [number, number, number] {
|
|
38
|
+
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function dot(a: ArrayLike<number>, b: ArrayLike<number>): number {
|
|
42
|
+
return (a[0] ?? 0) * (b[0] ?? 0) + (a[1] ?? 0) * (b[1] ?? 0) + (a[2] ?? 0) * (b[2] ?? 0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function stableRevision(input: {
|
|
46
|
+
readonly center: readonly [number, number, number];
|
|
47
|
+
readonly sunDirection: readonly [number, number, number];
|
|
48
|
+
readonly range: number;
|
|
49
|
+
readonly resolution: number;
|
|
50
|
+
}): number {
|
|
51
|
+
let hash = 2166136261;
|
|
52
|
+
const values = [...input.center, ...input.sunDirection, input.range, input.resolution];
|
|
53
|
+
for (const value of values) {
|
|
54
|
+
const bits = new Float32Array([value]);
|
|
55
|
+
const bytes = new Uint8Array(bits.buffer);
|
|
56
|
+
for (const byte of bytes) hash = Math.imul(hash ^ byte, 16777619);
|
|
57
|
+
}
|
|
58
|
+
return hash >>> 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Build a camera-independent light-space projection. The center is a world
|
|
63
|
+
* anchor chosen by Render (usually the active scene bounds), and is snapped to
|
|
64
|
+
* one texel so camera motion cannot crawl the cloud shadow.
|
|
65
|
+
*/
|
|
66
|
+
export function createCloudShadowProjection(input: {
|
|
67
|
+
readonly center: readonly [number, number, number];
|
|
68
|
+
readonly sunDirection: readonly [number, number, number];
|
|
69
|
+
readonly range: number;
|
|
70
|
+
readonly resolution?: number;
|
|
71
|
+
}): CloudShadowProjection {
|
|
72
|
+
const sunDirection = normalize(input.sunDirection);
|
|
73
|
+
const resolution = Math.max(16, Math.floor(input.resolution ?? 1024));
|
|
74
|
+
const range = Math.max(1, input.range);
|
|
75
|
+
const texelSize = range / resolution;
|
|
76
|
+
const reference = Math.abs(sunDirection[1]) < 0.95 ? ([0, 1, 0] as const) : ([1, 0, 0] as const);
|
|
77
|
+
const right = normalize(cross(reference, sunDirection));
|
|
78
|
+
const up = normalize(cross(sunDirection, right));
|
|
79
|
+
const center = input.center;
|
|
80
|
+
const lightX = dot(center, right);
|
|
81
|
+
const lightY = dot(center, up);
|
|
82
|
+
const lightZ = dot(center, sunDirection);
|
|
83
|
+
const snappedX = Math.floor(lightX / texelSize + 0.5) * texelSize;
|
|
84
|
+
const snappedY = Math.floor(lightY / texelSize + 0.5) * texelSize;
|
|
85
|
+
const origin: [number, number, number] = [
|
|
86
|
+
right[0] * snappedX + up[0] * snappedY + sunDirection[0] * lightZ,
|
|
87
|
+
right[1] * snappedX + up[1] * snappedY + sunDirection[1] * lightZ,
|
|
88
|
+
right[2] * snappedX + up[2] * snappedY + sunDirection[2] * lightZ,
|
|
89
|
+
];
|
|
90
|
+
return Object.freeze({
|
|
91
|
+
revision: stableRevision({ center, sunDirection, range, resolution }),
|
|
92
|
+
resolution,
|
|
93
|
+
range,
|
|
94
|
+
texelSize,
|
|
95
|
+
center: Object.freeze([...center] as [number, number, number]),
|
|
96
|
+
origin: Object.freeze(origin),
|
|
97
|
+
right,
|
|
98
|
+
up,
|
|
99
|
+
sunDirection,
|
|
100
|
+
lowSun: sunDirection[1] <= 0.08,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function projectCloudShadowUv(
|
|
105
|
+
projection: CloudShadowProjection,
|
|
106
|
+
position: readonly [number, number, number],
|
|
107
|
+
): { readonly uv: readonly [number, number]; readonly inRange: boolean } {
|
|
108
|
+
const relative: [number, number, number] = [
|
|
109
|
+
position[0] - projection.origin[0],
|
|
110
|
+
position[1] - projection.origin[1],
|
|
111
|
+
position[2] - projection.origin[2],
|
|
112
|
+
];
|
|
113
|
+
const x = dot(relative, projection.right);
|
|
114
|
+
const y = dot(relative, projection.up);
|
|
115
|
+
const uv: [number, number] = [0.5 + x / projection.range, 0.5 + y / projection.range];
|
|
116
|
+
return { uv, inRange: uv[0] >= 0 && uv[0] <= 1 && uv[1] >= 0 && uv[1] <= 1 };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Evaluate the stable world-space shadow term used by surface and volume sun paths. */
|
|
120
|
+
export function sampleCloudShadow(
|
|
121
|
+
params: ValidatedCloudLayer,
|
|
122
|
+
projection: CloudShadowProjection,
|
|
123
|
+
worldPosition: readonly [number, number, number],
|
|
124
|
+
options: { readonly cache?: CloudDensityCache; readonly timeSeconds?: number } = {},
|
|
125
|
+
): CloudShadowSample {
|
|
126
|
+
const projected = projectCloudShadowUv(projection, worldPosition);
|
|
127
|
+
if (projection.lowSun) {
|
|
128
|
+
return {
|
|
129
|
+
transmittance: 1,
|
|
130
|
+
uv: projected.uv,
|
|
131
|
+
valid: false,
|
|
132
|
+
fallback: 'low-sun',
|
|
133
|
+
revision: projection.revision,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (!projected.inRange) {
|
|
137
|
+
return {
|
|
138
|
+
transmittance: 1,
|
|
139
|
+
uv: projected.uv,
|
|
140
|
+
valid: false,
|
|
141
|
+
fallback: 'outside-range',
|
|
142
|
+
revision: projection.revision,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (params.coverage >= 1 || params.density <= 0) {
|
|
146
|
+
return {
|
|
147
|
+
transmittance: 1,
|
|
148
|
+
uv: projected.uv,
|
|
149
|
+
valid: false,
|
|
150
|
+
fallback: 'empty-coverage',
|
|
151
|
+
revision: projection.revision,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const integrated = integrateCloudSolarColumn(params, worldPosition, projection.sunDirection, {
|
|
155
|
+
steps: 20,
|
|
156
|
+
maxDistance: projection.range,
|
|
157
|
+
...(options.cache === undefined ? {} : { cache: options.cache }),
|
|
158
|
+
...(options.timeSeconds === undefined ? {} : { timeSeconds: options.timeSeconds }),
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
transmittance: integrated.transmittance,
|
|
162
|
+
uv: projected.uv,
|
|
163
|
+
valid: integrated.entered,
|
|
164
|
+
fallback: 'none',
|
|
165
|
+
revision: projection.revision,
|
|
166
|
+
};
|
|
167
|
+
}
|