@forgeax/engine-render 0.1.20 → 0.1.21
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 +215 -0
- package/dist/.tsbuildinfo +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 +21 -18
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +9 -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 +3 -0
- 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-4XINDLAY.mjs → chunk-5YADUCA7.mjs} +1552 -1361
- package/dist/chunk-5YADUCA7.mjs.map +1 -0
- package/dist/{chunk-TBQJOK2L.mjs → chunk-6OPXDQ2E.mjs} +364 -51
- package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
- package/dist/{chunk-M2MP4ZOU.mjs → chunk-BXBQQKFQ.mjs} +3 -9
- package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
- package/dist/{chunk-CDTWTHZR.mjs → chunk-FS2KNUQH.mjs} +548 -6
- package/dist/chunk-FS2KNUQH.mjs.map +1 -0
- 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 +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/construct-renderer.mjs +5826 -1003
- package/dist/construct-renderer.mjs.map +1 -1
- 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/render.d.ts +141 -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/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.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +0 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +19 -17
- 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 +28 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +51 -0
- 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.mjs +1 -1
- package/dist/light-buffer-layout.d.ts +10 -1
- package/dist/light-buffer-layout.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 +14 -4
- 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-spec.d.ts +40 -7
- package/dist/pipeline-spec.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/record/frame-lighting.d.ts +27 -32
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +28 -14
- 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 +10 -4
- 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 +8 -3
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +22 -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 +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +43 -2
- 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 +72 -4
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -4
- 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/projection.d.ts +91 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/render-contract.d.ts +49 -7
- 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 +42 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +58 -17
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +17 -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/render-scene.d.ts +14 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- 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/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/index.mjs +3 -3
- package/dist/typed-render-graph-primitives.d.ts +1 -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 +2 -2
- 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 +7 -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__/device-feature-admission.unit.test.ts +73 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/factory-contract.integration.test.ts +255 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
- 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__/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__/material-observation.integration.test.ts +101 -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__/public-surface.test-d.ts +10 -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-pass-encode.integration.test.ts +101 -0
- package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -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 +18 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
- 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 +48 -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 +132 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +11 -2
- 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 +232 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -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 +377 -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__/typed-pipeline-topology.unit.test.ts +395 -14
- package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/assembly/device-feature-admission.ts +73 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +877 -286
- package/src/assembly/host-contract.ts +25 -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/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 +2 -0
- package/src/components/light-helpers.ts +81 -7
- package/src/components/reflection-probe.ts +49 -0
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +12 -0
- package/src/errors/render.ts +286 -142
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/visibility.ts +25 -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 +1 -0
- package/src/gpu-driven/production-raster.ts +1 -3
- package/src/gpu-scene.ts +8 -1
- package/src/hdrp-buffers.ts +165 -59
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +148 -0
- package/src/inspection-types.ts +56 -0
- package/src/instances-derived-bounds.ts +171 -0
- package/src/light-buffer-layout.ts +20 -5
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +106 -17
- package/src/pipeline/standard-forward-lane.ts +46 -16
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +157 -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 +34 -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 +77 -0
- package/src/pipeline/standard-pipeline.ts +122 -193
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +17 -47
- package/src/pipeline-spec.ts +84 -21
- package/src/point-shadow-inspection.ts +55 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +367 -427
- package/src/record/frame-snapshot.ts +35 -27
- package/src/record/frame-targets.ts +17 -0
- package/src/record/frame.ts +261 -74
- 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 +21 -12
- package/src/record/main-pass-geometry.ts +120 -80
- package/src/record/main-pass-material.ts +95 -9
- package/src/record/main-pass-sprite-draws.ts +54 -25
- package/src/record/main-pass.ts +71 -15
- package/src/record/render-context.ts +72 -0
- package/src/record/shadow-pass.ts +17 -28
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +893 -44
- package/src/record/view-ubo.ts +63 -28
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/projection.ts +281 -0
- package/src/render-contract.ts +76 -5
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +117 -2
- package/src/render-system-extract.ts +557 -100
- package/src/render-system.ts +1095 -66
- package/src/renderer.ts +222 -0
- package/src/scene/render-scene.ts +115 -9
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- 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/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
- package/src/typed-render-graph-primitives.ts +5 -3
- package/src/typed-shadow-passes.ts +46 -40
- package/src/volume/passes.ts +15 -9
- package/dist/chunk-4XINDLAY.mjs.map +0 -1
- package/dist/chunk-CDTWTHZR.mjs.map +0 -1
- package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
- package/dist/chunk-TBQJOK2L.mjs.map +0 -1
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
import { TRANSPARENT_SORT_MODE_LAYER_Z, TRANSPARENT_SORT_MODE_LAYER_Y } from './chunk-RXZ3RGOU.mjs';
|
|
2
|
-
import { DEFAULT_CLUSTER_GRID,
|
|
2
|
+
import { DEFAULT_CLUSTER_GRID, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, GPU_TEXTURE_USAGE_COPY_SRC, EquirectProjectionFailedError, SHADOW_ATLAS_DEFAULT_LAYERS, SHADOW_ATLAS_DEFAULT_FACE_SIZE, ShadowAtlas, PointShadowAtlasUninitializedError, PointShadowAtlasBoundsViolationError, DEFAULT_STANDARD_PROFILE, StandardClusterTransportUnavailableError, createIblKernelCache, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_DST, GPU_TEXTURE_USAGE_TEXTURE_BINDING, STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, MAX_LIGHTS, CLUSTER_GRID_STRIDE_U32, LIGHT_INDEX_LIST_CAPACITY, StandardLightBudgetExceededError, createStandardClusterLayout, RenderTargetDescriptorInvalidError, RendererOperationError, StandardClusterIndexOverflowError, FXAA_POST_PROCESS_ID, VideoUploadUnsupportedError, VertexColorVariantConflictError } from './chunk-6OPXDQ2E.mjs';
|
|
3
3
|
import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-VFPLTKCU.mjs';
|
|
4
|
-
import {
|
|
4
|
+
import { worldEntityKey } from './chunk-BXBQQKFQ.mjs';
|
|
5
5
|
import { ok, derive, err as err$1, toShared, ASSET_ERROR_HINTS, deriveTextureLayout, KNOWN_PASS_KINDS, resolveMaterialTextureCoordinates, handleSlot } from '@forgeax/engine-types';
|
|
6
|
-
import { ok as ok$1, err, RhiError
|
|
7
|
-
import {
|
|
8
|
-
import { deriveVertexLayoutProjection, deriveVertexBufferLayout } from '@forgeax/engine-geometry';
|
|
6
|
+
import { ok as ok$1, err, RhiError } from '@forgeax/engine-rhi';
|
|
7
|
+
import { mat3, vec3, mat4 } from '@forgeax/engine-math';
|
|
9
8
|
import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_UNLIT_PARAM_SCHEMA } from '@forgeax/engine-shader';
|
|
9
|
+
import { deriveVertexLayoutProjection, deriveVertexBufferLayout } from '@forgeax/engine-geometry';
|
|
10
10
|
import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
11
11
|
import { probeVideoHighPerfUpload, VIDEO_ELEMENT_PROVIDER_KEY } from '@forgeax/engine-graphics-extras';
|
|
12
12
|
import { isCompressedFormat, bytesPerRow, blockParamsForFormat } from '@forgeax/engine-codec';
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
var GPU_TEXTURE_USAGE_TEXTURE_BINDING = 4;
|
|
18
|
-
var GPU_TEXTURE_USAGE_RENDER_ATTACHMENT = 16;
|
|
19
|
-
var GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING = GPU_TEXTURE_USAGE_RENDER_ATTACHMENT | GPU_TEXTURE_USAGE_TEXTURE_BINDING;
|
|
20
|
-
|
|
21
|
-
// src/render-pipeline.ts
|
|
14
|
+
function resolveOutputDither(config) {
|
|
15
|
+
return config?.outputDither ?? true;
|
|
16
|
+
}
|
|
22
17
|
function createRenderPipelineTarget(graph, label, descriptor, viewDescriptor = {}) {
|
|
23
18
|
const texture = graph.createTexture(label, descriptor);
|
|
24
19
|
if (!texture.ok) return texture;
|
|
@@ -88,628 +83,214 @@ function importRenderPipelineSurface(graph, topology) {
|
|
|
88
83
|
}
|
|
89
84
|
});
|
|
90
85
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
86
|
+
|
|
87
|
+
// src/gpu-stage.ts
|
|
88
|
+
var GPU_SHADER_STAGE_VERTEX = 1;
|
|
89
|
+
var GPU_SHADER_STAGE_FRAGMENT = 2;
|
|
90
|
+
var GPU_SHADER_STAGE_COMPUTE = 4;
|
|
91
|
+
|
|
92
|
+
// src/gpu-usage.ts
|
|
93
|
+
var GPU_BUFFER_USAGE_VERTEX = 32;
|
|
94
|
+
var GPU_BUFFER_USAGE_INDEX = 16;
|
|
95
|
+
var GPU_BUFFER_USAGE_COPY_DST = 8;
|
|
96
|
+
var GPU_BUFFER_USAGE_COPY_SRC = 4;
|
|
97
|
+
var GPU_BUFFER_USAGE_UNIFORM = 64;
|
|
98
|
+
var GPU_BUFFER_USAGE_STORAGE = 128;
|
|
99
|
+
var GPU_BUFFER_USAGE_INDIRECT = 256;
|
|
100
|
+
var GPU_BUFFER_USAGE_MAP_READ = 1;
|
|
101
|
+
var GPU_BUFFER_USAGE_QUERY_RESOLVE = 512;
|
|
102
|
+
var BYTES_PER_LIGHT_SLOT = 64;
|
|
103
|
+
var LightSlotKind = {
|
|
104
|
+
POINT: 0,
|
|
105
|
+
SPOT: 1
|
|
106
|
+
};
|
|
107
|
+
var STORAGE_BUFFER_MIN_REQUIRED = 4;
|
|
108
|
+
var POINT_LIGHT_STD430_BYTES = 32;
|
|
109
|
+
var SPOT_LIGHT_STD430_BYTES = 80;
|
|
110
|
+
var SPOT_LIGHT_SHADOW_TILE_SENTINEL = -1;
|
|
111
|
+
var SPOT_LIGHT_PROJECTOR_FLAG = 1073741824;
|
|
112
|
+
var SPOT_LIGHT_TILE_MASK = SPOT_LIGHT_PROJECTOR_FLAG - 1;
|
|
113
|
+
var LIGHT_ARRAY_HEADER_BYTES = 16;
|
|
114
|
+
var LIGHT_ARRAY_MAX_SLOTS = 4;
|
|
115
|
+
var POINT_LIGHT_SHADOW_LAYER_SENTINEL = -1;
|
|
116
|
+
function packLightSlot(snap, shadow, projectorSelected) {
|
|
117
|
+
const out = new Float32Array(16);
|
|
118
|
+
out[0] = snap.position[0] ?? 0;
|
|
119
|
+
out[1] = snap.position[1] ?? 0;
|
|
120
|
+
out[2] = snap.position[2] ?? 0;
|
|
121
|
+
out[3] = snap.invRangeSquared;
|
|
122
|
+
out[4] = snap.color[0] ?? 0;
|
|
123
|
+
out[5] = snap.color[1] ?? 0;
|
|
124
|
+
out[6] = snap.color[2] ?? 0;
|
|
125
|
+
out[7] = snap.kind === "point" ? 1 : snap.cosInner;
|
|
126
|
+
out[8] = snap.kind === "point" ? 0 : snap.direction[0] ?? 0;
|
|
127
|
+
out[9] = snap.kind === "point" ? 0 : snap.direction[1] ?? 0;
|
|
128
|
+
out[10] = snap.kind === "point" ? 0 : snap.direction[2] ?? 0;
|
|
129
|
+
out[11] = snap.kind === "point" ? 0 : snap.cosOuter;
|
|
130
|
+
const u32 = new Uint32Array(out.buffer);
|
|
131
|
+
u32[12] = snap.kind === "point" ? LightSlotKind.POINT : LightSlotKind.SPOT;
|
|
132
|
+
const i32 = new Int32Array(out.buffer);
|
|
133
|
+
if (snap.kind === "point" && shadow !== void 0) {
|
|
134
|
+
i32[13] = shadow.shadowAtlasLayer;
|
|
135
|
+
out[14] = shadow.near;
|
|
136
|
+
out[15] = shadow.far;
|
|
137
|
+
} else if (snap.kind === "spot") {
|
|
138
|
+
const hasProjector = projectorSelected ?? (snap.projectorAsset !== void 0 && snap.lightViewProj !== void 0);
|
|
139
|
+
const tile = snap.shadowAtlasTile >= 0 ? snap.shadowAtlasTile : 0;
|
|
140
|
+
i32[13] = hasProjector ? SPOT_LIGHT_PROJECTOR_FLAG | tile & SPOT_LIGHT_TILE_MASK : snap.shadowAtlasTile >= 0 ? snap.shadowAtlasTile : SPOT_LIGHT_SHADOW_TILE_SENTINEL;
|
|
141
|
+
out[14] = snap.shadowIntensity ?? 1;
|
|
142
|
+
out[15] = snap.pcfKernelSize ?? 3;
|
|
143
|
+
} else {
|
|
144
|
+
i32[13] = POINT_LIGHT_SHADOW_LAYER_SENTINEL;
|
|
114
145
|
}
|
|
115
|
-
|
|
116
|
-
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
function assertStorageBufferCap(cap) {
|
|
149
|
+
if (cap >= STORAGE_BUFFER_MIN_REQUIRED) {
|
|
150
|
+
return ok$1(true);
|
|
117
151
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
scratch.clusterDeltas = new Int32Array(differenceVolumeSize);
|
|
152
|
+
if (cap === 0) {
|
|
153
|
+
return ok$1(false);
|
|
121
154
|
}
|
|
155
|
+
return err(
|
|
156
|
+
new RhiError({
|
|
157
|
+
code: "limit-exceeded",
|
|
158
|
+
expected: `device.limits.maxStorageBuffersPerShaderStage >= ${STORAGE_BUFFER_MIN_REQUIRED}, or exactly 0 for uniform-fallback path`,
|
|
159
|
+
hint: `device.limits.maxStorageBuffersPerShaderStage = ${cap} < ${STORAGE_BUFFER_MIN_REQUIRED} and != 0. WebGPU spec default minimum is 8; this may be a downlevel adapter with partial storage support. Wait for todo-125 multi-light-pack which collapses point + spot into a single cluster storage buffer (1 entry instead of 2) for 2-3 buffer environments.`,
|
|
160
|
+
detail: {
|
|
161
|
+
maxStorageBufferBindingSize: cap,
|
|
162
|
+
requestedBytes: STORAGE_BUFFER_MIN_REQUIRED
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
);
|
|
122
166
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
167
|
+
var BGL_ONLY_SPEC_STUB = Object.freeze({
|
|
168
|
+
shader: { id: "", passKind: "forward", variantSet: void 0 },
|
|
169
|
+
attachments: { colorFormats: [], depthFormat: void 0, sampleCount: 1 },
|
|
170
|
+
geometry: { topology: "triangle-list", vertexLayout: {} },
|
|
171
|
+
renderState: void 0
|
|
172
|
+
});
|
|
173
|
+
function buildPbrMaterialUserRegionEntries(paramSchema = DEFAULT_STANDARD_PBR_PARAM_SCHEMA) {
|
|
174
|
+
const derived = derive(paramSchema);
|
|
175
|
+
const entries = derived.bglEntries.map(
|
|
176
|
+
(entry) => ({
|
|
177
|
+
binding: entry.binding,
|
|
178
|
+
visibility: entry.visibility,
|
|
179
|
+
...entry.buffer === void 0 ? {} : { buffer: entry.buffer },
|
|
180
|
+
...entry.sampler === void 0 ? {} : { sampler: entry.sampler },
|
|
181
|
+
...entry.texture === void 0 ? {} : { texture: entry.texture },
|
|
182
|
+
...entry.storageTexture === void 0 ? {} : { storageTexture: entry.storageTexture }
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
const ubo = entries[0];
|
|
186
|
+
if (ubo !== void 0 && ubo.binding === 0 && ubo.buffer?.type === "uniform") {
|
|
187
|
+
entries[0] = {
|
|
188
|
+
binding: 0,
|
|
189
|
+
visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
|
|
190
|
+
buffer: { type: "uniform", hasDynamicOffset: true }
|
|
191
|
+
};
|
|
126
192
|
}
|
|
127
|
-
|
|
128
|
-
return Math.min(derived, 1e3);
|
|
193
|
+
return entries;
|
|
129
194
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const sy = corner[1];
|
|
230
|
-
const ndc = projectToNdc(sx, sy, zTest, proj);
|
|
231
|
-
ndcMinX = Math.min(ndcMinX, ndc[0]);
|
|
232
|
-
ndcMaxX = Math.max(ndcMaxX, ndc[0]);
|
|
233
|
-
ndcMinY = Math.min(ndcMinY, ndc[1]);
|
|
234
|
-
ndcMaxY = Math.max(ndcMaxY, ndc[1]);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
ndcMinX = Math.max(ndcMinX, -1);
|
|
240
|
-
ndcMinY = Math.max(ndcMinY, -1);
|
|
241
|
-
ndcMaxX = Math.min(ndcMaxX, 1);
|
|
242
|
-
ndcMaxY = Math.min(ndcMaxY, 1);
|
|
243
|
-
result.min[0] = ndcMinX;
|
|
244
|
-
result.min[1] = ndcMinY;
|
|
245
|
-
result.min[2] = minViewZ;
|
|
246
|
-
result.max[0] = ndcMaxX;
|
|
247
|
-
result.max[1] = ndcMaxY;
|
|
248
|
-
result.max[2] = maxViewZ;
|
|
249
|
-
return result;
|
|
250
|
-
}
|
|
251
|
-
function projectToNdc(vx, vy, vz, proj) {
|
|
252
|
-
const p00 = proj[0] ?? 0;
|
|
253
|
-
const p10 = proj[4] ?? 0;
|
|
254
|
-
const p20 = proj[8] ?? 0;
|
|
255
|
-
const p30 = proj[12] ?? 0;
|
|
256
|
-
const p01 = proj[1] ?? 0;
|
|
257
|
-
const p11 = proj[5] ?? 0;
|
|
258
|
-
const p21 = proj[9] ?? 0;
|
|
259
|
-
const p31 = proj[13] ?? 0;
|
|
260
|
-
const p02 = proj[2] ?? 0;
|
|
261
|
-
const p12 = proj[6] ?? 0;
|
|
262
|
-
const p22 = proj[10] ?? 0;
|
|
263
|
-
const p32 = proj[14] ?? 0;
|
|
264
|
-
const p03 = proj[3] ?? 0;
|
|
265
|
-
const p13 = proj[7] ?? 0;
|
|
266
|
-
const p23 = proj[11] ?? 0;
|
|
267
|
-
const p33 = proj[15] ?? 0;
|
|
268
|
-
const cx = p00 * vx + p10 * vy + p20 * vz + p30;
|
|
269
|
-
const cy = p01 * vx + p11 * vy + p21 * vz + p31;
|
|
270
|
-
const cz = p02 * vx + p12 * vy + p22 * vz + p32;
|
|
271
|
-
const cw = p03 * vx + p13 * vy + p23 * vz + p33;
|
|
272
|
-
if (Math.abs(cw) < 1e-10) {
|
|
273
|
-
return [vx < 0 ? -1 : 1, vy < 0 ? -1 : 1, cz];
|
|
274
|
-
}
|
|
275
|
-
const invW = 1 / cw;
|
|
276
|
-
return [cx * invW, cy * invW, cz * invW];
|
|
277
|
-
}
|
|
278
|
-
function ndcPositionToCluster(ndc, viewZ, gridX, gridY, gridZ, near, far) {
|
|
279
|
-
const ndcX = ndc[0] ?? 0;
|
|
280
|
-
const ndcY = ndc[1] ?? 0;
|
|
281
|
-
let cx = Math.floor((ndcX * 0.5 + 0.5) * gridX);
|
|
282
|
-
let cy = Math.floor((ndcY * 0.5 + 0.5) * gridY);
|
|
283
|
-
if (cx < 0) cx = 0;
|
|
284
|
-
if (cx >= gridX) cx = gridX - 1;
|
|
285
|
-
if (cy < 0) cy = 0;
|
|
286
|
-
if (cy >= gridY) cy = gridY - 1;
|
|
287
|
-
const cz = viewZToZSlice(viewZ, gridZ, near, far);
|
|
288
|
-
return { x: cx, y: cy, z: cz };
|
|
289
|
-
}
|
|
290
|
-
function calculateSphereClusterBounds(aabb, gridX, gridY, gridZ, near, far, output) {
|
|
291
|
-
const result = output ?? {
|
|
292
|
-
min: { x: 0, y: 0, z: 0 },
|
|
293
|
-
max: { x: 0, y: 0, z: 0 }
|
|
294
|
-
};
|
|
295
|
-
const minZ = aabb.min[2] ?? 0;
|
|
296
|
-
const maxZ = aabb.max[2] ?? 0;
|
|
297
|
-
const idxMin = ndcPositionToCluster(aabb.min, minZ, gridX, gridY, gridZ, near, far);
|
|
298
|
-
const idxMax = ndcPositionToCluster(aabb.max, maxZ, gridX, gridY, gridZ, near, far);
|
|
299
|
-
result.min.x = Math.min(idxMin.x, idxMax.x);
|
|
300
|
-
result.min.y = Math.min(idxMin.y, idxMax.y);
|
|
301
|
-
result.min.z = Math.min(idxMin.z, idxMax.z);
|
|
302
|
-
result.max.x = Math.max(idxMin.x, idxMax.x);
|
|
303
|
-
result.max.y = Math.max(idxMin.y, idxMax.y);
|
|
304
|
-
result.max.z = Math.max(idxMin.z, idxMax.z);
|
|
305
|
-
return result;
|
|
306
|
-
}
|
|
307
|
-
function bin(lights, view, proj, grid, near, far, clusterGrid, lightIndexList, capacity, scratch, profile, options = {}) {
|
|
308
|
-
const gridX = grid.x;
|
|
309
|
-
const gridY = grid.y;
|
|
310
|
-
const gridZ = grid.z;
|
|
311
|
-
const clusterCount = gridX * gridY * gridZ;
|
|
312
|
-
const binScratch = scratch ?? createClusterBinScratch();
|
|
313
|
-
ensureScratchCapacity(binScratch, clusterCount, lights.length, gridX, gridY, gridZ);
|
|
314
|
-
const { clusterCounts, clusterCursors, lightBounds, clusterDeltas } = binScratch;
|
|
315
|
-
clusterGrid.fill(0, 0, clusterCount * 2);
|
|
316
|
-
clusterCounts.fill(0, 0, clusterCount);
|
|
317
|
-
let attemptedTotal = 0;
|
|
318
|
-
runClusterBinProfilePhase(profile, "light-bounds-and-occupancy", () => {
|
|
319
|
-
runClusterBinProfilePhase(profile, "light-bounds-and-occupancy/light-aabb", () => {
|
|
320
|
-
for (let lightIdx = 0; lightIdx < lights.length; lightIdx++) {
|
|
321
|
-
const boundsOffset = lightIdx * 6;
|
|
322
|
-
lightBounds[boundsOffset] = -1;
|
|
323
|
-
const light = lights[lightIdx];
|
|
324
|
-
if (!light) continue;
|
|
325
|
-
const radius = deriveCullingRadius(light.range, 1);
|
|
326
|
-
if (radius <= 0) {
|
|
327
|
-
continue;
|
|
328
|
-
}
|
|
329
|
-
const aabb = clusterSpaceObjectAabb(
|
|
330
|
-
light.position,
|
|
331
|
-
radius,
|
|
332
|
-
view,
|
|
333
|
-
proj,
|
|
334
|
-
binScratch.aabbOutput
|
|
335
|
-
);
|
|
336
|
-
const bounds = calculateSphereClusterBounds(
|
|
337
|
-
aabb,
|
|
338
|
-
gridX,
|
|
339
|
-
gridY,
|
|
340
|
-
gridZ,
|
|
341
|
-
near,
|
|
342
|
-
far,
|
|
343
|
-
binScratch.boundsOutput
|
|
344
|
-
);
|
|
345
|
-
if (bounds.min.x > bounds.max.x || bounds.min.y > bounds.max.y || bounds.min.z > bounds.max.z) {
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
lightBounds[boundsOffset] = bounds.min.x;
|
|
349
|
-
lightBounds[boundsOffset + 1] = bounds.min.y;
|
|
350
|
-
lightBounds[boundsOffset + 2] = bounds.min.z;
|
|
351
|
-
lightBounds[boundsOffset + 3] = bounds.max.x;
|
|
352
|
-
lightBounds[boundsOffset + 4] = bounds.max.y;
|
|
353
|
-
lightBounds[boundsOffset + 5] = bounds.max.z;
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
runClusterBinProfilePhase(profile, "light-bounds-and-occupancy/cluster-occupancy", () => {
|
|
357
|
-
const diffX = gridX + 1;
|
|
358
|
-
const diffY = gridY + 1;
|
|
359
|
-
const diffRow = diffX * diffY;
|
|
360
|
-
clusterDeltas.fill(0, 0, diffRow * (gridZ + 1));
|
|
361
|
-
const addDifference = (x, y, z, delta) => {
|
|
362
|
-
const index = z * diffRow + y * diffX + x;
|
|
363
|
-
clusterDeltas[index] = (clusterDeltas[index] ?? 0) + delta;
|
|
364
|
-
};
|
|
365
|
-
for (let lightIdx = 0; lightIdx < lights.length; lightIdx++) {
|
|
366
|
-
const boundsOffset = lightIdx * 6;
|
|
367
|
-
if ((lightBounds[boundsOffset] ?? -1) < 0) continue;
|
|
368
|
-
const minX = lightBounds[boundsOffset] ?? 0;
|
|
369
|
-
const minY = lightBounds[boundsOffset + 1] ?? 0;
|
|
370
|
-
const minZ = lightBounds[boundsOffset + 2] ?? 0;
|
|
371
|
-
const maxX = lightBounds[boundsOffset + 3] ?? -1;
|
|
372
|
-
const maxY = lightBounds[boundsOffset + 4] ?? -1;
|
|
373
|
-
const maxZ = lightBounds[boundsOffset + 5] ?? -1;
|
|
374
|
-
const endX = maxX + 1;
|
|
375
|
-
const endY = maxY + 1;
|
|
376
|
-
const endZ = maxZ + 1;
|
|
377
|
-
addDifference(minX, minY, minZ, 1);
|
|
378
|
-
addDifference(endX, minY, minZ, -1);
|
|
379
|
-
addDifference(minX, endY, minZ, -1);
|
|
380
|
-
addDifference(minX, minY, endZ, -1);
|
|
381
|
-
addDifference(endX, endY, minZ, 1);
|
|
382
|
-
addDifference(endX, minY, endZ, 1);
|
|
383
|
-
addDifference(minX, endY, endZ, 1);
|
|
384
|
-
addDifference(endX, endY, endZ, -1);
|
|
385
|
-
}
|
|
386
|
-
for (let cz = 0; cz < gridZ; cz++) {
|
|
387
|
-
for (let cy = 0; cy < gridY; cy++) {
|
|
388
|
-
for (let cx = 0; cx < gridX; cx++) {
|
|
389
|
-
const diffIdx = cz * diffRow + cy * diffX + cx;
|
|
390
|
-
let count = clusterDeltas[diffIdx] ?? 0;
|
|
391
|
-
if (cx > 0) count += clusterDeltas[diffIdx - 1] ?? 0;
|
|
392
|
-
if (cy > 0) count += clusterDeltas[diffIdx - diffX] ?? 0;
|
|
393
|
-
if (cz > 0) count += clusterDeltas[diffIdx - diffRow] ?? 0;
|
|
394
|
-
if (cx > 0 && cy > 0) count -= clusterDeltas[diffIdx - diffX - 1] ?? 0;
|
|
395
|
-
if (cx > 0 && cz > 0) count -= clusterDeltas[diffIdx - diffRow - 1] ?? 0;
|
|
396
|
-
if (cy > 0 && cz > 0) count -= clusterDeltas[diffIdx - diffRow - diffX] ?? 0;
|
|
397
|
-
if (cx > 0 && cy > 0 && cz > 0) {
|
|
398
|
-
count += clusterDeltas[diffIdx - diffRow - diffX - 1] ?? 0;
|
|
399
|
-
}
|
|
400
|
-
clusterDeltas[diffIdx] = count;
|
|
401
|
-
const clusterIdx = cz * gridY * gridX + cy * gridX + cx;
|
|
402
|
-
clusterCounts[clusterIdx] = count;
|
|
403
|
-
attemptedTotal += count;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
if (attemptedTotal > capacity) {
|
|
410
|
-
return err({
|
|
411
|
-
code: "index-overflow",
|
|
412
|
-
expected: `writeCount <= ${capacity}`,
|
|
413
|
-
hint: `light index list overflow: needed ${attemptedTotal} entries, capacity ${capacity}; reduce lights, shrink grid, or shrink ranges (overrun = ${attemptedTotal - capacity})`,
|
|
414
|
-
detail: { actual: attemptedTotal, capacity }
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
const writeCount = runClusterBinProfilePhase(profile, "cluster-reserve", () => {
|
|
418
|
-
let reserved = 0;
|
|
419
|
-
for (let ci = 0; ci < clusterCount; ci++) {
|
|
420
|
-
const base = ci * 2;
|
|
421
|
-
clusterGrid[base] = reserved;
|
|
422
|
-
clusterGrid[base + 1] = clusterCounts[ci] ?? 0;
|
|
423
|
-
clusterCursors[ci] = reserved;
|
|
424
|
-
reserved += clusterCounts[ci] ?? 0;
|
|
425
|
-
}
|
|
426
|
-
return reserved;
|
|
427
|
-
});
|
|
428
|
-
if (options.writeMembership !== false) {
|
|
429
|
-
runClusterBinProfilePhase(profile, "light-index-write", () => {
|
|
430
|
-
for (let lightIdx = 0; lightIdx < lights.length; lightIdx++) {
|
|
431
|
-
const boundsOffset = lightIdx * 6;
|
|
432
|
-
let valid = false;
|
|
433
|
-
let minX = 0;
|
|
434
|
-
let minY = 0;
|
|
435
|
-
let minZ = 0;
|
|
436
|
-
let maxX = -1;
|
|
437
|
-
let maxY = -1;
|
|
438
|
-
let maxZ = -1;
|
|
439
|
-
runClusterBinProfilePhase(profile, "light-index-write/bounds-read", () => {
|
|
440
|
-
if ((lightBounds[boundsOffset] ?? -1) < 0) return;
|
|
441
|
-
valid = true;
|
|
442
|
-
minX = lightBounds[boundsOffset] ?? 0;
|
|
443
|
-
minY = lightBounds[boundsOffset + 1] ?? 0;
|
|
444
|
-
minZ = lightBounds[boundsOffset + 2] ?? 0;
|
|
445
|
-
maxX = lightBounds[boundsOffset + 3] ?? -1;
|
|
446
|
-
maxY = lightBounds[boundsOffset + 4] ?? -1;
|
|
447
|
-
maxZ = lightBounds[boundsOffset + 5] ?? -1;
|
|
448
|
-
});
|
|
449
|
-
if (!valid) continue;
|
|
450
|
-
runClusterBinProfilePhase(profile, "light-index-write/cluster-write", () => {
|
|
451
|
-
for (let cz = minZ; cz <= maxZ; cz++) {
|
|
452
|
-
for (let cy = minY; cy <= maxY; cy++) {
|
|
453
|
-
for (let cx = minX; cx <= maxX; cx++) {
|
|
454
|
-
const clusterIdx = cz * gridY * gridX + cy * gridX + cx;
|
|
455
|
-
const cursor = clusterCursors[clusterIdx] ?? 0;
|
|
456
|
-
lightIndexList[cursor] = lightIdx;
|
|
457
|
-
clusterCursors[clusterIdx] = cursor + 1;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
return ok$1(writeCount);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// src/gpu-stage.ts
|
|
469
|
-
var GPU_SHADER_STAGE_VERTEX = 1;
|
|
470
|
-
var GPU_SHADER_STAGE_FRAGMENT = 2;
|
|
471
|
-
var GPU_SHADER_STAGE_COMPUTE = 4;
|
|
472
|
-
|
|
473
|
-
// src/gpu-usage.ts
|
|
474
|
-
var GPU_BUFFER_USAGE_VERTEX = 32;
|
|
475
|
-
var GPU_BUFFER_USAGE_INDEX = 16;
|
|
476
|
-
var GPU_BUFFER_USAGE_COPY_DST = 8;
|
|
477
|
-
var GPU_BUFFER_USAGE_COPY_SRC = 4;
|
|
478
|
-
var GPU_BUFFER_USAGE_UNIFORM = 64;
|
|
479
|
-
var GPU_BUFFER_USAGE_STORAGE = 128;
|
|
480
|
-
var GPU_BUFFER_USAGE_INDIRECT = 256;
|
|
481
|
-
var GPU_BUFFER_USAGE_MAP_READ = 1;
|
|
482
|
-
var GPU_BUFFER_USAGE_QUERY_RESOLVE = 512;
|
|
483
|
-
var BYTES_PER_LIGHT_SLOT = 64;
|
|
484
|
-
var LightSlotKind = {
|
|
485
|
-
POINT: 0,
|
|
486
|
-
SPOT: 1
|
|
487
|
-
};
|
|
488
|
-
var STORAGE_BUFFER_MIN_REQUIRED = 4;
|
|
489
|
-
var POINT_LIGHT_STD430_BYTES = 32;
|
|
490
|
-
var SPOT_LIGHT_STD430_BYTES = 80;
|
|
491
|
-
var SPOT_LIGHT_SHADOW_TILE_SENTINEL = -1;
|
|
492
|
-
var SPOT_LIGHT_PROJECTOR_ONLY_SENTINEL = -2;
|
|
493
|
-
var LIGHT_ARRAY_HEADER_BYTES = 16;
|
|
494
|
-
var LIGHT_ARRAY_MAX_SLOTS = 4;
|
|
495
|
-
var POINT_LIGHT_SHADOW_LAYER_SENTINEL = -1;
|
|
496
|
-
function packPointLight(snap) {
|
|
497
|
-
const out = new Float32Array(8);
|
|
498
|
-
out[0] = snap.position[0] ?? 0;
|
|
499
|
-
out[1] = snap.position[1] ?? 0;
|
|
500
|
-
out[2] = snap.position[2] ?? 0;
|
|
501
|
-
out[3] = snap.invRangeSquared;
|
|
502
|
-
out[4] = snap.color[0] ?? 0;
|
|
503
|
-
out[5] = snap.color[1] ?? 0;
|
|
504
|
-
out[6] = snap.color[2] ?? 0;
|
|
505
|
-
const i32 = new Int32Array(out.buffer);
|
|
506
|
-
i32[7] = snap.shadowAtlasLayer ?? POINT_LIGHT_SHADOW_LAYER_SENTINEL;
|
|
507
|
-
return out;
|
|
508
|
-
}
|
|
509
|
-
function packSpotLight(snap) {
|
|
510
|
-
const out = new Float32Array(20);
|
|
511
|
-
out[0] = snap.position[0] ?? 0;
|
|
512
|
-
out[1] = snap.position[1] ?? 0;
|
|
513
|
-
out[2] = snap.position[2] ?? 0;
|
|
514
|
-
out[3] = snap.invRangeSquared;
|
|
515
|
-
out[4] = snap.color[0] ?? 0;
|
|
516
|
-
out[5] = snap.color[1] ?? 0;
|
|
517
|
-
out[6] = snap.color[2] ?? 0;
|
|
518
|
-
out[7] = snap.cosInner;
|
|
519
|
-
out[8] = snap.direction[0] ?? 0;
|
|
520
|
-
out[9] = snap.direction[1] ?? 0;
|
|
521
|
-
out[10] = snap.direction[2] ?? 0;
|
|
522
|
-
out[11] = snap.cosOuter;
|
|
523
|
-
out[12] = snap.depthBias ?? 5e-3;
|
|
524
|
-
out[13] = snap.normalBias ?? 0.05;
|
|
525
|
-
out[14] = snap.pcfKernelSize ?? 3;
|
|
526
|
-
const i32 = new Int32Array(out.buffer);
|
|
527
|
-
i32[15] = snap.shadowAtlasTile >= 0 ? snap.shadowAtlasTile : snap.projectorAsset !== void 0 && snap.lightViewProj !== void 0 ? SPOT_LIGHT_PROJECTOR_ONLY_SENTINEL : SPOT_LIGHT_SHADOW_TILE_SENTINEL;
|
|
528
|
-
out[16] = snap.shadowIntensity ?? 1;
|
|
529
|
-
return out;
|
|
530
|
-
}
|
|
531
|
-
function packLightArrayHeader(count) {
|
|
532
|
-
const buf = new ArrayBuffer(LIGHT_ARRAY_HEADER_BYTES);
|
|
533
|
-
const u32 = new Uint32Array(buf);
|
|
534
|
-
u32[0] = count >>> 0;
|
|
535
|
-
return buf;
|
|
536
|
-
}
|
|
537
|
-
function packLightSlot(snap, shadow) {
|
|
538
|
-
const out = new Float32Array(16);
|
|
539
|
-
out[0] = snap.position[0] ?? 0;
|
|
540
|
-
out[1] = snap.position[1] ?? 0;
|
|
541
|
-
out[2] = snap.position[2] ?? 0;
|
|
542
|
-
out[3] = snap.invRangeSquared;
|
|
543
|
-
out[4] = snap.color[0] ?? 0;
|
|
544
|
-
out[5] = snap.color[1] ?? 0;
|
|
545
|
-
out[6] = snap.color[2] ?? 0;
|
|
546
|
-
out[7] = snap.kind === "point" ? 1 : snap.cosInner;
|
|
547
|
-
out[8] = snap.kind === "point" ? 0 : snap.direction[0] ?? 0;
|
|
548
|
-
out[9] = snap.kind === "point" ? 0 : snap.direction[1] ?? 0;
|
|
549
|
-
out[10] = snap.kind === "point" ? 0 : snap.direction[2] ?? 0;
|
|
550
|
-
out[11] = snap.kind === "point" ? 0 : snap.cosOuter;
|
|
551
|
-
const u32 = new Uint32Array(out.buffer);
|
|
552
|
-
u32[12] = snap.kind === "point" ? LightSlotKind.POINT : LightSlotKind.SPOT;
|
|
553
|
-
const i32 = new Int32Array(out.buffer);
|
|
554
|
-
if (snap.kind === "point" && shadow !== void 0) {
|
|
555
|
-
i32[13] = shadow.shadowAtlasLayer;
|
|
556
|
-
out[14] = shadow.near;
|
|
557
|
-
out[15] = shadow.far;
|
|
558
|
-
} else if (snap.kind === "spot") {
|
|
559
|
-
i32[13] = snap.shadowAtlasTile >= 0 ? snap.shadowAtlasTile : snap.projectorAsset !== void 0 && snap.lightViewProj !== void 0 ? SPOT_LIGHT_PROJECTOR_ONLY_SENTINEL : SPOT_LIGHT_SHADOW_TILE_SENTINEL;
|
|
560
|
-
out[14] = snap.shadowIntensity ?? 1;
|
|
561
|
-
out[15] = snap.pcfKernelSize ?? 3;
|
|
562
|
-
} else {
|
|
563
|
-
i32[13] = POINT_LIGHT_SHADOW_LAYER_SENTINEL;
|
|
564
|
-
}
|
|
565
|
-
return out;
|
|
566
|
-
}
|
|
567
|
-
function assertStorageBufferCap(cap) {
|
|
568
|
-
if (cap >= STORAGE_BUFFER_MIN_REQUIRED) {
|
|
569
|
-
return ok$1(true);
|
|
570
|
-
}
|
|
571
|
-
if (cap === 0) {
|
|
572
|
-
return ok$1(false);
|
|
573
|
-
}
|
|
574
|
-
return err(
|
|
575
|
-
new RhiError({
|
|
576
|
-
code: "limit-exceeded",
|
|
577
|
-
expected: `device.limits.maxStorageBuffersPerShaderStage >= ${STORAGE_BUFFER_MIN_REQUIRED}, or exactly 0 for uniform-fallback path`,
|
|
578
|
-
hint: `device.limits.maxStorageBuffersPerShaderStage = ${cap} < ${STORAGE_BUFFER_MIN_REQUIRED} and != 0. WebGPU spec default minimum is 8; this may be a downlevel adapter with partial storage support. Wait for todo-125 multi-light-pack which collapses point + spot into a single cluster storage buffer (1 entry instead of 2) for 2-3 buffer environments.`,
|
|
579
|
-
detail: {
|
|
580
|
-
maxStorageBufferBindingSize: cap,
|
|
581
|
-
requestedBytes: STORAGE_BUFFER_MIN_REQUIRED
|
|
582
|
-
}
|
|
583
|
-
})
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
var BGL_ONLY_SPEC_STUB = Object.freeze({
|
|
587
|
-
shader: { id: "", passKind: "forward", variantSet: void 0 },
|
|
588
|
-
attachments: { colorFormats: [], depthFormat: void 0, sampleCount: 1 },
|
|
589
|
-
geometry: { topology: "triangle-list", vertexLayout: {} },
|
|
590
|
-
renderState: void 0
|
|
591
|
-
});
|
|
592
|
-
function buildPbrMaterialUserRegionEntries(paramSchema = DEFAULT_STANDARD_PBR_PARAM_SCHEMA) {
|
|
593
|
-
const derived = derive(paramSchema);
|
|
594
|
-
const entries = derived.bglEntries.map(
|
|
595
|
-
(entry) => ({
|
|
596
|
-
binding: entry.binding,
|
|
597
|
-
visibility: entry.visibility,
|
|
598
|
-
...entry.buffer === void 0 ? {} : { buffer: entry.buffer },
|
|
599
|
-
...entry.sampler === void 0 ? {} : { sampler: entry.sampler },
|
|
600
|
-
...entry.texture === void 0 ? {} : { texture: entry.texture },
|
|
601
|
-
...entry.storageTexture === void 0 ? {} : { storageTexture: entry.storageTexture }
|
|
602
|
-
})
|
|
603
|
-
);
|
|
604
|
-
const ubo = entries[0];
|
|
605
|
-
if (ubo !== void 0 && ubo.binding === 0 && ubo.buffer?.type === "uniform") {
|
|
606
|
-
entries[0] = {
|
|
607
|
-
binding: 0,
|
|
608
|
-
visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
|
|
609
|
-
buffer: { type: "uniform", hasDynamicOffset: true }
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
return entries;
|
|
613
|
-
}
|
|
614
|
-
function appendInjection(bgl, kind) {
|
|
615
|
-
const start = bgl.length;
|
|
616
|
-
switch (kind) {
|
|
617
|
-
case "ibl":
|
|
618
|
-
return [
|
|
619
|
-
// binding start+0: irradianceMap (texture_cube)
|
|
620
|
-
{
|
|
621
|
-
binding: start,
|
|
622
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
623
|
-
texture: { sampleType: "float", viewDimension: "cube" }
|
|
624
|
-
},
|
|
625
|
-
// binding start+1: irradianceSampler
|
|
626
|
-
{
|
|
627
|
-
binding: start + 1,
|
|
628
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
629
|
-
sampler: { type: "filtering" }
|
|
630
|
-
},
|
|
631
|
-
// binding start+2: prefilterMap (texture_cube)
|
|
632
|
-
{
|
|
633
|
-
binding: start + 2,
|
|
634
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
635
|
-
texture: { sampleType: "float", viewDimension: "cube" }
|
|
636
|
-
},
|
|
637
|
-
// binding start+3: prefilterSampler
|
|
638
|
-
{
|
|
639
|
-
binding: start + 3,
|
|
640
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
641
|
-
sampler: { type: "filtering" }
|
|
642
|
-
},
|
|
643
|
-
// binding start+4: brdfLut (texture_2d)
|
|
644
|
-
{
|
|
645
|
-
binding: start + 4,
|
|
646
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
647
|
-
texture: { sampleType: "float", viewDimension: "2d" }
|
|
648
|
-
},
|
|
649
|
-
// binding start+5: brdfLutSampler
|
|
650
|
-
{
|
|
651
|
-
binding: start + 5,
|
|
652
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
653
|
-
sampler: { type: "filtering" }
|
|
654
|
-
},
|
|
655
|
-
// binding start+6: uniform { intensity: f32 }
|
|
656
|
-
{
|
|
657
|
-
binding: start + 6,
|
|
658
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
659
|
-
buffer: { type: "uniform" }
|
|
660
|
-
}
|
|
661
|
-
];
|
|
662
|
-
case "lightmap":
|
|
663
|
-
return [
|
|
664
|
-
// emissive sampler + texture pair
|
|
665
|
-
{
|
|
666
|
-
binding: start,
|
|
667
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
668
|
-
sampler: { type: "filtering" }
|
|
669
|
-
},
|
|
670
|
-
{
|
|
671
|
-
binding: start + 1,
|
|
672
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
673
|
-
texture: { sampleType: "float", viewDimension: "2d" }
|
|
674
|
-
},
|
|
675
|
-
// occlusion sampler + texture pair
|
|
676
|
-
{
|
|
677
|
-
binding: start + 2,
|
|
678
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
679
|
-
sampler: { type: "filtering" }
|
|
680
|
-
},
|
|
681
|
-
{
|
|
682
|
-
binding: start + 3,
|
|
683
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
684
|
-
texture: { sampleType: "float", viewDimension: "2d" }
|
|
685
|
-
}
|
|
686
|
-
];
|
|
687
|
-
case "shadow":
|
|
688
|
-
return [
|
|
689
|
-
{
|
|
690
|
-
binding: start,
|
|
691
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
692
|
-
sampler: { type: "comparison" }
|
|
693
|
-
},
|
|
694
|
-
{
|
|
695
|
-
binding: start + 1,
|
|
696
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
697
|
-
texture: { sampleType: "depth", viewDimension: "2d" }
|
|
698
|
-
}
|
|
699
|
-
];
|
|
700
|
-
case "transmission":
|
|
701
|
-
return [
|
|
702
|
-
{
|
|
703
|
-
binding: start,
|
|
704
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
705
|
-
sampler: { type: "filtering" }
|
|
706
|
-
},
|
|
707
|
-
{
|
|
708
|
-
binding: start + 1,
|
|
709
|
-
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
710
|
-
texture: { sampleType: "float", viewDimension: "2d" }
|
|
711
|
-
}
|
|
712
|
-
];
|
|
195
|
+
function appendInjection(bgl, kind) {
|
|
196
|
+
const start = bgl.length;
|
|
197
|
+
switch (kind) {
|
|
198
|
+
case "ibl":
|
|
199
|
+
return [
|
|
200
|
+
// binding start+0: irradianceMap (texture_cube)
|
|
201
|
+
{
|
|
202
|
+
binding: start,
|
|
203
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
204
|
+
texture: { sampleType: "float", viewDimension: "cube" }
|
|
205
|
+
},
|
|
206
|
+
// binding start+1: irradianceSampler
|
|
207
|
+
{
|
|
208
|
+
binding: start + 1,
|
|
209
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
210
|
+
sampler: { type: "filtering" }
|
|
211
|
+
},
|
|
212
|
+
// binding start+2: prefilterMap (texture_cube)
|
|
213
|
+
{
|
|
214
|
+
binding: start + 2,
|
|
215
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
216
|
+
texture: { sampleType: "float", viewDimension: "cube" }
|
|
217
|
+
},
|
|
218
|
+
// binding start+3: prefilterSampler
|
|
219
|
+
{
|
|
220
|
+
binding: start + 3,
|
|
221
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
222
|
+
sampler: { type: "filtering" }
|
|
223
|
+
},
|
|
224
|
+
// binding start+4: brdfLut (texture_2d)
|
|
225
|
+
{
|
|
226
|
+
binding: start + 4,
|
|
227
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
228
|
+
texture: { sampleType: "float", viewDimension: "2d" }
|
|
229
|
+
},
|
|
230
|
+
// binding start+5: brdfLutSampler
|
|
231
|
+
{
|
|
232
|
+
binding: start + 5,
|
|
233
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
234
|
+
sampler: { type: "filtering" }
|
|
235
|
+
},
|
|
236
|
+
// binding start+6: uniform { intensity: f32 }
|
|
237
|
+
{
|
|
238
|
+
binding: start + 6,
|
|
239
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
240
|
+
buffer: { type: "uniform" }
|
|
241
|
+
}
|
|
242
|
+
];
|
|
243
|
+
case "lightmap":
|
|
244
|
+
return [
|
|
245
|
+
// emissive sampler + texture pair
|
|
246
|
+
{
|
|
247
|
+
binding: start,
|
|
248
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
249
|
+
sampler: { type: "filtering" }
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
binding: start + 1,
|
|
253
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
254
|
+
texture: { sampleType: "float", viewDimension: "2d" }
|
|
255
|
+
},
|
|
256
|
+
// occlusion sampler + texture pair
|
|
257
|
+
{
|
|
258
|
+
binding: start + 2,
|
|
259
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
260
|
+
sampler: { type: "filtering" }
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
binding: start + 3,
|
|
264
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
265
|
+
texture: { sampleType: "float", viewDimension: "2d" }
|
|
266
|
+
}
|
|
267
|
+
];
|
|
268
|
+
case "shadow":
|
|
269
|
+
return [
|
|
270
|
+
{
|
|
271
|
+
binding: start,
|
|
272
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
273
|
+
sampler: { type: "comparison" }
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
binding: start + 1,
|
|
277
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
278
|
+
texture: { sampleType: "depth", viewDimension: "2d" }
|
|
279
|
+
}
|
|
280
|
+
];
|
|
281
|
+
case "transmission":
|
|
282
|
+
return [
|
|
283
|
+
{
|
|
284
|
+
binding: start,
|
|
285
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
286
|
+
sampler: { type: "filtering" }
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
binding: start + 1,
|
|
290
|
+
visibility: GPU_SHADER_STAGE_FRAGMENT,
|
|
291
|
+
texture: { sampleType: "float", viewDimension: "2d" }
|
|
292
|
+
}
|
|
293
|
+
];
|
|
713
294
|
}
|
|
714
295
|
}
|
|
715
296
|
function buildPbrViewBglEntries(caps) {
|
|
@@ -718,7 +299,9 @@ function buildPbrViewBglEntries(caps) {
|
|
|
718
299
|
{
|
|
719
300
|
binding: 0,
|
|
720
301
|
visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
|
|
721
|
-
|
|
302
|
+
// View captures use the same bind group with a per-face view slot.
|
|
303
|
+
// Keeping this dynamic is also valid for the display slot at offset 0.
|
|
304
|
+
buffer: { type: "uniform", hasDynamicOffset: true }
|
|
722
305
|
},
|
|
723
306
|
{
|
|
724
307
|
binding: 1,
|
|
@@ -873,8 +456,17 @@ function shadowCasterVariantSet(storageBuffer, skinned) {
|
|
|
873
456
|
if (storageBuffer && skinningDisabled) return "";
|
|
874
457
|
return `SKINNING_DISABLED=${String(skinningDisabled)}+STORAGE_BUFFER_AVAILABLE=${String(storageBuffer)}`;
|
|
875
458
|
}
|
|
876
|
-
function
|
|
877
|
-
|
|
459
|
+
function resolvePipelineGroup2Contract(source) {
|
|
460
|
+
const withoutComments = source.replace(/\/\*[\s\S]*?\*\//gu, "").replace(/\/\/.*$/gmu, "");
|
|
461
|
+
const bindings = [
|
|
462
|
+
...withoutComments.matchAll(/@group\s*\(\s*2\s*\)\s*@binding\s*\(\s*(\d+)\s*\)/gu)
|
|
463
|
+
].map((match) => Number(match[1]));
|
|
464
|
+
const hasSkinBindings = bindings.includes(1) || bindings.includes(2);
|
|
465
|
+
const hasClusterBindings = bindings.some((binding) => binding >= 3);
|
|
466
|
+
if (hasSkinBindings && hasClusterBindings) return "skin-cluster";
|
|
467
|
+
if (hasSkinBindings) return "skin";
|
|
468
|
+
if (hasClusterBindings) return "cluster";
|
|
469
|
+
return "mesh";
|
|
878
470
|
}
|
|
879
471
|
function isStandardPbrMaterialShader(shaderId) {
|
|
880
472
|
return shaderId === "forgeax::default-standard-pbr" || shaderId === SKIN_MATERIAL_SHADER_ID || shaderId === "forgeax::default-standard-pbr-skin";
|
|
@@ -907,16 +499,43 @@ function buildPbrSkinLayouts(device, caps, pbr) {
|
|
|
907
499
|
bindGroupLayouts: layouts
|
|
908
500
|
};
|
|
909
501
|
}
|
|
502
|
+
function createPbrSkinMeshBindGroupEntries(meshBuffer, meshSize, paletteBuffer, paletteWindowBytes) {
|
|
503
|
+
return [
|
|
504
|
+
{
|
|
505
|
+
binding: 0,
|
|
506
|
+
resource: { kind: "buffer", value: { buffer: meshBuffer, offset: 0, size: meshSize } }
|
|
507
|
+
},
|
|
508
|
+
...[1, 2].map((binding) => ({
|
|
509
|
+
binding,
|
|
510
|
+
resource: {
|
|
511
|
+
kind: "buffer",
|
|
512
|
+
value: {
|
|
513
|
+
buffer: paletteBuffer,
|
|
514
|
+
offset: 0,
|
|
515
|
+
size: paletteWindowBytes
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}))
|
|
519
|
+
];
|
|
520
|
+
}
|
|
521
|
+
function pbrSkinMeshDynamicOffsets(meshOffset, paletteOffset) {
|
|
522
|
+
return [meshOffset, paletteOffset, paletteOffset];
|
|
523
|
+
}
|
|
910
524
|
var SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET = "";
|
|
911
|
-
function createHdrpBindGroupLayoutDescriptor(
|
|
912
|
-
const meshBufType =
|
|
913
|
-
const clusterBufType =
|
|
525
|
+
function createHdrpBindGroupLayoutDescriptor() {
|
|
526
|
+
const meshBufType = "read-only-storage";
|
|
527
|
+
const clusterBufType = "read-only-storage";
|
|
914
528
|
return {
|
|
915
529
|
label: "hdrp-unified-bgl-group2",
|
|
916
530
|
entries: [
|
|
917
531
|
{
|
|
918
532
|
binding: 0,
|
|
919
|
-
|
|
533
|
+
// Standard fragment lighting (transmission/refraction and clustered
|
|
534
|
+
// evaluation) reads the same mesh transform window as the vertex
|
|
535
|
+
// stage. Keep this visibility in the HDRP descriptor aligned with
|
|
536
|
+
// the URP mesh-array descriptor; restricting it to vertex makes the
|
|
537
|
+
// HDRP pipeline invalid when fs_main accesses `meshes[0]`.
|
|
538
|
+
visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
|
|
920
539
|
buffer: { type: meshBufType, hasDynamicOffset: true }
|
|
921
540
|
},
|
|
922
541
|
// Bindings 1 and 2 stay absent for the URP physical isolation gap.
|
|
@@ -953,6 +572,31 @@ function createHdrpBindGroupLayoutDescriptor(storageBuffer = true) {
|
|
|
953
572
|
]
|
|
954
573
|
};
|
|
955
574
|
}
|
|
575
|
+
function createHdrpSkinBindGroupLayoutDescriptor() {
|
|
576
|
+
const base = createHdrpBindGroupLayoutDescriptor();
|
|
577
|
+
const baseEntries = base.entries;
|
|
578
|
+
if (baseEntries === void 0 || baseEntries[0] === void 0) {
|
|
579
|
+
throw new Error("HDRP base group(2) layout must declare mesh binding 0");
|
|
580
|
+
}
|
|
581
|
+
const paletteType = "read-only-storage";
|
|
582
|
+
return {
|
|
583
|
+
label: "hdrp-skin-unified-bgl-group2",
|
|
584
|
+
entries: [
|
|
585
|
+
baseEntries[0],
|
|
586
|
+
{
|
|
587
|
+
binding: 1,
|
|
588
|
+
visibility: GPU_SHADER_STAGE_VERTEX,
|
|
589
|
+
buffer: { type: paletteType, hasDynamicOffset: true }
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
binding: 2,
|
|
593
|
+
visibility: GPU_SHADER_STAGE_VERTEX,
|
|
594
|
+
buffer: { type: paletteType, hasDynamicOffset: true }
|
|
595
|
+
},
|
|
596
|
+
...baseEntries.slice(1)
|
|
597
|
+
]
|
|
598
|
+
};
|
|
599
|
+
}
|
|
956
600
|
function resolveMaterialParamSchema(spec, options) {
|
|
957
601
|
if (options.materialParamSchema !== void 0) return options.materialParamSchema;
|
|
958
602
|
if (options.registry !== void 0) {
|
|
@@ -1017,6 +661,11 @@ function buildBindGroupLayoutDescriptor(spec, options) {
|
|
|
1017
661
|
binding: 1,
|
|
1018
662
|
visibility: GPU_SHADER_STAGE_VERTEX,
|
|
1019
663
|
buffer: { type: meshBufType, hasDynamicOffset: true }
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
binding: 2,
|
|
667
|
+
visibility: GPU_SHADER_STAGE_VERTEX,
|
|
668
|
+
buffer: { type: meshBufType, hasDynamicOffset: true }
|
|
1020
669
|
}
|
|
1021
670
|
]
|
|
1022
671
|
};
|
|
@@ -1039,8 +688,7 @@ function buildBindGroupLayoutDescriptor(spec, options) {
|
|
|
1039
688
|
};
|
|
1040
689
|
}
|
|
1041
690
|
case "hdrp-7-slot": {
|
|
1042
|
-
const
|
|
1043
|
-
const desc = createHdrpBindGroupLayoutDescriptor(caps.storageBuffer);
|
|
691
|
+
const desc = createHdrpBindGroupLayoutDescriptor();
|
|
1044
692
|
return {
|
|
1045
693
|
label: desc.label ?? "hdrp-unified-bgl-group2",
|
|
1046
694
|
entries: [...desc.entries ?? []]
|
|
@@ -1131,8 +779,6 @@ function buildFullscreenPostInputEntries(spec) {
|
|
|
1131
779
|
}
|
|
1132
780
|
];
|
|
1133
781
|
}
|
|
1134
|
-
|
|
1135
|
-
// src/pipeline-spec.ts
|
|
1136
782
|
var DEFERRED_COLOR_FORMATS = [
|
|
1137
783
|
"rgba16float",
|
|
1138
784
|
"rgba8unorm",
|
|
@@ -1230,6 +876,24 @@ function variantSetFromVertexLayoutProjection(projection, authoredVariantSet) {
|
|
|
1230
876
|
parts.push(axis);
|
|
1231
877
|
return ok(parts.join("+"));
|
|
1232
878
|
}
|
|
879
|
+
function standardCapabilityVariantSet(clustered, storageBuffer, vertexColorAvailable) {
|
|
880
|
+
if (clustered && storageBuffer && vertexColorAvailable) return "";
|
|
881
|
+
return `CLUSTER_FORWARD_AVAILABLE=${clustered}+STORAGE_BUFFER_AVAILABLE=${storageBuffer}`;
|
|
882
|
+
}
|
|
883
|
+
function standardTopologyVariantSet(topology, storageBuffer, vertexColorAvailable) {
|
|
884
|
+
return standardCapabilityVariantSet(
|
|
885
|
+
topology?.kind === "clustered",
|
|
886
|
+
storageBuffer,
|
|
887
|
+
vertexColorAvailable
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
function standardTopologyBindGroupReady(topology, clusterBindGroup) {
|
|
891
|
+
return topology?.kind !== "clustered" || clusterBindGroup !== null && clusterBindGroup !== void 0;
|
|
892
|
+
}
|
|
893
|
+
function standardStorageVariantSet(storageBuffer, vertexColorAvailable) {
|
|
894
|
+
if (storageBuffer && vertexColorAvailable) return "";
|
|
895
|
+
return `STORAGE_BUFFER_AVAILABLE=${storageBuffer}+VERTEX_COLOR_AVAILABLE=${vertexColorAvailable}`;
|
|
896
|
+
}
|
|
1233
897
|
function buildPipelineDescriptor(spec, modules) {
|
|
1234
898
|
const { attachments, geometry, renderState } = spec;
|
|
1235
899
|
const vertexBuffers = geometry.vertexLayoutProjection === void 0 ? deriveVertexBufferLayout(geometry.vertexLayout, {
|
|
@@ -1552,7 +1216,7 @@ var TRI_GEOMETRY_PBR = {
|
|
|
1552
1216
|
vertexLayout: PROCEDURAL_ATTR_LAYOUT,
|
|
1553
1217
|
shaderUvSetCount: 8
|
|
1554
1218
|
};
|
|
1555
|
-
var
|
|
1219
|
+
var STANDARD_BOOT_VARIANT_SET = standardCapabilityVariantSet(false, true, false);
|
|
1556
1220
|
function buildSpecConstTable(ldrViewFormat) {
|
|
1557
1221
|
const TRI_ATTACHMENTS_LDR_S1 = {
|
|
1558
1222
|
colorFormats: [ldrViewFormat],
|
|
@@ -1631,19 +1295,19 @@ function buildSpecConstTable(ldrViewFormat) {
|
|
|
1631
1295
|
geometry: TRI_GEOMETRY_PBR,
|
|
1632
1296
|
renderState: void 0
|
|
1633
1297
|
},
|
|
1634
|
-
// ── M6 fix-up:
|
|
1635
|
-
//
|
|
1636
|
-
// `variantSet=
|
|
1298
|
+
// ── M6 fix-up: non-clustered standard-pbr prewarm ─────────────────────────
|
|
1299
|
+
// The default record path (`getMaterialShaderPipeline`) requests
|
|
1300
|
+
// `variantSet=STANDARD_BOOT_VARIANT_SET` for standard-shading entities; pre-M6
|
|
1637
1301
|
// the silent `selectStandardFallbackPipeline` shim served the no-variant
|
|
1638
1302
|
// boot prewarm during the 1-frame async-compile warmup. With M6's
|
|
1639
|
-
// explicit-failure surface, those
|
|
1303
|
+
// explicit-failure surface, those requests must hit the boot prewarm
|
|
1640
1304
|
// by their own variantSet — these 4 entries close that gap.
|
|
1641
1305
|
// standard PBR URP LDR S1
|
|
1642
1306
|
{
|
|
1643
1307
|
shader: {
|
|
1644
1308
|
id: "forgeax::default-standard-pbr",
|
|
1645
1309
|
passKind: "forward",
|
|
1646
|
-
variantSet:
|
|
1310
|
+
variantSet: STANDARD_BOOT_VARIANT_SET
|
|
1647
1311
|
},
|
|
1648
1312
|
attachments: TRI_ATTACHMENTS_LDR_S1,
|
|
1649
1313
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -1654,7 +1318,7 @@ function buildSpecConstTable(ldrViewFormat) {
|
|
|
1654
1318
|
shader: {
|
|
1655
1319
|
id: "forgeax::default-standard-pbr",
|
|
1656
1320
|
passKind: "forward",
|
|
1657
|
-
variantSet:
|
|
1321
|
+
variantSet: STANDARD_BOOT_VARIANT_SET
|
|
1658
1322
|
},
|
|
1659
1323
|
attachments: TRI_ATTACHMENTS_LDR_S4,
|
|
1660
1324
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -1665,7 +1329,7 @@ function buildSpecConstTable(ldrViewFormat) {
|
|
|
1665
1329
|
shader: {
|
|
1666
1330
|
id: "forgeax::default-standard-pbr",
|
|
1667
1331
|
passKind: "forward",
|
|
1668
|
-
variantSet:
|
|
1332
|
+
variantSet: STANDARD_BOOT_VARIANT_SET
|
|
1669
1333
|
},
|
|
1670
1334
|
attachments: TRI_ATTACHMENTS_HDR_S1,
|
|
1671
1335
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -1676,7 +1340,7 @@ function buildSpecConstTable(ldrViewFormat) {
|
|
|
1676
1340
|
shader: {
|
|
1677
1341
|
id: "forgeax::default-standard-pbr",
|
|
1678
1342
|
passKind: "forward",
|
|
1679
|
-
variantSet:
|
|
1343
|
+
variantSet: STANDARD_BOOT_VARIANT_SET
|
|
1680
1344
|
},
|
|
1681
1345
|
attachments: TRI_ATTACHMENTS_HDR_S4,
|
|
1682
1346
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -2102,7 +1766,8 @@ var UNIFORM_BYTES = 256;
|
|
|
2102
1766
|
var fallbackCache = /* @__PURE__ */ new WeakMap();
|
|
2103
1767
|
function getOrCreateSsaoFallbackTexture(runtime) {
|
|
2104
1768
|
const cached = fallbackCache.get(runtime);
|
|
2105
|
-
if (cached !== void 0) return cached;
|
|
1769
|
+
if (cached !== void 0 && cached.device === runtime.device) return cached;
|
|
1770
|
+
if (cached !== void 0) fallbackCache.delete(runtime);
|
|
2106
1771
|
const device = runtime.device;
|
|
2107
1772
|
const texRes = device.createTexture({
|
|
2108
1773
|
label: "hdrp-ssao-fallback-white",
|
|
@@ -2161,6 +1826,7 @@ function getOrCreateSsaoFallbackTexture(runtime) {
|
|
|
2161
1826
|
return null;
|
|
2162
1827
|
}
|
|
2163
1828
|
const resources = {
|
|
1829
|
+
device,
|
|
2164
1830
|
texture: texRes.value,
|
|
2165
1831
|
view: viewRes.value,
|
|
2166
1832
|
sampler: samplerRes.value
|
|
@@ -2171,7 +1837,8 @@ function getOrCreateSsaoFallbackTexture(runtime) {
|
|
|
2171
1837
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
2172
1838
|
function getOrCreateSsaoBuffers(runtime) {
|
|
2173
1839
|
const cached = cache.get(runtime);
|
|
2174
|
-
if (cached !== void 0) return cached;
|
|
1840
|
+
if (cached !== void 0 && cached.device === runtime.device) return cached;
|
|
1841
|
+
if (cached !== void 0) cache.delete(runtime);
|
|
2175
1842
|
const device = runtime.device;
|
|
2176
1843
|
const kernelSamples = generateSsaoKernel();
|
|
2177
1844
|
const kernelData = new Float32Array(SSAO_KERNEL_SAMPLE_COUNT * 4);
|
|
@@ -2244,6 +1911,7 @@ function getOrCreateSsaoBuffers(runtime) {
|
|
|
2244
1911
|
return null;
|
|
2245
1912
|
}
|
|
2246
1913
|
const buffers = {
|
|
1914
|
+
device,
|
|
2247
1915
|
kernelBuffer: kernelBufferRes.value,
|
|
2248
1916
|
kernelBytes: SSAO_KERNEL_SAMPLE_COUNT * BYTES_PER_KERNEL_ELEMENT,
|
|
2249
1917
|
noiseTexture: noiseTexRes.value,
|
|
@@ -2255,7 +1923,6 @@ function getOrCreateSsaoBuffers(runtime) {
|
|
|
2255
1923
|
}
|
|
2256
1924
|
|
|
2257
1925
|
// src/hdrp-buffers.ts
|
|
2258
|
-
var HDRP_UNIFORM_LIGHT_CAPACITY = 128;
|
|
2259
1926
|
function createHdrpClusterMembershipBindGroupLayoutDescriptor() {
|
|
2260
1927
|
return {
|
|
2261
1928
|
label: "hdrp-cluster-membership-bgl",
|
|
@@ -2285,46 +1952,67 @@ function createHdrpClusterMembershipBindGroupLayoutDescriptor() {
|
|
|
2285
1952
|
}
|
|
2286
1953
|
var cache2 = /* @__PURE__ */ new WeakMap();
|
|
2287
1954
|
function getOrCreateHdrpBuffers(runtime, grid = DEFAULT_CLUSTER_GRID) {
|
|
1955
|
+
if (runtime.device.caps?.storageBuffer !== true) return null;
|
|
1956
|
+
const deviceSurface = runtime.device;
|
|
1957
|
+
if (typeof deviceSurface.createBuffer !== "function" || typeof deviceSurface.createBindGroupLayout !== "function" || typeof deviceSurface.destroyBuffer !== "function") {
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
2288
1960
|
const cached = cache2.get(runtime);
|
|
2289
|
-
if (cached !== void 0
|
|
1961
|
+
if (cached !== void 0 && cached.device === runtime.device) {
|
|
1962
|
+
const requestedCells = grid.x * grid.y * grid.z;
|
|
1963
|
+
const cachedCells = cached.grid.x * cached.grid.y * cached.grid.z;
|
|
1964
|
+
if (requestedCells <= cachedCells) return cached;
|
|
1965
|
+
}
|
|
2290
1966
|
const device = runtime.device;
|
|
2291
|
-
const storageBuffer = runtime.device.caps?.storageBuffer === true;
|
|
2292
1967
|
const clusterUniformBytes = 32;
|
|
2293
|
-
const lightDataBytes =
|
|
1968
|
+
const lightDataBytes = MAX_LIGHTS * BYTES_PER_LIGHT_SLOT;
|
|
2294
1969
|
const clusterCells = grid.x * grid.y * grid.z;
|
|
2295
|
-
const clusterGridBytes =
|
|
2296
|
-
const lightIndexListBytes =
|
|
1970
|
+
const clusterGridBytes = clusterCells * CLUSTER_GRID_STRIDE_U32 * 4;
|
|
1971
|
+
const lightIndexListBytes = LIGHT_INDEX_LIST_CAPACITY * 4;
|
|
2297
1972
|
const lightBoundsBytes = MAX_LIGHTS * 6 * 4;
|
|
1973
|
+
const created = [];
|
|
1974
|
+
const releaseCreated = () => {
|
|
1975
|
+
for (const buffer of created) {
|
|
1976
|
+
const result = device.destroyBuffer(buffer);
|
|
1977
|
+
if (!result.ok) runtime.errorRegistry.fire(result.error);
|
|
1978
|
+
}
|
|
1979
|
+
created.length = 0;
|
|
1980
|
+
};
|
|
1981
|
+
const failAllocation = (error) => {
|
|
1982
|
+
runtime.errorRegistry.fire(error);
|
|
1983
|
+
releaseCreated();
|
|
1984
|
+
return null;
|
|
1985
|
+
};
|
|
2298
1986
|
const lightData = device.createBuffer({
|
|
2299
1987
|
label: "hdrp-light-data",
|
|
2300
1988
|
size: lightDataBytes,
|
|
2301
|
-
usage:
|
|
1989
|
+
usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
|
|
2302
1990
|
mappedAtCreation: false
|
|
2303
1991
|
});
|
|
2304
1992
|
if (!lightData.ok) {
|
|
2305
|
-
|
|
2306
|
-
return null;
|
|
1993
|
+
return failAllocation(lightData.error);
|
|
2307
1994
|
}
|
|
1995
|
+
created.push(lightData.value);
|
|
2308
1996
|
const clusterGrid = device.createBuffer({
|
|
2309
1997
|
label: "hdrp-cluster-grid",
|
|
2310
1998
|
size: clusterGridBytes,
|
|
2311
|
-
usage:
|
|
1999
|
+
usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
|
|
2312
2000
|
mappedAtCreation: false
|
|
2313
2001
|
});
|
|
2314
2002
|
if (!clusterGrid.ok) {
|
|
2315
|
-
|
|
2316
|
-
return null;
|
|
2003
|
+
return failAllocation(clusterGrid.error);
|
|
2317
2004
|
}
|
|
2005
|
+
created.push(clusterGrid.value);
|
|
2318
2006
|
const lightIndexList = device.createBuffer({
|
|
2319
2007
|
label: "hdrp-light-index-list",
|
|
2320
2008
|
size: lightIndexListBytes,
|
|
2321
|
-
usage:
|
|
2009
|
+
usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
|
|
2322
2010
|
mappedAtCreation: false
|
|
2323
2011
|
});
|
|
2324
2012
|
if (!lightIndexList.ok) {
|
|
2325
|
-
|
|
2326
|
-
return null;
|
|
2013
|
+
return failAllocation(lightIndexList.error);
|
|
2327
2014
|
}
|
|
2015
|
+
created.push(lightIndexList.value);
|
|
2328
2016
|
const clusterUniform = device.createBuffer({
|
|
2329
2017
|
label: "hdrp-cluster-uniform",
|
|
2330
2018
|
size: clusterUniformBytes,
|
|
@@ -2332,29 +2020,25 @@ function getOrCreateHdrpBuffers(runtime, grid = DEFAULT_CLUSTER_GRID) {
|
|
|
2332
2020
|
mappedAtCreation: false
|
|
2333
2021
|
});
|
|
2334
2022
|
if (!clusterUniform.ok) {
|
|
2335
|
-
|
|
2336
|
-
return null;
|
|
2023
|
+
return failAllocation(clusterUniform.error);
|
|
2337
2024
|
}
|
|
2025
|
+
created.push(clusterUniform.value);
|
|
2338
2026
|
const lightBounds = device.createBuffer({
|
|
2339
2027
|
label: "hdrp-light-bounds",
|
|
2340
2028
|
size: lightBoundsBytes,
|
|
2341
|
-
usage:
|
|
2029
|
+
usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
|
|
2342
2030
|
mappedAtCreation: false
|
|
2343
2031
|
});
|
|
2344
2032
|
if (!lightBounds.ok) {
|
|
2345
|
-
|
|
2346
|
-
return null;
|
|
2033
|
+
return failAllocation(lightBounds.error);
|
|
2347
2034
|
}
|
|
2348
|
-
|
|
2349
|
-
const unifiedBglRes = device.createBindGroupLayout(
|
|
2350
|
-
createHdrpBindGroupLayoutDescriptor(storageBufferCap)
|
|
2351
|
-
);
|
|
2035
|
+
created.push(lightBounds.value);
|
|
2036
|
+
const unifiedBglRes = device.createBindGroupLayout(createHdrpBindGroupLayoutDescriptor());
|
|
2352
2037
|
if (!unifiedBglRes.ok) {
|
|
2353
|
-
|
|
2354
|
-
return null;
|
|
2038
|
+
return failAllocation(unifiedBglRes.error);
|
|
2355
2039
|
}
|
|
2356
2040
|
const buffers = {
|
|
2357
|
-
|
|
2041
|
+
device,
|
|
2358
2042
|
lightDataBuffer: lightData.value,
|
|
2359
2043
|
lightDataBytes,
|
|
2360
2044
|
clusterGridBuffer: clusterGrid.value,
|
|
@@ -2369,261 +2053,647 @@ function getOrCreateHdrpBuffers(runtime, grid = DEFAULT_CLUSTER_GRID) {
|
|
|
2369
2053
|
unifiedBindGroupLayout: unifiedBglRes.value
|
|
2370
2054
|
};
|
|
2371
2055
|
cache2.set(runtime, buffers);
|
|
2056
|
+
if (cached !== void 0) {
|
|
2057
|
+
retireHdrpBuffers(runtime, cached);
|
|
2058
|
+
}
|
|
2372
2059
|
return buffers;
|
|
2373
2060
|
}
|
|
2374
|
-
function
|
|
2061
|
+
function resetHdrpBuffers(runtime) {
|
|
2062
|
+
const cached = cache2.get(runtime);
|
|
2063
|
+
if (cached === void 0) return;
|
|
2064
|
+
cache2.delete(runtime);
|
|
2065
|
+
retireHdrpBuffers(runtime, cached);
|
|
2066
|
+
}
|
|
2067
|
+
function retireHdrpBuffers(runtime, buffers) {
|
|
2068
|
+
const device = buffers.device;
|
|
2069
|
+
const destroy = () => {
|
|
2070
|
+
for (const buffer of [
|
|
2071
|
+
buffers.lightDataBuffer,
|
|
2072
|
+
buffers.clusterGridBuffer,
|
|
2073
|
+
buffers.lightIndexListBuffer,
|
|
2074
|
+
buffers.clusterUniformBuffer,
|
|
2075
|
+
buffers.lightBoundsBuffer
|
|
2076
|
+
]) {
|
|
2077
|
+
const result = device.destroyBuffer(buffer);
|
|
2078
|
+
if (!result.ok) runtime.errorRegistry.fire(result.error);
|
|
2079
|
+
}
|
|
2080
|
+
};
|
|
2081
|
+
const queue = device.queue;
|
|
2082
|
+
if (typeof queue.onSubmittedWorkDone === "function") {
|
|
2083
|
+
queue.onSubmittedWorkDone().then(destroy, destroy);
|
|
2084
|
+
} else {
|
|
2085
|
+
destroy();
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
function packClusterUniform(grid, near, far, ssaoIntensity = 0, lightCount = 0) {
|
|
2375
2089
|
const buf = new ArrayBuffer(32);
|
|
2376
2090
|
const u32 = new Uint32Array(buf);
|
|
2377
2091
|
const f32 = new Float32Array(buf);
|
|
2378
2092
|
u32[0] = grid.x >>> 0;
|
|
2379
2093
|
u32[1] = grid.y >>> 0;
|
|
2380
2094
|
u32[2] = grid.z >>> 0;
|
|
2381
|
-
u32[3] = Math.min(Math.max(lightCount, 0),
|
|
2095
|
+
u32[3] = Math.min(Math.max(lightCount, 0), MAX_LIGHTS) >>> 0;
|
|
2382
2096
|
f32[4] = near;
|
|
2383
2097
|
f32[5] = far;
|
|
2384
2098
|
f32[6] = near > 0 && far > near ? Math.log(far / near) : 0;
|
|
2385
2099
|
f32[7] = ssaoIntensity;
|
|
2386
2100
|
return buf;
|
|
2387
2101
|
}
|
|
2388
|
-
function createHdrpUnifiedBindGroup(runtime, hdrpBuffers, meshStorageBuffer, ssaoOptions = { enabled: false }) {
|
|
2389
|
-
const fallback = getOrCreateSsaoFallbackTexture(runtime);
|
|
2390
|
-
if (fallback === null) return null;
|
|
2391
|
-
const ssaoTexView = ssaoOptions.enabled ? ssaoOptions.ssaoBlurredView : fallback.view;
|
|
2392
|
-
const ssaoSampler = fallback.sampler;
|
|
2102
|
+
function createHdrpUnifiedBindGroup(runtime, hdrpBuffers, meshStorageBuffer, ssaoOptions = { enabled: false }) {
|
|
2103
|
+
const fallback = getOrCreateSsaoFallbackTexture(runtime);
|
|
2104
|
+
if (fallback === null) return null;
|
|
2105
|
+
const ssaoTexView = ssaoOptions.enabled ? ssaoOptions.ssaoBlurredView : fallback.view;
|
|
2106
|
+
const ssaoSampler = fallback.sampler;
|
|
2107
|
+
const result = runtime.device.createBindGroup({
|
|
2108
|
+
label: "hdrp-unified-bg-group2",
|
|
2109
|
+
layout: hdrpBuffers.unifiedBindGroupLayout,
|
|
2110
|
+
entries: [
|
|
2111
|
+
{
|
|
2112
|
+
binding: 0,
|
|
2113
|
+
resource: {
|
|
2114
|
+
kind: "buffer",
|
|
2115
|
+
value: {
|
|
2116
|
+
buffer: meshStorageBuffer,
|
|
2117
|
+
offset: 0,
|
|
2118
|
+
size: MESH_PER_ENTITY_STRIDE
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
},
|
|
2122
|
+
{
|
|
2123
|
+
binding: 3,
|
|
2124
|
+
resource: {
|
|
2125
|
+
kind: "buffer",
|
|
2126
|
+
value: { buffer: hdrpBuffers.lightDataBuffer }
|
|
2127
|
+
}
|
|
2128
|
+
},
|
|
2129
|
+
{
|
|
2130
|
+
binding: 4,
|
|
2131
|
+
resource: {
|
|
2132
|
+
kind: "buffer",
|
|
2133
|
+
value: { buffer: hdrpBuffers.clusterGridBuffer }
|
|
2134
|
+
}
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
binding: 5,
|
|
2138
|
+
resource: {
|
|
2139
|
+
kind: "buffer",
|
|
2140
|
+
value: { buffer: hdrpBuffers.lightIndexListBuffer }
|
|
2141
|
+
}
|
|
2142
|
+
},
|
|
2143
|
+
{
|
|
2144
|
+
binding: 6,
|
|
2145
|
+
resource: {
|
|
2146
|
+
kind: "buffer",
|
|
2147
|
+
value: { buffer: hdrpBuffers.clusterUniformBuffer }
|
|
2148
|
+
}
|
|
2149
|
+
},
|
|
2150
|
+
{
|
|
2151
|
+
binding: 7,
|
|
2152
|
+
resource: { kind: "textureView", value: ssaoTexView }
|
|
2153
|
+
},
|
|
2154
|
+
{
|
|
2155
|
+
binding: 8,
|
|
2156
|
+
resource: { kind: "sampler", value: ssaoSampler }
|
|
2157
|
+
}
|
|
2158
|
+
]
|
|
2159
|
+
});
|
|
2160
|
+
if (!result.ok) {
|
|
2161
|
+
runtime.errorRegistry.fire(result.error);
|
|
2162
|
+
return null;
|
|
2163
|
+
}
|
|
2164
|
+
return result.value;
|
|
2165
|
+
}
|
|
2166
|
+
function createHdrpSkinUnifiedBindGroup(runtime, hdrpBuffers, layout, meshStorageBuffer, paletteBuffer, paletteBindingWindowBytes, ssaoOptions = { enabled: false }) {
|
|
2167
|
+
const fallback = getOrCreateSsaoFallbackTexture(runtime);
|
|
2168
|
+
if (fallback === null) return null;
|
|
2169
|
+
const meshSize = MESH_PER_ENTITY_STRIDE;
|
|
2170
|
+
const result = runtime.device.createBindGroup({
|
|
2171
|
+
label: "hdrp-skin-unified-bg-group2",
|
|
2172
|
+
layout,
|
|
2173
|
+
entries: [
|
|
2174
|
+
...createPbrSkinMeshBindGroupEntries(
|
|
2175
|
+
meshStorageBuffer,
|
|
2176
|
+
meshSize,
|
|
2177
|
+
paletteBuffer,
|
|
2178
|
+
paletteBindingWindowBytes
|
|
2179
|
+
),
|
|
2180
|
+
{ binding: 3, resource: { kind: "buffer", value: { buffer: hdrpBuffers.lightDataBuffer } } },
|
|
2181
|
+
{
|
|
2182
|
+
binding: 4,
|
|
2183
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.clusterGridBuffer } }
|
|
2184
|
+
},
|
|
2185
|
+
{
|
|
2186
|
+
binding: 5,
|
|
2187
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.lightIndexListBuffer } }
|
|
2188
|
+
},
|
|
2189
|
+
{
|
|
2190
|
+
binding: 6,
|
|
2191
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.clusterUniformBuffer } }
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
binding: 7,
|
|
2195
|
+
resource: {
|
|
2196
|
+
kind: "textureView",
|
|
2197
|
+
value: ssaoOptions.enabled ? ssaoOptions.ssaoBlurredView : fallback.view
|
|
2198
|
+
}
|
|
2199
|
+
},
|
|
2200
|
+
{ binding: 8, resource: { kind: "sampler", value: fallback.sampler } }
|
|
2201
|
+
]
|
|
2202
|
+
});
|
|
2203
|
+
if (!result.ok) {
|
|
2204
|
+
runtime.errorRegistry.fire(result.error);
|
|
2205
|
+
return null;
|
|
2206
|
+
}
|
|
2207
|
+
return result.value;
|
|
2208
|
+
}
|
|
2209
|
+
function createHdrpClusterMembershipBindGroup(runtime, hdrpBuffers, layout) {
|
|
2393
2210
|
const result = runtime.device.createBindGroup({
|
|
2394
|
-
label: "hdrp-
|
|
2395
|
-
layout
|
|
2211
|
+
label: "hdrp-cluster-membership-bg",
|
|
2212
|
+
layout,
|
|
2396
2213
|
entries: [
|
|
2397
2214
|
{
|
|
2398
2215
|
binding: 0,
|
|
2399
|
-
resource: {
|
|
2400
|
-
kind: "buffer",
|
|
2401
|
-
value: {
|
|
2402
|
-
buffer: meshStorageBuffer,
|
|
2403
|
-
offset: 0,
|
|
2404
|
-
size: hdrpBuffers.storageBuffer ? MESH_PER_ENTITY_STRIDE : MESH_UBO_FULL_ARRAY_BYTES
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2216
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.clusterGridBuffer } }
|
|
2407
2217
|
},
|
|
2408
2218
|
{
|
|
2409
|
-
binding:
|
|
2410
|
-
resource: {
|
|
2411
|
-
kind: "buffer",
|
|
2412
|
-
value: { buffer: hdrpBuffers.lightDataBuffer }
|
|
2413
|
-
}
|
|
2219
|
+
binding: 1,
|
|
2220
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.lightIndexListBuffer } }
|
|
2414
2221
|
},
|
|
2415
2222
|
{
|
|
2416
|
-
binding:
|
|
2417
|
-
resource: {
|
|
2418
|
-
|
|
2419
|
-
|
|
2223
|
+
binding: 2,
|
|
2224
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.clusterUniformBuffer } }
|
|
2225
|
+
},
|
|
2226
|
+
{
|
|
2227
|
+
binding: 3,
|
|
2228
|
+
resource: { kind: "buffer", value: { buffer: hdrpBuffers.lightBoundsBuffer } }
|
|
2229
|
+
}
|
|
2230
|
+
]
|
|
2231
|
+
});
|
|
2232
|
+
if (!result.ok) {
|
|
2233
|
+
runtime.errorRegistry.fire(result.error);
|
|
2234
|
+
return null;
|
|
2235
|
+
}
|
|
2236
|
+
return result.value;
|
|
2237
|
+
}
|
|
2238
|
+
function runClusterBinProfilePhase(runner, phase, action) {
|
|
2239
|
+
return action() ;
|
|
2240
|
+
}
|
|
2241
|
+
function createClusterBinScratch() {
|
|
2242
|
+
return {
|
|
2243
|
+
clusterCounts: new Uint32Array(0),
|
|
2244
|
+
clusterCursors: new Uint32Array(0),
|
|
2245
|
+
lightBounds: new Int32Array(0),
|
|
2246
|
+
clusterDeltas: new Int32Array(0),
|
|
2247
|
+
aabbOutput: {
|
|
2248
|
+
min: vec3.create(0, 0, 0),
|
|
2249
|
+
max: vec3.create(0, 0, 0)
|
|
2250
|
+
},
|
|
2251
|
+
boundsOutput: {
|
|
2252
|
+
min: { x: 0, y: 0, z: 0 },
|
|
2253
|
+
max: { x: 0, y: 0, z: 0 }
|
|
2254
|
+
}
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
function ensureScratchCapacity(scratch, clusterCount, lightCount, gridX, gridY, gridZ) {
|
|
2258
|
+
if (scratch.clusterCounts.length < clusterCount) {
|
|
2259
|
+
scratch.clusterCounts = new Uint32Array(clusterCount);
|
|
2260
|
+
scratch.clusterCursors = new Uint32Array(clusterCount);
|
|
2261
|
+
}
|
|
2262
|
+
if (scratch.lightBounds.length < lightCount * 6) {
|
|
2263
|
+
scratch.lightBounds = new Int32Array(lightCount * 6);
|
|
2264
|
+
}
|
|
2265
|
+
const differenceVolumeSize = (gridX + 1) * (gridY + 1) * (gridZ + 1);
|
|
2266
|
+
if (scratch.clusterDeltas.length < differenceVolumeSize) {
|
|
2267
|
+
scratch.clusterDeltas = new Int32Array(differenceVolumeSize);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
function deriveCullingRadius(range, intensity, threshold = 1e-3) {
|
|
2271
|
+
if (Number.isFinite(range)) {
|
|
2272
|
+
return Math.max(0, range);
|
|
2273
|
+
}
|
|
2274
|
+
const derived = Math.sqrt(intensity / threshold);
|
|
2275
|
+
return Math.min(derived, 1e3);
|
|
2276
|
+
}
|
|
2277
|
+
function viewZToZSlice(viewZ, gridZ, near, far) {
|
|
2278
|
+
if (viewZ >= -near) {
|
|
2279
|
+
return 0;
|
|
2280
|
+
}
|
|
2281
|
+
const logFarOverNear = Math.log(far / near);
|
|
2282
|
+
const slice = Math.floor(Math.log(-viewZ / near) / logFarOverNear * gridZ);
|
|
2283
|
+
if (slice < 0) return 0;
|
|
2284
|
+
if (slice >= gridZ) return gridZ - 1;
|
|
2285
|
+
return slice;
|
|
2286
|
+
}
|
|
2287
|
+
function clusterSpaceObjectAabb(center, radius, view, proj, output) {
|
|
2288
|
+
const result = output ?? {
|
|
2289
|
+
min: vec3.create(0, 0, 0),
|
|
2290
|
+
max: vec3.create(0, 0, 0)
|
|
2291
|
+
};
|
|
2292
|
+
const cx = center[0] ?? 0;
|
|
2293
|
+
const cy = center[1] ?? 0;
|
|
2294
|
+
const cz = center[2] ?? 0;
|
|
2295
|
+
const v00 = view[0] ?? 0;
|
|
2296
|
+
const v01 = view[1] ?? 0;
|
|
2297
|
+
const v02 = view[2] ?? 0;
|
|
2298
|
+
const v10 = view[4] ?? 0;
|
|
2299
|
+
const v11 = view[5] ?? 0;
|
|
2300
|
+
const v12 = view[6] ?? 0;
|
|
2301
|
+
const v20 = view[8] ?? 0;
|
|
2302
|
+
const v21 = view[9] ?? 0;
|
|
2303
|
+
const v22 = view[10] ?? 0;
|
|
2304
|
+
const v30 = view[12] ?? 0;
|
|
2305
|
+
const v31 = view[13] ?? 0;
|
|
2306
|
+
const v32 = view[14] ?? 0;
|
|
2307
|
+
const vx = v00 * cx + v10 * cy + v20 * cz + v30;
|
|
2308
|
+
const vy = v01 * cx + v11 * cy + v21 * cz + v31;
|
|
2309
|
+
const vz = v02 * cx + v12 * cy + v22 * cz + v32;
|
|
2310
|
+
const viewScaleX = Math.hypot(v00, v01, v02);
|
|
2311
|
+
const viewScaleY = Math.hypot(v10, v11, v12);
|
|
2312
|
+
const viewScaleZ = Math.hypot(v20, v21, v22);
|
|
2313
|
+
const rx = radius * viewScaleX;
|
|
2314
|
+
const ry = radius * viewScaleY;
|
|
2315
|
+
const rz = radius * viewScaleZ;
|
|
2316
|
+
const vMinX = vx - rx;
|
|
2317
|
+
const vMaxX = vx + rx;
|
|
2318
|
+
const vMinY = vy - ry;
|
|
2319
|
+
const vMaxY = vy + ry;
|
|
2320
|
+
const vMinZ = vz - rz;
|
|
2321
|
+
const vMaxZ = vz + rz;
|
|
2322
|
+
const minViewZ = vMinZ;
|
|
2323
|
+
const maxViewZ = Math.min(vMaxZ, -1e-5);
|
|
2324
|
+
if (minViewZ > maxViewZ) {
|
|
2325
|
+
result.min[0] = 1;
|
|
2326
|
+
result.min[1] = 1;
|
|
2327
|
+
result.min[2] = -1e-5;
|
|
2328
|
+
result.max[0] = -1;
|
|
2329
|
+
result.max[1] = -1;
|
|
2330
|
+
result.max[2] = -1e-5;
|
|
2331
|
+
return result;
|
|
2332
|
+
}
|
|
2333
|
+
let ndcMinX = Infinity;
|
|
2334
|
+
let ndcMaxX = -Infinity;
|
|
2335
|
+
let ndcMinY = Infinity;
|
|
2336
|
+
let ndcMaxY = -Infinity;
|
|
2337
|
+
const p00 = proj[0] ?? 0;
|
|
2338
|
+
const p10 = proj[4] ?? 0;
|
|
2339
|
+
const p20 = proj[8] ?? 0;
|
|
2340
|
+
const p30 = proj[12] ?? 0;
|
|
2341
|
+
const p01 = proj[1] ?? 0;
|
|
2342
|
+
const p11 = proj[5] ?? 0;
|
|
2343
|
+
const p21 = proj[9] ?? 0;
|
|
2344
|
+
const p31 = proj[13] ?? 0;
|
|
2345
|
+
const p23 = proj[11] ?? 0;
|
|
2346
|
+
const perspectiveWOnlyZ = Math.abs(proj[3] ?? 0) < 1e-8 && Math.abs(proj[7] ?? 0) < 1e-8 && Math.abs(proj[15] ?? 0) < 1e-8 && Math.abs(p23) >= 1e-5;
|
|
2347
|
+
if (perspectiveWOnlyZ) {
|
|
2348
|
+
const xExtent = Math.abs(p00) * rx + Math.abs(p10) * ry;
|
|
2349
|
+
const yExtent = Math.abs(p01) * rx + Math.abs(p11) * ry;
|
|
2350
|
+
for (let face = 0; face < 2; face++) {
|
|
2351
|
+
const zTest = face === 0 ? minViewZ : maxViewZ;
|
|
2352
|
+
if (zTest > 0) continue;
|
|
2353
|
+
const invW = 1 / (p23 * zTest);
|
|
2354
|
+
const xCenter = p20 * zTest + p30;
|
|
2355
|
+
const yCenter = p21 * zTest + p31;
|
|
2356
|
+
const x0 = (xCenter - xExtent) * invW;
|
|
2357
|
+
const x1 = (xCenter + xExtent) * invW;
|
|
2358
|
+
const y0 = (yCenter - yExtent) * invW;
|
|
2359
|
+
const y1 = (yCenter + yExtent) * invW;
|
|
2360
|
+
ndcMinX = Math.min(ndcMinX, x0, x1);
|
|
2361
|
+
ndcMaxX = Math.max(ndcMaxX, x0, x1);
|
|
2362
|
+
ndcMinY = Math.min(ndcMinY, y0, y1);
|
|
2363
|
+
ndcMaxY = Math.max(ndcMaxY, y0, y1);
|
|
2364
|
+
}
|
|
2365
|
+
} else {
|
|
2366
|
+
const corners = [
|
|
2367
|
+
[vMinX, vMinY],
|
|
2368
|
+
[vMinX, vMaxY],
|
|
2369
|
+
[vMaxX, vMinY],
|
|
2370
|
+
[vMaxX, vMaxY]
|
|
2371
|
+
];
|
|
2372
|
+
for (const zTest of [minViewZ, maxViewZ]) {
|
|
2373
|
+
if (zTest <= 0) {
|
|
2374
|
+
for (const corner of corners) {
|
|
2375
|
+
const sx = corner[0];
|
|
2376
|
+
const sy = corner[1];
|
|
2377
|
+
const ndc = projectToNdc(sx, sy, zTest, proj);
|
|
2378
|
+
ndcMinX = Math.min(ndcMinX, ndc[0]);
|
|
2379
|
+
ndcMaxX = Math.max(ndcMaxX, ndc[0]);
|
|
2380
|
+
ndcMinY = Math.min(ndcMinY, ndc[1]);
|
|
2381
|
+
ndcMaxY = Math.max(ndcMaxY, ndc[1]);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
ndcMinX = Math.max(ndcMinX, -1);
|
|
2387
|
+
ndcMinY = Math.max(ndcMinY, -1);
|
|
2388
|
+
ndcMaxX = Math.min(ndcMaxX, 1);
|
|
2389
|
+
ndcMaxY = Math.min(ndcMaxY, 1);
|
|
2390
|
+
result.min[0] = ndcMinX;
|
|
2391
|
+
result.min[1] = ndcMinY;
|
|
2392
|
+
result.min[2] = minViewZ;
|
|
2393
|
+
result.max[0] = ndcMaxX;
|
|
2394
|
+
result.max[1] = ndcMaxY;
|
|
2395
|
+
result.max[2] = maxViewZ;
|
|
2396
|
+
return result;
|
|
2397
|
+
}
|
|
2398
|
+
function projectToNdc(vx, vy, vz, proj) {
|
|
2399
|
+
const p00 = proj[0] ?? 0;
|
|
2400
|
+
const p10 = proj[4] ?? 0;
|
|
2401
|
+
const p20 = proj[8] ?? 0;
|
|
2402
|
+
const p30 = proj[12] ?? 0;
|
|
2403
|
+
const p01 = proj[1] ?? 0;
|
|
2404
|
+
const p11 = proj[5] ?? 0;
|
|
2405
|
+
const p21 = proj[9] ?? 0;
|
|
2406
|
+
const p31 = proj[13] ?? 0;
|
|
2407
|
+
const p02 = proj[2] ?? 0;
|
|
2408
|
+
const p12 = proj[6] ?? 0;
|
|
2409
|
+
const p22 = proj[10] ?? 0;
|
|
2410
|
+
const p32 = proj[14] ?? 0;
|
|
2411
|
+
const p03 = proj[3] ?? 0;
|
|
2412
|
+
const p13 = proj[7] ?? 0;
|
|
2413
|
+
const p23 = proj[11] ?? 0;
|
|
2414
|
+
const p33 = proj[15] ?? 0;
|
|
2415
|
+
const cx = p00 * vx + p10 * vy + p20 * vz + p30;
|
|
2416
|
+
const cy = p01 * vx + p11 * vy + p21 * vz + p31;
|
|
2417
|
+
const cz = p02 * vx + p12 * vy + p22 * vz + p32;
|
|
2418
|
+
const cw = p03 * vx + p13 * vy + p23 * vz + p33;
|
|
2419
|
+
if (Math.abs(cw) < 1e-10) {
|
|
2420
|
+
return [vx < 0 ? -1 : 1, vy < 0 ? -1 : 1, cz];
|
|
2421
|
+
}
|
|
2422
|
+
const invW = 1 / cw;
|
|
2423
|
+
return [cx * invW, cy * invW, cz * invW];
|
|
2424
|
+
}
|
|
2425
|
+
function ndcPositionToCluster(ndc, viewZ, gridX, gridY, gridZ, near, far) {
|
|
2426
|
+
const ndcX = ndc[0] ?? 0;
|
|
2427
|
+
const ndcY = ndc[1] ?? 0;
|
|
2428
|
+
let cx = Math.floor((ndcX * 0.5 + 0.5) * gridX);
|
|
2429
|
+
let cy = Math.floor((ndcY * 0.5 + 0.5) * gridY);
|
|
2430
|
+
if (cx < 0) cx = 0;
|
|
2431
|
+
if (cx >= gridX) cx = gridX - 1;
|
|
2432
|
+
if (cy < 0) cy = 0;
|
|
2433
|
+
if (cy >= gridY) cy = gridY - 1;
|
|
2434
|
+
const cz = viewZToZSlice(viewZ, gridZ, near, far);
|
|
2435
|
+
return { x: cx, y: cy, z: cz };
|
|
2436
|
+
}
|
|
2437
|
+
function calculateSphereClusterBounds(aabb, gridX, gridY, gridZ, near, far, output) {
|
|
2438
|
+
const result = output ?? {
|
|
2439
|
+
min: { x: 0, y: 0, z: 0 },
|
|
2440
|
+
max: { x: 0, y: 0, z: 0 }
|
|
2441
|
+
};
|
|
2442
|
+
const minZ = aabb.min[2] ?? 0;
|
|
2443
|
+
const maxZ = aabb.max[2] ?? 0;
|
|
2444
|
+
const idxMin = ndcPositionToCluster(aabb.min, minZ, gridX, gridY, gridZ, near, far);
|
|
2445
|
+
const idxMax = ndcPositionToCluster(aabb.max, maxZ, gridX, gridY, gridZ, near, far);
|
|
2446
|
+
result.min.x = Math.min(idxMin.x, idxMax.x);
|
|
2447
|
+
result.min.y = Math.min(idxMin.y, idxMax.y);
|
|
2448
|
+
result.min.z = Math.min(idxMin.z, idxMax.z);
|
|
2449
|
+
result.max.x = Math.max(idxMin.x, idxMax.x);
|
|
2450
|
+
result.max.y = Math.max(idxMin.y, idxMax.y);
|
|
2451
|
+
result.max.z = Math.max(idxMin.z, idxMax.z);
|
|
2452
|
+
return result;
|
|
2453
|
+
}
|
|
2454
|
+
function bin(lights, view, proj, grid, near, far, clusterGrid, lightIndexList, capacity, scratch, profile, options = {}) {
|
|
2455
|
+
const gridX = grid.x;
|
|
2456
|
+
const gridY = grid.y;
|
|
2457
|
+
const gridZ = grid.z;
|
|
2458
|
+
const clusterCount = gridX * gridY * gridZ;
|
|
2459
|
+
const binScratch = scratch ?? createClusterBinScratch();
|
|
2460
|
+
ensureScratchCapacity(binScratch, clusterCount, lights.length, gridX, gridY, gridZ);
|
|
2461
|
+
const { clusterCounts, clusterCursors, lightBounds, clusterDeltas } = binScratch;
|
|
2462
|
+
clusterGrid.fill(0, 0, clusterCount * 2);
|
|
2463
|
+
clusterCounts.fill(0, 0, clusterCount);
|
|
2464
|
+
let attemptedTotal = 0;
|
|
2465
|
+
runClusterBinProfilePhase(profile, "light-bounds-and-occupancy", () => {
|
|
2466
|
+
runClusterBinProfilePhase(profile, "light-bounds-and-occupancy/light-aabb", () => {
|
|
2467
|
+
for (let lightIdx = 0; lightIdx < lights.length; lightIdx++) {
|
|
2468
|
+
const boundsOffset = lightIdx * 6;
|
|
2469
|
+
lightBounds[boundsOffset] = -1;
|
|
2470
|
+
const light = lights[lightIdx];
|
|
2471
|
+
if (!light) continue;
|
|
2472
|
+
const radius = deriveCullingRadius(light.range, 1);
|
|
2473
|
+
if (radius <= 0) {
|
|
2474
|
+
continue;
|
|
2420
2475
|
}
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2476
|
+
const aabb = clusterSpaceObjectAabb(
|
|
2477
|
+
light.position,
|
|
2478
|
+
radius,
|
|
2479
|
+
view,
|
|
2480
|
+
proj,
|
|
2481
|
+
binScratch.aabbOutput
|
|
2482
|
+
);
|
|
2483
|
+
const bounds = calculateSphereClusterBounds(
|
|
2484
|
+
aabb,
|
|
2485
|
+
gridX,
|
|
2486
|
+
gridY,
|
|
2487
|
+
gridZ,
|
|
2488
|
+
near,
|
|
2489
|
+
far,
|
|
2490
|
+
binScratch.boundsOutput
|
|
2491
|
+
);
|
|
2492
|
+
if (bounds.min.x > bounds.max.x || bounds.min.y > bounds.max.y || bounds.min.z > bounds.max.z) {
|
|
2493
|
+
continue;
|
|
2427
2494
|
}
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2495
|
+
lightBounds[boundsOffset] = bounds.min.x;
|
|
2496
|
+
lightBounds[boundsOffset + 1] = bounds.min.y;
|
|
2497
|
+
lightBounds[boundsOffset + 2] = bounds.min.z;
|
|
2498
|
+
lightBounds[boundsOffset + 3] = bounds.max.x;
|
|
2499
|
+
lightBounds[boundsOffset + 4] = bounds.max.y;
|
|
2500
|
+
lightBounds[boundsOffset + 5] = bounds.max.z;
|
|
2501
|
+
}
|
|
2502
|
+
});
|
|
2503
|
+
runClusterBinProfilePhase(profile, "light-bounds-and-occupancy/cluster-occupancy", () => {
|
|
2504
|
+
const diffX = gridX + 1;
|
|
2505
|
+
const diffY = gridY + 1;
|
|
2506
|
+
const diffRow = diffX * diffY;
|
|
2507
|
+
clusterDeltas.fill(0, 0, diffRow * (gridZ + 1));
|
|
2508
|
+
const addDifference = (x, y, z, delta) => {
|
|
2509
|
+
const index = z * diffRow + y * diffX + x;
|
|
2510
|
+
clusterDeltas[index] = (clusterDeltas[index] ?? 0) + delta;
|
|
2511
|
+
};
|
|
2512
|
+
for (let lightIdx = 0; lightIdx < lights.length; lightIdx++) {
|
|
2513
|
+
const boundsOffset = lightIdx * 6;
|
|
2514
|
+
if ((lightBounds[boundsOffset] ?? -1) < 0) continue;
|
|
2515
|
+
const minX = lightBounds[boundsOffset] ?? 0;
|
|
2516
|
+
const minY = lightBounds[boundsOffset + 1] ?? 0;
|
|
2517
|
+
const minZ = lightBounds[boundsOffset + 2] ?? 0;
|
|
2518
|
+
const maxX = lightBounds[boundsOffset + 3] ?? -1;
|
|
2519
|
+
const maxY = lightBounds[boundsOffset + 4] ?? -1;
|
|
2520
|
+
const maxZ = lightBounds[boundsOffset + 5] ?? -1;
|
|
2521
|
+
const endX = maxX + 1;
|
|
2522
|
+
const endY = maxY + 1;
|
|
2523
|
+
const endZ = maxZ + 1;
|
|
2524
|
+
addDifference(minX, minY, minZ, 1);
|
|
2525
|
+
addDifference(endX, minY, minZ, -1);
|
|
2526
|
+
addDifference(minX, endY, minZ, -1);
|
|
2527
|
+
addDifference(minX, minY, endZ, -1);
|
|
2528
|
+
addDifference(endX, endY, minZ, 1);
|
|
2529
|
+
addDifference(endX, minY, endZ, 1);
|
|
2530
|
+
addDifference(minX, endY, endZ, 1);
|
|
2531
|
+
addDifference(endX, endY, endZ, -1);
|
|
2532
|
+
}
|
|
2533
|
+
for (let cz = 0; cz < gridZ; cz++) {
|
|
2534
|
+
for (let cy = 0; cy < gridY; cy++) {
|
|
2535
|
+
for (let cx = 0; cx < gridX; cx++) {
|
|
2536
|
+
const diffIdx = cz * diffRow + cy * diffX + cx;
|
|
2537
|
+
let count = clusterDeltas[diffIdx] ?? 0;
|
|
2538
|
+
if (cx > 0) count += clusterDeltas[diffIdx - 1] ?? 0;
|
|
2539
|
+
if (cy > 0) count += clusterDeltas[diffIdx - diffX] ?? 0;
|
|
2540
|
+
if (cz > 0) count += clusterDeltas[diffIdx - diffRow] ?? 0;
|
|
2541
|
+
if (cx > 0 && cy > 0) count -= clusterDeltas[diffIdx - diffX - 1] ?? 0;
|
|
2542
|
+
if (cx > 0 && cz > 0) count -= clusterDeltas[diffIdx - diffRow - 1] ?? 0;
|
|
2543
|
+
if (cy > 0 && cz > 0) count -= clusterDeltas[diffIdx - diffRow - diffX] ?? 0;
|
|
2544
|
+
if (cx > 0 && cy > 0 && cz > 0) {
|
|
2545
|
+
count += clusterDeltas[diffIdx - diffRow - diffX - 1] ?? 0;
|
|
2546
|
+
}
|
|
2547
|
+
clusterDeltas[diffIdx] = count;
|
|
2548
|
+
const clusterIdx = cz * gridY * gridX + cy * gridX + cx;
|
|
2549
|
+
clusterCounts[clusterIdx] = count;
|
|
2550
|
+
attemptedTotal += count;
|
|
2551
|
+
}
|
|
2434
2552
|
}
|
|
2435
|
-
},
|
|
2436
|
-
{
|
|
2437
|
-
binding: 7,
|
|
2438
|
-
resource: { kind: "textureView", value: ssaoTexView }
|
|
2439
|
-
},
|
|
2440
|
-
{
|
|
2441
|
-
binding: 8,
|
|
2442
|
-
resource: { kind: "sampler", value: ssaoSampler }
|
|
2443
2553
|
}
|
|
2444
|
-
|
|
2554
|
+
});
|
|
2445
2555
|
});
|
|
2446
|
-
if (
|
|
2447
|
-
|
|
2448
|
-
|
|
2556
|
+
if (attemptedTotal > capacity) {
|
|
2557
|
+
return err({
|
|
2558
|
+
code: "index-overflow",
|
|
2559
|
+
expected: `writeCount <= ${capacity}`,
|
|
2560
|
+
hint: `light index list overflow: needed ${attemptedTotal} entries, capacity ${capacity}; reduce lights, shrink grid, or shrink ranges (overrun = ${attemptedTotal - capacity})`,
|
|
2561
|
+
detail: { actual: attemptedTotal, capacity }
|
|
2562
|
+
});
|
|
2449
2563
|
}
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
},
|
|
2461
|
-
{
|
|
2462
|
-
binding: 1,
|
|
2463
|
-
resource: { kind: "buffer", value: { buffer: hdrpBuffers.lightIndexListBuffer } }
|
|
2464
|
-
},
|
|
2465
|
-
{
|
|
2466
|
-
binding: 2,
|
|
2467
|
-
resource: { kind: "buffer", value: { buffer: hdrpBuffers.clusterUniformBuffer } }
|
|
2468
|
-
},
|
|
2469
|
-
{
|
|
2470
|
-
binding: 3,
|
|
2471
|
-
resource: { kind: "buffer", value: { buffer: hdrpBuffers.lightBoundsBuffer } }
|
|
2472
|
-
}
|
|
2473
|
-
]
|
|
2564
|
+
const writeCount = runClusterBinProfilePhase(profile, "cluster-reserve", () => {
|
|
2565
|
+
let reserved = 0;
|
|
2566
|
+
for (let ci = 0; ci < clusterCount; ci++) {
|
|
2567
|
+
const base = ci * 2;
|
|
2568
|
+
clusterGrid[base] = reserved;
|
|
2569
|
+
clusterGrid[base + 1] = clusterCounts[ci] ?? 0;
|
|
2570
|
+
clusterCursors[ci] = reserved;
|
|
2571
|
+
reserved += clusterCounts[ci] ?? 0;
|
|
2572
|
+
}
|
|
2573
|
+
return reserved;
|
|
2474
2574
|
});
|
|
2475
|
-
if (
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
* before that, `isAllocated()` stays `false` and tests can assert no GPU
|
|
2511
|
-
* resources were created.
|
|
2512
|
-
*/
|
|
2513
|
-
isAllocated() {
|
|
2514
|
-
return this.texture !== null;
|
|
2515
|
-
}
|
|
2516
|
-
/**
|
|
2517
|
-
* Lazy-allocate the atlas texture + cube_array sampling view + comparison
|
|
2518
|
-
* sampler. Idempotent: subsequent calls are zero-cost no-ops once the
|
|
2519
|
-
* resources exist.
|
|
2520
|
-
*
|
|
2521
|
-
* Throws (via the RHI error registry) on allocation failure. This is the
|
|
2522
|
-
* only path that touches the GPU — keeping it inside one method makes the
|
|
2523
|
-
* "zero-shadow scene = zero allocation" gate easy to enforce: the renderer
|
|
2524
|
-
* never calls this method on a frame with no PointLightShadow entities.
|
|
2525
|
-
*/
|
|
2526
|
-
ensure() {
|
|
2527
|
-
if (this.texture !== null) return;
|
|
2528
|
-
const usage = GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING;
|
|
2529
|
-
const texDesc = cubeArrayDepthDescriptor(this.faceSize, this.layers, usage);
|
|
2530
|
-
const texRes = this.device.createTexture(texDesc);
|
|
2531
|
-
if (!texRes.ok) throw texRes.error;
|
|
2532
|
-
this.texture = texRes.value;
|
|
2533
|
-
const viewRes = this.device.createTextureView(this.texture, {
|
|
2534
|
-
label: "shadow-atlas-cube-array-view",
|
|
2535
|
-
dimension: "cube-array",
|
|
2536
|
-
aspect: "depth-only",
|
|
2537
|
-
baseArrayLayer: 0,
|
|
2538
|
-
arrayLayerCount: 6 * this.layers,
|
|
2539
|
-
baseMipLevel: 0,
|
|
2540
|
-
mipLevelCount: 1
|
|
2575
|
+
if (options.writeMembership !== false) {
|
|
2576
|
+
runClusterBinProfilePhase(profile, "light-index-write", () => {
|
|
2577
|
+
for (let lightIdx = 0; lightIdx < lights.length; lightIdx++) {
|
|
2578
|
+
const boundsOffset = lightIdx * 6;
|
|
2579
|
+
let valid = false;
|
|
2580
|
+
let minX = 0;
|
|
2581
|
+
let minY = 0;
|
|
2582
|
+
let minZ = 0;
|
|
2583
|
+
let maxX = -1;
|
|
2584
|
+
let maxY = -1;
|
|
2585
|
+
let maxZ = -1;
|
|
2586
|
+
runClusterBinProfilePhase(profile, "light-index-write/bounds-read", () => {
|
|
2587
|
+
if ((lightBounds[boundsOffset] ?? -1) < 0) return;
|
|
2588
|
+
valid = true;
|
|
2589
|
+
minX = lightBounds[boundsOffset] ?? 0;
|
|
2590
|
+
minY = lightBounds[boundsOffset + 1] ?? 0;
|
|
2591
|
+
minZ = lightBounds[boundsOffset + 2] ?? 0;
|
|
2592
|
+
maxX = lightBounds[boundsOffset + 3] ?? -1;
|
|
2593
|
+
maxY = lightBounds[boundsOffset + 4] ?? -1;
|
|
2594
|
+
maxZ = lightBounds[boundsOffset + 5] ?? -1;
|
|
2595
|
+
});
|
|
2596
|
+
if (!valid) continue;
|
|
2597
|
+
runClusterBinProfilePhase(profile, "light-index-write/cluster-write", () => {
|
|
2598
|
+
for (let cz = minZ; cz <= maxZ; cz++) {
|
|
2599
|
+
for (let cy = minY; cy <= maxY; cy++) {
|
|
2600
|
+
for (let cx = minX; cx <= maxX; cx++) {
|
|
2601
|
+
const clusterIdx = cz * gridY * gridX + cy * gridX + cx;
|
|
2602
|
+
const cursor = clusterCursors[clusterIdx] ?? 0;
|
|
2603
|
+
lightIndexList[cursor] = lightIdx;
|
|
2604
|
+
clusterCursors[clusterIdx] = cursor + 1;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2541
2610
|
});
|
|
2542
|
-
if (!viewRes.ok) {
|
|
2543
|
-
this.device.destroyTexture(this.texture);
|
|
2544
|
-
this.texture = null;
|
|
2545
|
-
throw viewRes.error;
|
|
2546
|
-
}
|
|
2547
|
-
this.cubeArrayView = viewRes.value;
|
|
2548
|
-
const sampRes = this.device.createSampler(comparisonSamplerDescriptor());
|
|
2549
|
-
if (!sampRes.ok) {
|
|
2550
|
-
this.device.destroyTexture(this.texture);
|
|
2551
|
-
this.texture = null;
|
|
2552
|
-
this.cubeArrayView = null;
|
|
2553
|
-
throw sampRes.error;
|
|
2554
|
-
}
|
|
2555
|
-
this.compareSampler = sampRes.value;
|
|
2556
|
-
}
|
|
2557
|
-
/**
|
|
2558
|
-
* Whole-atlas cube_array sampling view (`texture_depth_cube_array`). Returns
|
|
2559
|
-
* `null` if the atlas is not yet allocated; the caller should gate on a
|
|
2560
|
-
* non-null pointShadow array before calling {@link ensure} + this getter.
|
|
2561
|
-
*/
|
|
2562
|
-
getAtlasView() {
|
|
2563
|
-
return this.cubeArrayView;
|
|
2564
|
-
}
|
|
2565
|
-
/**
|
|
2566
|
-
* Comparison sampler (`compare: 'less'`) for cube_array depth sampling.
|
|
2567
|
-
* Returns `null` if the atlas is not yet allocated.
|
|
2568
|
-
*/
|
|
2569
|
-
getComparisonSampler() {
|
|
2570
|
-
return this.compareSampler;
|
|
2571
2611
|
}
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2612
|
+
return ok$1(writeCount);
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// src/pipeline/standard-lighting/errors.ts
|
|
2616
|
+
function fromClusterBinError(error) {
|
|
2617
|
+
return new StandardClusterIndexOverflowError(error.detail.actual, error.detail.capacity);
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
// src/pipeline/standard-lighting/membership.ts
|
|
2621
|
+
function deriveStandardMembership(frame, layout, scratch = createClusterBinScratch()) {
|
|
2622
|
+
const clusterGrid = new Uint32Array(layout.clusterGridU32Length);
|
|
2623
|
+
const lightIndexList = new Uint32Array(layout.lightIndexListCapacity);
|
|
2624
|
+
const result = bin(
|
|
2625
|
+
frame.local,
|
|
2626
|
+
frame.view,
|
|
2627
|
+
frame.projection,
|
|
2628
|
+
layout.grid,
|
|
2629
|
+
frame.near,
|
|
2630
|
+
frame.far,
|
|
2631
|
+
clusterGrid,
|
|
2632
|
+
lightIndexList,
|
|
2633
|
+
layout.lightIndexListCapacity,
|
|
2634
|
+
scratch
|
|
2635
|
+
);
|
|
2636
|
+
if (!result.ok) return err$1(fromClusterBinError(result.error));
|
|
2637
|
+
return ok({
|
|
2638
|
+
clusterGrid,
|
|
2639
|
+
lightIndexList,
|
|
2640
|
+
lightBounds: scratch.lightBounds.slice(0, frame.local.length * 6),
|
|
2641
|
+
membershipEntryCount: result.value,
|
|
2642
|
+
scratch
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
// src/pipeline/standard-lighting/prepare.ts
|
|
2647
|
+
function prepareStandardLighting(frame) {
|
|
2648
|
+
if (frame.local.length > frame.lightCount || frame.local.length > MAX_LIGHTS) {
|
|
2649
|
+
return err$1(new StandardLightBudgetExceededError(frame.local.length, frame.lightCount));
|
|
2650
|
+
}
|
|
2651
|
+
const layout = createStandardClusterLayout(frame.grid);
|
|
2652
|
+
const membership = deriveStandardMembership(frame, layout);
|
|
2653
|
+
if (!membership.ok) return membership;
|
|
2654
|
+
return ok({
|
|
2655
|
+
...membership.value,
|
|
2656
|
+
directional: frame.directional,
|
|
2657
|
+
local: frame.local,
|
|
2658
|
+
layout,
|
|
2659
|
+
membershipLightCount: frame.local.length,
|
|
2660
|
+
renderPath: frame.renderPath,
|
|
2661
|
+
maxLights: frame.lightCount
|
|
2662
|
+
});
|
|
2663
|
+
}
|
|
2664
|
+
function occupiedClusterCount(prepared) {
|
|
2665
|
+
let occupied = 0;
|
|
2666
|
+
for (let index = 1; index < prepared.clusterGrid.length; index += 2) {
|
|
2667
|
+
if ((prepared.clusterGrid[index] ?? 0) > 0) occupied += 1;
|
|
2611
2668
|
}
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
this.cubeArrayView = null;
|
|
2624
|
-
this.compareSampler = null;
|
|
2669
|
+
return occupied;
|
|
2670
|
+
}
|
|
2671
|
+
function selectStandardClusterTransport(capabilities, prepared) {
|
|
2672
|
+
const requested = prepared.local.length;
|
|
2673
|
+
if (!capabilities.storageBuffer) {
|
|
2674
|
+
return err$1(
|
|
2675
|
+
new StandardClusterTransportUnavailableError(
|
|
2676
|
+
requested,
|
|
2677
|
+
"enable a proven storage-buffer Cluster transport; compute without storage is not a membership path"
|
|
2678
|
+
)
|
|
2679
|
+
);
|
|
2625
2680
|
}
|
|
2626
|
-
|
|
2681
|
+
const producer = capabilities.compute && capabilities.membershipPipelineReady ? "gpu" : "cpu";
|
|
2682
|
+
const kind = producer === "gpu" ? "compute-storage" : "cpu-storage";
|
|
2683
|
+
return ok({
|
|
2684
|
+
kind,
|
|
2685
|
+
producer,
|
|
2686
|
+
layout: prepared.layout,
|
|
2687
|
+
requestedLightCount: requested,
|
|
2688
|
+
admittedLightCount: requested,
|
|
2689
|
+
membershipEntryCount: prepared.membershipEntryCount,
|
|
2690
|
+
occupiedClusterCount: occupiedClusterCount(prepared),
|
|
2691
|
+
clusterGridBytes: prepared.layout.clusterGridU32Length * Uint32Array.BYTES_PER_ELEMENT,
|
|
2692
|
+
lightIndexListBytes: prepared.membershipEntryCount * Uint32Array.BYTES_PER_ELEMENT,
|
|
2693
|
+
lightDataBytes: requested * 64,
|
|
2694
|
+
lightBoundsBytes: prepared.lightBounds.byteLength
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2627
2697
|
|
|
2628
2698
|
// src/post-process-errors.ts
|
|
2629
2699
|
var POST_PROCESS_POLICY = {
|
|
@@ -2746,38 +2816,6 @@ function warnMultiLightDirectional(frameState, directionalCount, envOverride) {
|
|
|
2746
2816
|
}
|
|
2747
2817
|
}
|
|
2748
2818
|
}
|
|
2749
|
-
function warnMultiLightPoint(frameState, pointCount, envOverride) {
|
|
2750
|
-
if (!frameState.warnedMultiLightPoint && pointCount > 4) {
|
|
2751
|
-
frameState.warnedMultiLightPoint = true;
|
|
2752
|
-
const env = globalThis.process;
|
|
2753
|
-
if (env?.env?.NODE_ENV !== "production") {
|
|
2754
|
-
console.warn(
|
|
2755
|
-
"[forgeax] render-system-multi-light point: at most 4 entities (got N=" + pointCount + "). First 4 used; rest dropped.",
|
|
2756
|
-
{
|
|
2757
|
-
code: "render-system-multi-light",
|
|
2758
|
-
expected: "at most 4 point",
|
|
2759
|
-
detail: { type: "point", got: pointCount }
|
|
2760
|
-
}
|
|
2761
|
-
);
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
}
|
|
2765
|
-
function warnMultiLightSpot(frameState, spotCount, envOverride) {
|
|
2766
|
-
if (!frameState.warnedMultiLightSpot && spotCount > 4) {
|
|
2767
|
-
frameState.warnedMultiLightSpot = true;
|
|
2768
|
-
const env = globalThis.process;
|
|
2769
|
-
if (env?.env?.NODE_ENV !== "production") {
|
|
2770
|
-
console.warn(
|
|
2771
|
-
"[forgeax] render-system-multi-light spot: at most 4 entities (got N=" + spotCount + "). First 4 used; rest dropped.",
|
|
2772
|
-
{
|
|
2773
|
-
code: "render-system-multi-light",
|
|
2774
|
-
expected: "at most 4 spot",
|
|
2775
|
-
detail: { type: "spot", got: spotCount }
|
|
2776
|
-
}
|
|
2777
|
-
);
|
|
2778
|
-
}
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
2819
|
function warnMultiSkylight(frameState, skylightCount, winningEntityHandle) {
|
|
2782
2820
|
if (!frameState.warnedMultiSkylight && skylightCount > 1) {
|
|
2783
2821
|
frameState.warnedMultiSkylight = true;
|
|
@@ -2844,10 +2882,32 @@ var POINTS_LINES_VIEW_SLOT_COUNT = 1024;
|
|
|
2844
2882
|
var POINTS_LINES_VIEW_BUFFER_SIZE = POINTS_LINES_VIEW_SLOT_STRIDE * POINTS_LINES_VIEW_SLOT_COUNT;
|
|
2845
2883
|
var VIEW_UNIFORM_SLOT_STRIDE = 1024;
|
|
2846
2884
|
var POINT_SHADOW_VIEW_SLOT_COUNT = 24;
|
|
2847
|
-
var
|
|
2885
|
+
var CUBE_CAPTURE_VIEW_SLOT_BASE = 1 + POINT_SHADOW_VIEW_SLOT_COUNT;
|
|
2886
|
+
var REFLECTION_PROBE_VIEW_SLOT_BASE = CUBE_CAPTURE_VIEW_SLOT_BASE + 6;
|
|
2887
|
+
var REFLECTION_PROBE_VIEW_SLOT_COUNT = 16;
|
|
2888
|
+
var VIEW_UNIFORM_BUFFER_SIZE = VIEW_UNIFORM_SLOT_STRIDE * (REFLECTION_PROBE_VIEW_SLOT_BASE + REFLECTION_PROBE_VIEW_SLOT_COUNT);
|
|
2848
2889
|
function pointShadowViewOffset(layer, face) {
|
|
2849
2890
|
return VIEW_UNIFORM_SLOT_STRIDE * (1 + layer * 6 + face);
|
|
2850
2891
|
}
|
|
2892
|
+
function directionalShadowFilterCarrier(quality) {
|
|
2893
|
+
if (quality === void 0) return [0, 0, 0, 0];
|
|
2894
|
+
if (quality.kind === "pcss") {
|
|
2895
|
+
return [
|
|
2896
|
+
quality.preset === "medium" ? 4 : 5,
|
|
2897
|
+
quality.angularRadiusRadians,
|
|
2898
|
+
quality.maxPenumbraTexels,
|
|
2899
|
+
0
|
|
2900
|
+
];
|
|
2901
|
+
}
|
|
2902
|
+
switch (quality.kernel) {
|
|
2903
|
+
case 1:
|
|
2904
|
+
return [1, 0, 0, 0];
|
|
2905
|
+
case 3:
|
|
2906
|
+
return [2, 0, 0, 0];
|
|
2907
|
+
case 5:
|
|
2908
|
+
return [3, 0, 0, 0];
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2851
2911
|
function writePointsLinesViewUbo(queue, buffer, camera, width, height, model, style, byteOffset = 0) {
|
|
2852
2912
|
const projection = computeProjectionMatrix(camera);
|
|
2853
2913
|
const view = computeViewMatrix(camera);
|
|
@@ -2879,7 +2939,9 @@ function writePointsLinesViewUbo(queue, buffer, camera, width, height, model, st
|
|
|
2879
2939
|
const uploaded = queue.writeBuffer(buffer, byteOffset, payload);
|
|
2880
2940
|
if (!uploaded.ok) throw uploaded.error;
|
|
2881
2941
|
}
|
|
2882
|
-
function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShadowSnapshots,
|
|
2942
|
+
function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShadowSnapshots, fogOrTemporalOrOffset, temporal, projectorSpotIndex) {
|
|
2943
|
+
const byteOffset = typeof fogOrTemporalOrOffset === "number" ? fogOrTemporalOrOffset : 0;
|
|
2944
|
+
const fogOrTemporal = typeof fogOrTemporalOrOffset === "number" ? void 0 : fogOrTemporalOrOffset;
|
|
2883
2945
|
const isTemporal = fogOrTemporal !== void 0 && ("currentJitterUv" in fogOrTemporal || "currentUnjitteredViewProjection" in fogOrTemporal);
|
|
2884
2946
|
const fog = isTemporal ? void 0 : fogOrTemporal;
|
|
2885
2947
|
const resolvedTemporal = temporal ?? (isTemporal ? fogOrTemporal : void 0);
|
|
@@ -2935,14 +2997,20 @@ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShado
|
|
|
2935
2997
|
viewPayload[230] = camera.projection === "orthographic" ? 1 : 0;
|
|
2936
2998
|
if (lights.splitPlanes !== void 0) {
|
|
2937
2999
|
for (let s = 0; s < 4; s++) {
|
|
2938
|
-
|
|
3000
|
+
for (let lane = 0; lane < 4; lane++) {
|
|
3001
|
+
viewPayload[108 + s * 4 + lane] = lights.splitPlanes[s * 4 + lane] ?? 0;
|
|
3002
|
+
}
|
|
2939
3003
|
}
|
|
2940
3004
|
}
|
|
2941
3005
|
viewPayload[124] = lights.cascadeCount ?? 0;
|
|
2942
3006
|
viewPayload[125] = lights.cascadeBlend ?? 0;
|
|
2943
3007
|
viewPayload[126] = lights.depthBias ?? 5e-3;
|
|
2944
3008
|
viewPayload[127] = lights.normalBias ?? 0.05;
|
|
2945
|
-
|
|
3009
|
+
const filterCarrier = directionalShadowFilterCarrier(lights.directionalShadowQuality);
|
|
3010
|
+
viewPayload[128] = filterCarrier[0] ?? 0;
|
|
3011
|
+
viewPayload[129] = filterCarrier[1] ?? 0;
|
|
3012
|
+
viewPayload[130] = filterCarrier[2] ?? 0;
|
|
3013
|
+
viewPayload[131] = filterCarrier[3] ?? 0;
|
|
2946
3014
|
{
|
|
2947
3015
|
const SPOT_LVP_BASE_FLOAT = 132;
|
|
2948
3016
|
const SPOT_LVP_LANE_COUNT = 4;
|
|
@@ -2952,10 +3020,11 @@ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShado
|
|
|
2952
3020
|
const ss = spotSnaps[i];
|
|
2953
3021
|
if (ss === void 0) continue;
|
|
2954
3022
|
const tile = ss.shadowAtlasTile;
|
|
2955
|
-
if (tile < 0 || tile >= SPOT_LVP_LANE_COUNT) continue;
|
|
2956
3023
|
const lvp = ss.lightViewProj;
|
|
2957
3024
|
if (lvp === void 0) continue;
|
|
2958
|
-
const
|
|
3025
|
+
const lane = tile >= 0 && tile < SPOT_LVP_LANE_COUNT ? tile : i === projectorSpotIndex ? 0 : -1;
|
|
3026
|
+
if (lane < 0) continue;
|
|
3027
|
+
const base = SPOT_LVP_BASE_FLOAT + lane * SPOT_LVP_FLOATS_PER_LANE;
|
|
2959
3028
|
for (let f = 0; f < SPOT_LVP_FLOATS_PER_LANE; f++) {
|
|
2960
3029
|
viewPayload[base + f] = lvp[f] ?? 0;
|
|
2961
3030
|
}
|
|
@@ -2969,10 +3038,11 @@ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShado
|
|
|
2969
3038
|
viewPayload[236] = fog.heightFalloff;
|
|
2970
3039
|
viewPayload[237] = fog.maxOpacity;
|
|
2971
3040
|
}
|
|
2972
|
-
const viewUploadResult = queue.writeBuffer(viewUniformBuffer,
|
|
3041
|
+
const viewUploadResult = queue.writeBuffer(viewUniformBuffer, byteOffset, viewPayload);
|
|
2973
3042
|
if (!viewUploadResult.ok) throw viewUploadResult.error;
|
|
2974
3043
|
for (const snapshot of lights.pointShadow ?? []) {
|
|
2975
|
-
if (snapshot.shadowAtlasLayer < 0 || snapshot.shadowAtlasLayer >=
|
|
3044
|
+
if (snapshot.shadowAtlasLayer < 0 || snapshot.shadowAtlasLayer >= SHADOW_ATLAS_DEFAULT_LAYERS)
|
|
3045
|
+
continue;
|
|
2976
3046
|
for (let face = 0; face < 6; face += 1) {
|
|
2977
3047
|
const facePayload = viewPayload.slice();
|
|
2978
3048
|
const matrix = snapshot.shadowMatrices.subarray(face * 16, (face + 1) * 16);
|
|
@@ -2988,14 +3058,42 @@ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShado
|
|
|
2988
3058
|
}
|
|
2989
3059
|
|
|
2990
3060
|
// src/record/frame-lighting.ts
|
|
3061
|
+
function resolveReflectionProbeBinding(selection, table) {
|
|
3062
|
+
if (selection.kind !== "probe") return { probeIndex: void 0, useSkylight: true };
|
|
3063
|
+
const primitiveKey = `${selection.worldId}:${selection.entityKey}`;
|
|
3064
|
+
const tableIndex = table?.cpuIndexByPrimitive(primitiveKey);
|
|
3065
|
+
return { probeIndex: tableIndex ?? selection.entityKey, useSkylight: false };
|
|
3066
|
+
}
|
|
3067
|
+
function projectDeviceOwnedBindGroup(state, device, layout) {
|
|
3068
|
+
return state !== null && state !== void 0 && state.device === device && state.layout === layout ? state.bindGroup : null;
|
|
3069
|
+
}
|
|
2991
3070
|
function runHdrpClusterProfilePhase(runner, phase, action) {
|
|
2992
3071
|
return runner === void 0 ? action() : runner(phase, action);
|
|
2993
3072
|
}
|
|
2994
|
-
function
|
|
3073
|
+
function mapClusterUploadFailure(resource, error) {
|
|
3074
|
+
return new RendererOperationError("device-operation-failed", {
|
|
3075
|
+
operation: "draw",
|
|
3076
|
+
cause: {
|
|
3077
|
+
code: error.code,
|
|
3078
|
+
expected: `queue.writeBuffer succeeds for Standard Cluster ${resource}`,
|
|
3079
|
+
hint: `repair the device write for Standard Cluster ${resource} and retry the frame`,
|
|
3080
|
+
detail: error
|
|
3081
|
+
}
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
function buildPerFrameBindGroups(internals, frameState, pipelineState, hasValidated, bindGroupCounts, graphTargets, includeView = true, standardLighting) {
|
|
2995
3085
|
let viewBindGroup = null;
|
|
2996
3086
|
let meshBindGroup = null;
|
|
2997
3087
|
let hdrpClusterBindGroup = null;
|
|
2998
|
-
const
|
|
3088
|
+
const clusteredLighting = standardLighting?.kind === "clustered";
|
|
3089
|
+
const membershipLayout = pipelineState.hdrpClusterMembershipBindGroupLayout;
|
|
3090
|
+
const membership = frameState.hdrpClusterMembership;
|
|
3091
|
+
const expectedHdrpBuffers = hasValidated && clusteredLighting ? getOrCreateHdrpBuffers(internals, frameState.installedPipelineConfig?.clusterGrid) : null;
|
|
3092
|
+
const currentMembership = expectedHdrpBuffers !== null && membership?.clusterGridBuffer === expectedHdrpBuffers.clusterGridBuffer ? projectDeviceOwnedBindGroup(membership, internals.device, membershipLayout) : null;
|
|
3093
|
+
if (membership !== null && currentMembership === null) {
|
|
3094
|
+
frameState.hdrpClusterMembership = null;
|
|
3095
|
+
}
|
|
3096
|
+
const hdrpClusterMembershipBindGroup = clusteredLighting ? currentMembership : null;
|
|
2999
3097
|
if (hasValidated) {
|
|
3000
3098
|
if (includeView) {
|
|
3001
3099
|
const shadowSampler = pipelineState.perPassResources.shadowSampler;
|
|
@@ -3173,11 +3271,8 @@ function buildPerFrameBindGroups(internals, frameState, pipelineState, hasValida
|
|
|
3173
3271
|
},
|
|
3174
3272
|
bindGroupCounts
|
|
3175
3273
|
);
|
|
3176
|
-
if (
|
|
3177
|
-
const hdrpBuffers =
|
|
3178
|
-
internals,
|
|
3179
|
-
frameState.installedPipelineConfig?.clusterGrid
|
|
3180
|
-
);
|
|
3274
|
+
if (clusteredLighting) {
|
|
3275
|
+
const hdrpBuffers = expectedHdrpBuffers;
|
|
3181
3276
|
if (hdrpBuffers !== null) {
|
|
3182
3277
|
hdrpClusterBindGroup = getOrCreateFromChain(
|
|
3183
3278
|
frameState.meshBindGroupCache,
|
|
@@ -3211,27 +3306,19 @@ function buildPerFrameBindGroups(internals, frameState, pipelineState, hasValida
|
|
|
3211
3306
|
}
|
|
3212
3307
|
return { viewBindGroup, meshBindGroup, hdrpClusterBindGroup, hdrpClusterMembershipBindGroup };
|
|
3213
3308
|
}
|
|
3214
|
-
function prepareFrameLighting(internals, frameState, lights) {
|
|
3309
|
+
function prepareFrameLighting(internals, frameState, lights, camera, pipelineState) {
|
|
3215
3310
|
if (lights.directionalCount > 1) {
|
|
3216
3311
|
warnMultiLightDirectional(frameState, lights.directionalCount);
|
|
3217
3312
|
}
|
|
3218
|
-
if (!frameState.isHdrpActive) {
|
|
3219
|
-
if (lights.point.length > LIGHT_ARRAY_MAX_SLOTS) {
|
|
3220
|
-
warnMultiLightPoint(frameState, lights.point.length);
|
|
3221
|
-
}
|
|
3222
|
-
if (lights.spot.length > LIGHT_ARRAY_MAX_SLOTS) {
|
|
3223
|
-
warnMultiLightSpot(frameState, lights.spot.length);
|
|
3224
|
-
}
|
|
3225
|
-
}
|
|
3226
3313
|
frameState.pointShadowSnapshots = lights.pointShadow;
|
|
3227
3314
|
frameState.spotShadowSnapshots = lights.spot;
|
|
3228
3315
|
if (lights.pointShadow.length > 0) {
|
|
3229
3316
|
if (frameState.pointShadowAtlas === null) {
|
|
3230
3317
|
const firstSnap = lights.pointShadow[0];
|
|
3231
|
-
const faceSize = firstSnap?.mapSize ??
|
|
3318
|
+
const faceSize = firstSnap?.mapSize ?? SHADOW_ATLAS_DEFAULT_FACE_SIZE;
|
|
3232
3319
|
frameState.pointShadowAtlas = new ShadowAtlas(internals.device, {
|
|
3233
3320
|
faceSize,
|
|
3234
|
-
layers:
|
|
3321
|
+
layers: SHADOW_ATLAS_DEFAULT_LAYERS
|
|
3235
3322
|
});
|
|
3236
3323
|
}
|
|
3237
3324
|
try {
|
|
@@ -3254,49 +3341,60 @@ function prepareFrameLighting(internals, frameState, lights) {
|
|
|
3254
3341
|
intensity: 0
|
|
3255
3342
|
};
|
|
3256
3343
|
const totalLightCount = (directionalLight !== void 0 ? 1 : 0) + pointLights.length + spotLights.length;
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
)
|
|
3278
|
-
|
|
3344
|
+
const clusterGrid = frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
3345
|
+
const local = [
|
|
3346
|
+
...pointLights.map((source) => ({
|
|
3347
|
+
kind: "point",
|
|
3348
|
+
shadowed: source.shadowAtlasLayer !== void 0 && source.shadowAtlasLayer >= 0,
|
|
3349
|
+
position: source.position,
|
|
3350
|
+
range: Number.isFinite(source.invRangeSquared) && source.invRangeSquared > 0 ? Math.sqrt(1 / source.invRangeSquared) : 1e3,
|
|
3351
|
+
source
|
|
3352
|
+
})),
|
|
3353
|
+
...spotLights.map((source) => ({
|
|
3354
|
+
kind: "spot",
|
|
3355
|
+
shadowed: source.castShadow && source.shadowAtlasTile >= 0 && source.lightViewProj !== void 0,
|
|
3356
|
+
position: source.position,
|
|
3357
|
+
range: Number.isFinite(source.invRangeSquared) && source.invRangeSquared > 0 ? Math.sqrt(1 / source.invRangeSquared) : 1e3,
|
|
3358
|
+
source
|
|
3359
|
+
}))
|
|
3360
|
+
];
|
|
3361
|
+
const prepared = prepareStandardLighting({
|
|
3362
|
+
directional: directionalLight,
|
|
3363
|
+
local,
|
|
3364
|
+
view: computeViewMatrix(camera),
|
|
3365
|
+
projection: computeProjectionMatrix(camera),
|
|
3366
|
+
near: camera.near,
|
|
3367
|
+
far: camera.far,
|
|
3368
|
+
grid: clusterGrid,
|
|
3369
|
+
lightCount: internals.standardProfile?.lightCount ?? DEFAULT_STANDARD_PROFILE.lightCount,
|
|
3370
|
+
renderPath: internals.standardProfile?.renderPath ?? DEFAULT_STANDARD_PROFILE.renderPath
|
|
3371
|
+
});
|
|
3372
|
+
if (!prepared.ok) return prepared;
|
|
3373
|
+
if (prepared.value.local.length === 0 && !internals.device.caps.storageBuffer) {
|
|
3374
|
+
return ok({
|
|
3375
|
+
light,
|
|
3376
|
+
pointLights,
|
|
3377
|
+
spotLights,
|
|
3378
|
+
totalLightCount,
|
|
3379
|
+
standard: { kind: "no-local-lights", prepared: prepared.value }
|
|
3380
|
+
});
|
|
3279
3381
|
}
|
|
3280
|
-
const
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3382
|
+
const transport = selectStandardClusterTransport(
|
|
3383
|
+
{
|
|
3384
|
+
compute: internals.device.caps.compute,
|
|
3385
|
+
storageBuffer: internals.device.caps.storageBuffer,
|
|
3386
|
+
membershipPipelineReady: pipelineState !== void 0 && pipelineState.hdrpClusterMembershipPipeline !== null && pipelineState.hdrpClusterMembershipBindGroupLayout !== null
|
|
3387
|
+
},
|
|
3388
|
+
prepared.value
|
|
3286
3389
|
);
|
|
3287
|
-
if (!
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
offset,
|
|
3296
|
-
packed
|
|
3297
|
-
);
|
|
3298
|
-
if (!writeRes.ok) throw writeRes.error;
|
|
3299
|
-
}
|
|
3390
|
+
if (!transport.ok) return transport;
|
|
3391
|
+
return ok({
|
|
3392
|
+
light,
|
|
3393
|
+
pointLights,
|
|
3394
|
+
spotLights,
|
|
3395
|
+
totalLightCount,
|
|
3396
|
+
standard: { kind: "clustered", prepared: prepared.value, transport: transport.value }
|
|
3397
|
+
});
|
|
3300
3398
|
}
|
|
3301
3399
|
function writeShadowParamsBuffer(internals, frameState, pipelineState) {
|
|
3302
3400
|
const SHADOW_PARAMS_LANE_COUNT = 4;
|
|
@@ -3339,191 +3437,81 @@ function warnZeroLightStandard(frameState, renderables, skylight, totalLightCoun
|
|
|
3339
3437
|
}
|
|
3340
3438
|
}
|
|
3341
3439
|
}
|
|
3342
|
-
function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera,
|
|
3343
|
-
const
|
|
3344
|
-
|
|
3345
|
-
if (
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
const clusterSsaoIntensity = clusterSsaoConfig !== void 0 && clusterSsaoConfig.enabled === true ? clusterSsaoConfig.intensity ?? 1 : 0;
|
|
3352
|
-
const clusterUniformPayload = packClusterUniform(
|
|
3353
|
-
grid,
|
|
3354
|
-
camera.near,
|
|
3355
|
-
camera.far,
|
|
3356
|
-
clusterSsaoIntensity,
|
|
3357
|
-
0,
|
|
3358
|
-
lightCapacity
|
|
3359
|
-
);
|
|
3360
|
-
const clusterUniformUpload = internals.device.queue.writeBuffer(
|
|
3361
|
-
hdrpBuffers.clusterUniformBuffer,
|
|
3362
|
-
0,
|
|
3363
|
-
new Uint8Array(clusterUniformPayload)
|
|
3364
|
-
);
|
|
3365
|
-
if (!clusterUniformUpload.ok) internals.errorRegistry.fire(clusterUniformUpload.error);
|
|
3366
|
-
const clusterGridClear = internals.device.queue.writeBuffer(
|
|
3367
|
-
hdrpBuffers.clusterGridBuffer,
|
|
3368
|
-
0,
|
|
3369
|
-
new Uint8Array(hdrpBuffers.clusterGridBytes)
|
|
3370
|
-
);
|
|
3371
|
-
if (!clusterGridClear.ok) internals.errorRegistry.fire(clusterGridClear.error);
|
|
3372
|
-
const lightIndexListClear = internals.device.queue.writeBuffer(
|
|
3373
|
-
hdrpBuffers.lightIndexListBuffer,
|
|
3374
|
-
0,
|
|
3375
|
-
new Uint8Array(hdrpBuffers.lightIndexListBytes)
|
|
3440
|
+
function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, prepared, transport, profilePhase, gpuMembershipPipelineReady = false, membershipBindGroupLayout = null, projectorLightSlotIndex) {
|
|
3441
|
+
const configuredClusterGrid = prepared.layout.grid;
|
|
3442
|
+
const gpuMembership = transport.producer === "gpu";
|
|
3443
|
+
if (gpuMembership && (!gpuMembershipPipelineReady || membershipBindGroupLayout === null)) {
|
|
3444
|
+
return err$1(
|
|
3445
|
+
new StandardClusterTransportUnavailableError(
|
|
3446
|
+
prepared.local.length,
|
|
3447
|
+
"the selected GPU Cluster producer requires a ready membership pipeline and bind-group layout"
|
|
3448
|
+
)
|
|
3376
3449
|
);
|
|
3377
|
-
if (!lightIndexListClear.ok) internals.errorRegistry.fire(lightIndexListClear.error);
|
|
3378
|
-
return;
|
|
3379
|
-
}
|
|
3380
|
-
const HDRP_LIGHT_BUDGET = 256;
|
|
3381
|
-
let effectivePointLights = pointLights;
|
|
3382
|
-
let effectiveSpotLights = spotLights;
|
|
3383
|
-
if (hdrpLightCount > HDRP_LIGHT_BUDGET) {
|
|
3384
|
-
if (!frameState.hdrpOncePerFrameFired.has("hdrp-light-budget-exceeded")) {
|
|
3385
|
-
frameState.hdrpOncePerFrameFired.add("hdrp-light-budget-exceeded");
|
|
3386
|
-
internals.errorRegistry.fire(
|
|
3387
|
-
new HdrpLightBudgetExceededError(hdrpLightCount, HDRP_LIGHT_BUDGET)
|
|
3388
|
-
);
|
|
3389
|
-
}
|
|
3390
|
-
if (pointLights.length >= HDRP_LIGHT_BUDGET) {
|
|
3391
|
-
effectivePointLights = pointLights.slice(0, HDRP_LIGHT_BUDGET);
|
|
3392
|
-
effectiveSpotLights = [];
|
|
3393
|
-
} else {
|
|
3394
|
-
effectivePointLights = pointLights;
|
|
3395
|
-
effectiveSpotLights = spotLights.slice(0, HDRP_LIGHT_BUDGET - pointLights.length);
|
|
3396
|
-
}
|
|
3397
|
-
}
|
|
3398
|
-
const effectiveLightCount = effectivePointLights.length + effectiveSpotLights.length;
|
|
3399
|
-
const configuredClusterGrid = frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
3400
|
-
let gpuMembership = useGpuMembership && membershipBindGroupLayout !== null;
|
|
3401
|
-
if (gpuMembership && membershipBindGroupLayout !== null && frameState.hdrpClusterMembershipBindGroup === null) {
|
|
3402
|
-
const hdrpBuffers = getOrCreateHdrpBuffers(internals, configuredClusterGrid);
|
|
3403
|
-
if (hdrpBuffers !== null) {
|
|
3404
|
-
frameState.hdrpClusterMembershipBindGroup = createHdrpClusterMembershipBindGroup(
|
|
3405
|
-
internals,
|
|
3406
|
-
hdrpBuffers,
|
|
3407
|
-
membershipBindGroupLayout
|
|
3408
|
-
);
|
|
3409
|
-
}
|
|
3410
|
-
gpuMembership = frameState.hdrpClusterMembershipBindGroup !== null;
|
|
3411
3450
|
}
|
|
3412
|
-
const
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
const {
|
|
3419
|
-
hdrpLights,
|
|
3420
|
-
clusterGrid: clusterGrid2,
|
|
3421
|
-
gridX: gridX2,
|
|
3422
|
-
gridY: gridY2,
|
|
3423
|
-
gridZ: gridZ2,
|
|
3424
|
-
clusterGridBuf: clusterGridBuf2,
|
|
3425
|
-
lightIndexListBuf: lightIndexListBuf2,
|
|
3426
|
-
projMatrix,
|
|
3427
|
-
viewMatrix
|
|
3428
|
-
} = runHdrpClusterProfilePhase(
|
|
3429
|
-
profilePhase,
|
|
3430
|
-
"record/scene-state/hdrp-cluster/binner/input-preparation",
|
|
3431
|
-
() => {
|
|
3432
|
-
const hdrpLights2 = [];
|
|
3433
|
-
for (const pl of effectivePointLights) {
|
|
3434
|
-
const range = Number.isFinite(pl.invRangeSquared) && pl.invRangeSquared > 0 ? Math.sqrt(1 / pl.invRangeSquared) : 1e3;
|
|
3435
|
-
hdrpLights2.push({ position: pl.position, range });
|
|
3436
|
-
}
|
|
3437
|
-
for (const sl of effectiveSpotLights) {
|
|
3438
|
-
const range = Number.isFinite(sl.invRangeSquared) && sl.invRangeSquared > 0 ? Math.sqrt(1 / sl.invRangeSquared) : 1e3;
|
|
3439
|
-
hdrpLights2.push({ position: sl.position, range });
|
|
3440
|
-
}
|
|
3441
|
-
const clusterGrid3 = frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
3442
|
-
const gridX3 = clusterGrid3.x;
|
|
3443
|
-
const gridY3 = clusterGrid3.y;
|
|
3444
|
-
const gridZ3 = clusterGrid3.z;
|
|
3445
|
-
const clusterCount = gridX3 * gridY3 * gridZ3;
|
|
3446
|
-
const projMatrix2 = computeProjectionMatrix(camera);
|
|
3447
|
-
const viewMatrix2 = computeViewMatrix(camera);
|
|
3448
|
-
const clusterGridBuf3 = frameState.hdrpClusterGridScratch === null || frameState.hdrpClusterGridScratch.length < clusterCount * 2 ? new Uint32Array(clusterCount * 2) : frameState.hdrpClusterGridScratch;
|
|
3449
|
-
frameState.hdrpClusterGridScratch = clusterGridBuf3;
|
|
3450
|
-
const lightIndexListBuf3 = frameState.hdrpLightIndexListScratch === null || frameState.hdrpLightIndexListScratch.length < LIGHT_INDEX_LIST_CAPACITY ? new Uint32Array(LIGHT_INDEX_LIST_CAPACITY) : frameState.hdrpLightIndexListScratch;
|
|
3451
|
-
frameState.hdrpLightIndexListScratch = lightIndexListBuf3;
|
|
3452
|
-
return {
|
|
3453
|
-
hdrpLights: hdrpLights2,
|
|
3454
|
-
clusterGrid: clusterGrid3,
|
|
3455
|
-
gridX: gridX3,
|
|
3456
|
-
gridY: gridY3,
|
|
3457
|
-
gridZ: gridZ3,
|
|
3458
|
-
clusterGridBuf: clusterGridBuf3,
|
|
3459
|
-
lightIndexListBuf: lightIndexListBuf3,
|
|
3460
|
-
projMatrix: projMatrix2,
|
|
3461
|
-
viewMatrix: viewMatrix2
|
|
3462
|
-
};
|
|
3463
|
-
}
|
|
3464
|
-
);
|
|
3465
|
-
const binResult = runHdrpClusterProfilePhase(
|
|
3466
|
-
profilePhase,
|
|
3467
|
-
"record/scene-state/hdrp-cluster/binner/bin-core",
|
|
3468
|
-
() => bin(
|
|
3469
|
-
hdrpLights,
|
|
3470
|
-
viewMatrix,
|
|
3471
|
-
projMatrix,
|
|
3472
|
-
{ x: gridX2, y: gridY2, z: gridZ2 },
|
|
3473
|
-
camera.near,
|
|
3474
|
-
camera.far,
|
|
3475
|
-
clusterGridBuf2,
|
|
3476
|
-
lightIndexListBuf2,
|
|
3477
|
-
LIGHT_INDEX_LIST_CAPACITY,
|
|
3478
|
-
frameState.hdrpClusterBinScratch,
|
|
3479
|
-
binnerProfile,
|
|
3480
|
-
{ writeMembership: !gpuMembership }
|
|
3451
|
+
const hdrpBuffers = getOrCreateHdrpBuffers(internals, configuredClusterGrid);
|
|
3452
|
+
if (hdrpBuffers === null) {
|
|
3453
|
+
return err$1(
|
|
3454
|
+
new StandardClusterTransportUnavailableError(
|
|
3455
|
+
prepared.local.length,
|
|
3456
|
+
"the selected Standard Cluster transport could not allocate its persistent buffers"
|
|
3481
3457
|
)
|
|
3482
3458
|
);
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3459
|
+
}
|
|
3460
|
+
const existingMembership = projectDeviceOwnedBindGroup(
|
|
3461
|
+
frameState.hdrpClusterMembership,
|
|
3462
|
+
internals.device,
|
|
3463
|
+
membershipBindGroupLayout
|
|
3464
|
+
);
|
|
3465
|
+
const membershipMatchesBuffers = existingMembership !== null && frameState.hdrpClusterMembership?.clusterGridBuffer === hdrpBuffers.clusterGridBuffer;
|
|
3466
|
+
if (!membershipMatchesBuffers) frameState.hdrpClusterMembership = null;
|
|
3467
|
+
if (gpuMembership && membershipBindGroupLayout !== null && frameState.hdrpClusterMembership === null) {
|
|
3468
|
+
const bindGroup = createHdrpClusterMembershipBindGroup(
|
|
3469
|
+
internals,
|
|
3470
|
+
hdrpBuffers,
|
|
3471
|
+
membershipBindGroupLayout
|
|
3472
|
+
);
|
|
3473
|
+
if (bindGroup === null) {
|
|
3474
|
+
return err$1(
|
|
3475
|
+
new StandardClusterTransportUnavailableError(
|
|
3476
|
+
prepared.local.length,
|
|
3477
|
+
"the selected GPU Cluster producer could not create its membership bind group"
|
|
3478
|
+
)
|
|
3488
3479
|
);
|
|
3489
3480
|
}
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
clusterGrid: clusterGrid2,
|
|
3496
|
-
gridX: gridX2,
|
|
3497
|
-
gridY: gridY2,
|
|
3498
|
-
gridZ: gridZ2,
|
|
3499
|
-
clusterGridBuf: clusterGridBuf2,
|
|
3500
|
-
lightIndexListBuf: lightIndexListBuf2,
|
|
3501
|
-
lightIndexCount: binResult.ok ? binResult.value : 0
|
|
3481
|
+
frameState.hdrpClusterMembership = {
|
|
3482
|
+
device: internals.device,
|
|
3483
|
+
layout: membershipBindGroupLayout,
|
|
3484
|
+
bindGroup,
|
|
3485
|
+
clusterGridBuffer: hdrpBuffers.clusterGridBuffer
|
|
3502
3486
|
};
|
|
3503
|
-
}
|
|
3487
|
+
}
|
|
3488
|
+
const gridX = prepared.layout.grid.x;
|
|
3489
|
+
const gridY = prepared.layout.grid.y;
|
|
3490
|
+
const gridZ = prepared.layout.grid.z;
|
|
3491
|
+
const clusterGridBuf = prepared.clusterGrid;
|
|
3492
|
+
const lightIndexListBuf = prepared.lightIndexList;
|
|
3493
|
+
const lightIndexCount = prepared.membershipEntryCount;
|
|
3494
|
+
const envFalsify = globalThis.process?.env;
|
|
3495
|
+
if (envFalsify?.FORGEAX_HDRP_FALSIFY_CLUSTER_GRID_ZERO) clusterGridBuf.fill(0);
|
|
3504
3496
|
const hdrpPayload = runHdrpClusterProfilePhase(
|
|
3505
3497
|
profilePhase,
|
|
3506
3498
|
"record/scene-state/hdrp-cluster/payload-packing",
|
|
3507
3499
|
() => {
|
|
3508
|
-
const
|
|
3509
|
-
if (hdrpBuffers === null) return null;
|
|
3510
|
-
const lightCapacity = hdrpBuffers.storageBuffer ? 256 : HDRP_UNIFORM_LIGHT_CAPACITY;
|
|
3511
|
-
const lightDataPayload = new Float32Array(lightCapacity * 16);
|
|
3500
|
+
const lightDataPayload = new Float32Array(prepared.layout.lightDataSlotCount * 16);
|
|
3512
3501
|
let slotIdx = 0;
|
|
3513
|
-
for (const
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
const
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
const packed = packLightSlot(sl);
|
|
3502
|
+
for (const local of prepared.local) {
|
|
3503
|
+
const source = local.source;
|
|
3504
|
+
if (source === void 0) return null;
|
|
3505
|
+
const projectorSelected = projectorLightSlotIndex !== void 0 && projectorLightSlotIndex === slotIdx;
|
|
3506
|
+
const packed = source.kind === "point" && source.shadowAtlasLayer !== void 0 && source.shadowAtlasLayer >= 0 && source.shadowNear !== void 0 && source.shadowFar !== void 0 ? packLightSlot(
|
|
3507
|
+
source,
|
|
3508
|
+
{
|
|
3509
|
+
shadowAtlasLayer: source.shadowAtlasLayer,
|
|
3510
|
+
near: source.shadowNear,
|
|
3511
|
+
far: source.shadowFar
|
|
3512
|
+
},
|
|
3513
|
+
projectorSelected
|
|
3514
|
+
) : packLightSlot(source, void 0, projectorSelected);
|
|
3527
3515
|
lightDataPayload.set(packed, slotIdx * 16);
|
|
3528
3516
|
slotIdx += 1;
|
|
3529
3517
|
}
|
|
@@ -3534,8 +3522,7 @@ function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, pointLigh
|
|
|
3534
3522
|
camera.near,
|
|
3535
3523
|
camera.far,
|
|
3536
3524
|
clusterSsaoIntensity,
|
|
3537
|
-
|
|
3538
|
-
lightCapacity
|
|
3525
|
+
transport.admittedLightCount
|
|
3539
3526
|
);
|
|
3540
3527
|
return {
|
|
3541
3528
|
hdrpBuffers,
|
|
@@ -3544,73 +3531,97 @@ function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, pointLigh
|
|
|
3544
3531
|
};
|
|
3545
3532
|
}
|
|
3546
3533
|
);
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3534
|
+
if (hdrpPayload === null) {
|
|
3535
|
+
return err$1(
|
|
3536
|
+
new StandardClusterTransportUnavailableError(
|
|
3537
|
+
prepared.local.length,
|
|
3538
|
+
"the prepared Standard Cluster payload could not be materialized"
|
|
3539
|
+
)
|
|
3540
|
+
);
|
|
3541
|
+
}
|
|
3542
|
+
const bufferUpload = runHdrpClusterProfilePhase(
|
|
3543
|
+
profilePhase,
|
|
3544
|
+
"record/scene-state/hdrp-cluster/buffer-upload",
|
|
3545
|
+
() => {
|
|
3546
|
+
const { hdrpBuffers: hdrpBuffers2, lightDataUploadPayload, clusterUniformPayload } = hdrpPayload;
|
|
3550
3547
|
const lightDataUpload = internals.device.queue.writeBuffer(
|
|
3551
|
-
|
|
3548
|
+
hdrpBuffers2.lightDataBuffer,
|
|
3552
3549
|
0,
|
|
3553
3550
|
lightDataUploadPayload
|
|
3554
3551
|
);
|
|
3555
|
-
if (!lightDataUpload.ok)
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
0,
|
|
3561
|
-
frameState.hdrpClusterBinScratch.lightBounds.subarray(0, effectiveLightCount * 6)
|
|
3562
|
-
);
|
|
3563
|
-
if (!lightBoundsUpload.ok) internals.errorRegistry.fire(lightBoundsUpload.error);
|
|
3564
|
-
}
|
|
3565
|
-
const clusterGridUpload = internals.device.queue.writeBuffer(
|
|
3566
|
-
hdrpBuffers.clusterGridBuffer,
|
|
3552
|
+
if (!lightDataUpload.ok)
|
|
3553
|
+
return err$1(mapClusterUploadFailure("light-data", lightDataUpload.error));
|
|
3554
|
+
if (gpuMembership) {
|
|
3555
|
+
const lightBoundsUpload = internals.device.queue.writeBuffer(
|
|
3556
|
+
hdrpBuffers2.lightBoundsBuffer,
|
|
3567
3557
|
0,
|
|
3568
|
-
|
|
3558
|
+
prepared.lightBounds
|
|
3569
3559
|
);
|
|
3570
|
-
if (!
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3560
|
+
if (!lightBoundsUpload.ok)
|
|
3561
|
+
return err$1(mapClusterUploadFailure("light-bounds", lightBoundsUpload.error));
|
|
3562
|
+
}
|
|
3563
|
+
const clusterGridUpload = internals.device.queue.writeBuffer(
|
|
3564
|
+
hdrpBuffers2.clusterGridBuffer,
|
|
3565
|
+
0,
|
|
3566
|
+
clusterGridBuf.subarray(0, gridX * gridY * gridZ * 2)
|
|
3567
|
+
);
|
|
3568
|
+
if (!clusterGridUpload.ok)
|
|
3569
|
+
return err$1(mapClusterUploadFailure("cluster-grid", clusterGridUpload.error));
|
|
3570
|
+
if (!gpuMembership && lightIndexCount > 0) {
|
|
3571
|
+
const lightIndexListUpload = internals.device.queue.writeBuffer(
|
|
3572
|
+
hdrpBuffers2.lightIndexListBuffer,
|
|
3573
|
+
0,
|
|
3574
|
+
lightIndexListBuf.subarray(0, lightIndexCount)
|
|
3575
|
+
);
|
|
3576
|
+
if (!lightIndexListUpload.ok) {
|
|
3577
|
+
return err$1(mapClusterUploadFailure("light-index-list", lightIndexListUpload.error));
|
|
3578
3578
|
}
|
|
3579
3579
|
}
|
|
3580
3580
|
const clusterUniformUpload = internals.device.queue.writeBuffer(
|
|
3581
|
-
|
|
3581
|
+
hdrpBuffers2.clusterUniformBuffer,
|
|
3582
3582
|
0,
|
|
3583
3583
|
clusterUniformPayload
|
|
3584
3584
|
);
|
|
3585
|
-
if (!clusterUniformUpload.ok)
|
|
3585
|
+
if (!clusterUniformUpload.ok) {
|
|
3586
|
+
return err$1(mapClusterUploadFailure("cluster-uniform", clusterUniformUpload.error));
|
|
3587
|
+
}
|
|
3588
|
+
return ok(void 0);
|
|
3586
3589
|
}
|
|
3587
|
-
|
|
3590
|
+
);
|
|
3591
|
+
if (!bufferUpload.ok) return bufferUpload;
|
|
3592
|
+
const ssaoUpload = runHdrpClusterProfilePhase(
|
|
3593
|
+
profilePhase,
|
|
3594
|
+
"record/scene-state/hdrp-cluster/buffer-upload",
|
|
3595
|
+
() => {
|
|
3588
3596
|
const ssaoBufs = getOrCreateSsaoBuffers(internals);
|
|
3589
|
-
if (ssaoBufs
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3597
|
+
if (ssaoBufs === null) return ok(void 0);
|
|
3598
|
+
const sProj = computeProjectionMatrix(camera);
|
|
3599
|
+
const sView = computeViewMatrix(camera);
|
|
3600
|
+
const invProjOnly = mat4.create();
|
|
3601
|
+
mat4.invert(invProjOnly, sProj);
|
|
3602
|
+
const ssaoUniformPayload = new Float32Array(64);
|
|
3603
|
+
ssaoUniformPayload.set(sView, 0);
|
|
3604
|
+
ssaoUniformPayload.set(sProj, 16);
|
|
3605
|
+
ssaoUniformPayload.set(invProjOnly, 32);
|
|
3606
|
+
const ssaoConfig = frameState.installedPipelineConfig?.ssao;
|
|
3607
|
+
const parameters = getSsaoParameters(
|
|
3608
|
+
ssaoConfig !== void 0 && ssaoConfig.enabled === true ? ssaoConfig : void 0
|
|
3609
|
+
);
|
|
3610
|
+
ssaoUniformPayload[48] = parameters.intensity;
|
|
3611
|
+
ssaoUniformPayload[49] = parameters.radius;
|
|
3612
|
+
ssaoUniformPayload[50] = parameters.bias;
|
|
3613
|
+
const ssaoUniformRes = internals.device.queue.writeBuffer(
|
|
3614
|
+
ssaoBufs.uniformBuffer,
|
|
3615
|
+
0,
|
|
3616
|
+
ssaoUniformPayload
|
|
3617
|
+
);
|
|
3618
|
+
if (!ssaoUniformRes.ok)
|
|
3619
|
+
return err$1(mapClusterUploadFailure("ssao-uniform", ssaoUniformRes.error));
|
|
3620
|
+
return ok(void 0);
|
|
3612
3621
|
}
|
|
3613
|
-
|
|
3622
|
+
);
|
|
3623
|
+
if (!ssaoUpload.ok) return ssaoUpload;
|
|
3624
|
+
return ok(void 0);
|
|
3614
3625
|
}
|
|
3615
3626
|
function resolveSkyboxActive(internals, frameState, camera, skybox) {
|
|
3616
3627
|
const tonemapActive = camera.tonemap !== "none";
|
|
@@ -3636,6 +3647,7 @@ function getOrCreateIblCache(scope) {
|
|
|
3636
3647
|
const existing = scopeCaches.get(scope);
|
|
3637
3648
|
if (existing !== void 0) return existing;
|
|
3638
3649
|
const cache3 = {
|
|
3650
|
+
probeKernel: createIblKernelCache(scope.generation),
|
|
3639
3651
|
irradianceBakeCount: 0,
|
|
3640
3652
|
prefilterBakeCount: 0,
|
|
3641
3653
|
brdfLutBakeCount: 0
|
|
@@ -4780,6 +4792,51 @@ function deriveRenderDataCubemap(source) {
|
|
|
4780
4792
|
cubeUsage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING | GPU_TEXTURE_USAGE_COPY_DST | GPU_TEXTURE_USAGE_COPY_SRC
|
|
4781
4793
|
});
|
|
4782
4794
|
}
|
|
4795
|
+
|
|
4796
|
+
// src/targets/material-source.ts
|
|
4797
|
+
var sourceBindings = /* @__PURE__ */ new WeakMap();
|
|
4798
|
+
function sourceToken() {
|
|
4799
|
+
return Object.freeze({});
|
|
4800
|
+
}
|
|
4801
|
+
function resolveRenderTargetMaterialSource(source) {
|
|
4802
|
+
return sourceBindings.get(source);
|
|
4803
|
+
}
|
|
4804
|
+
function invalid(field, value, expected) {
|
|
4805
|
+
return {
|
|
4806
|
+
ok: false,
|
|
4807
|
+
error: new RenderTargetDescriptorInvalidError({ field, value, expected })
|
|
4808
|
+
};
|
|
4809
|
+
}
|
|
4810
|
+
function createRenderTargetMaterialSource(target, descriptor, options) {
|
|
4811
|
+
if (options.aspect !== "color") return invalid("aspect", options.aspect, "color");
|
|
4812
|
+
if (options.dimension !== descriptor.shape) {
|
|
4813
|
+
return invalid("dimension", options.dimension, `dimension matches ${descriptor.shape}`);
|
|
4814
|
+
}
|
|
4815
|
+
const mipCount = descriptor.mipLevels === 1 ? 1 : Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
|
|
4816
|
+
if (!Number.isInteger(options.mipLevel) || options.mipLevel < 0 || options.mipLevel >= mipCount) {
|
|
4817
|
+
return invalid("mipLevel", options.mipLevel, `an admitted mip level below ${mipCount}`);
|
|
4818
|
+
}
|
|
4819
|
+
if (!Number.isInteger(options.generation) || options.generation < 0) {
|
|
4820
|
+
return invalid("generation", options.generation, "a non-negative device generation");
|
|
4821
|
+
}
|
|
4822
|
+
const result = {
|
|
4823
|
+
ok: true,
|
|
4824
|
+
value: Object.freeze({
|
|
4825
|
+
source: sourceToken(),
|
|
4826
|
+
target,
|
|
4827
|
+
generation: options.generation,
|
|
4828
|
+
shape: descriptor.shape,
|
|
4829
|
+
format: descriptor.format,
|
|
4830
|
+
view: Object.freeze({
|
|
4831
|
+
dimension: options.dimension,
|
|
4832
|
+
mipLevel: options.mipLevel,
|
|
4833
|
+
resolveRequired: descriptor.sampleCount === 4
|
|
4834
|
+
})
|
|
4835
|
+
})
|
|
4836
|
+
};
|
|
4837
|
+
sourceBindings.set(result.value.source, result.value);
|
|
4838
|
+
return result;
|
|
4839
|
+
}
|
|
4783
4840
|
var STANDARD_PBR_UBO_SIZE = 384;
|
|
4784
4841
|
var MATERIAL_PER_ENTITY_STRIDE = 512;
|
|
4785
4842
|
function resolveSurfaceProfile(storageFormat, viewFormat, facts) {
|
|
@@ -4892,6 +4949,11 @@ function selectSwapChainFormat(storageBufferCapable, surfaceViewFormats = true)
|
|
|
4892
4949
|
}
|
|
4893
4950
|
|
|
4894
4951
|
// src/record/main-pass-material.ts
|
|
4952
|
+
function selectMaterialGroup2(clusterGroup, meshGroup, group2Contract) {
|
|
4953
|
+
if (group2Contract === "cluster") return clusterGroup;
|
|
4954
|
+
if (group2Contract === "mesh") return meshGroup;
|
|
4955
|
+
return null;
|
|
4956
|
+
}
|
|
4895
4957
|
var DERIVED_PARAM_SCHEMA_CACHE = /* @__PURE__ */ new WeakMap();
|
|
4896
4958
|
function derivedParamSchema(schema) {
|
|
4897
4959
|
const cached = DERIVED_PARAM_SCHEMA_CACHE.get(schema);
|
|
@@ -5119,6 +5181,10 @@ function materialTextureForField(material, field) {
|
|
|
5119
5181
|
if (field === "occlusionTexture") return material.occlusionTexture;
|
|
5120
5182
|
return material.textureHandles?.get(field);
|
|
5121
5183
|
}
|
|
5184
|
+
function materialRenderTargetSourceForField(material, field, resolveSource) {
|
|
5185
|
+
const source = material.textureSources?.get(field);
|
|
5186
|
+
return source === void 0 ? void 0 : resolveSource?.(source) ?? resolveRenderTargetMaterialSource(source);
|
|
5187
|
+
}
|
|
5122
5188
|
function materialUboFloatView(payload) {
|
|
5123
5189
|
if (payload instanceof Float32Array) return payload;
|
|
5124
5190
|
return payload instanceof Uint8Array ? new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4) : new Float32Array(payload);
|
|
@@ -5210,7 +5276,11 @@ function userRegionTextureFieldOrder(schema) {
|
|
|
5210
5276
|
const fields = [...derivedParamSchema(schema).textureFieldNames];
|
|
5211
5277
|
return fields;
|
|
5212
5278
|
}
|
|
5213
|
-
function defaultViewForUserRegionField(field, pipelineState) {
|
|
5279
|
+
function defaultViewForUserRegionField(field, pipelineState, schema) {
|
|
5280
|
+
const parameter = schema?.find((entry) => entry.name === field);
|
|
5281
|
+
if (parameter?.type === "texture_cube") {
|
|
5282
|
+
return pipelineState.skylightFallback?.prefilterView ?? pipelineState.defaultWhiteTextureView;
|
|
5283
|
+
}
|
|
5214
5284
|
if (field === "normalTexture") return pipelineState.defaultNormalTextureView;
|
|
5215
5285
|
if (field === "baseColorTexture") return pipelineState.fallbackTextureView;
|
|
5216
5286
|
return pipelineState.defaultWhiteTextureView;
|
|
@@ -5320,11 +5390,14 @@ function buildPerSubmeshMaterialBg(deps, submeshMaterial, entityKey, materialWor
|
|
|
5320
5390
|
materialSlice,
|
|
5321
5391
|
videoHighPerfAvailable,
|
|
5322
5392
|
skylightResources,
|
|
5393
|
+
resolveRenderTargetTextureSource,
|
|
5394
|
+
resolveReflectionProbeResources,
|
|
5323
5395
|
materialBgShared,
|
|
5324
5396
|
materialBgAssemblyCache,
|
|
5325
5397
|
transmissionBackdropView,
|
|
5326
5398
|
bindGroupCounts
|
|
5327
5399
|
} = deps;
|
|
5400
|
+
const effectiveSkylightResources = resolveReflectionProbeResources?.(materialWorld, entityKey) ?? skylightResources;
|
|
5328
5401
|
const smMaterialHandle = submeshMaterial.materialHandle;
|
|
5329
5402
|
const materialCacheKey = smMaterialHandle === void 0 ? void 0 : `${materialWorld.identity}:${smMaterialHandle}`;
|
|
5330
5403
|
const smHasVideoFields = (submeshMaterial.videoTextureFields?.size ?? 0) > 0;
|
|
@@ -5339,7 +5412,7 @@ function buildPerSubmeshMaterialBg(deps, submeshMaterial, entityKey, materialWor
|
|
|
5339
5412
|
submeshMaterial,
|
|
5340
5413
|
smMaterialBgl,
|
|
5341
5414
|
pipelineState.materialUniformBuffer.buffer,
|
|
5342
|
-
|
|
5415
|
+
effectiveSkylightResources,
|
|
5343
5416
|
store.materialResourceEpoch,
|
|
5344
5417
|
transmissionBackdropView
|
|
5345
5418
|
)) {
|
|
@@ -5374,9 +5447,17 @@ function buildPerSubmeshMaterialBg(deps, submeshMaterial, entityKey, materialWor
|
|
|
5374
5447
|
const field = smUserRegionFields[fi];
|
|
5375
5448
|
const samplerBinding = 1 + fi * 2;
|
|
5376
5449
|
const textureBinding = samplerBinding + 1;
|
|
5377
|
-
let smView = field !== void 0 ? defaultViewForUserRegionField(field, pipelineState) : pipelineState.defaultWhiteTextureView;
|
|
5450
|
+
let smView = field !== void 0 ? defaultViewForUserRegionField(field, pipelineState, smSchema) : pipelineState.defaultWhiteTextureView;
|
|
5378
5451
|
const smVideoClip = field !== void 0 ? submeshMaterial.videoTextureFields?.get(field) : void 0;
|
|
5379
|
-
|
|
5452
|
+
const smTargetSource = field === void 0 ? void 0 : materialRenderTargetSourceForField(
|
|
5453
|
+
submeshMaterial,
|
|
5454
|
+
field,
|
|
5455
|
+
resolveRenderTargetTextureSource
|
|
5456
|
+
);
|
|
5457
|
+
if (smTargetSource !== void 0) {
|
|
5458
|
+
if (smTargetSource.textureView !== void 0) smView = smTargetSource.textureView;
|
|
5459
|
+
else materialResourcesResident = false;
|
|
5460
|
+
} else if (smVideoClip !== void 0) {
|
|
5380
5461
|
const view = videoTextureView(
|
|
5381
5462
|
materialWorld,
|
|
5382
5463
|
runtime.dynamicTextureStore,
|
|
@@ -5405,11 +5486,15 @@ function buildPerSubmeshMaterialBg(deps, submeshMaterial, entityKey, materialWor
|
|
|
5405
5486
|
}
|
|
5406
5487
|
);
|
|
5407
5488
|
}
|
|
5408
|
-
const transmissionSampler = transmissionBackdropView != null ?
|
|
5409
|
-
const smMergedEntries = assembleMaterialWithSkylightEntries(
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5489
|
+
const transmissionSampler = transmissionBackdropView != null ? effectiveSkylightResources.prefilterSampler : pipelineState.defaultSampler;
|
|
5490
|
+
const smMergedEntries = assembleMaterialWithSkylightEntries(
|
|
5491
|
+
smBaseEntries,
|
|
5492
|
+
effectiveSkylightResources,
|
|
5493
|
+
{
|
|
5494
|
+
sampler: transmissionSampler,
|
|
5495
|
+
...transmissionBackdropView === void 0 ? {} : { backdropView: transmissionBackdropView }
|
|
5496
|
+
}
|
|
5497
|
+
);
|
|
5413
5498
|
const createBindGroup = () => {
|
|
5414
5499
|
const result = runtime.device.createBindGroup({
|
|
5415
5500
|
label: "pbr-material-skylight-bg",
|
|
@@ -5434,7 +5519,7 @@ function buildPerSubmeshMaterialBg(deps, submeshMaterial, entityKey, materialWor
|
|
|
5434
5519
|
materialResourceEpoch: store.materialResourceEpoch,
|
|
5435
5520
|
materialBgl: smMaterialBgl,
|
|
5436
5521
|
materialBuffer: pipelineState.materialUniformBuffer.buffer,
|
|
5437
|
-
skylightResources,
|
|
5522
|
+
skylightResources: effectiveSkylightResources,
|
|
5438
5523
|
bindGroup: smBindGroup
|
|
5439
5524
|
});
|
|
5440
5525
|
}
|
|
@@ -5495,9 +5580,11 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5495
5580
|
msaaActive,
|
|
5496
5581
|
validatedOrdered,
|
|
5497
5582
|
splitLdrSprite,
|
|
5498
|
-
viewBindGroup
|
|
5583
|
+
viewBindGroup,
|
|
5584
|
+
viewBindGroupDynamicOffset = 0
|
|
5499
5585
|
} = c;
|
|
5500
5586
|
const colorFormatOverride = c.transparentColorFormat;
|
|
5587
|
+
const clusteredLighting = c.standardLighting?.kind === "clustered";
|
|
5501
5588
|
const isHdrTarget = tonemapActive || colorFormatOverride === "rgba16float";
|
|
5502
5589
|
let lastVertexBuffer = null;
|
|
5503
5590
|
let lastIndexBuffer = null;
|
|
@@ -5516,7 +5603,6 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5516
5603
|
const profilePhase = c.profilePhase;
|
|
5517
5604
|
const materialGroup1DynamicOffsets = new Uint32Array(1);
|
|
5518
5605
|
const meshGroup2DynamicOffsets = [0];
|
|
5519
|
-
const skinGroup2DynamicOffsets = [0, 0];
|
|
5520
5606
|
let lastStencilReference = null;
|
|
5521
5607
|
const materialPipelineLookupCache = /* @__PURE__ */ new Map();
|
|
5522
5608
|
const resolveMaterialPipeline = (materialShaderId, renderState, topology, indexFormat, variantSet, colorFormat, layoutProjection) => {
|
|
@@ -5536,7 +5622,7 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5536
5622
|
return null;
|
|
5537
5623
|
}
|
|
5538
5624
|
const resolvedVariantSet = resolvedVariantSetResult.value;
|
|
5539
|
-
const resolvePipeline = () => runtime.
|
|
5625
|
+
const resolvePipeline = () => runtime.getMaterialShaderPipelineEntry?.(
|
|
5540
5626
|
materialShaderId,
|
|
5541
5627
|
isHdrTarget,
|
|
5542
5628
|
renderState,
|
|
@@ -5583,7 +5669,7 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5583
5669
|
for (let i = 0; i < validatedOrdered.length; i++) {
|
|
5584
5670
|
const entry = validatedOrdered[i];
|
|
5585
5671
|
if (entry === void 0) continue;
|
|
5586
|
-
const pointsLinesSubmission = c.pointsLines?.prepare(entry,
|
|
5672
|
+
const pointsLinesSubmission = c.pointsLines?.prepare(entry, clusteredLighting);
|
|
5587
5673
|
if (entry.source.pointsLines !== void 0 && pointsLinesSubmission?.plan.drawCount !== 1)
|
|
5588
5674
|
continue;
|
|
5589
5675
|
if (passKind === "forward" && c.gpuDrivenEntityKeys.has(worldEntityKey(entry.source.worldId, entry.source.entityKey))) {
|
|
@@ -5609,7 +5695,7 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5609
5695
|
entry.source.entityKey,
|
|
5610
5696
|
entry.world ?? c.world
|
|
5611
5697
|
);
|
|
5612
|
-
const
|
|
5698
|
+
const pointsLinesPipelineEntry = resolveMaterialPipeline(
|
|
5613
5699
|
POINTS_LINES_MATERIAL_SHADER_ID,
|
|
5614
5700
|
{
|
|
5615
5701
|
...pointsLinesMaterial.renderState,
|
|
@@ -5621,7 +5707,8 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5621
5707
|
colorFormatOverride,
|
|
5622
5708
|
pointsLinesSubmission.layoutProjection
|
|
5623
5709
|
);
|
|
5624
|
-
if (
|
|
5710
|
+
if (pointsLinesPipelineEntry === null) continue;
|
|
5711
|
+
const pointsLinesPipeline = pointsLinesPipelineEntry.pipeline;
|
|
5625
5712
|
if (pipelineState.pointsLinesViewBuffer === void 0) continue;
|
|
5626
5713
|
writePointsLinesViewUbo(
|
|
5627
5714
|
runtime.device.queue,
|
|
@@ -5636,9 +5723,9 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5636
5723
|
pass.setBindGroup(
|
|
5637
5724
|
0,
|
|
5638
5725
|
viewBindGroup,
|
|
5639
|
-
new Uint32Array([i * POINTS_LINES_VIEW_SLOT_STRIDE]),
|
|
5726
|
+
new Uint32Array([0, i * POINTS_LINES_VIEW_SLOT_STRIDE]),
|
|
5640
5727
|
0,
|
|
5641
|
-
|
|
5728
|
+
2
|
|
5642
5729
|
);
|
|
5643
5730
|
pass.setPipeline(pointsLinesPipeline);
|
|
5644
5731
|
pass.setVertexBuffer(0, pointsLinesSubmission.vertexBuffer);
|
|
@@ -5653,7 +5740,7 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5653
5740
|
identityInstanceDraws[0]?.instanceBindGroup ?? resolveGeometryInstancesBindGroup(c, identityInstanceBuffer)
|
|
5654
5741
|
);
|
|
5655
5742
|
recordPointsLinesDraw(pass, pointsLinesSubmission.plan);
|
|
5656
|
-
pass.setBindGroup(0, viewBindGroup, [0]);
|
|
5743
|
+
pass.setBindGroup(0, viewBindGroup, [viewBindGroupDynamicOffset, 0]);
|
|
5657
5744
|
continue;
|
|
5658
5745
|
}
|
|
5659
5746
|
if (entry.mesh.vertexBuffer !== lastVertexBuffer) {
|
|
@@ -5675,14 +5762,22 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5675
5762
|
const isSkinEntry = entry.source.skin !== void 0;
|
|
5676
5763
|
const skinAllocator = pipelineState.skinPaletteAllocator;
|
|
5677
5764
|
const skinSlice = entry.source.skin;
|
|
5678
|
-
const
|
|
5679
|
-
|
|
5765
|
+
const clusteredSkin = clusteredLighting;
|
|
5766
|
+
const skinMeshBindGroupLayout = clusteredSkin ? pipelineState.hdrpSkinMeshBindGroupLayout : pipelineState.pbrSkinMeshBindGroupLayout;
|
|
5767
|
+
const hdrpSkinBuffers = isSkinEntry && clusteredSkin ? getOrCreateHdrpBuffers(runtime, frameState.installedPipelineConfig?.clusterGrid) : null;
|
|
5768
|
+
const skinResources = isSkinEntry && skinMeshBindGroupLayout !== null && skinAllocator !== null && skinSlice !== void 0 && (!clusteredSkin || hdrpSkinBuffers !== null) ? {
|
|
5769
|
+
meshArrayBgl: skinMeshBindGroupLayout,
|
|
5680
5770
|
paletteBuffer: skinSlice.buffer,
|
|
5681
|
-
paletteBindingWindowBytes: skinAllocator.bindingWindowBytes
|
|
5771
|
+
paletteBindingWindowBytes: skinAllocator.bindingWindowBytes,
|
|
5772
|
+
hdrpBuffers: hdrpSkinBuffers
|
|
5682
5773
|
} : null;
|
|
5683
5774
|
const skinVariantSetResult = variantSetFromVertexLayoutProjection(
|
|
5684
5775
|
entry.mesh.layoutProjection,
|
|
5685
|
-
|
|
5776
|
+
standardTopologyVariantSet(
|
|
5777
|
+
c.standardLighting,
|
|
5778
|
+
runtime.device.caps.storageBuffer,
|
|
5779
|
+
entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === "color")
|
|
5780
|
+
)
|
|
5686
5781
|
);
|
|
5687
5782
|
if (!skinVariantSetResult.ok) runtime.errorRegistry.fire(skinVariantSetResult.error);
|
|
5688
5783
|
const skinVariantSet = skinVariantSetResult.ok ? skinVariantSetResult.value : void 0;
|
|
@@ -5709,45 +5804,45 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5709
5804
|
const skinMissesBefore = bindGroupCounts.createBindGroup;
|
|
5710
5805
|
const skinBindGroup = getOrCreateFromChain(
|
|
5711
5806
|
frameState.meshBindGroupCache,
|
|
5712
|
-
[
|
|
5807
|
+
[
|
|
5808
|
+
pipelineState.meshStorageBuffer.buffer,
|
|
5809
|
+
skinResources.paletteBuffer,
|
|
5810
|
+
...skinResources.hdrpBuffers === null ? [] : [
|
|
5811
|
+
skinResources.hdrpBuffers.lightDataBuffer,
|
|
5812
|
+
skinResources.hdrpBuffers.clusterGridBuffer,
|
|
5813
|
+
skinResources.hdrpBuffers.lightIndexListBuffer,
|
|
5814
|
+
skinResources.hdrpBuffers.clusterUniformBuffer
|
|
5815
|
+
]
|
|
5816
|
+
],
|
|
5713
5817
|
"pbr-skin-mesh",
|
|
5714
5818
|
() => {
|
|
5819
|
+
if (skinResources.hdrpBuffers !== null) {
|
|
5820
|
+
const result2 = createHdrpSkinUnifiedBindGroup(
|
|
5821
|
+
runtime,
|
|
5822
|
+
skinResources.hdrpBuffers,
|
|
5823
|
+
skinResources.meshArrayBgl,
|
|
5824
|
+
pipelineState.meshStorageBuffer.buffer,
|
|
5825
|
+
skinResources.paletteBuffer,
|
|
5826
|
+
skinResources.paletteBindingWindowBytes
|
|
5827
|
+
);
|
|
5828
|
+
if (result2 === null) {
|
|
5829
|
+
throw new RhiError({
|
|
5830
|
+
code: "webgpu-runtime-error",
|
|
5831
|
+
expected: "HDRP clustered skin BindGroup creation succeeds",
|
|
5832
|
+
hint: "inspect prior errorRegistry events for createBindGroup failure detail"
|
|
5833
|
+
});
|
|
5834
|
+
}
|
|
5835
|
+
return result2;
|
|
5836
|
+
}
|
|
5715
5837
|
const result = runtime.device.createBindGroup({
|
|
5716
5838
|
label: "pbr-skin-mesh-bg",
|
|
5717
5839
|
layout: skinResources.meshArrayBgl,
|
|
5718
|
-
entries:
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
buffer: pipelineState.meshStorageBuffer.buffer,
|
|
5725
|
-
offset: 0,
|
|
5726
|
-
size: meshBindSize
|
|
5727
|
-
}
|
|
5728
|
-
}
|
|
5729
|
-
},
|
|
5730
|
-
{
|
|
5731
|
-
binding: 1,
|
|
5732
|
-
resource: {
|
|
5733
|
-
kind: "buffer",
|
|
5734
|
-
value: {
|
|
5735
|
-
buffer: skinResources.paletteBuffer,
|
|
5736
|
-
offset: 0,
|
|
5737
|
-
// M6 SSOT: static BG entry size (= MAX_JOINTS * 64 =
|
|
5738
|
-
// 16320 B) sourced from the allocator. The per-draw
|
|
5739
|
-
// window slides via `group2DynamicOffsets[1]`
|
|
5740
|
-
// (= entry.source.skin.byteOffset) so this size
|
|
5741
|
-
// stays at the worst case across all skin entries
|
|
5742
|
-
// -- one BG covers every skinned draw in the frame
|
|
5743
|
-
// (m3-1b miss=1 + hit=N-1 contract). The allocator
|
|
5744
|
-
// guarantees `buffer.size >= byteOffset + this size`
|
|
5745
|
-
// so dynOffset[1] passes WebGPU validation.
|
|
5746
|
-
size: skinResources.paletteBindingWindowBytes
|
|
5747
|
-
}
|
|
5748
|
-
}
|
|
5749
|
-
}
|
|
5750
|
-
]
|
|
5840
|
+
entries: createPbrSkinMeshBindGroupEntries(
|
|
5841
|
+
pipelineState.meshStorageBuffer.buffer,
|
|
5842
|
+
meshBindSize,
|
|
5843
|
+
skinResources.paletteBuffer,
|
|
5844
|
+
skinResources.paletteBindingWindowBytes
|
|
5845
|
+
)
|
|
5751
5846
|
});
|
|
5752
5847
|
if (!result.ok) throw result.error;
|
|
5753
5848
|
return result.value;
|
|
@@ -5759,9 +5854,10 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5759
5854
|
else skinStats.hit += 1;
|
|
5760
5855
|
}
|
|
5761
5856
|
group2BindGroup = skinBindGroup;
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5857
|
+
group2DynamicOffsets = pbrSkinMeshDynamicOffsets(
|
|
5858
|
+
i * MESH_PER_ENTITY_STRIDE,
|
|
5859
|
+
entry.source.skin?.byteOffset ?? 0
|
|
5860
|
+
);
|
|
5765
5861
|
} else if (isSkinEntry) {
|
|
5766
5862
|
continue;
|
|
5767
5863
|
}
|
|
@@ -5811,6 +5907,8 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5811
5907
|
} : geometryRenderStateForTopology(smTopology, submeshMaterial.renderState);
|
|
5812
5908
|
const pipelineRenderState = geometryRenderStateForPass(basePipelineRenderState, passKind);
|
|
5813
5909
|
let smPipelineHandle;
|
|
5910
|
+
let materialGroup2Contract;
|
|
5911
|
+
let materialPipelineEntry = null;
|
|
5814
5912
|
if (smMaterialShaderId === void 0 || smMaterialShaderId === "forgeax::default-unlit") {
|
|
5815
5913
|
const unlitShaderId = smMaterialShaderId ?? "forgeax::default-unlit";
|
|
5816
5914
|
const unlitProjectionVariantResult = variantSetFromVertexLayoutProjection(
|
|
@@ -5822,7 +5920,10 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5822
5920
|
continue;
|
|
5823
5921
|
}
|
|
5824
5922
|
const unlitHasColor = unlitProjectionVariantResult.value === "VERTEX_COLOR_AVAILABLE=true";
|
|
5825
|
-
const unlitVariantSet =
|
|
5923
|
+
const unlitVariantSet = standardStorageVariantSet(
|
|
5924
|
+
runtime.device.caps.storageBuffer,
|
|
5925
|
+
unlitHasColor
|
|
5926
|
+
);
|
|
5826
5927
|
const unlitRsp = resolveMaterialPipeline(
|
|
5827
5928
|
unlitShaderId,
|
|
5828
5929
|
pipelineRenderState,
|
|
@@ -5832,12 +5933,17 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5832
5933
|
colorFormatOverride,
|
|
5833
5934
|
entry.mesh.layoutProjection
|
|
5834
5935
|
);
|
|
5835
|
-
|
|
5936
|
+
materialPipelineEntry = unlitRsp;
|
|
5937
|
+
smPipelineHandle = unlitRsp?.pipeline ?? (colorFormatOverride === void 0 ? selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive) : null);
|
|
5836
5938
|
} else if (smMaterialShaderId !== void 0) {
|
|
5837
5939
|
const hasVertexColor = entry.mesh.layoutProjection.attributes.some(
|
|
5838
5940
|
(attribute) => attribute.key === "color"
|
|
5839
5941
|
);
|
|
5840
|
-
const capabilityVariantSet =
|
|
5942
|
+
const capabilityVariantSet = standardTopologyVariantSet(
|
|
5943
|
+
c.standardLighting,
|
|
5944
|
+
runtime.device.caps.storageBuffer,
|
|
5945
|
+
hasVertexColor
|
|
5946
|
+
);
|
|
5841
5947
|
const variantSet = isSpriteShader ? smMaterialShaderId === "forgeax::sprite" && entry.source.spriteInstances !== void 0 ? "" : void 0 : entry.variantSet === void 0 ? capabilityVariantSet : capabilityVariantSet === "" ? entry.variantSet : `${capabilityVariantSet}+${entry.variantSet}`;
|
|
5842
5948
|
const projectionVariantSetResult = isSpriteShader ? { ok: true, value: variantSet } : variantSetFromVertexLayoutProjection(entry.mesh.layoutProjection, variantSet);
|
|
5843
5949
|
if (!projectionVariantSetResult.ok) {
|
|
@@ -5853,23 +5959,24 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
|
|
|
5853
5959
|
colorFormatOverride,
|
|
5854
5960
|
entry.mesh.layoutProjection
|
|
5855
5961
|
);
|
|
5856
|
-
|
|
5962
|
+
materialPipelineEntry = cachedPipeline;
|
|
5963
|
+
smPipelineHandle = cachedPipeline?.pipeline ?? null;
|
|
5857
5964
|
} else {
|
|
5858
5965
|
smPipelineHandle = selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive);
|
|
5859
5966
|
}
|
|
5860
5967
|
if (smPipelineHandle === null) {
|
|
5861
5968
|
continue;
|
|
5862
5969
|
}
|
|
5863
|
-
const usesStandardClusterBindings = smMaterialShaderId === "forgeax::default-standard-pbr";
|
|
5864
5970
|
if (!isSkinEntry) {
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5971
|
+
materialGroup2Contract = materialPipelineEntry?.group2Contract;
|
|
5972
|
+
if (materialGroup2Contract === void 0) continue;
|
|
5973
|
+
const selectedGroup = selectMaterialGroup2(
|
|
5974
|
+
meshGroup2,
|
|
5975
|
+
meshBindGroup,
|
|
5976
|
+
materialGroup2Contract
|
|
5977
|
+
);
|
|
5978
|
+
if (selectedGroup === null) continue;
|
|
5979
|
+
group2BindGroup = selectedGroup;
|
|
5873
5980
|
}
|
|
5874
5981
|
pass.setBindGroup(2, group2BindGroup, group2DynamicOffsets);
|
|
5875
5982
|
if (profilePhase === void 0) {
|
|
@@ -5907,6 +6014,7 @@ function resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws) {
|
|
|
5907
6014
|
const { runtime, pipelineState, frameState } = c;
|
|
5908
6015
|
const inst = entry.source.instances;
|
|
5909
6016
|
if (inst === void 0) return identityInstanceDraws;
|
|
6017
|
+
if (inst.instanceCount === 0) return [];
|
|
5910
6018
|
let instanceBuffer = pipelineState.identityInstanceBuffer;
|
|
5911
6019
|
let instanceCount = 1;
|
|
5912
6020
|
{
|
|
@@ -6126,8 +6234,13 @@ function recordSpritePass(c, pass, matchedIndices, materialSlotIndices, sampleCo
|
|
|
6126
6234
|
ldrSpriteColorView,
|
|
6127
6235
|
geometryDepthView,
|
|
6128
6236
|
viewBindGroup,
|
|
6237
|
+
meshBindGroup,
|
|
6238
|
+
hdrpClusterBindGroup,
|
|
6239
|
+
viewBindGroupDynamicOffset = 0,
|
|
6129
6240
|
splitLdrSprite
|
|
6130
6241
|
} = c;
|
|
6242
|
+
const clusteredLighting = c.standardLighting?.kind === "clustered";
|
|
6243
|
+
const meshGroup2 = clusteredLighting ? hdrpClusterBindGroup : meshBindGroup;
|
|
6131
6244
|
const spriteIsHdr = c.tonemapActive || transparentPassColorFormat(c, pipelineState) === "rgba16float";
|
|
6132
6245
|
let geometryPassEnded = false;
|
|
6133
6246
|
if (splitLdrSprite && (graphPass !== void 0 || ldrSpritePassView !== null)) {
|
|
@@ -6155,7 +6268,7 @@ function recordSpritePass(c, pass, matchedIndices, materialSlotIndices, sampleCo
|
|
|
6155
6268
|
{ colorLoadOp: "load", depthLoadOp: "load" }
|
|
6156
6269
|
)
|
|
6157
6270
|
);
|
|
6158
|
-
spritePass.setBindGroup(0, viewBindGroup, [0]);
|
|
6271
|
+
spritePass.setBindGroup(0, viewBindGroup, [viewBindGroupDynamicOffset, 0]);
|
|
6159
6272
|
const spritePremulBlend = {
|
|
6160
6273
|
depthWriteEnabled: false,
|
|
6161
6274
|
depthCompare: "less-equal",
|
|
@@ -6211,7 +6324,12 @@ function recordSpritePass(c, pass, matchedIndices, materialSlotIndices, sampleCo
|
|
|
6211
6324
|
spritePremulBlend,
|
|
6212
6325
|
"triangle-list",
|
|
6213
6326
|
void 0,
|
|
6214
|
-
|
|
6327
|
+
// sprite-lit declares the same Standard capability axes as PBR. The
|
|
6328
|
+
// boot artifact is intentionally the direct compatibility variant,
|
|
6329
|
+
// so a clustered frame must request its explicit Cluster artifact;
|
|
6330
|
+
// otherwise the host binds the unified group(2) while the shader
|
|
6331
|
+
// still reads the now-cleared direct-light headers.
|
|
6332
|
+
standardTopologyVariantSet(c.standardLighting, runtime.device.caps.storageBuffer, false),
|
|
6215
6333
|
"forward",
|
|
6216
6334
|
void 0,
|
|
6217
6335
|
msaaActive ? 4 : 1,
|
|
@@ -6233,14 +6351,15 @@ function recordSpritePass(c, pass, matchedIndices, materialSlotIndices, sampleCo
|
|
|
6233
6351
|
matchedIndices,
|
|
6234
6352
|
materialSlotIndices,
|
|
6235
6353
|
sampleCount,
|
|
6236
|
-
resolveMaterialBindGroup
|
|
6354
|
+
resolveMaterialBindGroup,
|
|
6355
|
+
meshGroup2
|
|
6237
6356
|
);
|
|
6238
6357
|
if (graphPass === void 0) spritePass.end();
|
|
6239
6358
|
}
|
|
6240
6359
|
return geometryPassEnded;
|
|
6241
6360
|
}
|
|
6242
|
-
function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, materialSlotIndices, sampleCount, resolveMaterialBindGroup) {
|
|
6243
|
-
const { runtime, pipelineState, frameState, bindGroupCounts, validatedOrdered
|
|
6361
|
+
function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, materialSlotIndices, sampleCount, resolveMaterialBindGroup, meshGroup2) {
|
|
6362
|
+
const { runtime, pipelineState, frameState, bindGroupCounts, validatedOrdered } = c;
|
|
6244
6363
|
const isHdrTarget = c.tonemapActive || transparentPassColorFormat(c, pipelineState) === "rgba16float";
|
|
6245
6364
|
let lastPbrSubPipelineHandle = null;
|
|
6246
6365
|
let lastPbrSubVertexBuffer = null;
|
|
@@ -6263,7 +6382,6 @@ function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, material
|
|
|
6263
6382
|
spritePass.setIndexBuffer(entry.mesh.indexBuffer.handle, entry.mesh.indexFormat);
|
|
6264
6383
|
lastPbrSubIndexBuffer = entry.mesh.indexBuffer;
|
|
6265
6384
|
}
|
|
6266
|
-
spritePass.setBindGroup(2, meshBindGroup, [i * MESH_PER_ENTITY_STRIDE]);
|
|
6267
6385
|
const identityInstBg = getOrCreatePerEntity(
|
|
6268
6386
|
frameState.instancesBgPerEntity,
|
|
6269
6387
|
worldEntityKey(entry.source.worldId, entry.source.entityKey),
|
|
@@ -6289,7 +6407,11 @@ function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, material
|
|
|
6289
6407
|
bindGroupCounts
|
|
6290
6408
|
);
|
|
6291
6409
|
spritePass.setBindGroup(3, identityInstBg);
|
|
6292
|
-
const subVariantSet =
|
|
6410
|
+
const subVariantSet = standardTopologyVariantSet(
|
|
6411
|
+
c.standardLighting,
|
|
6412
|
+
runtime.device.caps.storageBuffer,
|
|
6413
|
+
entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === "color")
|
|
6414
|
+
);
|
|
6293
6415
|
const projectionVariantSetResult = variantSetFromVertexLayoutProjection(
|
|
6294
6416
|
entry.mesh.layoutProjection,
|
|
6295
6417
|
subVariantSet
|
|
@@ -6307,15 +6429,7 @@ function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, material
|
|
|
6307
6429
|
if (submeshMaterial.transparent !== true) continue;
|
|
6308
6430
|
const smShaderId = submeshMaterial.materialShaderId;
|
|
6309
6431
|
if (smShaderId === void 0) continue;
|
|
6310
|
-
const
|
|
6311
|
-
const subBg = resolveMaterialBindGroup(
|
|
6312
|
-
materialSlot,
|
|
6313
|
-
submeshMaterial,
|
|
6314
|
-
entry.source.entityKey,
|
|
6315
|
-
entry.world ?? c.world
|
|
6316
|
-
);
|
|
6317
|
-
spritePass.setBindGroup(1, subBg, [materialSlot * MATERIAL_PER_ENTITY_STRIDE]);
|
|
6318
|
-
const subPipeline = runtime.getMaterialShaderPipeline?.(
|
|
6432
|
+
const subPipelineEntry = c.runtime.getMaterialShaderPipelineEntry?.(
|
|
6319
6433
|
smShaderId,
|
|
6320
6434
|
isHdrTarget,
|
|
6321
6435
|
submeshMaterial.renderState,
|
|
@@ -6332,7 +6446,20 @@ function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, material
|
|
|
6332
6446
|
void 0,
|
|
6333
6447
|
entry.mesh.layoutProjection
|
|
6334
6448
|
) ?? null;
|
|
6335
|
-
if (
|
|
6449
|
+
if (subPipelineEntry === null) continue;
|
|
6450
|
+
const submeshContract = subPipelineEntry.group2Contract;
|
|
6451
|
+
const submeshGroup2 = selectMaterialGroup2(meshGroup2, c.meshBindGroup, submeshContract);
|
|
6452
|
+
if (submeshGroup2 === null) continue;
|
|
6453
|
+
spritePass.setBindGroup(2, submeshGroup2, [i * MESH_PER_ENTITY_STRIDE]);
|
|
6454
|
+
const materialSlot = materialSlotIndices[i]?.[matSlotIdx] ?? materialSlotIndices[i]?.[0] ?? 0;
|
|
6455
|
+
const subBg = resolveMaterialBindGroup(
|
|
6456
|
+
materialSlot,
|
|
6457
|
+
submeshMaterial,
|
|
6458
|
+
entry.source.entityKey,
|
|
6459
|
+
entry.world ?? c.world
|
|
6460
|
+
);
|
|
6461
|
+
spritePass.setBindGroup(1, subBg, [materialSlot * MATERIAL_PER_ENTITY_STRIDE]);
|
|
6462
|
+
const subPipeline = subPipelineEntry.pipeline;
|
|
6336
6463
|
if (lastPbrSubPipelineHandle !== subPipeline) {
|
|
6337
6464
|
spritePass.setPipeline(subPipeline);
|
|
6338
6465
|
lastPbrSubPipelineHandle = subPipeline;
|
|
@@ -6564,6 +6691,7 @@ function recordSpriteEntityDraws(c, spritePass, matchedIndices, skylightResource
|
|
|
6564
6691
|
);
|
|
6565
6692
|
spriteInstanceBuffer = _si.buffer;
|
|
6566
6693
|
spriteInstanceCount = _si.count;
|
|
6694
|
+
const spriteGroup2 = entityShaderId === "forgeax::sprite-lit" && c.standardLighting?.kind === "clustered" ? c.hdrpClusterBindGroup : meshBindGroup;
|
|
6567
6695
|
const spriteInstancesBg = getOrCreatePerEntity(
|
|
6568
6696
|
frameState.instancesBgPerEntity,
|
|
6569
6697
|
worldEntityKey(spriteEntry.source.worldId, spriteEntry.source.entityKey),
|
|
@@ -6588,7 +6716,7 @@ function recordSpriteEntityDraws(c, spritePass, matchedIndices, skylightResource
|
|
|
6588
6716
|
},
|
|
6589
6717
|
bindGroupCounts
|
|
6590
6718
|
);
|
|
6591
|
-
spritePass.setBindGroup(2,
|
|
6719
|
+
spritePass.setBindGroup(2, spriteGroup2, [i * MESH_PER_ENTITY_STRIDE]);
|
|
6592
6720
|
const spriteTexHandle = spriteEntry.source.material.baseColorTexture;
|
|
6593
6721
|
let spriteTexView = pipelineState.defaultWhiteTextureView;
|
|
6594
6722
|
if (spriteTexHandle !== void 0) {
|
|
@@ -6940,25 +7068,12 @@ function skinnedShadowMeshBindGroup(c, entry) {
|
|
|
6940
7068
|
const created = c.runtime.device.createBindGroup({
|
|
6941
7069
|
label: "shadow-pbr-skin-mesh-bg",
|
|
6942
7070
|
layout,
|
|
6943
|
-
entries:
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
buffer: c.pipelineState.meshStorageBuffer.buffer,
|
|
6950
|
-
size: c.runtime.device.caps.storageBuffer ? MESH_SSBO_BYTES : MESH_UBO_FULL_ARRAY_BYTES
|
|
6951
|
-
}
|
|
6952
|
-
}
|
|
6953
|
-
},
|
|
6954
|
-
{
|
|
6955
|
-
binding: 1,
|
|
6956
|
-
resource: {
|
|
6957
|
-
kind: "buffer",
|
|
6958
|
-
value: { buffer: skin.buffer, size: allocator.bindingWindowBytes }
|
|
6959
|
-
}
|
|
6960
|
-
}
|
|
6961
|
-
]
|
|
7071
|
+
entries: createPbrSkinMeshBindGroupEntries(
|
|
7072
|
+
c.pipelineState.meshStorageBuffer.buffer,
|
|
7073
|
+
c.runtime.device.caps.storageBuffer ? MESH_SSBO_BYTES : MESH_UBO_FULL_ARRAY_BYTES,
|
|
7074
|
+
skin.buffer,
|
|
7075
|
+
allocator.bindingWindowBytes
|
|
7076
|
+
)
|
|
6962
7077
|
});
|
|
6963
7078
|
if (!created.ok) throw created.error;
|
|
6964
7079
|
return created.value;
|
|
@@ -6980,7 +7095,7 @@ function encodeDirectionalShadowPass(c, pass, cascadeIndex, viewport) {
|
|
|
6980
7095
|
c.frameState.directionalShadowCacheRecorded = true;
|
|
6981
7096
|
pass.setViewport(viewport.x, viewport.y, viewport.w, viewport.h, 0, 1);
|
|
6982
7097
|
pass.setPipeline(pipeline);
|
|
6983
|
-
pass.setBindGroup(0, viewBg, [0]);
|
|
7098
|
+
pass.setBindGroup(0, viewBg, [0, 0]);
|
|
6984
7099
|
pass.setBindGroup(1, materialBg, [0]);
|
|
6985
7100
|
recordShadowCasterDraws(
|
|
6986
7101
|
c,
|
|
@@ -7004,7 +7119,7 @@ function encodePointShadowPass(c, pass, snapshotIndex, face) {
|
|
|
7004
7119
|
const materialBg = ensureSpotShadowMaterialBg(c);
|
|
7005
7120
|
if (pipeline === null || viewBg === null || materialBg === null) return;
|
|
7006
7121
|
pass.setPipeline(pipeline);
|
|
7007
|
-
pass.setBindGroup(0, viewBg, [0]);
|
|
7122
|
+
pass.setBindGroup(0, viewBg, [0, 0]);
|
|
7008
7123
|
pass.setBindGroup(1, materialBg, [0]);
|
|
7009
7124
|
recordShadowCasterDraws(
|
|
7010
7125
|
c,
|
|
@@ -7042,7 +7157,7 @@ function encodeSpotShadowPass(c, pass, snapshotIndex) {
|
|
|
7042
7157
|
1
|
|
7043
7158
|
);
|
|
7044
7159
|
pass.setPipeline(pipeline);
|
|
7045
|
-
pass.setBindGroup(0, viewBg, [0]);
|
|
7160
|
+
pass.setBindGroup(0, viewBg, [0, 0]);
|
|
7046
7161
|
pass.setBindGroup(1, materialBg, [0]);
|
|
7047
7162
|
recordShadowCasterDraws(
|
|
7048
7163
|
c,
|
|
@@ -7117,16 +7232,18 @@ function recordShadowCasterDraws(c, shadowPass, shadowPipeline2, shadowMeshBindG
|
|
|
7117
7232
|
if (entry.source.skin !== void 0) {
|
|
7118
7233
|
const skinMeshBindGroup = skinnedShadowMeshBindGroup(c, entry);
|
|
7119
7234
|
if (skinMeshBindGroup === null) continue;
|
|
7120
|
-
shadowPass.setBindGroup(
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7235
|
+
shadowPass.setBindGroup(
|
|
7236
|
+
2,
|
|
7237
|
+
skinMeshBindGroup,
|
|
7238
|
+
pbrSkinMeshDynamicOffsets(i * MESH_PER_ENTITY_STRIDE, entry.source.skin.byteOffset)
|
|
7239
|
+
);
|
|
7124
7240
|
} else {
|
|
7125
7241
|
shadowPass.setBindGroup(2, shadowMeshBindGroup, [i * MESH_PER_ENTITY_STRIDE]);
|
|
7126
7242
|
}
|
|
7127
7243
|
let shadowInstanceBuffer = pipelineState.identityInstanceBuffer;
|
|
7128
7244
|
let shadowInstanceCount = 1;
|
|
7129
7245
|
const shadowInst = entry.source.instances;
|
|
7246
|
+
if (shadowInst?.instanceCount === 0) continue;
|
|
7130
7247
|
if (shadowInst !== void 0) {
|
|
7131
7248
|
const uniformFallback = runtime.device.caps.storageBuffer === false;
|
|
7132
7249
|
if (uniformFallback && shadowInst.instanceCount > MAX_UNIFORM_INSTANCES) {
|
|
@@ -7341,6 +7458,7 @@ function recordMainPass(c, selector, options, graphPass) {
|
|
|
7341
7458
|
geometryDepthView,
|
|
7342
7459
|
validatedOrdered,
|
|
7343
7460
|
viewBindGroup,
|
|
7461
|
+
viewBindGroupDynamicOffset = 0,
|
|
7344
7462
|
meshBindGroup,
|
|
7345
7463
|
frameState,
|
|
7346
7464
|
bindGroupCounts,
|
|
@@ -7375,8 +7493,10 @@ function recordMainPass(c, selector, options, graphPass) {
|
|
|
7375
7493
|
const targetDepthView = options?.depthView ?? geometryDepthView;
|
|
7376
7494
|
const clearColor = options?.clearColor ?? clear;
|
|
7377
7495
|
const videoHighPerfAvailable = probeVideoHighPerfUpload(runtime.device);
|
|
7496
|
+
const clusteredLighting = c.standardLighting?.kind === "clustered";
|
|
7497
|
+
const clusteredBindGroupMissing = validatedOrdered.length > 0 && !standardTopologyBindGroupReady(c.standardLighting, hdrpClusterBindGroup);
|
|
7378
7498
|
let hdrpSsaoBindGroup = null;
|
|
7379
|
-
if (
|
|
7499
|
+
if (clusteredLighting && hdrpClusterBindGroup !== null && c.hdrpSsaoBlurredView !== void 0) {
|
|
7380
7500
|
const hdrpBuffers = getOrCreateHdrpBuffers(
|
|
7381
7501
|
runtime,
|
|
7382
7502
|
frameState.installedPipelineConfig?.clusterGrid
|
|
@@ -7390,7 +7510,7 @@ function recordMainPass(c, selector, options, graphPass) {
|
|
|
7390
7510
|
);
|
|
7391
7511
|
}
|
|
7392
7512
|
}
|
|
7393
|
-
const meshGroup2 =
|
|
7513
|
+
const meshGroup2 = clusteredLighting ? hdrpSsaoBindGroup ?? hdrpClusterBindGroup : meshBindGroup;
|
|
7394
7514
|
let geometryPassEnded = false;
|
|
7395
7515
|
const mainColorLoadOp = skyboxActive ? "load" : "clear";
|
|
7396
7516
|
const mainPassResolves = passKind === "forward" && msaaActive && geometryColorResolveView !== null && !splitLdrSprite;
|
|
@@ -7426,7 +7546,16 @@ function recordMainPass(c, selector, options, graphPass) {
|
|
|
7426
7546
|
...recordMode === "transmission" ? { variantSet: TRANSMISSION_VARIANT_SET } : {}
|
|
7427
7547
|
}))
|
|
7428
7548
|
};
|
|
7429
|
-
if (
|
|
7549
|
+
if (clusteredBindGroupMissing) {
|
|
7550
|
+
runtime.errorRegistry.fire(
|
|
7551
|
+
new RhiError({
|
|
7552
|
+
code: "webgpu-runtime-error",
|
|
7553
|
+
expected: "clustered Standard frame has a unified group(2) BindGroup",
|
|
7554
|
+
hint: "repair the clustered buffer/layout admission before retrying the frame; direct URP fallback is unsafe"
|
|
7555
|
+
})
|
|
7556
|
+
);
|
|
7557
|
+
}
|
|
7558
|
+
if (validatedOrdered.length > 0 && !clusteredBindGroupMissing) {
|
|
7430
7559
|
const MATERIAL_SLICE = STANDARD_PBR_UBO_SIZE;
|
|
7431
7560
|
const skylightFallback = pipelineState.skylightFallback;
|
|
7432
7561
|
if (skylightFallback === null) {
|
|
@@ -7477,6 +7606,31 @@ function recordMainPass(c, selector, options, graphPass) {
|
|
|
7477
7606
|
materialSlice: MATERIAL_SLICE,
|
|
7478
7607
|
videoHighPerfAvailable,
|
|
7479
7608
|
skylightResources,
|
|
7609
|
+
resolveRenderTargetTextureSource: runtime.resolveRenderTargetTextureSource,
|
|
7610
|
+
resolveReflectionProbeResources: (materialWorld, entityKey) => {
|
|
7611
|
+
const reflectionProbes = c.reflectionProbes;
|
|
7612
|
+
if (reflectionProbes === void 0) return void 0;
|
|
7613
|
+
const selection = reflectionProbes.selections.get(`${materialWorld.identity}:${entityKey}`);
|
|
7614
|
+
if (selection === void 0) return void 0;
|
|
7615
|
+
const binding = resolveReflectionProbeBinding(selection, reflectionProbes.table);
|
|
7616
|
+
if (binding.useSkylight || binding.probeIndex === void 0) return void 0;
|
|
7617
|
+
const row = reflectionProbes.table.rows.find(
|
|
7618
|
+
(candidate) => candidate.index === binding.probeIndex
|
|
7619
|
+
);
|
|
7620
|
+
if (row?.filteredView === void 0 || row.sampler === void 0 || row.uniformBuffer === void 0) {
|
|
7621
|
+
return void 0;
|
|
7622
|
+
}
|
|
7623
|
+
const probeResources = {
|
|
7624
|
+
irradianceView: skylightResources.irradianceView,
|
|
7625
|
+
irradianceSampler: skylightResources.irradianceSampler,
|
|
7626
|
+
prefilterView: row.filteredView,
|
|
7627
|
+
prefilterSampler: row.sampler,
|
|
7628
|
+
brdfLutView: skylightResources.brdfLutView,
|
|
7629
|
+
brdfLutSampler: skylightResources.brdfLutSampler,
|
|
7630
|
+
intensityBuffer: row.uniformBuffer
|
|
7631
|
+
};
|
|
7632
|
+
return probeResources;
|
|
7633
|
+
},
|
|
7480
7634
|
materialBgShared: frameState.materialBgShared,
|
|
7481
7635
|
materialBgAssemblyCache: c.materialBgAssemblyCache,
|
|
7482
7636
|
bindGroupCounts,
|
|
@@ -7585,7 +7739,7 @@ function recordMainPass(c, selector, options, graphPass) {
|
|
|
7585
7739
|
);
|
|
7586
7740
|
}
|
|
7587
7741
|
const resolveMaterialBindGroup = (materialSlot, material, entityKey, materialWorld = world) => material.materialShaderId !== POINTS_LINES_MATERIAL_SHADER_ID ? preparedMaterialBindGroups[materialSlot] ?? buildPerSubmeshMaterialBg2(material, entityKey, materialWorld) : buildPerSubmeshMaterialBg2(material, entityKey, materialWorld);
|
|
7588
|
-
pass.setBindGroup(0, viewBindGroup, [0]);
|
|
7742
|
+
pass.setBindGroup(0, viewBindGroup, [viewBindGroupDynamicOffset, 0]);
|
|
7589
7743
|
const recordGeometry = () => {
|
|
7590
7744
|
recordGeometryDraws(
|
|
7591
7745
|
recordContext,
|
|
@@ -7984,14 +8138,20 @@ function recordBloomCompositePass(_c, resolve, graphPass) {
|
|
|
7984
8138
|
function recordFxaaPass(c, resolve, graphPass) {
|
|
7985
8139
|
const { runtime, pipelineState, encoder, camera, currentTexture } = c;
|
|
7986
8140
|
const fxaaActive = camera.antialias === "fxaa";
|
|
7987
|
-
if (fxaaActive && pipelineState.perPassResources.fxaaPipeline !== null && pipelineState.perPassResources.fxaaBindGroupLayout !== null && pipelineState.perPassResources.fxaaSampler !== null) {
|
|
8141
|
+
if (fxaaActive && pipelineState.perPassResources.fxaaPipeline !== null && pipelineState.perPassResources.fxaaBindGroupLayout !== null && pipelineState.perPassResources.fxaaSampler !== null && runtime.getPostProcessParamsBuffer !== void 0) {
|
|
7988
8142
|
const inputView = resolve.resolve("ldrColor");
|
|
7989
8143
|
if (inputView === void 0) return;
|
|
8144
|
+
const fxaaParams = runtime.getPostProcessParamsBuffer(FXAA_POST_PROCESS_ID);
|
|
8145
|
+
if (fxaaParams === void 0) return;
|
|
8146
|
+
const params = new Float32Array(4);
|
|
8147
|
+
params[0] = resolveOutputDither(c.frameState.installedPipelineConfig) ? 1 : 0;
|
|
8148
|
+
const paramsWrite = runtime.device.queue.writeBuffer(fxaaParams, 0, params);
|
|
8149
|
+
if (!paramsWrite.ok) throw paramsWrite.error;
|
|
7990
8150
|
const fxaaBglLayout = pipelineState.perPassResources.fxaaBindGroupLayout;
|
|
7991
8151
|
const fxaaSampler = pipelineState.perPassResources.fxaaSampler;
|
|
7992
8152
|
const fxaaBg = getOrCreateFromChain(
|
|
7993
8153
|
c.frameState.postProcessBgCache,
|
|
7994
|
-
[inputView],
|
|
8154
|
+
[inputView, fxaaParams],
|
|
7995
8155
|
"fxaa",
|
|
7996
8156
|
() => {
|
|
7997
8157
|
const fxaaBgRes = runtime.device.createBindGroup({
|
|
@@ -8008,6 +8168,10 @@ function recordFxaaPass(c, resolve, graphPass) {
|
|
|
8008
8168
|
{
|
|
8009
8169
|
binding: 1,
|
|
8010
8170
|
resource: { kind: "sampler", value: fxaaSampler }
|
|
8171
|
+
},
|
|
8172
|
+
{
|
|
8173
|
+
binding: 2,
|
|
8174
|
+
resource: { kind: "buffer", value: { buffer: fxaaParams } }
|
|
8011
8175
|
}
|
|
8012
8176
|
]
|
|
8013
8177
|
});
|
|
@@ -8053,6 +8217,32 @@ var FULLSCREEN_DEFAULT_SPEC = Object.freeze({
|
|
|
8053
8217
|
geometry: { topology: "triangle-list", vertexLayout: {} },
|
|
8054
8218
|
renderState: void 0
|
|
8055
8219
|
});
|
|
8220
|
+
function postProcessSourceDigest(source) {
|
|
8221
|
+
let first = 2166136261;
|
|
8222
|
+
let second = 2654435769;
|
|
8223
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
8224
|
+
const code = source.charCodeAt(index);
|
|
8225
|
+
first = Math.imul(first ^ code, 16777619);
|
|
8226
|
+
second = Math.imul(second ^ code + index, 16777619);
|
|
8227
|
+
}
|
|
8228
|
+
return `${source.length.toString(16)}-${(first >>> 0).toString(16).padStart(8, "0")}-${(second >>> 0).toString(16).padStart(8, "0")}`;
|
|
8229
|
+
}
|
|
8230
|
+
function postProcessShaderPipelineLabel(identity, source) {
|
|
8231
|
+
return `post-process-${identity}-pso-${postProcessSourceDigest(source)}`;
|
|
8232
|
+
}
|
|
8233
|
+
function postProcessShaderModuleLabel(identity, source) {
|
|
8234
|
+
return `${postProcessShaderPipelineLabel(identity, source)}-module`;
|
|
8235
|
+
}
|
|
8236
|
+
function postProcessShaderEntrySignature(entry) {
|
|
8237
|
+
return JSON.stringify({
|
|
8238
|
+
source: entry.source,
|
|
8239
|
+
params: entry.params === void 0 ? void 0 : {
|
|
8240
|
+
byteSize: entry.params.byteSize,
|
|
8241
|
+
defaultValue: Array.from(entry.params.defaultValue)
|
|
8242
|
+
},
|
|
8243
|
+
reads: entry.reads
|
|
8244
|
+
});
|
|
8245
|
+
}
|
|
8056
8246
|
function isTemporalFullscreenBinding(values) {
|
|
8057
8247
|
return values.temporal !== void 0 || values.shader === "forgeax.taa-resolve" || values.shader === "forgeax.motion-blur";
|
|
8058
8248
|
}
|
|
@@ -8401,7 +8591,7 @@ function recordSsaoBlurPass(_c, resolveCtx, ssaoBlurredKey, ssaoRawKey, gbuf0Key
|
|
|
8401
8591
|
pass.draw(3, 1, 0, 0);
|
|
8402
8592
|
if (graphPass === void 0) pass.end();
|
|
8403
8593
|
}
|
|
8404
|
-
function dispatchFullscreenPass(ctx, name, shader, color, reads, resolveCtx, compositeOverSwapchain = false, rawSwapchainOutput = false, graphPass, graphOutputFormat, graphDepthView) {
|
|
8594
|
+
function dispatchFullscreenPass(ctx, name, shader, color, reads, resolveCtx, compositeOverSwapchain = false, rawSwapchainOutput = false, graphPass, graphOutputFormat, graphDepthView, paramsOverride) {
|
|
8405
8595
|
if (shader === "fxaa") {
|
|
8406
8596
|
if (resolveCtx === void 0) {
|
|
8407
8597
|
throw new PostProcessError({
|
|
@@ -8512,7 +8702,7 @@ function dispatchFullscreenPass(ctx, name, shader, color, reads, resolveCtx, com
|
|
|
8512
8702
|
if (entry.params !== void 0) {
|
|
8513
8703
|
const ubo = ctx.runtime.getPostProcessParamsBuffer?.(shader);
|
|
8514
8704
|
if (ubo !== void 0) {
|
|
8515
|
-
const data = ctx.postProcessParams.get(shader);
|
|
8705
|
+
const data = paramsOverride ?? ctx.postProcessParams.get(shader);
|
|
8516
8706
|
if (data !== void 0) {
|
|
8517
8707
|
if (data.byteLength !== entry.params.byteSize) {
|
|
8518
8708
|
throw new PostProcessError({
|
|
@@ -8559,9 +8749,7 @@ function dispatchFullscreenPass(ctx, name, shader, color, reads, resolveCtx, com
|
|
|
8559
8749
|
if (lookupPipeline === void 0) return;
|
|
8560
8750
|
const postColorFormat = writeFormat;
|
|
8561
8751
|
const pipeline = lookupPipeline(shader, built.bindGroupLayout, postColorFormat);
|
|
8562
|
-
if (pipeline === null)
|
|
8563
|
-
return;
|
|
8564
|
-
}
|
|
8752
|
+
if (pipeline === null) return;
|
|
8565
8753
|
const handle = built.createHandle(name, pipeline, paramsBuffer);
|
|
8566
8754
|
const pass = graphPass ?? ctx.encoder.beginRenderPass(
|
|
8567
8755
|
buildBeginRenderPassDescriptor(
|
|
@@ -8587,7 +8775,8 @@ function encodeFullscreenPass(ctx, pass, input) {
|
|
|
8587
8775
|
input.rawSwapchainOutput ?? false,
|
|
8588
8776
|
pass,
|
|
8589
8777
|
input.outputFormat,
|
|
8590
|
-
input.depthView
|
|
8778
|
+
input.depthView,
|
|
8779
|
+
input.paramsOverride
|
|
8591
8780
|
);
|
|
8592
8781
|
}
|
|
8593
8782
|
|
|
@@ -8912,7 +9101,9 @@ function addTypedScenePass(graph, options) {
|
|
|
8912
9101
|
spotShadow,
|
|
8913
9102
|
projector: internal.spotLightProjector?.view ?? internal.volumetricFog?.projectorView,
|
|
8914
9103
|
projectorSampler: internal.spotLightProjector?.sampler ?? internal.volumetricFog?.projectorSampler
|
|
8915
|
-
}
|
|
9104
|
+
},
|
|
9105
|
+
true,
|
|
9106
|
+
internal.standardLighting
|
|
8916
9107
|
);
|
|
8917
9108
|
if (groups.viewBindGroup !== null) {
|
|
8918
9109
|
options.gpuDriven?.encode(groups.viewBindGroup, pass, resources);
|
|
@@ -9297,7 +9488,7 @@ function addTypedOutputTransformPass(graph, input, output, options = {}) {
|
|
|
9297
9488
|
output,
|
|
9298
9489
|
outputOnly,
|
|
9299
9490
|
rawSwapchainOutput: outputOnly,
|
|
9300
|
-
...options.
|
|
9491
|
+
...options.dither !== void 0 ? {
|
|
9301
9492
|
paramsTransform: (params) => {
|
|
9302
9493
|
if (params === void 0 || params.byteLength !== 16) return params;
|
|
9303
9494
|
const transformed = params.slice();
|
|
@@ -9305,7 +9496,7 @@ function addTypedOutputTransformPass(graph, input, output, options = {}) {
|
|
|
9305
9496
|
transformed.buffer,
|
|
9306
9497
|
transformed.byteOffset,
|
|
9307
9498
|
transformed.byteLength
|
|
9308
|
-
).setFloat32(12, 1, true);
|
|
9499
|
+
).setFloat32(12, options.dither === true ? 1 : 0, true);
|
|
9309
9500
|
return transformed;
|
|
9310
9501
|
}
|
|
9311
9502
|
} : {}
|
|
@@ -9399,6 +9590,6 @@ function addTaaResolvePass(graph, current, currentTemporal, previousColor, previ
|
|
|
9399
9590
|
});
|
|
9400
9591
|
}
|
|
9401
9592
|
|
|
9402
|
-
export { CAPTURE_VIEW_PROJS, CUBEMAP_FACE_VERTICES, DEFERRED_COLOR_FORMATS, DEPTH_MIN_PARAMS_BYTE_SIZE, FALLBACK_BYTES_PER_ROW, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_COPY_SRC, GPU_BUFFER_USAGE_INDEX, GPU_BUFFER_USAGE_INDIRECT, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_STORAGE, GPU_BUFFER_USAGE_UNIFORM, GPU_BUFFER_USAGE_VERTEX, GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX,
|
|
9403
|
-
//# sourceMappingURL=chunk-
|
|
9404
|
-
//# sourceMappingURL=chunk-
|
|
9593
|
+
export { CAPTURE_VIEW_PROJS, CUBEMAP_FACE_VERTICES, CUBE_CAPTURE_VIEW_SLOT_BASE, DEFERRED_COLOR_FORMATS, DEPTH_MIN_PARAMS_BYTE_SIZE, FALLBACK_BYTES_PER_ROW, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_COPY_SRC, GPU_BUFFER_USAGE_INDEX, GPU_BUFFER_USAGE_INDIRECT, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_STORAGE, GPU_BUFFER_USAGE_UNIFORM, GPU_BUFFER_USAGE_VERTEX, GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX, GpuBuffer, GpuTexture, LIGHT_ARRAY_HEADER_BYTES, LIGHT_ARRAY_MAX_SLOTS, MATERIAL_PER_ENTITY_STRIDE, POINTS_LINES_MATERIAL_SHADER_ID, POINTS_LINES_VIEW_BUFFER_SIZE, POINT_LIGHT_STD430_BYTES, PREFILTER_MIP_LEVELS, PREFILTER_SIZE, PipelineSpecError, PostProcessError, REFLECTION_PROBE_VIEW_SLOT_BASE, SHADOW_CASTER_BUFFER_SIZE, SKIN_MATERIAL_SHADER_ID, SPOT_LIGHT_STD430_BYTES, TYPED_BLOOM_PASS_NAMES, VIEW_UNIFORM_BUFFER_SIZE, VIEW_UNIFORM_BYTES, VIEW_UNIFORM_SLOT_STRIDE, abortTemporalGpuSubmit, addStandardSceneDataPass, addTaaResolvePass, addTypedBloomPasses, addTypedCompositePostEffects, addTypedFrameObservationPass, addTypedFullscreenPass, addTypedOutputTransformPass, addTypedScenePass, addTypedSkyboxPass, addTypedSsaoPasses, addTypedTemporalResolvePass, aggregateTemporalDemand, applyParamSnapshotToUbo, assembleMaterialWithSkylightEntries, assertStorageBufferCap, buildBindGroupLayoutDescriptor, buildFoldDispatchPlan, buildFullscreenPostProcessPass, buildLinearLdrMaterialSpecTable, buildPbrMaterialUserRegionEntries, buildPbrPipelineLayouts, buildPbrSkinLayouts, buildPerFrameBindGroups, buildSpecConstTable, cacheKeyOf, cleanPerEntityCache, colorFormatsForPassKind, commitTemporalGpuSubmit, computeProjectionMatrix, computeSplitLdrSprite, computeViewMatrix, configureSurface, createClusterBinScratch, createFullscreenBindGroup, createHdrpBindGroupLayoutDescriptor, createHdrpClusterMembershipBindGroupLayoutDescriptor, createHdrpSkinBindGroupLayoutDescriptor, createIblPipelines, createPointsLinesLaneAdapter, createPointsLinesLaneContract, createRenderPipelineTarget, createRenderTargetMaterialSource, createSkylightFallback, createStandardSceneDataTarget, deriveRenderDataCubemap, deriveRenderDataMesh, deriveRenderDataTexture, describeTemporalDemand, driveLazyEquirectProjection, encodeDirectionalShadowPass, encodeMainPass, encodePointShadowPass, encodeSpotShadowPass, ensureMeshSsboCapacity, entryHasDepthRead, evaluateFoldBucketUniformCap, foldDispatchBuckets, geometryRenderStateForTopology, getOrBuildPipeline, getOrCreateHdrpBuffers, getOrCreateIblCache, getTemporalGpuState, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, incrementFoldedDrawsMetric, isStandardPbrMaterialShader, isTemporalFullscreenBinding, postProcessShaderEntrySignature, postProcessShaderModuleLabel, postProcessShaderPipelineLabel, prepareFrameLighting, resetHdrpBuffers, residentTextureView, resolveOutputDither, resolvePipelineGroup2Contract, resolveRenderTargetMaterialSource, resolveSkyboxActive, resolveSsaoParameters, resolveSurfaceFormatPair, resolveSurfaceProfile, retireTemporalGpuState, retireTemporalGpuStateAfterFence, runIblPrecompute, selectLazyEquirectHandle, selectPasses, selectSwapChainFormat, setIblComposedShaders, standardTemporalLaneAdmission, standardTemporalPostOrder, temporalReadIndex, temporalWriteIndex, typedFrameClearColor, uploadMeshSsboBatch, variantSetFromDefines, warnMultiSkybox, warnMultiSkylight, warnZeroLightStandard, writeHdrpClusterAndSsaoBuffers, writePointsLinesViewUbo, writeShadowCasterUniforms, writeShadowParamsBuffer, writeViewUbo };
|
|
9594
|
+
//# sourceMappingURL=chunk-5YADUCA7.mjs.map
|
|
9595
|
+
//# sourceMappingURL=chunk-5YADUCA7.mjs.map
|