@forgeax/engine-runtime 0.1.4 → 0.1.6
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 +49 -83
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-serialize.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-serialize.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts +2 -0
- package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts.map +1 -0
- package/dist/__tests__/asset-error-exhaustive.test-d.d.ts +11 -0
- package/dist/__tests__/asset-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-guid-reverse.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-guid-reverse.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mounts.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mounts.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.browser.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.browser.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.dawn.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.listCatalog.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.listCatalog.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.mesh-bin.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.mesh-bin.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.recursive.spec.d.ts +2 -0
- package/dist/__tests__/asset-registry.recursive.spec.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset.unit.test.d.ts +2 -0
- package/dist/__tests__/asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/audio-load-by-guid.unit.test.d.ts +2 -0
- package/dist/__tests__/audio-load-by-guid.unit.test.d.ts.map +1 -0
- package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
- package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
- package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts +2 -0
- package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/builtin-asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/collect-scene-asset.test.d.ts +1 -2
- package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/collect-scene-mount-collapse.test.d.ts +2 -0
- package/dist/__tests__/collect-scene-mount-collapse.test.d.ts.map +1 -0
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts +1 -1
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -1
- package/dist/__tests__/collect-transient-skip.test.d.ts +1 -2
- package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -1
- package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts +2 -0
- package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/draw-published.d.ts +2 -2
- package/dist/__tests__/draw-published.d.ts.map +1 -1
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
- package/dist/__tests__/errors.unit.test.d.ts +2 -0
- package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts +2 -0
- package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fetch-binary-decompress.test.d.ts +2 -0
- package/dist/__tests__/fetch-binary-decompress.test.d.ts.map +1 -0
- package/dist/__tests__/four-path-compression.integration.test.d.ts +2 -0
- package/dist/__tests__/four-path-compression.integration.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/guid-for-asset.unit.test.d.ts +2 -0
- package/dist/__tests__/guid-for-asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/handle-migration.test.d.ts +2 -0
- package/dist/__tests__/handle-migration.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -1
- package/dist/__tests__/host-custom-kind-contract.test-d.d.ts +2 -0
- package/dist/__tests__/host-custom-kind-contract.test-d.d.ts.map +1 -0
- package/dist/__tests__/host-custom-kind-contract.test.d.ts +2 -0
- package/dist/__tests__/host-custom-kind-contract.test.d.ts.map +1 -0
- package/dist/__tests__/inspect-name.test.d.ts +2 -0
- package/dist/__tests__/inspect-name.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts +2 -0
- package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts.map +1 -0
- package/dist/__tests__/loadbyguid-payload.unit.test.d.ts +2 -0
- package/dist/__tests__/loadbyguid-payload.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts +2 -0
- package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-extract-graceful.test.d.ts +2 -0
- package/dist/__tests__/loader-extract-graceful.test.d.ts.map +1 -0
- package/dist/__tests__/loader-name-survival.test.d.ts +2 -0
- package/dist/__tests__/loader-name-survival.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-contract.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-contract.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/new-kind-refs-contract.test.d.ts +2 -0
- package/dist/__tests__/new-kind-refs-contract.test.d.ts.map +1 -0
- package/dist/__tests__/package-promotion.test.d.ts +2 -0
- package/dist/__tests__/package-promotion.test.d.ts.map +1 -0
- package/dist/__tests__/package-rename.test.d.ts +2 -0
- package/dist/__tests__/package-rename.test.d.ts.map +1 -0
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +1 -1
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts +1 -1
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts +10 -0
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -0
- package/dist/__tests__/render-system-extract.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-extract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-test-utils.d.ts +10 -0
- package/dist/__tests__/renderer-test-utils.d.ts.map +1 -0
- package/dist/__tests__/renderer.test-d.d.ts +2 -0
- package/dist/__tests__/renderer.test-d.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle-err.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle-err.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-fallback.test.d.ts +2 -0
- package/dist/__tests__/resolveName-fallback.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-null-package.test.d.ts +2 -0
- package/dist/__tests__/resolveName-null-package.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-unified-entry.test.d.ts +2 -0
- package/dist/__tests__/resolveName-unified-entry.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName.test.d.ts +2 -0
- package/dist/__tests__/resolveName.test.d.ts.map +1 -0
- package/dist/__tests__/roots-to-scene-asset.test.d.ts +1 -1
- package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/roundtrip-primitive.test.d.ts +2 -0
- package/dist/__tests__/roundtrip-primitive.test.d.ts.map +1 -0
- package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts +2 -0
- package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/scene-instance-authoring.integration.test.d.ts +2 -0
- package/dist/__tests__/scene-instance-authoring.integration.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-fixed-point.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-fixed-point.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-sugar-instantiate.test.d.ts +2 -0
- package/dist/__tests__/scene-sugar-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-scene-asset.test.d.ts +1 -1
- package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/template-game-default-api-contract.test.d.ts +2 -0
- package/dist/__tests__/template-game-default-api-contract.test.d.ts.map +1 -0
- package/dist/__tests__/tileset-asset-validate.test.d.ts +2 -0
- package/dist/__tests__/tileset-asset-validate.test.d.ts.map +1 -0
- package/dist/__tests__/transcode-fallback.unit.test.d.ts +2 -0
- package/dist/__tests__/transcode-fallback.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transient-runtime-behavior.test.d.ts +2 -0
- package/dist/__tests__/transient-runtime-behavior.test.d.ts.map +1 -0
- package/dist/__tests__/video-loader-consumption.test.d.ts +2 -0
- package/dist/__tests__/video-loader-consumption.test.d.ts.map +1 -0
- package/dist/__tests__/video-loader-smoke.dawn.test.d.ts +2 -0
- package/dist/__tests__/video-loader-smoke.dawn.test.d.ts.map +1 -0
- package/dist/backend-selection.d.ts +13 -0
- package/dist/backend-selection.d.ts.map +1 -0
- package/dist/collect-scene-asset.d.ts +3 -3
- package/dist/collect-scene-asset.d.ts.map +1 -1
- package/dist/createRenderer.d.ts +14 -2
- package/dist/createRenderer.d.ts.map +1 -1
- package/dist/errors/environment.d.ts +1 -1
- package/dist/errors/environment.d.ts.map +1 -1
- package/dist/index.d.ts +19 -81
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +105 -108
- package/dist/index.mjs.map +1 -1
- package/dist/renderer-host.d.ts +9 -0
- package/dist/renderer-host.d.ts.map +1 -0
- package/dist/renderer-host.mjs +62 -0
- package/dist/renderer-host.mjs.map +1 -0
- package/dist/scene-instances/index.d.ts +2 -0
- package/dist/scene-instances/index.d.ts.map +1 -0
- package/dist/scene-utils/mount-override-fold.d.ts +1 -2
- package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
- package/dist/systems/sprite-animation-tick.d.ts +1 -1
- package/dist/systems/sprite-animation-tick.d.ts.map +1 -1
- package/dist/systems/transparent-sort.d.ts +1 -2
- package/dist/systems/transparent-sort.d.ts.map +1 -1
- package/dist/tilemap-register-validate.d.ts.map +1 -1
- package/package.json +34 -33
- package/src/__tests__/active-camera.unit.test.ts +19 -9
- package/src/__tests__/animation-graph-collect-roundtrip.test.ts +213 -0
- package/src/__tests__/animation-graph-serialize.unit.test.ts +171 -0
- package/src/__tests__/append-injection.test.ts +1 -1
- package/src/__tests__/asset-brand-and-name-retirement.test.ts +102 -0
- package/src/__tests__/asset-error-exhaustive.test-d.ts +62 -0
- package/src/__tests__/asset-registry-guid-reverse.test.ts +575 -0
- package/src/__tests__/asset-registry-hdr-equirect.test.ts +78 -0
- package/src/__tests__/asset-registry-mesh-pack-payload.dawn.test.ts +232 -0
- package/src/__tests__/asset-registry-mounts.test.ts +806 -0
- package/src/__tests__/asset-registry.browser.test.ts +81 -0
- package/src/__tests__/asset-registry.dawn.test.ts +94 -0
- package/src/__tests__/asset-registry.listCatalog.test.ts +170 -0
- package/src/__tests__/asset-registry.mesh-bin.test.ts +316 -0
- package/src/__tests__/asset-registry.pack-cache.test.ts +969 -0
- package/src/__tests__/asset-registry.raw-container-failfast.test.ts +225 -0
- package/src/__tests__/asset-registry.recursive.spec.ts +1397 -0
- package/src/__tests__/asset-registry.unit.test.ts +1030 -0
- package/src/__tests__/asset.unit.test.ts +7107 -0
- package/src/__tests__/audio-load-by-guid.unit.test.ts +126 -0
- package/src/__tests__/backend-selection.integration.test.ts +11 -0
- package/src/__tests__/basis-catalog-dispatch.integration.test.ts +320 -0
- package/src/__tests__/bind-group-cache-keying.test.ts +4 -4
- package/src/__tests__/block-upload-math.unit.test.ts +2 -2
- package/src/__tests__/builtin-asset-registry.unit.test.ts +112 -0
- package/src/__tests__/builtin-shader-register-e2e.test.ts +1 -1
- package/src/__tests__/cache-false-eviction.test.ts +2 -1
- package/src/__tests__/cache-isolation-matrix.test.ts +2 -1
- package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +5 -6
- package/src/__tests__/clamp-to-last.e2e.browser.test.ts +29 -19
- package/src/__tests__/collect-scene-asset.test.ts +49 -52
- package/src/__tests__/collect-scene-mount-collapse.test.ts +391 -0
- package/src/__tests__/collect-subtree.unit.test.ts +1 -2
- package/src/__tests__/collect-transient-children-absent.test.ts +24 -10
- package/src/__tests__/collect-transient-roundtrip.test.ts +44 -20
- package/src/__tests__/collect-transient-skip.test.ts +24 -13
- package/src/__tests__/components.test-d.ts +1 -6
- package/src/__tests__/components.unit.test.ts +20 -19
- package/src/__tests__/composite-skybox-cross-world.browser.test.ts +59 -27
- package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +139 -0
- package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -29
- package/src/__tests__/createRenderer-dispose.test.ts +35 -402
- package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +25 -30
- package/src/__tests__/createRenderer.unit.test.ts +1 -1
- package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +27 -63
- package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +56 -47
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +49 -29
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +26 -15
- package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +13 -14
- package/src/__tests__/dawn/material-alpha.dawn.test.ts +23 -31
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +0 -18
- package/src/__tests__/dawn/{mesh-update.dawn.test.ts → mesh-update-dawn.test.ts} +42 -134
- package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +14 -7
- package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +16 -28
- package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +23 -39
- package/src/__tests__/dawn/upload-texture.dawn.test.ts +198 -0
- package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +12 -14
- package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +27 -22
- package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +25 -28
- package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +10 -11
- package/src/__tests__/demo-sortscope-migration.unit.test.ts +5 -5
- package/src/__tests__/derive-bgl-integration.test.ts +34 -44
- package/src/__tests__/derive-render-data-skin.unit.test.ts +1 -1
- package/src/__tests__/draw-published.ts +11 -4
- package/src/__tests__/dynamic-texture-store.unit.test.ts +190 -0
- package/src/__tests__/equirect-bc6h.integration.test.ts +144 -21
- package/src/__tests__/errors.unit.test.ts +1203 -0
- package/src/__tests__/extract-frames-graceful-degradation.test.ts +3 -7
- package/src/__tests__/extract-frames-merge.test.ts +35 -22
- package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +5 -16
- package/src/__tests__/extract-skin-mismatch.unit.test.ts +322 -0
- package/src/__tests__/fetch-binary-decompress.test.ts +356 -0
- package/src/__tests__/four-path-compression.integration.test.ts +395 -0
- package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +1 -1
- package/src/__tests__/fullscreen-feature-host.dawn.test.ts +80 -0
- package/src/__tests__/fullscreen-post-bgl-depth.test.ts +4 -2
- package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +3 -3
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +39 -23
- package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +4 -2
- package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +28 -17
- package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +29 -18
- package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +16 -12
- package/src/__tests__/geometry.unit.test.ts +525 -159
- package/src/__tests__/glyph-tilemap-worldid.test.ts +1 -1
- package/src/__tests__/gpu-resource-cow-survivor.test.ts +6 -4
- package/src/__tests__/guid-for-asset.unit.test.ts +102 -0
- package/src/__tests__/handle-migration.test.ts +136 -0
- package/src/__tests__/helpers/register-runtime-components.ts +4 -2
- package/src/__tests__/helpers/register-scene-components.ts +1 -1
- package/src/__tests__/host-custom-kind-contract.test-d.ts +47 -0
- package/src/__tests__/host-custom-kind-contract.test.ts +578 -0
- package/src/__tests__/inspect-name.test.ts +139 -0
- package/src/__tests__/instances.test-d.ts +1 -1
- package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +112 -0
- package/src/__tests__/light-casters-9-light.browser.test.ts +73 -76
- package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +7 -10
- package/src/__tests__/light-snapshot.test-d.ts +2 -2
- package/src/__tests__/lights-vec-negative.unit.test.ts +1 -1
- package/src/__tests__/lights.unit.test.ts +16 -500
- package/src/__tests__/loadbyguid-payload.unit.test.ts +117 -0
- package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +213 -0
- package/src/__tests__/loader-extract-graceful.test.ts +146 -0
- package/src/__tests__/loader-name-survival.test.ts +213 -0
- package/src/__tests__/m3-vec-negative.unit.test.ts +3 -2
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +101 -31
- package/src/__tests__/materials.unit.test.ts +10 -27
- package/src/__tests__/mesh-bin-contract.test.ts +28 -0
- package/src/__tests__/mesh-bin-skin-roundtrip.unit.test.ts +149 -0
- package/src/__tests__/mesh-bin.test.ts +38 -0
- package/src/__tests__/mesh-loader-skin-contract.unit.test.ts +120 -0
- package/src/__tests__/mesh-ssbo-grow.unit.test.ts +3 -3
- package/src/__tests__/mip-gate.unit.test.ts +1 -1
- package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +29 -68
- package/src/__tests__/new-kind-refs-contract.test.ts +132 -0
- package/src/__tests__/node-shims.d.ts +4 -6
- package/src/__tests__/package-promotion.test.ts +88 -0
- package/src/__tests__/package-rename.test.ts +103 -0
- package/src/__tests__/pass-selector.unit.test.ts +2 -2
- package/src/__tests__/pbr-pipeline.unit.test.ts +14 -21
- package/src/__tests__/pipeline-builder-msaa.unit.test.ts +6 -9
- package/src/__tests__/pipeline-cache-keying.unit.test.ts +6 -9
- package/src/__tests__/pipeline-spec.test.ts +16 -177
- package/src/__tests__/pipeline.unit.test.ts +154 -1693
- package/src/__tests__/point-light-shadow.dawn.test.ts +33 -42
- package/src/__tests__/point-light-shadow.unit.test.ts +19 -60
- package/src/__tests__/post-process-error-codes.unit.test.ts +4 -1
- package/src/__tests__/post-process-params-component.unit.test.ts +1 -1
- package/src/__tests__/post-process-params-extract.unit.test.ts +2 -5
- package/src/__tests__/postprocess-camera-consistency.test.ts +4 -7
- package/src/__tests__/profiler-assembly.integration.test.ts +1 -1
- package/src/__tests__/propagate-transforms.dawn.test.ts +12 -11
- package/src/__tests__/record-worldid-isolation.test.ts +7 -29
- package/src/__tests__/recover-error-exhaustive.test-d.ts +1 -1
- package/src/__tests__/render-error-exhaustive.test-d.ts +81 -71
- package/src/__tests__/render-feature-assembly.test-d.ts +20 -9
- package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +8 -6
- package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +60 -558
- package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +57 -544
- package/src/__tests__/render-feature-prepared-graphics.fixture.ts +104 -0
- package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +40 -248
- package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +83 -340
- package/src/__tests__/render-feature-recover.integration.test.ts +9 -49
- package/src/__tests__/render-feature-runtime-surface.test-d.ts +17 -20
- package/src/__tests__/render-schema-consumer.integration.test.ts +20 -13
- package/src/__tests__/render-schema-owner-boundary.unit.test.ts +2 -6
- package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +5 -5
- package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +16 -31
- package/src/__tests__/render-system-extract.test.ts +36 -51
- package/src/__tests__/render-system-extract.unit.test.ts +360 -0
- package/src/__tests__/render-system-fold-bucket.unit.test.ts +3 -5
- package/src/__tests__/render-system-fold-fallback.unit.test.ts +6 -3
- package/src/__tests__/render-system-fold-material.unit.test.ts +3 -5
- package/src/__tests__/render-system-fold-metrics.unit.test.ts +5 -5
- package/src/__tests__/render-system-fold-modegate.unit.test.ts +6 -6
- package/src/__tests__/render-system-fold.dawn.test.ts +7 -5
- package/src/__tests__/render-system-mega.test.ts +292 -190
- package/src/__tests__/render-system-owner-split-contract.test.ts +10 -32
- package/src/__tests__/render-system-record-multi-material-textureview.test.ts +59 -45
- package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +23 -29
- package/src/__tests__/render-system-record.test.ts +398 -235
- package/src/__tests__/render-system-record.unit.test.ts +25 -26
- package/src/__tests__/render-system-skin-bg.unit.test.ts +8 -12
- package/src/__tests__/renderer-consumer.test-d.ts +16 -3
- package/src/__tests__/renderer-health.unit.test.ts +26 -916
- package/src/__tests__/renderer-lifecycle.integration.test.ts +19 -6
- package/src/__tests__/renderer-recover.unit.test.ts +49 -1069
- package/src/__tests__/renderer-result.test-d.ts +19 -9
- package/src/__tests__/renderer-surface.unit.test.ts +3 -5
- package/src/__tests__/renderer-test-utils.ts +56 -0
- package/src/__tests__/renderer.test-d.ts +59 -0
- package/src/__tests__/resolve-asset-handle-err.test.ts +111 -0
- package/src/__tests__/resolve-asset-handle.unit.test.ts +64 -0
- package/src/__tests__/resolve-depth-only-view.test.ts +1 -1
- package/src/__tests__/resolveName-fallback.test.ts +64 -0
- package/src/__tests__/resolveName-null-package.test.ts +38 -0
- package/src/__tests__/resolveName-unified-entry.test.ts +65 -0
- package/src/__tests__/resolveName.test.ts +64 -0
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +43 -261
- package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +41 -169
- package/src/__tests__/roots-to-scene-asset.test.ts +199 -93
- package/src/__tests__/roundtrip-primitive.test.ts +351 -0
- package/src/__tests__/scene-bare-guid-refs-instantiate.test.ts +123 -0
- package/src/__tests__/scene-equirect-roundtrip.test.ts +103 -16
- package/src/__tests__/scene-instance-authoring.integration.test.ts +8 -0
- package/src/__tests__/scene-instance-bridge.integration.test.ts +1 -1
- package/src/__tests__/scene-instance-component.test.ts +1 -1
- package/src/__tests__/scene-mount-fixed-point.test.ts +257 -0
- package/src/__tests__/scene-mount-roundtrip.test.ts +987 -0
- package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +202 -0
- package/src/__tests__/scene-sugar-instantiate.test.ts +324 -0
- package/src/__tests__/serialize-mounts-roundtrip.test.ts +533 -0
- package/src/__tests__/serialize-scene-asset.test.ts +219 -22
- package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -3
- package/src/__tests__/shadow-csm-cascade-loadop.test.ts +37 -17
- package/src/__tests__/shadow-csm-component.test.ts +3 -5
- package/src/__tests__/shadow-csm-extract.test.ts +2 -100
- package/src/__tests__/shadow-csm-orthoz.test.ts +2 -16
- package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +19 -14
- package/src/__tests__/shadow-csm-tile-consistency.test.ts +32 -26
- package/src/__tests__/shadow-csm-ubo.dawn.test.ts +8 -49
- package/src/__tests__/shadow-csm-ubo.test.ts +3 -25
- package/src/__tests__/shadow-csm-viewport.browser.test.ts +1 -1
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +67 -56
- package/src/__tests__/shadow-m1.dawn.test.ts +8 -9
- package/src/__tests__/shadow-mesh-ssbo-order.test.ts +11 -27
- package/src/__tests__/skin-errors.unit.test.ts +1 -1
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +7 -5
- package/src/__tests__/skylight-lazy-projection.test.ts +36 -15
- package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +5 -5
- package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +47 -64
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +12 -11
- package/src/__tests__/sprite-lit-extract-branch.test.ts +1 -1
- package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +1 -1
- package/src/__tests__/ssao-bgl.test.ts +16 -9
- package/src/__tests__/ssao-buffers.test.ts +2 -2
- package/src/__tests__/ssao-data.test.ts +2 -2
- package/src/__tests__/ssao-errors.test.ts +1 -1
- package/src/__tests__/ssao-passes.test.ts +64 -392
- package/src/__tests__/ssao-pipelines.test.ts +1 -1
- package/src/__tests__/ssao-uniform-layout.test.ts +8 -6
- package/src/__tests__/stencil-outline-pixel.dawn.test.ts +25 -17
- package/src/__tests__/swap-chain-format.unit.test.ts +5 -7
- package/src/__tests__/systems.unit.test.ts +536 -1326
- package/src/__tests__/template-game-default-api-contract.test.ts +362 -0
- package/src/__tests__/text.unit.test.ts +56 -33
- package/src/__tests__/tilemap-childed-despawn.test.ts +8 -14
- package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +8 -12
- package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +2 -1
- package/src/__tests__/tilemap-chunk-extract.test.ts +13 -17
- package/src/__tests__/tilemap-dirty-rebuild.test.ts +7 -11
- package/src/__tests__/tilemap-material-cache.test.ts +8 -13
- package/src/__tests__/tilemap-multi-atlas.test.ts +12 -32
- package/src/__tests__/tilemap-owner-boundary.unit.test.ts +5 -2
- package/src/__tests__/tilemap-region-pack.test.ts +8 -12
- package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +8 -12
- package/src/__tests__/tilemap-uv-inset.test.ts +11 -14
- package/src/__tests__/tilemap-validate.test.ts +1 -1
- package/src/__tests__/tileset-asset-validate.test.ts +638 -0
- package/src/__tests__/transcode-fallback.unit.test.ts +207 -0
- package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +36 -28
- package/src/__tests__/transient-fields-collect.test.ts +28 -21
- package/src/__tests__/transient-runtime-behavior.test.ts +227 -0
- package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +4 -4
- package/src/__tests__/variant-selection.unit.test.ts +1 -1
- package/src/__tests__/video-extract-bindgroup.dawn.test.ts +89 -136
- package/src/__tests__/video-loader-consumption.test.ts +86 -0
- package/src/__tests__/video-loader-smoke.dawn.test.ts +60 -0
- package/src/__tests__/view-ubo-layout.browser.test.ts +0 -22
- package/src/__tests__/world-entity-key.test.ts +1 -1
- package/src/__tests__/world-scene-despawn.test.ts +1 -1
- package/src/__tests__/world-scene-instantiate.test.ts +2 -36
- package/src/__tests__/world-scene-nested.test.ts +1 -1
- package/src/__tests__/world-scene-override.test.ts +1 -1
- package/src/backend-selection.ts +69 -0
- package/src/collect-scene-asset.ts +28 -23
- package/src/components/__tests__/camera.test-d.ts +1 -1
- package/src/components/__tests__/camera.test.ts +1 -1
- package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
- package/src/components/__tests__/tile-layer.test-d.ts +1 -1
- package/src/components/__tests__/tile-layer.unit.test.ts +2 -2
- package/src/createRenderer.ts +24 -36
- package/src/errors/environment.ts +1 -1
- package/src/index.ts +47 -113
- package/src/renderer-host.ts +33 -0
- package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +1 -1
- package/src/scene-instances/index.ts +4 -0
- package/src/scene-utils/mount-override-fold.ts +3 -7
- package/src/systems/__tests__/transparent-sort.bench.ts +3 -3
- package/src/systems/sprite-animation-tick.ts +1 -1
- package/src/systems/transparent-sort.ts +38 -38
- package/src/tilemap-register-validate.ts +4 -4
- package/dist/__tests__/bind-group-cache-binding.test.d.ts +0 -2
- package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +0 -1
- package/dist/__tests__/bind-group-cache-frame.test.d.ts +0 -2
- package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +0 -1
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +0 -2
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-manifest.d.ts +0 -131
- package/dist/__tests__/fog-producer-manifest.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel-probe.d.ts +0 -42
- package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +0 -2
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +0 -2
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-real-fixture.d.ts +0 -5
- package/dist/__tests__/fog-producer-real-fixture.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-vfx-effect.d.ts +0 -3
- package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +0 -1
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts +0 -2
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +0 -1
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +0 -2
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +0 -1
- package/dist/__tests__/gpu-resource.test.d.ts +0 -2
- package/dist/__tests__/gpu-resource.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +0 -2
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts +0 -2
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +0 -2
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +0 -2
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +0 -2
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +0 -1
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +0 -2
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +0 -2
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +0 -1
- package/dist/__tests__/helpers/primitive-world.d.ts +0 -8
- package/dist/__tests__/helpers/primitive-world.d.ts.map +0 -1
- package/dist/__tests__/helpers/render-asset-port.d.ts +0 -15
- package/dist/__tests__/helpers/render-asset-port.d.ts.map +0 -1
- package/dist/__tests__/helpers/scene-asset-port.d.ts +0 -9
- package/dist/__tests__/helpers/scene-asset-port.d.ts.map +0 -1
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +0 -2
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +0 -1
- package/dist/__tests__/pipeline-layout-selection.test.d.ts +0 -2
- package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +0 -1
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +0 -2
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +0 -1
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +0 -2
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +0 -2
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +0 -1
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +0 -2
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-pssm.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-viewport.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m2.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3-calibrate.d.ts +0 -83
- package/dist/__tests__/shadow-m3-calibrate.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/temporal-off-path.unit.test.d.ts +0 -2
- package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +0 -1
- package/dist/__tests__/video-cache-regression.unit.test.d.ts +0 -2
- package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +0 -1
- package/dist/asset-kind.d.ts +0 -4
- package/dist/asset-kind.d.ts.map +0 -1
- package/dist/errors/sprite-animation.d.ts +0 -3
- package/dist/errors/sprite-animation.d.ts.map +0 -1
- package/dist/scene-asset-port.d.ts +0 -17
- package/dist/scene-asset-port.d.ts.map +0 -1
- package/dist/scene-collect-errors.d.ts +0 -22
- package/dist/scene-collect-errors.d.ts.map +0 -1
- package/dist/shadow-m3-calibrate.d.ts +0 -40
- package/dist/shadow-m3-calibrate.d.ts.map +0 -1
- package/src/__tests__/bind-group-cache-binding.test.ts +0 -2513
- package/src/__tests__/bind-group-cache-frame.test.ts +0 -1511
- package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +0 -204
- package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +0 -297
- package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +0 -271
- package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +0 -321
- package/src/__tests__/fog-producer-manifest.ts +0 -162
- package/src/__tests__/fog-producer-pixel-probe.ts +0 -263
- package/src/__tests__/fog-producer-pixel.browser.test.ts +0 -26
- package/src/__tests__/fog-producer-pixel.dawn.test.ts +0 -55
- package/src/__tests__/fog-producer-real-fixture.ts +0 -805
- package/src/__tests__/fog-producer-vfx-effect.ts +0 -272
- package/src/__tests__/fog-scene-asset.integration.test.ts +0 -123
- package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +0 -207
- package/src/__tests__/gpu-resource.test.ts +0 -1206
- package/src/__tests__/hdrp-bgl-slots.browser.test.ts +0 -50
- package/src/__tests__/hdrp-buffers.unit.test.ts +0 -70
- package/src/__tests__/hdrp-execute-filter.unit.test.ts +0 -200
- package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +0 -64
- package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +0 -139
- package/src/__tests__/hdrp-ssao-boundary.test.ts +0 -237
- package/src/__tests__/hdrp-ssao-falsification.test.ts +0 -289
- package/src/__tests__/helpers/primitive-world.ts +0 -91
- package/src/__tests__/helpers/render-asset-port.ts +0 -65
- package/src/__tests__/helpers/scene-asset-port.ts +0 -23
- package/src/__tests__/material-derived-coordinates.integration.test.ts +0 -100
- package/src/__tests__/pipeline-layout-selection.test.ts +0 -298
- package/src/__tests__/post-process-reads-narrowing.test-d.ts +0 -52
- package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +0 -230
- package/src/__tests__/render-feature-zero-feature.browser.test.ts +0 -152
- package/src/__tests__/render-pipeline-trivial.dawn.test.ts +0 -525
- package/src/__tests__/shadow-csm-caster-membership.test.ts +0 -232
- package/src/__tests__/shadow-csm-pssm.test.ts +0 -142
- package/src/__tests__/shadow-csm-temporal.browser.test.ts +0 -145
- package/src/__tests__/shadow-csm-viewport.test.ts +0 -74
- package/src/__tests__/shadow-m2.dawn.test.ts +0 -394
- package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +0 -248
- package/src/__tests__/shadow-m3-calibrate.ts +0 -203
- package/src/__tests__/shadow-m3.dawn.test.ts +0 -288
- package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +0 -264
- package/src/__tests__/shadow-quality-metrics.dawn.test.ts +0 -324
- package/src/__tests__/temporal-off-path.unit.test.ts +0 -69
- package/src/__tests__/video-cache-regression.unit.test.ts +0 -186
- package/src/asset-kind.ts +0 -7
- package/src/errors/sprite-animation.ts +0 -5
- package/src/scene-asset-port.ts +0 -32
- package/src/scene-collect-errors.ts +0 -30
- package/src/shadow-m3-calibrate.ts +0 -171
|
@@ -1,394 +0,0 @@
|
|
|
1
|
-
// shadow-m2.dawn.test.ts - feat-20260520-directional-light-shadow-mapping
|
|
2
|
-
// M2 / w12+fix: AC-12 naive shadow factor sampling, fixture with occluder
|
|
3
|
-
// cube above ground plane, acne expected as M2 baseline artifact.
|
|
4
|
-
//
|
|
5
|
-
// AC anchor: requirements AC-12 (shadow factor < 1 for occluded, approx 1
|
|
6
|
-
// for non-occluded, acne presence as M2 expected artifact). plan-strategy
|
|
7
|
-
// D-6 (M2 red-green gate), research F3 (ShadowCalculation 5 steps, acne is
|
|
8
|
-
// contractual).
|
|
9
|
-
//
|
|
10
|
-
// Fixture: single DirectionalLight pointing straight down + ground plane at
|
|
11
|
-
// y=0 + cube occluder centred at y=1.3 (1x1x1). Shadow factor is sampled
|
|
12
|
-
// via renderer.debugSampleShadowFactor which reads the GPU shadow depth
|
|
13
|
-
// texture (copyTextureToBuffer + mapAsync) and computes the projection +
|
|
14
|
-
// depth comparison on the CPU.
|
|
15
|
-
//
|
|
16
|
-
// The test reads the pre-built hello-triangle shader manifest (with real
|
|
17
|
-
// composed WGSL for pbr + unlit + tonemap + shadow_caster) so dawn-node's
|
|
18
|
-
// real WebGPU device can compile the shadow pipeline and populate the
|
|
19
|
-
// shadow depth texture on the first draw() call.
|
|
20
|
-
|
|
21
|
-
import { readFileSync } from 'node:fs';
|
|
22
|
-
import { resolve } from 'node:path';
|
|
23
|
-
import { fileURLToPath } from 'node:url';
|
|
24
|
-
import { World } from '@forgeax/engine-ecs';
|
|
25
|
-
import { createPrimitiveMesh } from '@forgeax/engine-geometry';
|
|
26
|
-
import {
|
|
27
|
-
Camera,
|
|
28
|
-
DirectionalLight,
|
|
29
|
-
MeshFilter,
|
|
30
|
-
MeshRenderer,
|
|
31
|
-
} from '@forgeax/engine-render/internal';
|
|
32
|
-
import { createRenderer } from '@forgeax/engine-runtime';
|
|
33
|
-
import { Transform } from '@forgeax/engine-scene';
|
|
34
|
-
import { describe, expect, it } from 'vitest';
|
|
35
|
-
import { drawPublished } from './draw-published';
|
|
36
|
-
|
|
37
|
-
// ── Fixture constants SSOT (plan-strategy section 8.1 test anchor) ─────────
|
|
38
|
-
|
|
39
|
-
/** Canvas size for the mock HTMLCanvasElement. */
|
|
40
|
-
const WIDTH = 256;
|
|
41
|
-
const HEIGHT = 256;
|
|
42
|
-
|
|
43
|
-
/** Directional light points approximately down with a slight horizontal tilt to avoid lookAt degeneracy (dir parallel to up vector). See shadow-m1.dawn.test.ts AC-11 comment on the (0,-1,0) degeneracy. */
|
|
44
|
-
const FIXTURE_LIGHT_DIR: [number, number, number] = [0.2, -0.98, 0];
|
|
45
|
-
|
|
46
|
-
/** Shadow map resolution. */
|
|
47
|
-
const FIXTURE_MAP_SIZE = 1024;
|
|
48
|
-
|
|
49
|
-
/** Ground-plane scale (flattened cube, top face at y=0). */
|
|
50
|
-
const GROUND_SIZE = 20;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* World-space sample positions. Light direction (0.2, -0.98, 0) = mostly
|
|
54
|
-
* down with a slight +X tilt. 2x2 cube occluder at (0, 1.5, 0) casts
|
|
55
|
-
* shadow toward +X on the ground (y=0). Ground points at -X are lit;
|
|
56
|
-
* ground points near x=0 within the cube footprint are occluded.
|
|
57
|
-
*
|
|
58
|
-
* M3 probe upgrade (feat-20260520 w16): PCF with 3x3 kernel replaces the
|
|
59
|
-
* naive comparison sampler; positions use ground-plane sampling to detect
|
|
60
|
-
* shadow from the 2x2 cube.
|
|
61
|
-
*
|
|
62
|
-
* - SAMPLE_LIT_*: ground (-X, 0.0, *) — outside the cube's shadow.
|
|
63
|
-
* - SAMPLE_OCCLUDED_*: ground (0, 0.0, 0) — inside the cube's shadow core.
|
|
64
|
-
*/
|
|
65
|
-
const SAMPLE_LIT_A: [number, number, number] = [-3, 0.0, 0];
|
|
66
|
-
const SAMPLE_LIT_B: [number, number, number] = [-2, 0.0, 1];
|
|
67
|
-
const SAMPLE_LIT_C: [number, number, number] = [-1.5, 0.0, -1];
|
|
68
|
-
const SAMPLE_OCCLUDED_A: [number, number, number] = [0.2, 0.0, 0];
|
|
69
|
-
const SAMPLE_OCCLUDED_B: [number, number, number] = [0.5, 0.0, 0];
|
|
70
|
-
|
|
71
|
-
// ── Manifest: pre-built hello-triangle composed WGSL ──────────────────────
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* The shadow depth pass needs a valid shader manifest with WGSL for
|
|
75
|
-
* `shadow_caster`. We read the hello-triangle demo's `pnpm build` output
|
|
76
|
-
* `dist/shaders/manifest.json`. The manifest is loaded once per vitest
|
|
77
|
-
* module via vitest's native ESM `import()` (supports both JSON and
|
|
78
|
-
* top-level await in vitest's pool). We then encode it as a `data:` URL
|
|
79
|
-
* so ShaderRegistry can fetch it via Node.js native fetch().
|
|
80
|
-
*
|
|
81
|
-
* Precondition: `pnpm -r build` (or `pnpm -F hello-triangle build`).
|
|
82
|
-
*
|
|
83
|
-
* Vitest dawn runs tests in Node.js ESM context, so `import()` resolves
|
|
84
|
-
* relative to the source file. The relative path goes up 4 levels from
|
|
85
|
-
* `packages/runtime/src/__tests__/` to the repo root, then down into
|
|
86
|
-
* `apps/hello/triangle/dist/shaders/`.
|
|
87
|
-
*/
|
|
88
|
-
async function loadManifestDataUrl(): Promise<string | null> {
|
|
89
|
-
// fs.readFileSync (not `await import('...json')`) so tsc does not try
|
|
90
|
-
// to statically resolve the path — the manifest is a build artifact only
|
|
91
|
-
// present after `pnpm -F hello-triangle build` and CI's typecheck phase
|
|
92
|
-
// runs before any app build (would error TS2307 on dynamic JSON import).
|
|
93
|
-
try {
|
|
94
|
-
const here = fileURLToPath(import.meta.url);
|
|
95
|
-
const manifestPath = resolve(
|
|
96
|
-
here,
|
|
97
|
-
'../../../../../apps/hello/triangle/dist/shaders/manifest.json',
|
|
98
|
-
);
|
|
99
|
-
const text = readFileSync(manifestPath, 'utf8');
|
|
100
|
-
return `data:application/json,${encodeURIComponent(text)}`;
|
|
101
|
-
} catch {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
107
|
-
|
|
108
|
-
const TEXTURE_USAGE_RENDER_ATTACHMENT = 0x10;
|
|
109
|
-
const TEXTURE_USAGE_COPY_SRC = 0x01;
|
|
110
|
-
|
|
111
|
-
// biome-ignore lint/suspicious/noExplicitAny: dawn-node detection guard
|
|
112
|
-
const dawnReady = typeof navigator !== 'undefined' && (navigator as any).gpu !== undefined;
|
|
113
|
-
|
|
114
|
-
/** Shared GPUDevice captured during adapter hook for render target creation. */
|
|
115
|
-
let sharedDevice: GPUDevice | undefined;
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Create a minimal offscreen render target so dawn-node can run beginRenderPass.
|
|
119
|
-
*/
|
|
120
|
-
function createMockCanvas(width: number, height: number): HTMLCanvasElement {
|
|
121
|
-
let renderTarget: GPUTexture | undefined;
|
|
122
|
-
const originalRequestAdapter = globalThis.navigator.gpu.requestAdapter.bind(
|
|
123
|
-
globalThis.navigator.gpu,
|
|
124
|
-
);
|
|
125
|
-
globalThis.navigator.gpu.requestAdapter = async (opts) => {
|
|
126
|
-
const rawAdapter = await originalRequestAdapter(opts);
|
|
127
|
-
if (rawAdapter === null) return rawAdapter;
|
|
128
|
-
const originalRequestDevice = rawAdapter.requestDevice.bind(rawAdapter);
|
|
129
|
-
rawAdapter.requestDevice = async (desc) => {
|
|
130
|
-
const dev = await originalRequestDevice(desc);
|
|
131
|
-
if (sharedDevice === undefined) sharedDevice = dev;
|
|
132
|
-
return dev;
|
|
133
|
-
};
|
|
134
|
-
return rawAdapter;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const ensureRenderTarget = (device: GPUDevice, format: GPUTextureFormat): GPUTexture => {
|
|
138
|
-
if (renderTarget !== undefined) return renderTarget;
|
|
139
|
-
renderTarget = device.createTexture({
|
|
140
|
-
size: { width, height, depthOrArrayLayers: 1 },
|
|
141
|
-
format,
|
|
142
|
-
usage: TEXTURE_USAGE_RENDER_ATTACHMENT | TEXTURE_USAGE_COPY_SRC,
|
|
143
|
-
viewFormats: ['rgba8unorm-srgb'],
|
|
144
|
-
});
|
|
145
|
-
return renderTarget;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
width,
|
|
150
|
-
height,
|
|
151
|
-
// biome-ignore lint/suspicious/noExplicitAny: HTMLCanvasElement mock for dawn-node
|
|
152
|
-
getContext(kind: string): any {
|
|
153
|
-
if (kind !== 'webgpu') return null;
|
|
154
|
-
return {
|
|
155
|
-
configure(desc: { device: GPUDevice; format?: GPUTextureFormat }) {
|
|
156
|
-
ensureRenderTarget(desc.device, desc.format ?? 'rgba8unorm');
|
|
157
|
-
},
|
|
158
|
-
unconfigure() {},
|
|
159
|
-
getCurrentTexture(): GPUTexture {
|
|
160
|
-
if (renderTarget === undefined) {
|
|
161
|
-
if (sharedDevice === undefined)
|
|
162
|
-
throw new Error('render target requested before device captured');
|
|
163
|
-
return ensureRenderTarget(sharedDevice, 'rgba8unorm');
|
|
164
|
-
}
|
|
165
|
-
return renderTarget;
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
},
|
|
169
|
-
addEventListener() {},
|
|
170
|
-
removeEventListener() {},
|
|
171
|
-
} as unknown as HTMLCanvasElement;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Spawn the full fixture world: light + shadow, camera, ground plane, cube
|
|
176
|
-
* occluder. Components are registered, entities spawned, ready for
|
|
177
|
-
* `renderer.draw(world)`.
|
|
178
|
-
*/
|
|
179
|
-
function buildFixtureWorld(): World {
|
|
180
|
-
const world = new World();
|
|
181
|
-
const cubeHandle = world.internSharedRef('MeshAsset', createPrimitiveMesh('cube').unwrap());
|
|
182
|
-
|
|
183
|
-
// Light + shadow on same entity.
|
|
184
|
-
world.spawn({
|
|
185
|
-
component: DirectionalLight,
|
|
186
|
-
data: {
|
|
187
|
-
direction: [FIXTURE_LIGHT_DIR[0], FIXTURE_LIGHT_DIR[1], FIXTURE_LIGHT_DIR[2]],
|
|
188
|
-
color: [1, 1, 1],
|
|
189
|
-
intensity: 1,
|
|
190
|
-
// feat-20260613-csm M6 / w22: shadow-m2 fixture predates CSM and
|
|
191
|
-
// expects all geometry to land in cascade 0 (the test reads
|
|
192
|
-
// debug.center, which always samples the cascade-0 tile -- see
|
|
193
|
-
// debugReadbackShadowDepth in createRenderer.ts). With cascadeCount=4
|
|
194
|
-
// (CSM default), PSSM splits between [camera near,
|
|
195
|
-
// shadowDistance=50] place cascade 0 in view-space z [~0.1, 3.5];
|
|
196
|
-
// the fixture's geometry sits at world z=0 (camera at z=10), which
|
|
197
|
-
// is in view-space z=10 -> cascade 2/3, leaving cascade 0 empty.
|
|
198
|
-
// Pinning cascadeCount=1 keeps the AC-12 single-shadow contract.
|
|
199
|
-
cascadeCount: 1,
|
|
200
|
-
mapSize: FIXTURE_MAP_SIZE,
|
|
201
|
-
shadowDistance: 50,
|
|
202
|
-
},
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Camera at (0, 0, 10) identity quat looking along -Z, orthographic
|
|
206
|
-
// projection wide enough to capture the ground plane (y in [-5, 5]) and
|
|
207
|
-
// the cube occluder at y=1.5. feat-20260613-csm M6 / w20 fixture
|
|
208
|
-
// migration: CSM fits the light-space AABB to the camera frustum, so
|
|
209
|
-
// the camera must SEE the shadowable geometry for the atlas to capture
|
|
210
|
-
// it (the prior fixture sat at (0,10,0) identity quat looking -Z, which
|
|
211
|
-
// missed both the ground and the cube). An orthographic camera at the
|
|
212
|
-
// origin's z+10 plane with extents [-5,5] x [-5,5] gives camera-space
|
|
213
|
-
// frustum x in [-5,5], y in [-5,5], z in [-99.9, 9.9] -> contains the
|
|
214
|
-
// cube and the ground.
|
|
215
|
-
world.spawn(
|
|
216
|
-
{
|
|
217
|
-
component: Transform,
|
|
218
|
-
data: {
|
|
219
|
-
pos: [0, 0, 10],
|
|
220
|
-
quat: [0, 0, 0, 1],
|
|
221
|
-
scale: [1, 1, 1],
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
component: Camera,
|
|
226
|
-
data: {
|
|
227
|
-
projection: 1, // orthographic
|
|
228
|
-
left: -5,
|
|
229
|
-
right: 5,
|
|
230
|
-
bottom: -5,
|
|
231
|
-
top: 5,
|
|
232
|
-
near: 0.1,
|
|
233
|
-
far: 100,
|
|
234
|
-
fov: 0,
|
|
235
|
-
aspect: 1,
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
// Ground plane -- flattened cube, top face at y=0.
|
|
241
|
-
world.spawn(
|
|
242
|
-
{
|
|
243
|
-
component: Transform,
|
|
244
|
-
data: {
|
|
245
|
-
pos: [0, -0.005, 0],
|
|
246
|
-
quat: [0, 0, 0, 1],
|
|
247
|
-
scale: [GROUND_SIZE, 0.01, GROUND_SIZE],
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
component: MeshFilter,
|
|
252
|
-
data: { assetHandle: cubeHandle },
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
component: MeshRenderer,
|
|
256
|
-
data: {},
|
|
257
|
-
},
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
// Cube occluder: 2x2x2 centred at y=1.5 (matches M3 fixture).
|
|
261
|
-
world.spawn(
|
|
262
|
-
{
|
|
263
|
-
component: Transform,
|
|
264
|
-
data: {
|
|
265
|
-
pos: [0, 1.5, 0],
|
|
266
|
-
quat: [0, 0, 0, 1],
|
|
267
|
-
scale: [2, 2, 2],
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
component: MeshFilter,
|
|
272
|
-
data: { assetHandle: cubeHandle },
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
component: MeshRenderer,
|
|
276
|
-
data: {},
|
|
277
|
-
},
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
return world;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// ── Tests ──────────────────────────────────────────────────────────────────
|
|
284
|
-
|
|
285
|
-
describe('shadow M2 dawn (AC-12 real)', () => {
|
|
286
|
-
it.skipIf(!dawnReady)("'dawn-binding-missing' -- dawn.node binding injection failed", () => {
|
|
287
|
-
expect(dawnReady).toBe(true);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
describe('AC-12 naive shadow factor sampling', () => {
|
|
291
|
-
it('occluded positions measurably darker than lit, lit approx 1.0', async () => {
|
|
292
|
-
const manifestUrl = await loadManifestDataUrl();
|
|
293
|
-
if (manifestUrl === null) {
|
|
294
|
-
// manifest not built; skip gracefully
|
|
295
|
-
console.warn('[AC-12] hello-triangle manifest not found -- skipping shadow test');
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
const canvas = createMockCanvas(WIDTH, HEIGHT);
|
|
299
|
-
const renderer = await createRenderer(canvas, {}, { shaderManifestUrl: manifestUrl });
|
|
300
|
-
expect(renderer.backend).toBe('webgpu');
|
|
301
|
-
|
|
302
|
-
const ready = await renderer.ready;
|
|
303
|
-
expect(ready.ok).toBe(true);
|
|
304
|
-
|
|
305
|
-
// Build fixture world and render at least one frame to populate
|
|
306
|
-
// the shadow depth texture.
|
|
307
|
-
const world = buildFixtureWorld();
|
|
308
|
-
const drawResult = drawPublished(renderer, world);
|
|
309
|
-
expect(drawResult.ok).toBe(true);
|
|
310
|
-
|
|
311
|
-
// Verify the shadow RT exists (shadow pass ran).
|
|
312
|
-
const debug = await renderer.debugReadback?.();
|
|
313
|
-
expect(debug).not.toBeNull();
|
|
314
|
-
if (debug !== null && debug !== undefined) {
|
|
315
|
-
expect(debug.mapSize).toBe(FIXTURE_MAP_SIZE);
|
|
316
|
-
expect(debug.center).toBeGreaterThanOrEqual(0);
|
|
317
|
-
expect(debug.center).toBeLessThanOrEqual(1);
|
|
318
|
-
console.warn('[AC-12 debug] debugReadback:', JSON.stringify(debug));
|
|
319
|
-
|
|
320
|
-
// ── Core fix (M1c gap): shadow depth must have non-zero, non-
|
|
321
|
-
// uniform values. These are load-bearing — they prove the
|
|
322
|
-
// shadow depth pass wrote real geometry to the depth32float
|
|
323
|
-
// attachment.
|
|
324
|
-
// feat-20260613-csm M6 / w22: the legacy fixed-extent path placed
|
|
325
|
-
// the cube at the tile centre; CSM AABB-fits the camera frustum
|
|
326
|
-
// so the cube lands wherever its world-space projection maps under
|
|
327
|
-
// the per-cascade ortho. The substantive AC-12 check is the
|
|
328
|
-
// lit/occluded factor gap below (probe path is shader-identical
|
|
329
|
-
// to the main pass). Replace centre/corner pixel checks with a
|
|
330
|
-
// non-uniformity probe: at least one of the 5 sampled pixels must
|
|
331
|
-
// have written cube depth (< 1), proving the depth pass ran.
|
|
332
|
-
const samples = [
|
|
333
|
-
debug.center,
|
|
334
|
-
debug.corners.tl,
|
|
335
|
-
debug.corners.tr,
|
|
336
|
-
debug.corners.bl,
|
|
337
|
-
debug.corners.br,
|
|
338
|
-
];
|
|
339
|
-
expect(samples.some((s) => s < 0.99)).toBe(true);
|
|
340
|
-
expect(samples.some((s) => s > 0.5)).toBe(true);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Sample shadow factor at lit positions.
|
|
344
|
-
const litPositions = [SAMPLE_LIT_A, SAMPLE_LIT_B, SAMPLE_LIT_C];
|
|
345
|
-
const litResults = await renderer.debugSampleShadowFactor?.(litPositions);
|
|
346
|
-
expect(litResults).not.toBeNull();
|
|
347
|
-
if (!litResults) throw new Error('unreachable: debugSampleShadowFactor returned null');
|
|
348
|
-
expect(litResults.length).toBe(3);
|
|
349
|
-
|
|
350
|
-
// Sample shadow factor at occluded positions.
|
|
351
|
-
const occPositions = [SAMPLE_OCCLUDED_A, SAMPLE_OCCLUDED_B];
|
|
352
|
-
const occResults = await renderer.debugSampleShadowFactor?.(occPositions);
|
|
353
|
-
expect(occResults).not.toBeNull();
|
|
354
|
-
if (!occResults) throw new Error('unreachable: occluded debugSampleShadowFactor null');
|
|
355
|
-
expect(occResults.length).toBe(2);
|
|
356
|
-
|
|
357
|
-
const litFactors = litResults.map((r) => r.shadowFactor);
|
|
358
|
-
const occFactors = occResults.map((r) => r.shadowFactor);
|
|
359
|
-
|
|
360
|
-
console.warn('[AC-12 debug] litFactors:', JSON.stringify(litFactors));
|
|
361
|
-
console.warn('[AC-12 debug] occFactors:', JSON.stringify(occFactors));
|
|
362
|
-
|
|
363
|
-
// Also check directionalShadow for lightSpaceMatrix
|
|
364
|
-
const ds = renderer.directionalShadow;
|
|
365
|
-
console.warn('[AC-12 debug] directionalShadow mapSize:', ds?.mapSize);
|
|
366
|
-
console.warn('[AC-12 debug] directionalShadow lightSpaceMatrix:', ds?.lightSpaceMatrix);
|
|
367
|
-
|
|
368
|
-
// ── AC-12 numerical assertion (OOS-7 retired by feat-20260520 M2/w15).
|
|
369
|
-
//
|
|
370
|
-
// debugSampleShadowFactor now drives a fragment-stage GPU probe
|
|
371
|
-
// pipeline that runs textureSampleCompareLevel byte-for-byte mirroring
|
|
372
|
-
// pbr.wgsl::evalDirectional() — same UV remap, same OOB guard, same
|
|
373
|
-
// PipelineState.shadowSampler. The factor returned for a world
|
|
374
|
-
// position is the exact factor a fragment at that worldPos receives
|
|
375
|
-
// in the main pass, so the lit-vs-occluded gap is load-bearing
|
|
376
|
-
// semantic evidence the M2 shadow lookup is wired correctly.
|
|
377
|
-
//
|
|
378
|
-
// Lit positions land on the -X side of the light frustum where the
|
|
379
|
-
// cube does not project; comparison returns 1 (fully lit). Occluded
|
|
380
|
-
// positions land on the +X side under the cube's projected shadow;
|
|
381
|
-
// comparison returns 0 (fully shadowed). M2 has no PCF (M3 work),
|
|
382
|
-
// so values cluster at the discrete 0/1 endpoints and the gap is
|
|
383
|
-
// the full unit interval.
|
|
384
|
-
const litMin = Math.min(...litFactors);
|
|
385
|
-
const occMax = Math.max(...occFactors);
|
|
386
|
-
expect(litMin).toBeGreaterThan(0.5);
|
|
387
|
-
expect(occMax).toBeLessThan(0.2);
|
|
388
|
-
// The lit/occluded gap is the AC-12 semantic guarantee — that the
|
|
389
|
-
// shadow term in the main pass actually responds to occluder
|
|
390
|
-
// geometry (M3 probe with PCF preserves this gap).
|
|
391
|
-
expect(litMin - occMax).toBeGreaterThan(0.3);
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
});
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
// shadow-m3-calibrate-run.dawn.test.ts - feat-20260520-directional-light-shadow-mapping
|
|
2
|
-
// M3 / w15+w16: one-off calibration runner. Not part of the normal CI suite —
|
|
3
|
-
// run explicitly with `npx vitest run <this-file>` after w16 bias+PCF lands
|
|
4
|
-
// to measure shadow factor improvements and freeze AC_13_THRESHOLD_X.
|
|
5
|
-
//
|
|
6
|
-
// This file IS a .dawn.test.ts (so vitest gives it a dawn-node WebGPU device)
|
|
7
|
-
// but it is intentionally gated behind `dawnReady` and prints a calibration
|
|
8
|
-
// report rather than performing pass/fail assertions.
|
|
9
|
-
|
|
10
|
-
import { readFileSync } from 'node:fs';
|
|
11
|
-
import { resolve } from 'node:path';
|
|
12
|
-
import { fileURLToPath } from 'node:url';
|
|
13
|
-
import { World } from '@forgeax/engine-ecs';
|
|
14
|
-
import { createPrimitiveMesh } from '@forgeax/engine-geometry';
|
|
15
|
-
import {
|
|
16
|
-
Camera,
|
|
17
|
-
DirectionalLight,
|
|
18
|
-
MeshFilter,
|
|
19
|
-
MeshRenderer,
|
|
20
|
-
} from '@forgeax/engine-render/internal';
|
|
21
|
-
import { createRenderer } from '@forgeax/engine-runtime';
|
|
22
|
-
import { Transform } from '@forgeax/engine-scene';
|
|
23
|
-
import { describe, expect, it } from 'vitest';
|
|
24
|
-
import { drawPublished } from './draw-published';
|
|
25
|
-
import {
|
|
26
|
-
CALIBRATION_POSITIONS,
|
|
27
|
-
calibrateThresholdX,
|
|
28
|
-
measureShadowFactors,
|
|
29
|
-
printCalibrationReport,
|
|
30
|
-
} from './shadow-m3-calibrate';
|
|
31
|
-
|
|
32
|
-
// ── Fixture (same as shadow-m3.dawn.test.ts SSOT) ───────────────────────────
|
|
33
|
-
|
|
34
|
-
const WIDTH = 256;
|
|
35
|
-
const HEIGHT = 256;
|
|
36
|
-
const FIXTURE_LIGHT_DIR: [number, number, number] = [0.2, -0.98, 0];
|
|
37
|
-
const FIXTURE_MAP_SIZE = 1024;
|
|
38
|
-
const GROUND_SIZE = 20;
|
|
39
|
-
|
|
40
|
-
// biome-ignore lint/suspicious/noExplicitAny: dawn-node detection guard
|
|
41
|
-
const dawnReady = typeof navigator !== 'undefined' && (navigator as any).gpu !== undefined;
|
|
42
|
-
|
|
43
|
-
async function loadManifestDataUrl(): Promise<string | null> {
|
|
44
|
-
// fs.readFileSync (not dynamic JSON import) so tsc does not statically
|
|
45
|
-
// resolve the path — manifest only exists after `pnpm -F hello-triangle build`.
|
|
46
|
-
try {
|
|
47
|
-
const here = fileURLToPath(import.meta.url);
|
|
48
|
-
const manifestPath = resolve(
|
|
49
|
-
here,
|
|
50
|
-
'../../../../../apps/hello/triangle/dist/shaders/manifest.json',
|
|
51
|
-
);
|
|
52
|
-
const text = readFileSync(manifestPath, 'utf8');
|
|
53
|
-
return `data:application/json,${encodeURIComponent(text)}`;
|
|
54
|
-
} catch {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const TEXTURE_USAGE_RENDER_ATTACHMENT = 0x10;
|
|
60
|
-
const TEXTURE_USAGE_COPY_SRC = 0x01;
|
|
61
|
-
let sharedDevice: GPUDevice | undefined;
|
|
62
|
-
|
|
63
|
-
function createMockCanvas(width: number, height: number): HTMLCanvasElement {
|
|
64
|
-
let renderTarget: GPUTexture | undefined;
|
|
65
|
-
const originalRequestAdapter = globalThis.navigator.gpu.requestAdapter.bind(
|
|
66
|
-
globalThis.navigator.gpu,
|
|
67
|
-
);
|
|
68
|
-
globalThis.navigator.gpu.requestAdapter = async (opts) => {
|
|
69
|
-
const rawAdapter = await originalRequestAdapter(opts);
|
|
70
|
-
if (rawAdapter === null) return rawAdapter;
|
|
71
|
-
const originalRequestDevice = rawAdapter.requestDevice.bind(rawAdapter);
|
|
72
|
-
rawAdapter.requestDevice = async (desc) => {
|
|
73
|
-
const dev = await originalRequestDevice(desc);
|
|
74
|
-
if (sharedDevice === undefined) sharedDevice = dev;
|
|
75
|
-
return dev;
|
|
76
|
-
};
|
|
77
|
-
return rawAdapter;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const ensureRenderTarget = (device: GPUDevice, format: GPUTextureFormat): GPUTexture => {
|
|
81
|
-
if (renderTarget !== undefined) return renderTarget;
|
|
82
|
-
renderTarget = device.createTexture({
|
|
83
|
-
size: { width, height, depthOrArrayLayers: 1 },
|
|
84
|
-
format,
|
|
85
|
-
usage: TEXTURE_USAGE_RENDER_ATTACHMENT | TEXTURE_USAGE_COPY_SRC,
|
|
86
|
-
viewFormats: ['rgba8unorm-srgb'],
|
|
87
|
-
});
|
|
88
|
-
return renderTarget;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
width,
|
|
93
|
-
height,
|
|
94
|
-
// biome-ignore lint/suspicious/noExplicitAny: HTMLCanvasElement mock for dawn-node
|
|
95
|
-
getContext(kind: string): any {
|
|
96
|
-
if (kind !== 'webgpu') return null;
|
|
97
|
-
return {
|
|
98
|
-
configure(desc: { device: GPUDevice; format?: GPUTextureFormat }) {
|
|
99
|
-
ensureRenderTarget(desc.device, desc.format ?? 'rgba8unorm');
|
|
100
|
-
},
|
|
101
|
-
unconfigure() {},
|
|
102
|
-
getCurrentTexture(): GPUTexture {
|
|
103
|
-
if (renderTarget === undefined) {
|
|
104
|
-
if (sharedDevice === undefined)
|
|
105
|
-
throw new Error('render target requested before device captured');
|
|
106
|
-
return ensureRenderTarget(sharedDevice, 'rgba8unorm');
|
|
107
|
-
}
|
|
108
|
-
return renderTarget;
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
},
|
|
112
|
-
addEventListener() {},
|
|
113
|
-
removeEventListener() {},
|
|
114
|
-
} as unknown as HTMLCanvasElement;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function buildFixtureWorld(): World {
|
|
118
|
-
const world = new World();
|
|
119
|
-
const cubeHandle = world.internSharedRef('MeshAsset', createPrimitiveMesh('cube').unwrap());
|
|
120
|
-
|
|
121
|
-
world.spawn({
|
|
122
|
-
component: DirectionalLight,
|
|
123
|
-
data: {
|
|
124
|
-
direction: [FIXTURE_LIGHT_DIR[0], FIXTURE_LIGHT_DIR[1], FIXTURE_LIGHT_DIR[2]],
|
|
125
|
-
color: [1, 1, 1],
|
|
126
|
-
intensity: 1,
|
|
127
|
-
mapSize: FIXTURE_MAP_SIZE,
|
|
128
|
-
shadowDistance: 50,
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
world.spawn(
|
|
133
|
-
{
|
|
134
|
-
component: Transform,
|
|
135
|
-
data: {
|
|
136
|
-
pos: [0, 10, 0],
|
|
137
|
-
quat: [0, 0, 0, 1],
|
|
138
|
-
scale: [1, 1, 1],
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
component: Camera,
|
|
143
|
-
data: {
|
|
144
|
-
projection: 1,
|
|
145
|
-
left: -5,
|
|
146
|
-
right: 5,
|
|
147
|
-
bottom: -5,
|
|
148
|
-
top: 5,
|
|
149
|
-
near: 0.1,
|
|
150
|
-
far: 100,
|
|
151
|
-
fov: 0,
|
|
152
|
-
aspect: 1,
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
world.spawn(
|
|
158
|
-
{
|
|
159
|
-
component: Transform,
|
|
160
|
-
data: {
|
|
161
|
-
pos: [0, -0.005, 0],
|
|
162
|
-
quat: [0, 0, 0, 1],
|
|
163
|
-
scale: [GROUND_SIZE, 0.01, GROUND_SIZE],
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
component: MeshFilter,
|
|
168
|
-
data: { assetHandle: cubeHandle },
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
component: MeshRenderer,
|
|
172
|
-
data: {},
|
|
173
|
-
},
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
world.spawn(
|
|
177
|
-
{
|
|
178
|
-
component: Transform,
|
|
179
|
-
data: {
|
|
180
|
-
pos: [0, 1.3, 0],
|
|
181
|
-
quat: [0, 0, 0, 1],
|
|
182
|
-
scale: [1, 1, 1],
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
component: MeshFilter,
|
|
187
|
-
data: { assetHandle: cubeHandle },
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
component: MeshRenderer,
|
|
191
|
-
data: {},
|
|
192
|
-
},
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
return world;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
describe('M3 calibration runner (one-off)', () => {
|
|
199
|
-
it.skipIf(!dawnReady)("'dawn-binding-missing' -- dawn.node binding injection failed", () => {
|
|
200
|
-
expect(dawnReady).toBe(true);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('calibrate AC-13 threshold X', async () => {
|
|
204
|
-
const manifestUrl = await loadManifestDataUrl();
|
|
205
|
-
if (manifestUrl === null) {
|
|
206
|
-
console.warn('[calibrate] manifest not found -- skipping');
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
const canvas = createMockCanvas(WIDTH, HEIGHT);
|
|
210
|
-
const renderer = await createRenderer(canvas, {}, { shaderManifestUrl: manifestUrl });
|
|
211
|
-
expect(renderer.backend).toBe('webgpu');
|
|
212
|
-
|
|
213
|
-
const ready = await renderer.ready;
|
|
214
|
-
expect(ready.ok).toBe(true);
|
|
215
|
-
|
|
216
|
-
// Draw one frame to populate the shadow depth texture.
|
|
217
|
-
const world = buildFixtureWorld();
|
|
218
|
-
const drawResult = drawPublished(renderer, world);
|
|
219
|
-
expect(drawResult.ok).toBe(true);
|
|
220
|
-
|
|
221
|
-
// In the single-session calibration workflow, M2 and M3 measurements
|
|
222
|
-
// happen on the SAME renderer, but at different points in time.
|
|
223
|
-
// Pre-w16: both read the same (naive) shadow factors → diffs = 0.
|
|
224
|
-
// Post-w16: re-run this runner after rebuilding; diffs reflect the
|
|
225
|
-
// bias+PCF improvement.
|
|
226
|
-
//
|
|
227
|
-
// The "M2 baseline" is recorded first, then w16 is applied (pbr.wgsl
|
|
228
|
-
// edit + rebuild), then this runner is called again — the M3 factors
|
|
229
|
-
// will be the post-change values. For the single-session case both are
|
|
230
|
-
// the same (the renderer reflects the CURRENT shader), so the implementer
|
|
231
|
-
// must record M2 factors before the w16 commit, then re-measure after.
|
|
232
|
-
const result = await calibrateThresholdX(
|
|
233
|
-
CALIBRATION_POSITIONS,
|
|
234
|
-
// measureM2: current factors (pre-w16 = same as M3, diffs 0)
|
|
235
|
-
// In the actual two-step workflow this records before w16 commit.
|
|
236
|
-
async () => measureShadowFactors(renderer, CALIBRATION_POSITIONS),
|
|
237
|
-
// measureM3: current factors (post-w16 = bias+PCF active)
|
|
238
|
-
async () => measureShadowFactors(renderer, CALIBRATION_POSITIONS),
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
printCalibrationReport(result);
|
|
242
|
-
|
|
243
|
-
// In the RED phase (pre-w16), maxDiff == 0 and suggestedX == 0.02.
|
|
244
|
-
// That's expected — calibration is aspirational until w16 lands.
|
|
245
|
-
// Post-w16, maxDiff > 0 and the implementer copies suggestedX into
|
|
246
|
-
// shadow-m3.dawn.test.ts AC_13_THRESHOLD_X and re-runs pnpm test:dawn.
|
|
247
|
-
});
|
|
248
|
-
});
|