@forgeax/engine-render 0.1.20 → 0.1.23
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 +365 -29
- package/dist/assembly/backend-contract.d.ts +13 -0
- package/dist/assembly/backend-contract.d.ts.map +1 -1
- package/dist/assembly/device-feature-admission.d.ts +18 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -0
- package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
- package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +30 -19
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +19 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/render-target-host.d.ts +46 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -0
- package/dist/assets/render-asset-port.d.ts.map +1 -1
- package/dist/authoring.mjs +4 -1
- package/dist/authoring.mjs.map +1 -1
- package/dist/capture/cube-views.d.ts +21 -0
- package/dist/capture/cube-views.d.ts.map +1 -0
- package/dist/capture/scheduler.d.ts +54 -0
- package/dist/capture/scheduler.d.ts.map +1 -0
- package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
- package/dist/chunk-4L3P6DT5.mjs.map +1 -0
- package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
- package/dist/chunk-4NPUASZR.mjs.map +1 -0
- package/dist/chunk-DIYW3M5D.mjs +5085 -0
- package/dist/chunk-DIYW3M5D.mjs.map +1 -0
- package/dist/chunk-FBC4R44J.mjs +1003 -0
- package/dist/chunk-FBC4R44J.mjs.map +1 -0
- package/dist/{chunk-CDTWTHZR.mjs → chunk-FF7K3FSO.mjs} +474 -168
- package/dist/chunk-FF7K3FSO.mjs.map +1 -0
- package/dist/chunk-HZUPSYW7.mjs +1104 -0
- package/dist/chunk-HZUPSYW7.mjs.map +1 -0
- package/dist/{chunk-TBQJOK2L.mjs → chunk-QODA5UKU.mjs} +321 -269
- package/dist/chunk-QODA5UKU.mjs.map +1 -0
- package/dist/chunk-YALPS44A.mjs +296 -0
- package/dist/chunk-YALPS44A.mjs.map +1 -0
- package/dist/{chunk-4XINDLAY.mjs → chunk-ZUWKAZ2I.mjs} +1963 -2178
- package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
- package/dist/cluster-binner.d.ts +5 -0
- package/dist/cluster-binner.d.ts.map +1 -1
- package/dist/components/camera.d.ts +1 -0
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/cube-camera.d.ts +20 -0
- package/dist/components/cube-camera.d.ts.map +1 -0
- package/dist/components/directional-light.d.ts +11 -2
- package/dist/components/directional-light.d.ts.map +1 -1
- package/dist/components/directional-shadow-filter.d.ts +25 -0
- package/dist/components/directional-shadow-filter.d.ts.map +1 -0
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts +4 -0
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/light-probe.d.ts +9 -0
- package/dist/components/light-probe.d.ts.map +1 -0
- package/dist/components/rect-area-light.d.ts +12 -0
- package/dist/components/rect-area-light.d.ts.map +1 -0
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/components/scene-instance.d.ts +4 -0
- package/dist/components/scene-instance.d.ts.map +1 -1
- package/dist/components/spot-light.d.ts +3 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +14836 -9620
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +8 -1
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/device/lifecycle-transaction.d.ts +2 -0
- package/dist/device/lifecycle-transaction.d.ts.map +1 -0
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +5 -0
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/gpu-driven.d.ts +26 -0
- package/dist/errors/gpu-driven.d.ts.map +1 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/recover.d.ts +9 -1
- package/dist/errors/recover.d.ts.map +1 -1
- package/dist/errors/render.d.ts +166 -93
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/directional-shadow-projection.d.ts +23 -0
- package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
- package/dist/extract/environment.d.ts +14 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/extract/gpu-driven.d.ts +50 -0
- package/dist/extract/gpu-driven.d.ts.map +1 -0
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/features/fullscreen.d.ts.map +1 -1
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +10 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +13 -2
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts +34 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts +63 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +97 -2
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/view-gpu.d.ts +64 -1
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts +14 -0
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +8 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +0 -1
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +21 -19
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +4 -0
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/kernel-cache.d.ts +36 -0
- package/dist/ibl/kernel-cache.d.ts.map +1 -0
- package/dist/index.d.ts +39 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +91 -6
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +214 -1
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +50 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -0
- package/dist/internal.d.ts +9 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +23 -2
- package/dist/internal.mjs.map +1 -1
- package/dist/light-buffer-layout.d.ts +58 -140
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/materials.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +54 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +38 -14
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts +2 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
- package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
- package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
- package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts +4 -13
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline/standard-profile.d.ts +5 -26
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +2 -0
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +40 -7
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/point-shadow-inspection.d.ts +21 -0
- package/dist/point-shadow-inspection.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
- package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/resources.d.ts +72 -0
- package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/state.d.ts +24 -0
- package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +33 -36
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +78 -24
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts +5 -0
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +16 -6
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
- package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
- package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/index.d.ts +8 -0
- package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
- package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/session.d.ts +43 -0
- package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +20 -3
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/helpers.d.ts +0 -20
- package/dist/record/helpers.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +6 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +25 -2
- 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 +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +98 -6
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +119 -4
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -5
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/reflection/filter.d.ts +22 -0
- package/dist/reflection/filter.d.ts.map +1 -0
- package/dist/reflection/gpu-table.d.ts +25 -0
- package/dist/reflection/gpu-table.d.ts.map +1 -0
- package/dist/reflection/inspection.d.ts +10 -0
- package/dist/reflection/inspection.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +140 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/reflection/record-owner.d.ts +60 -0
- package/dist/reflection/record-owner.d.ts.map +1 -0
- package/dist/render-contract.d.ts +62 -14
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +49 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +160 -31
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +28 -2
- package/dist/render-system.d.ts.map +1 -1
- package/dist/renderer.d.ts +43 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/scene/probe-blend-record.d.ts +22 -0
- package/dist/scene/probe-blend-record.d.ts.map +1 -0
- package/dist/scene/probe-blend.d.ts +142 -0
- package/dist/scene/probe-blend.d.ts.map +1 -0
- package/dist/scene/render-scene-types.d.ts +0 -6
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +117 -9
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/visibility/bounds.d.ts +20 -0
- package/dist/scene/visibility/bounds.d.ts.map +1 -0
- package/dist/scene/visibility/budget.d.ts +16 -0
- package/dist/scene/visibility/budget.d.ts.map +1 -0
- package/dist/scene/visibility/facet.d.ts +73 -0
- package/dist/scene/visibility/facet.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-lod.d.ts +46 -0
- package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
- package/dist/scene/visibility/inspection.d.ts +132 -0
- package/dist/scene/visibility/inspection.d.ts.map +1 -0
- package/dist/scene/visibility/lod-selector.d.ts +25 -0
- package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
- package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
- package/dist/scene/visibility/types.d.ts +34 -0
- package/dist/scene/visibility/types.d.ts.map +1 -0
- package/dist/shadow-atlas.d.ts +3 -3
- package/dist/shadow-atlas.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +3 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/ssr/admission.d.ts +122 -0
- package/dist/ssr/admission.d.ts.map +1 -0
- package/dist/ssr/composition.d.ts +32 -0
- package/dist/ssr/composition.d.ts.map +1 -0
- package/dist/ssr/errors.d.ts +39 -0
- package/dist/ssr/errors.d.ts.map +1 -0
- package/dist/ssr/identity.d.ts +13 -0
- package/dist/ssr/identity.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts +1 -1
- package/dist/targets/contracts.d.ts +66 -0
- package/dist/targets/contracts.d.ts.map +1 -0
- package/dist/targets/graph-projection.d.ts +29 -0
- package/dist/targets/graph-projection.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +34 -0
- package/dist/targets/material-source.d.ts.map +1 -0
- package/dist/targets/owner.d.ts +32 -0
- package/dist/targets/owner.d.ts.map +1 -0
- package/dist/targets/physical.d.ts +18 -0
- package/dist/targets/physical.d.ts.map +1 -0
- package/dist/targets/readback.d.ts +39 -0
- package/dist/targets/readback.d.ts.map +1 -0
- package/dist/temporal/frame-coordinator.d.ts +13 -0
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/frame.d.ts +2 -0
- package/dist/temporal/frame.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -5
- package/dist/temporal/view.d.ts +7 -0
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/tilemap-chunk-extract-system.d.ts +1 -1
- package/dist/typed-render-graph-primitives.d.ts +5 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-passes.d.ts +1 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +9 -5
- package/dist/volume/passes.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
- package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
- package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
- package/src/__tests__/cluster-binner.unit.test.ts +35 -0
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +12 -2
- package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
- package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
- package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
- package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
- package/src/__tests__/cube-camera.integration.test.ts +42 -0
- package/src/__tests__/detached-inspection.integration.test.ts +6 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +85 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +62 -6
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/environment-generation.integration.test.ts +16 -0
- package/src/__tests__/evidence-identity.ts +13 -0
- package/src/__tests__/evidence-identity.unit.test.ts +24 -0
- package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
- package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
- package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
- package/src/__tests__/factory-contract.integration.test.ts +288 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/frame-observation.contract.test.ts +15 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -8
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +18 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +579 -17
- package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +101 -6
- package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
- package/src/__tests__/gpu-lod-evidence.ts +188 -0
- package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
- package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
- package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
- package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
- package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
- package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
- package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
- package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
- package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
- package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
- package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
- package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
- package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
- package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
- package/src/__tests__/gpu-scene.unit.test.ts +49 -3
- package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
- package/src/__tests__/instances-culling.integration.test.ts +94 -0
- package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
- package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
- package/src/__tests__/light-inspection.unit.test.ts +55 -0
- package/src/__tests__/light-resource-error.unit.test.ts +43 -0
- package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
- package/src/__tests__/lod-bounds.unit.test.ts +42 -0
- package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
- package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
- package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
- package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
- package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
- package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
- package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
- package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
- package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
- package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
- package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
- package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
- package/src/__tests__/lod-selector.profile.test.ts +35 -0
- package/src/__tests__/lod-selector.unit.test.ts +68 -0
- package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
- package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
- package/src/__tests__/ltc-resources.unit.test.ts +32 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
- package/src/__tests__/material-observation.integration.test.ts +101 -0
- package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
- package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
- package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
- package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
- package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
- package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
- package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
- package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
- package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
- package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
- package/src/__tests__/occlusion-query.evidence.ts +178 -0
- package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
- package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
- package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
- package/src/__tests__/probe-bindings.unit.test.ts +200 -0
- package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
- package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
- package/src/__tests__/probe-capacity.integration.test.ts +97 -0
- package/src/__tests__/probe-recovery.integration.test.ts +104 -0
- package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
- package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
- package/src/__tests__/profiler-phase-token.test.ts +1 -0
- package/src/__tests__/public-surface.test-d.ts +10 -0
- package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
- package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
- package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
- package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
- package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
- package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
- package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
- package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
- package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
- package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
- package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
- package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
- package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
- package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
- package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +19 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
- package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
- package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
- package/src/__tests__/render-target-admission.unit.test.ts +80 -0
- package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
- package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
- package/src/__tests__/render-target-material-source.test-d.ts +30 -0
- package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
- package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
- package/src/__tests__/render-target-owner.unit.test.ts +122 -0
- package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
- package/src/__tests__/render-target-public-schema.json +107 -0
- package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
- package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
- package/src/__tests__/render-target-readback.integration.test.ts +90 -0
- package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +124 -0
- package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
- package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
- package/src/__tests__/skin-motion-regression.unit.test.ts +154 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +13 -4
- package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
- package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
- package/src/__tests__/ssr-composition.unit.test.ts +46 -0
- package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
- package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
- package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
- package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +299 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +15 -5
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
- package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
- package/src/__tests__/standard-lighting-write.unit.test.ts +441 -0
- package/src/__tests__/standard-lighting.integration.test.ts +67 -0
- package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
- package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
- package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
- package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -38
- package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
- package/src/__tests__/temporal-view.unit.test.ts +3 -3
- package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
- package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
- package/src/__tests__/visibility-budget.integration.test.ts +140 -0
- package/src/__tests__/visibility-budget.unit.test.ts +70 -0
- package/src/__tests__/visibility-extract.integration.test.ts +11 -6
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
- package/src/assembly/backend-contract.ts +13 -0
- package/src/assembly/device-feature-admission.ts +80 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +1411 -366
- package/src/assembly/host-contract.ts +35 -0
- package/src/assembly/render-target-host.ts +847 -0
- package/src/assets/asset-decoders.ts +1 -1
- package/src/assets/render-asset-port.ts +7 -1
- package/src/capture/cube-views.ts +69 -0
- package/src/capture/scheduler.ts +265 -0
- package/src/cluster-binner.ts +31 -0
- package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
- package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
- package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
- package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
- package/src/components/camera.ts +4 -0
- package/src/components/cube-camera.ts +52 -0
- package/src/components/directional-light.ts +22 -2
- package/src/components/directional-shadow-filter.ts +57 -0
- package/src/components/index.ts +5 -0
- package/src/components/light-helpers.ts +133 -8
- package/src/components/light-probe.ts +13 -0
- package/src/components/rect-area-light.ts +15 -0
- package/src/components/reflection-probe.ts +49 -0
- package/src/components/scene-instance.ts +6 -0
- package/src/components/spot-light.ts +3 -0
- package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
- package/src/device/gpu-residency.ts +140 -9
- package/src/device/lifecycle-transaction.ts +12 -0
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +20 -1
- package/src/errors/gpu-driven.ts +92 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/recover.ts +32 -0
- package/src/errors/render.ts +341 -143
- package/src/extract/camera.ts +3 -3
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/gpu-driven.ts +108 -0
- package/src/extract/visibility.ts +2 -1
- package/src/features/fullscreen.ts +3 -0
- package/src/features/targets.ts +4 -1
- package/src/features/types.ts +10 -0
- package/src/fullscreen-post-process-pass.ts +43 -2
- package/src/gpu-driven/batch-topology.ts +207 -28
- package/src/gpu-driven/prepared-draw.ts +208 -0
- package/src/gpu-driven/production-raster.ts +953 -43
- package/src/gpu-driven/view-gpu.ts +411 -29
- package/src/gpu-scene-schema.ts +13 -0
- package/src/gpu-scene.ts +140 -64
- package/src/gpu-usage.ts +0 -1
- package/src/hdrp-buffers.ts +169 -63
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +222 -0
- package/src/inspection-types.ts +276 -1
- package/src/instances-derived-bounds.ts +171 -0
- package/src/internal.ts +38 -0
- package/src/light-buffer-layout.ts +155 -310
- package/src/materials.ts +16 -2
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +255 -60
- package/src/pipeline/standard-forward-lane.ts +93 -16
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +158 -0
- package/src/pipeline/standard-lighting/inspection.ts +88 -0
- package/src/pipeline/standard-lighting/layout.ts +31 -0
- package/src/pipeline/standard-lighting/light-frame.ts +35 -0
- package/src/pipeline/standard-lighting/membership.ts +43 -0
- package/src/pipeline/standard-lighting/prepare.ts +37 -0
- package/src/pipeline/standard-lighting/topology.ts +120 -0
- package/src/pipeline/standard-lighting/transport.ts +78 -0
- package/src/pipeline/standard-pipeline.ts +124 -193
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +17 -47
- package/src/pipeline-builder.ts +5 -2
- package/src/pipeline-spec.ts +95 -21
- package/src/plugin.ts +4 -0
- package/src/point-shadow-inspection.ts +55 -0
- package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
- package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
- package/src/prepare/extended-lighting/resources.ts +389 -0
- package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
- package/src/prepare/extended-lighting/state.ts +92 -0
- package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +64 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +591 -452
- package/src/record/frame-snapshot.ts +92 -39
- package/src/record/frame-targets.ts +17 -0
- package/src/record/frame.ts +662 -158
- package/src/record/gpu-pass-timing/contract.ts +180 -0
- package/src/record/gpu-pass-timing/errors.ts +34 -0
- package/src/record/gpu-pass-timing/index.ts +37 -0
- package/src/record/gpu-pass-timing/parser.ts +97 -0
- package/src/record/gpu-pass-timing/session.ts +938 -0
- package/src/record/gpu-timing.ts +112 -39
- package/src/record/helpers.ts +0 -58
- package/src/record/main-pass-geometry.ts +324 -119
- package/src/record/main-pass-material.ts +103 -10
- package/src/record/main-pass-sprite-draws.ts +99 -103
- package/src/record/main-pass.ts +71 -15
- package/src/record/mesh-ssbo.ts +47 -36
- package/src/record/render-context.ts +136 -3
- package/src/record/shadow-pass.ts +83 -68
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +1034 -43
- package/src/record/view-ubo.ts +72 -47
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/inspection.ts +67 -0
- package/src/reflection/projection.ts +476 -0
- package/src/reflection/record-owner.ts +1283 -0
- package/src/render-contract.ts +93 -10
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +122 -2
- package/src/render-system-extract.ts +1041 -225
- package/src/render-system.ts +1310 -85
- package/src/renderer.ts +222 -0
- package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
- package/src/scene/probe-blend-record.ts +54 -0
- package/src/scene/probe-blend.ts +813 -0
- package/src/scene/render-scene-types.ts +0 -7
- package/src/scene/render-scene.ts +942 -171
- package/src/scene/visibility/bounds.ts +57 -0
- package/src/scene/visibility/budget.ts +40 -0
- package/src/scene/visibility/facet.ts +400 -0
- package/src/scene/visibility/gpu-frame-timing.ts +101 -0
- package/src/scene/visibility/gpu-lod.ts +119 -0
- package/src/scene/visibility/inspection.ts +313 -0
- package/src/scene/visibility/lod-selector.ts +84 -0
- package/src/scene/visibility/occlusion-confidence.ts +478 -0
- package/src/scene/visibility/occlusion-pass.ts +165 -0
- package/src/scene/visibility/occlusion-query-pool.ts +178 -0
- package/src/scene/visibility/occlusion-runtime.ts +672 -0
- package/src/scene/visibility/types.ts +50 -0
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- package/src/ssr/admission.ts +451 -0
- package/src/ssr/composition.ts +73 -0
- package/src/ssr/errors.ts +76 -0
- package/src/ssr/identity.ts +12 -0
- package/src/systems/skin-palette-allocator.ts +1 -1
- package/src/targets/contracts.ts +182 -0
- package/src/targets/graph-projection.ts +169 -0
- package/src/targets/material-source.ts +143 -0
- package/src/targets/owner.ts +214 -0
- package/src/targets/physical.ts +18 -0
- package/src/targets/readback.ts +153 -0
- package/src/temporal/frame-coordinator.ts +26 -0
- package/src/temporal/frame.ts +14 -1
- package/src/temporal/view.ts +11 -0
- package/src/tilemap-chunk-extract-system.ts +4 -4
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
- package/src/typed-render-graph-primitives.ts +53 -3
- package/src/typed-shadow-passes.ts +46 -40
- package/src/volume/passes.ts +61 -58
- package/dist/.tsbuildinfo +0 -1
- package/dist/chunk-4XINDLAY.mjs.map +0 -1
- package/dist/chunk-CDTWTHZR.mjs.map +0 -1
- package/dist/chunk-M2MP4ZOU.mjs +0 -73
- package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
- package/dist/chunk-PCHBPYML.mjs.map +0 -1
- package/dist/chunk-TBQJOK2L.mjs.map +0 -1
- package/dist/chunk-VFPLTKCU.mjs.map +0 -1
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import type { Buffer, Result, RhiDevice, Sampler, Texture } from '@forgeax/engine-rhi';
|
|
2
|
+
import { RhiError } from '@forgeax/engine-rhi';
|
|
3
|
+
import { err, ok } from '@forgeax/engine-types';
|
|
4
|
+
import type { DeviceScope } from '../../device/device-scope';
|
|
5
|
+
import { LifecycleTransaction } from '../../device/lifecycle-transaction';
|
|
6
|
+
import {
|
|
7
|
+
GPU_TEXTURE_USAGE_COPY_DST,
|
|
8
|
+
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
9
|
+
} from '../../gpu-texture-usage';
|
|
10
|
+
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../../gpu-usage';
|
|
11
|
+
|
|
12
|
+
export const EXTENDED_LIGHTING_TOPOLOGY = 'extendedLighting' as const;
|
|
13
|
+
export const IES_SLICE_CAPACITY = 32;
|
|
14
|
+
export const COOKIE_SLICE_CAPACITY = 32;
|
|
15
|
+
export const PROBE_RECORD_CAPACITY = 64;
|
|
16
|
+
export const IES_SLICE_WIDTH = 256;
|
|
17
|
+
export const IES_SLICE_HEIGHT = 128;
|
|
18
|
+
export const COOKIE_SLICE_SIZE = 256;
|
|
19
|
+
export const COOKIE_MATRIX_BYTES = 32 * 16 * Float32Array.BYTES_PER_ELEMENT;
|
|
20
|
+
/**
|
|
21
|
+
* Minimum per-stage sampled-texture limit for the shared PBR + extended-
|
|
22
|
+
* lighting pipeline-layout topology. The current BGL closure reserves 18
|
|
23
|
+
* sampled textures for the URP path and 20 for the HDRP/Probe path after the
|
|
24
|
+
* material IBL and transmission injections; WebGPU validates this pipeline-
|
|
25
|
+
* layout count even when a compiled shader variant does not read every
|
|
26
|
+
* optional entry.
|
|
27
|
+
*/
|
|
28
|
+
export const EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES = 20;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Keep shader-variant selection and resource admission on one capability fact.
|
|
32
|
+
* An omitted limit is treated as unavailable: a caller must not claim the
|
|
33
|
+
* extended topology without a numeric device limit proving it fits.
|
|
34
|
+
*/
|
|
35
|
+
export function extendedLightingSampledTextureCapacityAvailable(
|
|
36
|
+
maxSampledTexturesPerShaderStage: number | undefined,
|
|
37
|
+
): boolean {
|
|
38
|
+
return (
|
|
39
|
+
maxSampledTexturesPerShaderStage !== undefined &&
|
|
40
|
+
maxSampledTexturesPerShaderStage >= EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ExtendedLightingCapabilityResult {
|
|
45
|
+
readonly admitted: boolean;
|
|
46
|
+
readonly topology: typeof EXTENDED_LIGHTING_TOPOLOGY;
|
|
47
|
+
readonly reason: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ExtendedLightingResourceInput {
|
|
51
|
+
readonly device: RhiDevice | undefined;
|
|
52
|
+
readonly scope: DeviceScope;
|
|
53
|
+
readonly iesSliceCount: number;
|
|
54
|
+
readonly cookieSliceCount: number;
|
|
55
|
+
readonly cookieMatrices: number;
|
|
56
|
+
readonly iesData?: Uint8Array | undefined;
|
|
57
|
+
readonly cookieData?: Uint8Array | undefined;
|
|
58
|
+
readonly cookieMatrixData?: Float32Array | undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ExtendedLightingResourceCandidate {
|
|
62
|
+
readonly topology: typeof EXTENDED_LIGHTING_TOPOLOGY;
|
|
63
|
+
readonly generation: number;
|
|
64
|
+
readonly scope: DeviceScope;
|
|
65
|
+
readonly iesSliceCount: number;
|
|
66
|
+
readonly cookieSliceCount: number;
|
|
67
|
+
readonly cookieMatrices: number;
|
|
68
|
+
readonly sampler: Sampler;
|
|
69
|
+
readonly iesTexture: Texture | undefined;
|
|
70
|
+
readonly cookieTexture: Texture | undefined;
|
|
71
|
+
readonly cookieMatrixBuffer: Buffer | undefined;
|
|
72
|
+
readonly descriptorBytes: number;
|
|
73
|
+
readonly uploadCount: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ExtendedLightingResourceInspection {
|
|
77
|
+
readonly topology: typeof EXTENDED_LIGHTING_TOPOLOGY;
|
|
78
|
+
readonly generation: number;
|
|
79
|
+
readonly status: 'empty' | 'candidate' | 'accepted';
|
|
80
|
+
readonly accepted: boolean;
|
|
81
|
+
readonly resourceCount: number;
|
|
82
|
+
readonly descriptorBytes: number;
|
|
83
|
+
readonly uploadCount: number;
|
|
84
|
+
readonly blendInvalidations: number;
|
|
85
|
+
readonly passCount: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function failure(expected: string, actual: string): Result<never, RhiError> {
|
|
89
|
+
return err(
|
|
90
|
+
new RhiError({
|
|
91
|
+
code: 'webgpu-runtime-error',
|
|
92
|
+
expected,
|
|
93
|
+
hint: 'repair the extended lighting resource facts and retry the candidate generation',
|
|
94
|
+
detail: { error: { code: 'extended-lighting-resource', message: actual } },
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function validCount(value: number, capacity: number): boolean {
|
|
100
|
+
return Number.isSafeInteger(value) && value >= 0 && value <= capacity;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Derive admission from the RHI facts; no backend-kind policy is involved. */
|
|
104
|
+
export function deriveExtendedLightingCapability(
|
|
105
|
+
device: Pick<RhiDevice, 'caps' | 'limits'>,
|
|
106
|
+
): ExtendedLightingCapabilityResult {
|
|
107
|
+
const maxSampledTextures = device.limits.maxSampledTexturesPerShaderStage;
|
|
108
|
+
if (!extendedLightingSampledTextureCapacityAvailable(maxSampledTextures)) {
|
|
109
|
+
return {
|
|
110
|
+
admitted: false,
|
|
111
|
+
topology: EXTENDED_LIGHTING_TOPOLOGY,
|
|
112
|
+
reason: `maxSampledTexturesPerShaderStage ${maxSampledTextures ?? 0} < ${EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES}`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const maxLayers = device.limits.maxTextureArrayLayers ?? 0;
|
|
116
|
+
const maxUniformBuffers = device.limits.maxUniformBuffersPerShaderStage ?? 0;
|
|
117
|
+
if (maxLayers < IES_SLICE_CAPACITY) {
|
|
118
|
+
return {
|
|
119
|
+
admitted: false,
|
|
120
|
+
topology: EXTENDED_LIGHTING_TOPOLOGY,
|
|
121
|
+
reason: `maxTextureArrayLayers ${maxLayers} < ${IES_SLICE_CAPACITY}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (maxUniformBuffers < 1) {
|
|
125
|
+
return {
|
|
126
|
+
admitted: false,
|
|
127
|
+
topology: EXTENDED_LIGHTING_TOPOLOGY,
|
|
128
|
+
reason: `maxUniformBuffersPerShaderStage ${maxUniformBuffers} < 1`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (
|
|
132
|
+
!device.caps.storageBuffer ||
|
|
133
|
+
!device.caps.rgba16floatRenderable ||
|
|
134
|
+
!device.caps.samplerAliasing
|
|
135
|
+
) {
|
|
136
|
+
return {
|
|
137
|
+
admitted: false,
|
|
138
|
+
topology: EXTENDED_LIGHTING_TOPOLOGY,
|
|
139
|
+
reason: 'required storage-buffer, rgba16float, or sampler capability is unavailable',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return { admitted: true, topology: EXTENDED_LIGHTING_TOPOLOGY, reason: undefined };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function createTexture(
|
|
146
|
+
device: RhiDevice,
|
|
147
|
+
label: string,
|
|
148
|
+
format: 'r16float' | 'rgba8unorm',
|
|
149
|
+
width: number,
|
|
150
|
+
height: number,
|
|
151
|
+
layers: number,
|
|
152
|
+
): Result<Texture, RhiError> {
|
|
153
|
+
return device.createTexture({
|
|
154
|
+
label,
|
|
155
|
+
size: { width, height, depthOrArrayLayers: layers },
|
|
156
|
+
mipLevelCount: 1,
|
|
157
|
+
sampleCount: 1,
|
|
158
|
+
dimension: '2d',
|
|
159
|
+
format,
|
|
160
|
+
usage: GPU_TEXTURE_USAGE_COPY_DST | GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
161
|
+
viewFormats: [],
|
|
162
|
+
textureBindingViewDimension: undefined,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function requireResource<T>(result: Result<T, RhiError>): T {
|
|
167
|
+
if (!result.ok) throw result.error;
|
|
168
|
+
return result.value;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function writeTextureSlices(
|
|
172
|
+
device: RhiDevice,
|
|
173
|
+
texture: Texture,
|
|
174
|
+
data: Uint8Array | undefined,
|
|
175
|
+
bytesPerRow: number,
|
|
176
|
+
height: number,
|
|
177
|
+
layerCount: number,
|
|
178
|
+
width: number,
|
|
179
|
+
): number {
|
|
180
|
+
if (data === undefined || layerCount === 0) return 0;
|
|
181
|
+
const bytesPerSlice = bytesPerRow * height;
|
|
182
|
+
const requiredBytes = bytesPerSlice * layerCount;
|
|
183
|
+
if (data.byteLength < requiredBytes) {
|
|
184
|
+
throw new Error(`extended lighting texture upload requires ${requiredBytes} bytes`);
|
|
185
|
+
}
|
|
186
|
+
for (let layer = 0; layer < layerCount; layer += 1) {
|
|
187
|
+
const start = layer * bytesPerSlice;
|
|
188
|
+
requireResource(
|
|
189
|
+
device.queue.writeTexture(
|
|
190
|
+
{ texture, mipLevel: 0, origin: { x: 0, y: 0, z: layer } },
|
|
191
|
+
data.subarray(start, start + bytesPerSlice),
|
|
192
|
+
{ offset: 0, bytesPerRow, rowsPerImage: height },
|
|
193
|
+
{ width, height, depthOrArrayLayers: 1 },
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return layerCount;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Build a complete candidate; nothing is adopted until the transaction commits. */
|
|
201
|
+
export async function createExtendedLightingResourceCandidate(
|
|
202
|
+
input: ExtendedLightingResourceInput,
|
|
203
|
+
): Promise<Result<ExtendedLightingResourceCandidate, RhiError>> {
|
|
204
|
+
const { device, scope } = input;
|
|
205
|
+
if (device === undefined) return failure('a live RHI device is required', 'device is undefined');
|
|
206
|
+
if (!validCount(input.iesSliceCount, IES_SLICE_CAPACITY)) {
|
|
207
|
+
return failure(`IES slice count <= ${IES_SLICE_CAPACITY}`, String(input.iesSliceCount));
|
|
208
|
+
}
|
|
209
|
+
if (!validCount(input.cookieSliceCount, COOKIE_SLICE_CAPACITY)) {
|
|
210
|
+
return failure(
|
|
211
|
+
`Cookie slice count <= ${COOKIE_SLICE_CAPACITY}`,
|
|
212
|
+
String(input.cookieSliceCount),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
if (!validCount(input.cookieMatrices, COOKIE_SLICE_CAPACITY)) {
|
|
216
|
+
return failure(`Cookie matrix count <= ${COOKIE_SLICE_CAPACITY}`, String(input.cookieMatrices));
|
|
217
|
+
}
|
|
218
|
+
const capability = deriveExtendedLightingCapability(device);
|
|
219
|
+
if (!capability.admitted)
|
|
220
|
+
return failure('extendedLighting capability admission', capability.reason ?? 'unavailable');
|
|
221
|
+
if (
|
|
222
|
+
input.cookieMatrixData !== undefined &&
|
|
223
|
+
input.cookieMatrixData.byteLength < input.cookieMatrices * 16 * Float32Array.BYTES_PER_ELEMENT
|
|
224
|
+
) {
|
|
225
|
+
return failure(
|
|
226
|
+
'cookie matrix upload payload',
|
|
227
|
+
`requires ${input.cookieMatrices * 16 * Float32Array.BYTES_PER_ELEMENT} bytes`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const transaction = new LifecycleTransaction(scope);
|
|
232
|
+
let iesTexture: Texture | undefined;
|
|
233
|
+
let cookieTexture: Texture | undefined;
|
|
234
|
+
let cookieMatrixBuffer: Buffer | undefined;
|
|
235
|
+
let sampler: Sampler | undefined;
|
|
236
|
+
let uploadCount = 0;
|
|
237
|
+
transaction.add({
|
|
238
|
+
kind: 'texture',
|
|
239
|
+
create: () => {
|
|
240
|
+
const created = requireResource(
|
|
241
|
+
createTexture(
|
|
242
|
+
device,
|
|
243
|
+
'extended-lighting-ies',
|
|
244
|
+
'r16float',
|
|
245
|
+
IES_SLICE_WIDTH,
|
|
246
|
+
IES_SLICE_HEIGHT,
|
|
247
|
+
IES_SLICE_CAPACITY,
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
uploadCount += writeTextureSlices(
|
|
251
|
+
device,
|
|
252
|
+
created,
|
|
253
|
+
input.iesData,
|
|
254
|
+
IES_SLICE_WIDTH * 2,
|
|
255
|
+
IES_SLICE_HEIGHT,
|
|
256
|
+
input.iesSliceCount,
|
|
257
|
+
IES_SLICE_WIDTH,
|
|
258
|
+
);
|
|
259
|
+
iesTexture = created;
|
|
260
|
+
return created;
|
|
261
|
+
},
|
|
262
|
+
cleanup: (value) => {
|
|
263
|
+
const destroyed = device.destroyTexture(value);
|
|
264
|
+
if (!destroyed.ok) throw destroyed.error;
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
transaction.add({
|
|
268
|
+
kind: 'texture',
|
|
269
|
+
create: () => {
|
|
270
|
+
const created = requireResource(
|
|
271
|
+
createTexture(
|
|
272
|
+
device,
|
|
273
|
+
'extended-lighting-cookie',
|
|
274
|
+
'rgba8unorm',
|
|
275
|
+
COOKIE_SLICE_SIZE,
|
|
276
|
+
COOKIE_SLICE_SIZE,
|
|
277
|
+
COOKIE_SLICE_CAPACITY,
|
|
278
|
+
),
|
|
279
|
+
);
|
|
280
|
+
uploadCount += writeTextureSlices(
|
|
281
|
+
device,
|
|
282
|
+
created,
|
|
283
|
+
input.cookieData,
|
|
284
|
+
COOKIE_SLICE_SIZE * 4,
|
|
285
|
+
COOKIE_SLICE_SIZE,
|
|
286
|
+
input.cookieSliceCount,
|
|
287
|
+
COOKIE_SLICE_SIZE,
|
|
288
|
+
);
|
|
289
|
+
cookieTexture = created;
|
|
290
|
+
return created;
|
|
291
|
+
},
|
|
292
|
+
cleanup: (value) => {
|
|
293
|
+
const destroyed = device.destroyTexture(value);
|
|
294
|
+
if (!destroyed.ok) throw destroyed.error;
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
transaction.add({
|
|
298
|
+
kind: 'buffer',
|
|
299
|
+
create: () => {
|
|
300
|
+
const created = requireResource(
|
|
301
|
+
device.createBuffer({
|
|
302
|
+
label: 'extended-lighting-cookie-matrices',
|
|
303
|
+
size: COOKIE_MATRIX_BYTES,
|
|
304
|
+
usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_UNIFORM,
|
|
305
|
+
mappedAtCreation: false,
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
if (input.cookieMatrixData !== undefined && input.cookieMatrices > 0) {
|
|
309
|
+
requireResource(device.queue.writeBuffer(created, 0, input.cookieMatrixData));
|
|
310
|
+
uploadCount += 1;
|
|
311
|
+
}
|
|
312
|
+
cookieMatrixBuffer = created;
|
|
313
|
+
return created;
|
|
314
|
+
},
|
|
315
|
+
cleanup: (value) => {
|
|
316
|
+
const destroyed = device.destroyBuffer(value);
|
|
317
|
+
if (!destroyed.ok) throw destroyed.error;
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
transaction.add({
|
|
321
|
+
// Samplers are bindable GPU resources, not host listeners. Keeping the
|
|
322
|
+
// lifecycle kind aligned with the resource's actual renderer role makes
|
|
323
|
+
// scope inspection and rollback receipts truthful.
|
|
324
|
+
kind: 'binding',
|
|
325
|
+
create: () => {
|
|
326
|
+
const created = requireResource(
|
|
327
|
+
device.createSampler({
|
|
328
|
+
label: 'extended-lighting-clamp-linear',
|
|
329
|
+
addressModeU: 'clamp-to-edge',
|
|
330
|
+
addressModeV: 'clamp-to-edge',
|
|
331
|
+
addressModeW: 'clamp-to-edge',
|
|
332
|
+
magFilter: 'linear',
|
|
333
|
+
minFilter: 'linear',
|
|
334
|
+
mipmapFilter: 'nearest',
|
|
335
|
+
}),
|
|
336
|
+
);
|
|
337
|
+
sampler = created;
|
|
338
|
+
return created;
|
|
339
|
+
},
|
|
340
|
+
cleanup: () => undefined,
|
|
341
|
+
});
|
|
342
|
+
const committed = await transaction.commit();
|
|
343
|
+
if (!committed.ok)
|
|
344
|
+
return failure(committed.error.primary.expected, committed.error.primary.message);
|
|
345
|
+
if (
|
|
346
|
+
iesTexture === undefined ||
|
|
347
|
+
cookieTexture === undefined ||
|
|
348
|
+
cookieMatrixBuffer === undefined ||
|
|
349
|
+
sampler === undefined
|
|
350
|
+
) {
|
|
351
|
+
return failure(
|
|
352
|
+
'complete extendedLighting candidate resources',
|
|
353
|
+
'resource transaction returned an incomplete set',
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
return ok({
|
|
357
|
+
topology: EXTENDED_LIGHTING_TOPOLOGY,
|
|
358
|
+
generation: scope.generation,
|
|
359
|
+
scope,
|
|
360
|
+
iesSliceCount: input.iesSliceCount,
|
|
361
|
+
cookieSliceCount: input.cookieSliceCount,
|
|
362
|
+
cookieMatrices: input.cookieMatrices,
|
|
363
|
+
sampler,
|
|
364
|
+
iesTexture,
|
|
365
|
+
cookieTexture,
|
|
366
|
+
cookieMatrixBuffer,
|
|
367
|
+
descriptorBytes:
|
|
368
|
+
IES_SLICE_WIDTH * IES_SLICE_HEIGHT * 2 * IES_SLICE_CAPACITY +
|
|
369
|
+
COOKIE_SLICE_SIZE * COOKIE_SLICE_SIZE * 4 * COOKIE_SLICE_CAPACITY +
|
|
370
|
+
COOKIE_MATRIX_BYTES,
|
|
371
|
+
uploadCount,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function inspectExtendedLightingResources(
|
|
376
|
+
scope: DeviceScope,
|
|
377
|
+
): ExtendedLightingResourceInspection {
|
|
378
|
+
return {
|
|
379
|
+
topology: EXTENDED_LIGHTING_TOPOLOGY,
|
|
380
|
+
generation: scope.generation,
|
|
381
|
+
status: 'empty',
|
|
382
|
+
accepted: false,
|
|
383
|
+
resourceCount: 0,
|
|
384
|
+
descriptorBytes: 0,
|
|
385
|
+
uploadCount: 0,
|
|
386
|
+
blendInvalidations: 0,
|
|
387
|
+
passCount: 0,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { TextureAsset } from '@forgeax/engine-types';
|
|
2
|
+
import { COOKIE_SLICE_SIZE } from './resources';
|
|
3
|
+
|
|
4
|
+
export interface SpotModifierFactors {
|
|
5
|
+
readonly brdf: number;
|
|
6
|
+
readonly range: number;
|
|
7
|
+
readonly cone: number;
|
|
8
|
+
readonly ies?: number | undefined;
|
|
9
|
+
readonly cookie?: number | undefined;
|
|
10
|
+
readonly shadow: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface IesCoordinates {
|
|
14
|
+
readonly azimuth: number;
|
|
15
|
+
readonly elevation: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CookieUv {
|
|
19
|
+
readonly u: number;
|
|
20
|
+
readonly v: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The fixed GPU representation consumed by the extended-lighting Cookie
|
|
25
|
+
* array. The matrix is deliberately keyed by Cookie slice rather than by
|
|
26
|
+
* light: it carries only the source texture aspect correction. The shader
|
|
27
|
+
* still owns the light-local basis, roll, and outer-cone projection, so one
|
|
28
|
+
* Cookie can be shared by Spots with different directions or cone angles.
|
|
29
|
+
*/
|
|
30
|
+
export interface CookieProjection {
|
|
31
|
+
readonly data: Uint8Array;
|
|
32
|
+
readonly matrix: Float32Array;
|
|
33
|
+
readonly aspect: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DEG_TO_RAD = Math.PI / 180;
|
|
37
|
+
|
|
38
|
+
const COOKIE_PROJECTION_CACHE = new WeakMap<TextureAsset, CookieProjection | null>();
|
|
39
|
+
|
|
40
|
+
function srgbToLinear(value: number): number {
|
|
41
|
+
return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function clamp01(value: number): number {
|
|
45
|
+
return Math.min(1, Math.max(0, value));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function sourceChannel(asset: TextureAsset, x: number, y: number, channel: number): number {
|
|
49
|
+
const offset = (y * asset.shape.extent.width + x) * 4 + channel;
|
|
50
|
+
const encoded = (asset.data[offset] ?? 0) / 255;
|
|
51
|
+
return channel < 3 && asset.colorSpace === 'srgb' ? srgbToLinear(encoded) : encoded;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sampleSourceChannel(asset: TextureAsset, x: number, y: number, channel: number): number {
|
|
55
|
+
const sourceX = clamp01((x + 0.5) / COOKIE_SLICE_SIZE) * (asset.shape.extent.width - 1);
|
|
56
|
+
const sourceY = clamp01((y + 0.5) / COOKIE_SLICE_SIZE) * (asset.shape.extent.height - 1);
|
|
57
|
+
const x0 = Math.floor(sourceX);
|
|
58
|
+
const y0 = Math.floor(sourceY);
|
|
59
|
+
const x1 = Math.min(asset.shape.extent.width - 1, x0 + 1);
|
|
60
|
+
const y1 = Math.min(asset.shape.extent.height - 1, y0 + 1);
|
|
61
|
+
const tx = sourceX - x0;
|
|
62
|
+
const ty = sourceY - y0;
|
|
63
|
+
const top =
|
|
64
|
+
sourceChannel(asset, x0, y0, channel) * (1 - tx) + sourceChannel(asset, x1, y0, channel) * tx;
|
|
65
|
+
const bottom =
|
|
66
|
+
sourceChannel(asset, x0, y1, channel) * (1 - tx) + sourceChannel(asset, x1, y1, channel) * tx;
|
|
67
|
+
return top * (1 - ty) + bottom * ty;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Project a filterable 2D RGBA Cookie into the renderer's fixed linear
|
|
72
|
+
* 256x256 array slice. This is a producer-boundary operation and is cached by
|
|
73
|
+
* the immutable TextureAsset object, so the frame path never decodes or
|
|
74
|
+
* resamples the source repeatedly.
|
|
75
|
+
*/
|
|
76
|
+
export function prepareCookieProjection(asset: TextureAsset): CookieProjection | undefined {
|
|
77
|
+
if (COOKIE_PROJECTION_CACHE.has(asset)) {
|
|
78
|
+
return COOKIE_PROJECTION_CACHE.get(asset) ?? undefined;
|
|
79
|
+
}
|
|
80
|
+
const supportedFormat = asset.format === 'rgba8unorm' || asset.format === 'rgba8unorm-srgb';
|
|
81
|
+
const validDimensions =
|
|
82
|
+
Number.isSafeInteger(asset.shape.extent.width) &&
|
|
83
|
+
Number.isSafeInteger(asset.shape.extent.height) &&
|
|
84
|
+
asset.shape.extent.width > 0 &&
|
|
85
|
+
asset.shape.extent.height > 0;
|
|
86
|
+
const validFormatPair =
|
|
87
|
+
(asset.format === 'rgba8unorm-srgb' && asset.colorSpace === 'srgb') ||
|
|
88
|
+
(asset.format === 'rgba8unorm' && asset.colorSpace === 'linear');
|
|
89
|
+
const validPayload =
|
|
90
|
+
asset.data.byteLength >= asset.shape.extent.width * asset.shape.extent.height * 4;
|
|
91
|
+
if (!supportedFormat || !validDimensions || !validFormatPair || !validPayload) {
|
|
92
|
+
COOKIE_PROJECTION_CACHE.set(asset, null);
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const data = new Uint8Array(COOKIE_SLICE_SIZE * COOKIE_SLICE_SIZE * 4);
|
|
97
|
+
for (let y = 0; y < COOKIE_SLICE_SIZE; y += 1) {
|
|
98
|
+
for (let x = 0; x < COOKIE_SLICE_SIZE; x += 1) {
|
|
99
|
+
const target = (y * COOKIE_SLICE_SIZE + x) * 4;
|
|
100
|
+
data[target] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 0)) * 255);
|
|
101
|
+
data[target + 1] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 1)) * 255);
|
|
102
|
+
data[target + 2] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 2)) * 255);
|
|
103
|
+
// Alpha stays linear and is intentionally preserved: the shader
|
|
104
|
+
// multiplies sampled RGB by this lane as part of Cookie semantics.
|
|
105
|
+
data[target + 3] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 3)) * 255);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Column-major mat4. The shader multiplies the unprojected local
|
|
110
|
+
// (x/depth, y/depth) pair by this aspect-only matrix, then applies the
|
|
111
|
+
// Spot's outer-cone tangent and the [0,1] translation. Keeping outerCone
|
|
112
|
+
// out of this slice-keyed matrix allows one Cookie to be shared by lights.
|
|
113
|
+
const matrix = new Float32Array(16);
|
|
114
|
+
matrix[0] = asset.shape.extent.height / asset.shape.extent.width;
|
|
115
|
+
matrix[5] = 1;
|
|
116
|
+
matrix[10] = 1;
|
|
117
|
+
matrix[15] = 1;
|
|
118
|
+
const projection = {
|
|
119
|
+
data,
|
|
120
|
+
matrix,
|
|
121
|
+
aspect: asset.shape.extent.width / asset.shape.extent.height,
|
|
122
|
+
};
|
|
123
|
+
COOKIE_PROJECTION_CACHE.set(asset, projection);
|
|
124
|
+
return projection;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Create the deterministic identity payload used for unused Cookie slices. */
|
|
128
|
+
export function createCookieProjectionMatrixData(count: number): Float32Array {
|
|
129
|
+
const data = new Float32Array(count * 16);
|
|
130
|
+
for (let index = 0; index < count; index += 1) {
|
|
131
|
+
const base = index * 16;
|
|
132
|
+
data[base] = 1;
|
|
133
|
+
data[base + 5] = 1;
|
|
134
|
+
data[base + 10] = 1;
|
|
135
|
+
data[base + 15] = 1;
|
|
136
|
+
}
|
|
137
|
+
return data;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function normalized(vector: ArrayLike<number>): [number, number, number] | undefined {
|
|
141
|
+
const x = vector[0] ?? 0;
|
|
142
|
+
const y = vector[1] ?? 0;
|
|
143
|
+
const z = vector[2] ?? 0;
|
|
144
|
+
const length = Math.hypot(x, y, z);
|
|
145
|
+
return length > 0 && Number.isFinite(length) ? [x / length, y / length, z / length] : undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function spotModifierProduct(factors: SpotModifierFactors): number {
|
|
149
|
+
return (
|
|
150
|
+
factors.brdf *
|
|
151
|
+
factors.range *
|
|
152
|
+
factors.cone *
|
|
153
|
+
(factors.ies ?? 1) *
|
|
154
|
+
(factors.cookie ?? 1) *
|
|
155
|
+
factors.shadow
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function projectIesCoordinates(
|
|
160
|
+
toPoint: ArrayLike<number>,
|
|
161
|
+
rollDeg: number,
|
|
162
|
+
): IesCoordinates | undefined {
|
|
163
|
+
const direction = normalized(toPoint);
|
|
164
|
+
if (direction === undefined || direction[2] >= 0) return undefined;
|
|
165
|
+
const roll = rollDeg * DEG_TO_RAD;
|
|
166
|
+
const rolledX = direction[0] * Math.cos(roll) - direction[1] * Math.sin(roll);
|
|
167
|
+
const rolledY = direction[0] * Math.sin(roll) + direction[1] * Math.cos(roll);
|
|
168
|
+
return {
|
|
169
|
+
azimuth: (Math.atan2(rolledY, rolledX) + Math.PI * 2) % (Math.PI * 2),
|
|
170
|
+
elevation: Math.acos(Math.min(1, Math.max(-1, -direction[2]))) / Math.PI,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function projectCookieUv(
|
|
175
|
+
toPoint: ArrayLike<number>,
|
|
176
|
+
rollDeg: number,
|
|
177
|
+
aspect: number,
|
|
178
|
+
outerConeDeg = 45,
|
|
179
|
+
): CookieUv | undefined {
|
|
180
|
+
const direction = normalized(toPoint);
|
|
181
|
+
if (direction === undefined || direction[2] >= 0 || !Number.isFinite(aspect) || aspect <= 0)
|
|
182
|
+
return undefined;
|
|
183
|
+
const cone = Math.atan2(Math.hypot(direction[0], direction[1]), -direction[2]);
|
|
184
|
+
const outerCone = outerConeDeg * DEG_TO_RAD;
|
|
185
|
+
if (cone > outerCone) return undefined;
|
|
186
|
+
const roll = rollDeg * DEG_TO_RAD;
|
|
187
|
+
const x = direction[0] * Math.cos(roll) - direction[1] * Math.sin(roll);
|
|
188
|
+
const y = direction[0] * Math.sin(roll) + direction[1] * Math.cos(roll);
|
|
189
|
+
const scale = Math.tan(outerCone);
|
|
190
|
+
return {
|
|
191
|
+
u: 0.5 + (x / -direction[2] / scale / aspect) * 0.5,
|
|
192
|
+
v: 0.5 + (y / -direction[2] / scale) * 0.5,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { LightResourceUnavailableError } from '../../errors/render';
|
|
2
|
+
import {
|
|
3
|
+
type LightInspection,
|
|
4
|
+
lightInspectionIdentity,
|
|
5
|
+
projectLightInspection,
|
|
6
|
+
} from '../../inspection-types';
|
|
7
|
+
import type { ExtendedLightingResourceCandidate } from './resources';
|
|
8
|
+
|
|
9
|
+
export type ExtendedLightingResourceStatus = 'empty' | 'candidate' | 'accepted';
|
|
10
|
+
|
|
11
|
+
export interface ExtendedLightingState {
|
|
12
|
+
readonly enabled: boolean;
|
|
13
|
+
readonly generation: number;
|
|
14
|
+
readonly status: ExtendedLightingResourceStatus;
|
|
15
|
+
readonly candidate: ExtendedLightingResourceCandidate | undefined;
|
|
16
|
+
readonly accepted: ExtendedLightingResourceCandidate | undefined;
|
|
17
|
+
readonly lastKnownGood: ExtendedLightingResourceCandidate | undefined;
|
|
18
|
+
readonly resourceCount: number;
|
|
19
|
+
readonly descriptorBytes: number;
|
|
20
|
+
readonly uploadCount: number;
|
|
21
|
+
readonly passCount: number;
|
|
22
|
+
readonly bindGroupCount: number;
|
|
23
|
+
readonly failure: LightResourceUnavailableError | undefined;
|
|
24
|
+
readonly failureKeys: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createExtendedLightingState(generation: number): ExtendedLightingState {
|
|
28
|
+
return {
|
|
29
|
+
enabled: false,
|
|
30
|
+
generation,
|
|
31
|
+
status: 'empty',
|
|
32
|
+
candidate: undefined,
|
|
33
|
+
accepted: undefined,
|
|
34
|
+
lastKnownGood: undefined,
|
|
35
|
+
resourceCount: 0,
|
|
36
|
+
descriptorBytes: 0,
|
|
37
|
+
uploadCount: 0,
|
|
38
|
+
passCount: 0,
|
|
39
|
+
bindGroupCount: 0,
|
|
40
|
+
failure: undefined,
|
|
41
|
+
failureKeys: [],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function promoteExtendedLightingCandidate(
|
|
46
|
+
state: ExtendedLightingState,
|
|
47
|
+
candidate: ExtendedLightingResourceCandidate | undefined,
|
|
48
|
+
): ExtendedLightingState {
|
|
49
|
+
if (candidate === undefined) return state;
|
|
50
|
+
return {
|
|
51
|
+
...state,
|
|
52
|
+
enabled: true,
|
|
53
|
+
generation: candidate.generation,
|
|
54
|
+
status: 'accepted',
|
|
55
|
+
candidate: undefined,
|
|
56
|
+
accepted: candidate,
|
|
57
|
+
lastKnownGood: candidate,
|
|
58
|
+
resourceCount: 4,
|
|
59
|
+
descriptorBytes: candidate.descriptorBytes,
|
|
60
|
+
uploadCount: candidate.uploadCount,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function recordExtendedLightingFailure(
|
|
65
|
+
state: ExtendedLightingState,
|
|
66
|
+
failure: LightResourceUnavailableError,
|
|
67
|
+
): ExtendedLightingState {
|
|
68
|
+
const key = `${failure.detail.entity}:${failure.detail.feature}:${failure.detail.generation}`;
|
|
69
|
+
if (state.failureKeys.includes(key)) return state;
|
|
70
|
+
return {
|
|
71
|
+
...state,
|
|
72
|
+
failure,
|
|
73
|
+
failureKeys: [...state.failureKeys, key],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function projectExtendedLightingInspection(state: ExtendedLightingState): LightInspection {
|
|
78
|
+
const identity = (candidate: ExtendedLightingResourceCandidate | undefined) =>
|
|
79
|
+
candidate === undefined
|
|
80
|
+
? undefined
|
|
81
|
+
: lightInspectionIdentity(candidate.topology, candidate.generation);
|
|
82
|
+
return projectLightInspection({
|
|
83
|
+
generation: state.generation,
|
|
84
|
+
candidate: identity(state.candidate),
|
|
85
|
+
accepted: identity(state.accepted),
|
|
86
|
+
lastKnownGood: identity(state.lastKnownGood),
|
|
87
|
+
failure: state.failure?.code,
|
|
88
|
+
failureKeys: state.failureKeys,
|
|
89
|
+
resourceCount: state.resourceCount,
|
|
90
|
+
uploadBytes: state.descriptorBytes,
|
|
91
|
+
});
|
|
92
|
+
}
|