@forgeax/engine-render 0.1.24 → 0.1.26
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 +118 -1
- package/dist/assembly/factory.d.ts +1 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +4 -17
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -1
- package/dist/assembly/material/surface-projection.d.ts +24 -0
- package/dist/assembly/material/surface-projection.d.ts.map +1 -0
- package/dist/assembly/material-shader-policy.d.ts +20 -0
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer.d.ts +1 -2
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/assembly/webgpu-vertex-layouts.d.ts +89 -0
- package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -0
- package/dist/assets/asset-decoders.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/{chunk-Q752SHI5.mjs → chunk-ADHHVYLW.mjs} +3 -3
- package/dist/chunk-ADHHVYLW.mjs.map +1 -0
- package/dist/{chunk-TFH5I7JJ.mjs → chunk-E34VL5VI.mjs} +3 -3
- package/dist/{chunk-TFH5I7JJ.mjs.map → chunk-E34VL5VI.mjs.map} +1 -1
- package/dist/{chunk-YKB5DQV7.mjs → chunk-GF523LHF.mjs} +89 -21
- package/dist/chunk-GF523LHF.mjs.map +1 -0
- package/dist/{chunk-KZFTK6DO.mjs → chunk-HKXTW355.mjs} +7 -4
- package/dist/chunk-HKXTW355.mjs.map +1 -0
- package/dist/{chunk-UQYS7FRM.mjs → chunk-KM2NOX2I.mjs} +4 -4
- package/dist/{chunk-UQYS7FRM.mjs.map → chunk-KM2NOX2I.mjs.map} +1 -1
- package/dist/{chunk-YRUYGA4A.mjs → chunk-TMIASV2N.mjs} +944 -577
- package/dist/chunk-TMIASV2N.mjs.map +1 -0
- package/dist/{chunk-Z3YYH2MB.mjs → chunk-YUQXSEHG.mjs} +160 -73
- package/dist/chunk-YUQXSEHG.mjs.map +1 -0
- package/dist/{chunk-RR5L4SRS.mjs → chunk-ZZ4YQ474.mjs} +2 -2
- package/dist/{chunk-RR5L4SRS.mjs.map → chunk-ZZ4YQ474.mjs.map} +1 -1
- package/dist/components/instances.d.ts +13 -31
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +1012 -149
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/extract/contracts.d.ts +6 -6
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +6 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +4 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +27 -9
- package/dist/index.mjs.map +1 -1
- package/dist/instance-buffer-cache.d.ts +7 -1
- package/dist/instance-buffer-cache.d.ts.map +1 -1
- package/dist/instances.d.ts +101 -0
- package/dist/instances.d.ts.map +1 -0
- package/dist/internal.mjs +5 -5
- package/dist/materials.d.ts +63 -2
- package/dist/materials.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec-types.d.ts +2 -0
- package/dist/pipeline-spec-types.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +13 -2
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +23 -4
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +20 -2
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts +3 -3
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/material-uniforms.d.ts +4 -0
- package/dist/record/material-uniforms.d.ts.map +1 -0
- package/dist/record/render-context.d.ts +4 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +10 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts +1 -1
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/render-contract.d.ts +4 -0
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +6 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +44 -9
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +4 -1
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene-types.d.ts +2 -0
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +12 -1
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/systems/skin-palette-allocator.d.ts +6 -0
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/temporal/index.mjs +5 -5
- package/package.json +20 -20
- package/src/__tests__/fixtures/ai-weapon-spirit/README.md +20 -0
- package/src/__tests__/fixtures/ai-weapon-spirit/low-poly-toon.wgsl +178 -0
- package/src/__tests__/fixtures/ai-weapon-spirit/material.json +97 -0
- package/src/__tests__/fixtures/ai-weapon-spirit/painterly-surface.wgsl +55 -0
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +3 -3
- package/src/__tests__/gpu-driven-view.browser.test.ts +11 -3
- package/src/__tests__/gpu-scene.unit.test.ts +38 -2
- package/src/__tests__/instances-store.unit.test.ts +46 -0
- package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +48 -13
- package/src/__tests__/{material-static-dynamic-route.unit.test.ts → material-layer-projection.unit.test.ts} +30 -47
- package/src/__tests__/material-pass-policy.unit.test.ts +69 -0
- package/src/__tests__/material-program-dispatch.unit.test.ts +48 -0
- package/src/__tests__/material-snapshot-mutation.integration.test.ts +69 -0
- package/src/__tests__/material-surface-authoring.test-d.ts +62 -0
- package/src/__tests__/materials-transmission-validation.unit.test.ts +24 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +0 -4
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +44 -2
- package/src/__tests__/skin-motion-regression.unit.test.ts +33 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +30 -2
- package/src/__tests__/surface-adjacent-regressions.integration.test.ts +60 -0
- package/src/__tests__/surface-standard-pipeline.browser.test.ts +20 -0
- package/src/__tests__/surface-standard-pipeline.dawn.test.ts +20 -0
- package/src/__tests__/surface-standard-pipeline.fixture.ts +132 -0
- package/src/__tests__/surface-variant-provenance.integration.test.ts +33 -0
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +1 -1
- package/src/assembly/factory.ts +2 -3
- package/src/assembly/material/__tests__/standard-layer-plan-projection.integration.test.ts +18 -0
- package/src/assembly/material/__tests__/surface-pass-projection.integration.test.ts +62 -0
- package/src/assembly/material/assembly.ts +8 -40
- package/src/assembly/material/standard-layer-projection.ts +3 -1
- package/src/assembly/material/surface-projection.ts +91 -0
- package/src/assembly/material-shader-policy.ts +88 -10
- package/src/assembly/recovery/renderer-recover.ts +1 -1
- package/src/assembly/webgpu-ready.ts +3 -16
- package/src/assembly/webgpu-renderer.ts +106 -166
- package/src/assembly/webgpu-vertex-layouts.ts +132 -0
- package/src/assets/asset-decoders.ts +27 -4
- package/src/components/instances.ts +14 -197
- package/src/extract/contracts.ts +6 -6
- package/src/gpu-driven/production-raster.ts +34 -1
- package/src/gpu-scene.ts +84 -29
- package/src/index.ts +1 -0
- package/src/instance-buffer-cache.ts +14 -1
- package/src/instances.ts +288 -0
- package/src/materials.ts +109 -14
- package/src/pipeline-builder.ts +14 -10
- package/src/pipeline-spec-types.ts +2 -0
- package/src/pipeline-spec.ts +13 -17
- package/src/record/frame-snapshot.ts +19 -2
- package/src/record/frame.ts +38 -3
- package/src/record/main-pass-geometry.ts +837 -337
- package/src/record/main-pass-material.ts +87 -2
- package/src/record/main-pass-sprite-draws.ts +66 -169
- package/src/record/main-pass.ts +24 -246
- package/src/record/material-uniforms.ts +186 -0
- package/src/record/render-context.ts +8 -0
- package/src/record/shadow-pass.ts +120 -115
- package/src/recovery/render-system-candidate.ts +46 -5
- package/src/render-contract.ts +4 -0
- package/src/render-system-extract-tail.ts +153 -57
- package/src/render-system-extract.ts +110 -73
- package/src/render-system.ts +59 -5
- package/src/scene/render-scene-types.ts +2 -0
- package/src/scene/render-scene.ts +579 -36
- package/src/systems/skin-palette-allocator.ts +129 -7
- package/src/transmission/__tests__/surface-compatibility.integration.test.ts +32 -0
- package/dist/assembly/material/pipeline-projection.d.ts +0 -30
- package/dist/assembly/material/pipeline-projection.d.ts.map +0 -1
- package/dist/chunk-KZFTK6DO.mjs.map +0 -1
- package/dist/chunk-Q752SHI5.mjs.map +0 -1
- package/dist/chunk-YKB5DQV7.mjs.map +0 -1
- package/dist/chunk-YRUYGA4A.mjs.map +0 -1
- package/dist/chunk-Z3YYH2MB.mjs.map +0 -1
- package/src/assembly/material/pipeline-projection.ts +0 -63
|
@@ -6,11 +6,13 @@ import type { DeviceScope, LifecycleResourceSpec } from '../device/device-scope'
|
|
|
6
6
|
import { type SubmissionPlan } from '../gpu-driven/batch-topology';
|
|
7
7
|
import { GpuScene } from '../gpu-scene';
|
|
8
8
|
import type { PersistentRenderSceneInspection } from '../inspection-types';
|
|
9
|
+
import type { InstanceProjectionStore } from '../instances';
|
|
9
10
|
import type { PointsLinesInspection } from '../points-lines/inspection';
|
|
10
11
|
import type { PointsLinesRetainedSnapshot } from '../points-lines/snapshot';
|
|
11
12
|
import { type ReflectionProbeFact, ReflectionProbeProjection, type ReflectionProbeSelectionResult } from '../reflection/projection';
|
|
12
13
|
import type { CameraSnapshot } from '../render-contract';
|
|
13
14
|
import type { DispatchEntry, ExtractedFrame, MaterialSnapshotCachesByWorld, RenderableSnapshot, RenderableTemporalSnapshot } from '../render-system-extract';
|
|
15
|
+
import type { SkinPaletteAllocator } from '../systems/skin-palette-allocator';
|
|
14
16
|
import { type TransmissionDemand } from '../transmission/projection';
|
|
15
17
|
import type { RenderSceneApplyResult, RenderSceneBounds, RenderSceneInspection, RenderSceneOperation, RenderSceneSlot } from './render-scene-types';
|
|
16
18
|
import { type VisibilityBudget } from './visibility/budget';
|
|
@@ -22,6 +24,12 @@ interface WorldTransformSpan {
|
|
|
22
24
|
readonly entities: Readonly<Uint32Array>;
|
|
23
25
|
readonly worlds: Readonly<Float32Array>;
|
|
24
26
|
}
|
|
27
|
+
/** The normal extract request used by the persistent scene owner. */
|
|
28
|
+
export type PersistentRenderCandidateRequest = 'full' | 'none' | {
|
|
29
|
+
readonly kind: 'partial';
|
|
30
|
+
/** Entity keys are local to the corresponding World entry. */
|
|
31
|
+
readonly entitiesByWorld: readonly (ReadonlySet<number> | undefined)[];
|
|
32
|
+
};
|
|
25
33
|
export interface RenderSceneSubmissionCapture {
|
|
26
34
|
readonly revision: number;
|
|
27
35
|
readonly slots: readonly {
|
|
@@ -113,6 +121,9 @@ export interface PersistentRenderSceneOptions {
|
|
|
113
121
|
readonly onGpuError?: ((error: RhiError) => void) | undefined;
|
|
114
122
|
readonly onSharedRefMutation?: ((worldId: number, handle: number) => void) | undefined;
|
|
115
123
|
readonly configuredQueryBudget?: number | undefined;
|
|
124
|
+
/** Rebuildable projection of World-owned instance matrices. */
|
|
125
|
+
readonly instanceCollections?: InstanceProjectionStore | undefined;
|
|
126
|
+
readonly getSkinPaletteAllocator?: (() => SkinPaletteAllocator | null) | undefined;
|
|
116
127
|
}
|
|
117
128
|
export interface PersistentGpuDrivenState {
|
|
118
129
|
readonly scene: GpuScene;
|
|
@@ -238,7 +249,7 @@ export declare class PersistentRenderScene {
|
|
|
238
249
|
extractComposition(worlds: readonly World[], owner: {
|
|
239
250
|
readonly cameraOwner: number;
|
|
240
251
|
readonly resourceOwner: number;
|
|
241
|
-
}, catalogEpoch: number, buildCandidateFrame: (
|
|
252
|
+
}, catalogEpoch: number, buildCandidateFrame: (request: PersistentRenderCandidateRequest) => ExtractedFrame, leases?: readonly RenderReadLease[]): ExtractedFrame;
|
|
242
253
|
invalidate(): void;
|
|
243
254
|
setCompositionGpuSceneDemand(sceneRowsRequired: boolean): void;
|
|
244
255
|
detach(world: World): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-scene.d.ts","sourceRoot":"","sources":["../../src/scene/render-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"render-scene.d.ts","sourceRoot":"","sources":["../../src/scene/render-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,gCAAgC,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAwB7D,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EACL,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,8BAA8B,EACpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAEd,6BAA6B,EAE7B,kBAAkB,EAClB,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EAGpB,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAGL,oBAAoB,EAGrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAErF,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAW9B,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;CACzC;AAID,qEAAqE;AACrE,MAAM,MAAM,gCAAgC,GACxC,MAAM,GACN,MAAM,GACN;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC;CACxE,CAAC;AAEN,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,CAAC;KAC/C,EAAE,CAAC;IACJ,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AA4KD;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA0C;IAC7E,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAuC;IAC3E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0C;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAyB;IAC/D,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,oBAAoB,CAAqB;IACjD,OAAO,CAAC,cAAc,CAAK;IAI3B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmD;IACrF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6B;IACjE,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,gBAAgB,CAAsC;IAE9D,sEAAsE;IACtE,wBAAwB,IAAI,MAAM;IAIlC,KAAK,CAAC,UAAU,EAAE,SAAS,oBAAoB,EAAE,GAAG,sBAAsB;IA4H1E,+FAA+F;IAC/F,mBAAmB,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,GAAG,sBAAsB;IAkDjF,8EAA8E;IAC9E,KAAK,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,cAAc,UAAO,GAAG,IAAI;IA0C5E,OAAO,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI;IAIvD,mFAAmF;IACnF,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAU3C,WAAW,IAAI,kBAAkB,EAAE;IAWnC,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAInE,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;IAK5E,YAAY,CAAC,QAAQ,EAAE,kBAAkB,GAAG,kBAAkB;IAK9D,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;IAIlE,iBAAiB,CACf,OAAO,EAAE,SAAS,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,WAAW,CAAC,EAAE,GACpE,4BAA4B;IAgB/B,gBAAgB,CAAC,OAAO,EAAE,4BAA4B,GAAG,0BAA0B;IA0BnF,aAAa,IAAI,SAAS,eAAe,EAAE;IAW3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIrE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAIhD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI5E,oBAAoB,IAAI,SAAS,2BAA2B,EAAE;IAY9D,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,eAAe,EAAE;IAWpE,YAAY,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,eAAe,EAAE;IAYnE,OAAO,IAAI,qBAAqB;IAoBhC,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,QAAQ;IA+BhB,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,gBAAgB;IA+CxB,OAAO,CAAC,mBAAmB;IAK3B;;;;;OAKG;IACH,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,iBAAiB,GAAG,SAAS;IA4B1E,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,iBAAiB,GAAG,SAAS;CAIhF;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,SAAS,CAAC,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACvF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,+DAA+D;IAC/D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IACnE,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;CACpF;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;IAC3C,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;CACzC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C,uEAAuE;IACvE,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,kFAAkF;AAClF,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,SAAS,kBAAkB,EAAE,GACnC,SAAS,kBAAkB,EAAE,CAS/B;AAED,qEAAqE;AACrE,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACrD,yEAAyE;IACzE,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACvE,OAAO,IAAI,IAAI,CAAC;IAChB,OAAO,IAAI,IAAI,CAAC;IAChB,yEAAyE;IACzE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AA2YD,uFAAuF;AACvF,qBAAa,qBAAqB;IAgDpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IA/CpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuB;IACxD,oGAAoG;IACpG,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6B;IACjE,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAgD;IACvF,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,SAAS,CACJ;IACb,OAAO,CAAC,eAAe,CAET;IACd,oFAAoF;IACpF,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,oBAAoB,CAMd;IACd,OAAO,CAAC,yBAAyB,CASnB;IACd,OAAO,CAAC,4BAA4B,CAAK;IACzC,OAAO,CAAC,oBAAoB,CAAkC;IAC9D,mFAAmF;IACnF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsC;IACzE,OAAO,CAAC,sBAAsB,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmC;gBAEvC,OAAO,GAAE,4BAAiC;IAKvE,iFAAiF;IACjF,0BAA0B,IAAI,6BAA6B;IAI3D,uEAAuE;IACvE,oBAAoB,IAAI,oBAAoB;IAI5C,qBAAqB,IAAI,gBAAgB;IAIzC,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,UAAU;IAIlB,2EAA2E;IAC3E,sBAAsB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,MAAM,EAAE;IAInE,+EAA+E;IAC/E,gBAAgB,IAAI,SAAS,eAAe,EAAE;IAI9C,sFAAsF;IACtF,6BAA6B,IAAI,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC;IAIrE,OAAO,CAAC,eAAe;IAOvB,gFAAgF;IAChF,qBAAqB,CACnB,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,WAAW,EAAE,SAAS,kBAAkB,EAAE,GACzC,IAAI;IA8CP;;;;;;;;;OASG;IACH,iBAAiB,CACf,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,WAAW,EAAE,SAAS,kBAAkB,EAAE,EAC1C,QAAQ,EAAE,SAAS,aAAa,EAAE,GACjC,8BAA8B;IA0GjC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,8BAA8B;IAKtC,uFAAuF;IACvF,uBAAuB,CAAC,MAAM,EAAE,SAAS,mBAAmB,EAAE,GAAG,IAAI;IA2BrE,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,8BAA8B;IAI5F,yBAAyB,IAAI,UAAU,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;IAI9E,kBAAkB,CAChB,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,KAAK,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;KAAE,EACvE,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,CAAC,OAAO,EAAE,gCAAgC,KAAK,cAAc,EAClF,MAAM,CAAC,EAAE,SAAS,eAAe,EAAE,GAClC,cAAc;IAmZjB,UAAU,IAAI,IAAI;IAWlB,4BAA4B,CAAC,iBAAiB,EAAE,OAAO,GAAG,IAAI;IAM9D,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAmC1B,wFAAwF;IACxF,kBAAkB,IAAI,IAAI;IAQ1B,4EAA4E;IAC5E,iCAAiC,CAC/B,MAAM,EAAE,SAAS,GAChB,MAAM,CAAC,4BAA4B,EAAE,QAAQ,CAAC;IAoFjD,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,qBAAqB,CAAC,OAAO,CAAC;IAkBtE,yBAAyB,CAAC,WAAW,EAAE,SAAS,qBAAqB,EAAE,GAAG,IAAI;IAQ9E,OAAO,IAAI,IAAI;IAgBf,OAAO,IAAI,+BAA+B;IA2B1C,yBAAyB,IAAI,wBAAwB,GAAG,SAAS;IAajE,yEAAyE;IACzE,mBAAmB,IAAI,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC;IAwB7C,6FAA6F;IAC7F,oBAAoB,CAClB,OAAO,EAAE,SAAS,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,WAAW,CAAC,EAAE,GACpE,IAAI;IAQP,oBAAoB,IAAI,SAAS,2BAA2B,EAAE;IAI9D,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,kBAAkB;IAiK1B,iFAAiF;IACjF,0BAA0B,IAAI,kBAAkB;IAShD;;;OAGG;IACH,OAAO,CAAC,eAAe;IA2DvB,OAAO,CAAC,aAAa;IA8CrB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,eAAe;IA2CvB,OAAO,CAAC,OAAO;CAOhB"}
|
|
@@ -28,6 +28,12 @@ export interface SkinPaletteAllocator {
|
|
|
28
28
|
* `device.limits.maxStorageBufferBindingSize`
|
|
29
29
|
*/
|
|
30
30
|
allocateSlice(jointCount: number): SkinPaletteSlice;
|
|
31
|
+
/** Allocate one stable slice for a retained render source. */
|
|
32
|
+
allocateSliceFor(key: string, jointCount: number): SkinPaletteSlice;
|
|
33
|
+
/** Release a stable slice when its render source leaves the scene. */
|
|
34
|
+
releaseSliceFor(key: string): void;
|
|
35
|
+
/** Reconcile stable slices after a full render-source extraction. */
|
|
36
|
+
retainSliceKeys(keys: ReadonlySet<string>): void;
|
|
31
37
|
/**
|
|
32
38
|
* Write joint matrices into the slice's buffer at the slice's offset.
|
|
33
39
|
* Computes M_i = jointWorldTransforms[i] * ibm[i] per joint.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skin-palette-allocator.d.ts","sourceRoot":"","sources":["../../src/systems/skin-palette-allocator.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAO7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAmB7D,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACpD;;;;;;;;OAQG;IACH,iBAAiB,CACf,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,WAAW,EAAE,SAAS,IAAI,EAAE,GAC3B,IAAI,CAAC;IACR;;;;OAIG;IACH,aAAa,IAAI,IAAI,CAAC;CACvB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,cAAc,EAAE,MAAM,EACtB,gBAAgB,UAAO,GACtB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"skin-palette-allocator.d.ts","sourceRoot":"","sources":["../../src/systems/skin-palette-allocator.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAO7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAmB7D,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACpD,8DAA8D;IAC9D,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACpE,sEAAsE;IACtE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,qEAAqE;IACrE,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACjD;;;;;;;;OAQG;IACH,iBAAiB,CACf,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,WAAW,EAAE,SAAS,IAAI,EAAE,GAC3B,IAAI,CAAC;IACR;;;;OAIG;IACH,aAAa,IAAI,IAAI,CAAC;CACvB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,cAAc,EAAE,MAAM,EACtB,gBAAgB,UAAO,GACtB,oBAAoB,CAgPtB"}
|
package/dist/temporal/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { addStandardSceneDataPass, addTaaResolvePass, aggregateTemporalDemand, createStandardSceneDataTarget, describeTemporalDemand, standardTemporalLaneAdmission, standardTemporalPostOrder } from '../chunk-
|
|
1
|
+
export { addStandardSceneDataPass, addTaaResolvePass, aggregateTemporalDemand, createStandardSceneDataTarget, describeTemporalDemand, standardTemporalLaneAdmission, standardTemporalPostOrder } from '../chunk-TMIASV2N.mjs';
|
|
2
2
|
import '../chunk-RXZ3RGOU.mjs';
|
|
3
|
-
export { SCENE_DATA_TEMPORAL_V1_DESCRIPTOR, SCENE_DATA_TEMPORAL_V1_SCHEMA, createSceneDataCatalog, isSceneDataTarget, registerSceneDataTarget, sceneDataError, sceneDataTargetAsAttachment, sceneDataTargetOwner, sceneDataTokenMismatch } from '../chunk-
|
|
4
|
-
import '../chunk-
|
|
3
|
+
export { SCENE_DATA_TEMPORAL_V1_DESCRIPTOR, SCENE_DATA_TEMPORAL_V1_SCHEMA, createSceneDataCatalog, isSceneDataTarget, registerSceneDataTarget, sceneDataError, sceneDataTargetAsAttachment, sceneDataTargetOwner, sceneDataTokenMismatch } from '../chunk-E34VL5VI.mjs';
|
|
4
|
+
import '../chunk-GF523LHF.mjs';
|
|
5
5
|
export { TEMPORAL_JITTER_SAMPLE_COUNT, TemporalFrameCoordinator, classifySceneDataCoverage, createTemporalCoverage, projectTemporalView, scanSceneDataCoverage, snapshotSubmittedTemporalView, temporalJitterSample, temporalViewId } from '../chunk-GE3SDD72.mjs';
|
|
6
|
-
import '../chunk-
|
|
7
|
-
import '../chunk-
|
|
6
|
+
import '../chunk-HKXTW355.mjs';
|
|
7
|
+
import '../chunk-ZZ4YQ474.mjs';
|
|
8
8
|
//# sourceMappingURL=index.mjs.map
|
|
9
9
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-render",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Canonical ECS render schemas and renderer boundary.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -37,27 +37,27 @@
|
|
|
37
37
|
"LICENSE"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@forgeax/engine-assets-runtime": "0.1.
|
|
41
|
-
"@forgeax/engine-audio-webaudio": "0.1.
|
|
42
|
-
"@forgeax/engine-codec": "0.1.
|
|
43
|
-
"@forgeax/engine-ecs": "0.1.
|
|
44
|
-
"@forgeax/engine-geometry": "0.1.
|
|
45
|
-
"@forgeax/engine-graphics-extras": "0.1.
|
|
46
|
-
"@forgeax/engine-math": "0.1.
|
|
47
|
-
"@forgeax/engine-pack": "0.1.
|
|
48
|
-
"@forgeax/engine-plugin": "0.1.
|
|
49
|
-
"@forgeax/engine-profiler": "0.1.
|
|
50
|
-
"@forgeax/engine-render-graph": "0.1.
|
|
51
|
-
"@forgeax/engine-rhi": "0.1.
|
|
52
|
-
"@forgeax/engine-scene": "0.1.
|
|
53
|
-
"@forgeax/engine-shader": "0.1.
|
|
54
|
-
"@forgeax/engine-skinning": "0.1.
|
|
55
|
-
"@forgeax/engine-types": "0.1.
|
|
40
|
+
"@forgeax/engine-assets-runtime": "0.1.26",
|
|
41
|
+
"@forgeax/engine-audio-webaudio": "0.1.26",
|
|
42
|
+
"@forgeax/engine-codec": "0.1.26",
|
|
43
|
+
"@forgeax/engine-ecs": "0.1.26",
|
|
44
|
+
"@forgeax/engine-geometry": "0.1.26",
|
|
45
|
+
"@forgeax/engine-graphics-extras": "0.1.26",
|
|
46
|
+
"@forgeax/engine-math": "0.1.26",
|
|
47
|
+
"@forgeax/engine-pack": "0.1.26",
|
|
48
|
+
"@forgeax/engine-plugin": "0.1.26",
|
|
49
|
+
"@forgeax/engine-profiler": "0.1.26",
|
|
50
|
+
"@forgeax/engine-render-graph": "0.1.26",
|
|
51
|
+
"@forgeax/engine-rhi": "0.1.26",
|
|
52
|
+
"@forgeax/engine-scene": "0.1.26",
|
|
53
|
+
"@forgeax/engine-shader": "0.1.26",
|
|
54
|
+
"@forgeax/engine-skinning": "0.1.26",
|
|
55
|
+
"@forgeax/engine-types": "0.1.26"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@forgeax/engine-rhi-null": "0.1.
|
|
59
|
-
"@forgeax/engine-rhi-webgpu": "0.1.
|
|
60
|
-
"@forgeax/engine-vite-plugin-shader": "0.1.
|
|
58
|
+
"@forgeax/engine-rhi-null": "0.1.26",
|
|
59
|
+
"@forgeax/engine-rhi-webgpu": "0.1.26",
|
|
60
|
+
"@forgeax/engine-vite-plugin-shader": "0.1.26"
|
|
61
61
|
},
|
|
62
62
|
"forgeax": {
|
|
63
63
|
"metrics": {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# ai-weapon-spirit material regression fixture
|
|
2
|
+
|
|
3
|
+
Frozen on 2026-09-09 from the consumer working tree, including its uncommitted
|
|
4
|
+
0.1.25 migration. The WGSL files are verbatim copies, not approximations.
|
|
5
|
+
Tests use this local closure and never read the consumer checkout.
|
|
6
|
+
|
|
7
|
+
| Source file in ai-weapon-spirit | SHA-256 |
|
|
8
|
+
|:--|:--|
|
|
9
|
+
| `src/shaders/low-poly-toon.wgsl` | `ebdd63714683f2178a973d9392911bd0d5e607ad1df198a0c3b70f277c34b371` |
|
|
10
|
+
| `src/shaders/includes/painterly-surface.wgsl` | `48573786f86c3b6be1d5231797ed77b2206c54563f83d8edc6f597575805f1bb` |
|
|
11
|
+
|
|
12
|
+
The root parameter layout is the game's 11-field Toon contract (80 bytes).
|
|
13
|
+
The fixture exercises its migrated same-module Forward + ShadowCaster path,
|
|
14
|
+
and the intended Toon Forward + Engine ShadowCaster composition. Child values
|
|
15
|
+
include emissionStrength=0, pigmentStrength=0, surfaceMetallic=0 and sideShade=0.84.
|
|
16
|
+
A successful cook is only the compiler checkpoint: the runtime regression must
|
|
17
|
+
also submit real WebGPU draws, inspect validation errors and prove shadow pixels.
|
|
18
|
+
|
|
19
|
+
Source feedback: Engine Harness `2026-09-09-engine-025-material-contract-composition`,
|
|
20
|
+
especially cases D (child scalar decoding) and E (shadow material bind group).
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#define_import_path ai_weapon_spirit::low_poly_toon
|
|
2
|
+
|
|
3
|
+
#import forgeax_view::common::{view, meshes, instances, shadowCasterCascade}
|
|
4
|
+
#import forgeax_pbr::lighting_directional::{evalDirectionalShadowFactor}
|
|
5
|
+
#import ai_weapon_spirit::painterly_surface::{applyPigment, paintedSpecular, paintedRim}
|
|
6
|
+
|
|
7
|
+
struct Material {
|
|
8
|
+
baseColor : vec4<f32>,
|
|
9
|
+
shadowColor : vec4<f32>,
|
|
10
|
+
rimColor : vec4<f32>,
|
|
11
|
+
rimStrength : f32,
|
|
12
|
+
specularStrength : f32,
|
|
13
|
+
emissionStrength : f32,
|
|
14
|
+
sideShade : f32,
|
|
15
|
+
surfaceRoughness : f32,
|
|
16
|
+
surfaceMetallic : f32,
|
|
17
|
+
pigmentStrength : f32,
|
|
18
|
+
pigmentScale : f32,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
@group(1) @binding(0) var<uniform> material : Material;
|
|
22
|
+
|
|
23
|
+
struct VsIn {
|
|
24
|
+
@location(0) pos : vec3<f32>,
|
|
25
|
+
@location(1) normal : vec3<f32>,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
struct VsOut {
|
|
29
|
+
@builtin(position) clip : vec4<f32>,
|
|
30
|
+
@location(0) worldPos : vec3<f32>,
|
|
31
|
+
@location(1) worldNormal : vec3<f32>,
|
|
32
|
+
@location(2) viewZ : f32,
|
|
33
|
+
@location(3) paintPos : vec3<f32>,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
@vertex
|
|
37
|
+
fn vs_main(input : VsIn, @builtin(instance_index) idx : u32) -> VsOut {
|
|
38
|
+
// One path covers regular meshes (the renderer binds one identity instance)
|
|
39
|
+
// and explicit GPU Instances batches used by projectiles.
|
|
40
|
+
let model = meshes[0].worldFromLocal * instances[idx].localFromInstance;
|
|
41
|
+
let world = model * vec4<f32>(input.pos, 1.0);
|
|
42
|
+
var output : VsOut;
|
|
43
|
+
output.clip = view.worldViewProj * world;
|
|
44
|
+
output.worldPos = world.xyz;
|
|
45
|
+
output.paintPos = input.pos * vec3<f32>(length(model[0].xyz), length(model[1].xyz), length(model[2].xyz));
|
|
46
|
+
output.worldNormal = normalize((model * vec4<f32>(input.normal, 0.0)).xyz);
|
|
47
|
+
output.viewZ = -output.clip.w;
|
|
48
|
+
return output;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@fragment
|
|
52
|
+
fn fs_main(input : VsOut, @builtin(front_facing) frontFacing : bool) -> @location(0) vec4<f32> {
|
|
53
|
+
// PCG crowd meshes share the eight geometric cube corners instead of
|
|
54
|
+
// duplicating four vertices per face. Reconstructing the face normal from
|
|
55
|
+
// world-space derivatives preserves exact hard Low Poly planes while
|
|
56
|
+
// reducing full-stage stress vertex traffic by roughly three times.
|
|
57
|
+
// WebGPU framebuffer Y grows downward, so dy × dx produces the outward
|
|
58
|
+
// normal for the front-facing triangle winding used by ForgeAX meshes.
|
|
59
|
+
var normal = normalize(cross(dpdy(input.worldPos), dpdx(input.worldPos)));
|
|
60
|
+
if (!frontFacing) {
|
|
61
|
+
normal = -normal;
|
|
62
|
+
}
|
|
63
|
+
let toLight = normalize(vec3<f32>(0.46, 1.0, 0.32));
|
|
64
|
+
let toCamera = normalize(view.cameraPos - input.worldPos);
|
|
65
|
+
let nDotL = dot(normal, toLight);
|
|
66
|
+
let upFacing = dot(normal, vec3<f32>(0.0, 1.0, 0.0));
|
|
67
|
+
let paintNormal = normalize(cross(dpdy(input.paintPos), dpdx(input.paintPos)));
|
|
68
|
+
let surfaceColor = applyPigment(material.baseColor.rgb, input.paintPos, paintNormal, material.pigmentScale, material.pigmentStrength);
|
|
69
|
+
|
|
70
|
+
// Three broad light bands keep the blocks graphic instead of plastic.
|
|
71
|
+
var lightBand = 0.16;
|
|
72
|
+
if (nDotL > 0.08) {
|
|
73
|
+
lightBand = 0.58;
|
|
74
|
+
}
|
|
75
|
+
if (nDotL > 0.68) {
|
|
76
|
+
lightBand = 1.0;
|
|
77
|
+
}
|
|
78
|
+
var color = mix(material.shadowColor.rgb, surfaceColor, lightBand);
|
|
79
|
+
|
|
80
|
+
// Preserve native PCF and cascade blending. Thresholding BRDF radiance
|
|
81
|
+
// makes shadow edges depend on view direction and amplifies small changes.
|
|
82
|
+
// Toon bands stay authored here, with a readable cool ambient floor.
|
|
83
|
+
let shadowVisibility = evalDirectionalShadowFactor(normal, input.worldPos, input.viewZ);
|
|
84
|
+
if (nDotL > 0.08) {
|
|
85
|
+
color *= mix(0.46, 1.0, shadowVisibility);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Top planes carry the clean local color; sides become the darker cut face.
|
|
89
|
+
var planeShade = material.sideShade;
|
|
90
|
+
if (upFacing > 0.72) {
|
|
91
|
+
planeShade = 1.0;
|
|
92
|
+
}
|
|
93
|
+
if (upFacing < -0.72) {
|
|
94
|
+
planeShade = material.sideShade * 0.72;
|
|
95
|
+
}
|
|
96
|
+
color *= planeShade;
|
|
97
|
+
|
|
98
|
+
color += paintedSpecular(surfaceColor, normal, toLight, toCamera, material.surfaceRoughness,
|
|
99
|
+
material.surfaceMetallic, material.specularStrength, shadowVisibility);
|
|
100
|
+
let rim = paintedRim(normal, toCamera, material.surfaceRoughness, material.rimStrength, shadowVisibility);
|
|
101
|
+
color += material.rimColor.rgb * rim;
|
|
102
|
+
color += material.rimColor.rgb * material.emissionStrength;
|
|
103
|
+
|
|
104
|
+
return vec4<f32>(color, material.baseColor.a);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Isolated candidate entry for the readability preview. Production
|
|
108
|
+
// materials continue to use fs_main; this variant only tests a coloured
|
|
109
|
+
// ambient floor and a restrained Fresnel lift before the values are approved.
|
|
110
|
+
@fragment
|
|
111
|
+
fn fs_readability_candidate(input : VsOut, @builtin(front_facing) frontFacing : bool) -> @location(0) vec4<f32> {
|
|
112
|
+
var normal = normalize(cross(dpdy(input.worldPos), dpdx(input.worldPos)));
|
|
113
|
+
if (!frontFacing) {
|
|
114
|
+
normal = -normal;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let toLight = normalize(vec3<f32>(0.46, 1.0, 0.32));
|
|
118
|
+
let toCamera = normalize(view.cameraPos - input.worldPos);
|
|
119
|
+
let nDotL = dot(normal, toLight);
|
|
120
|
+
let upFacing = dot(normal, vec3<f32>(0.0, 1.0, 0.0));
|
|
121
|
+
let paintNormal = normalize(cross(dpdy(input.paintPos), dpdx(input.paintPos)));
|
|
122
|
+
let surfaceColor = applyPigment(material.baseColor.rgb, input.paintPos, paintNormal, material.pigmentScale, material.pigmentStrength);
|
|
123
|
+
|
|
124
|
+
var lightBand = 0.24;
|
|
125
|
+
if (nDotL > -0.22) {
|
|
126
|
+
lightBand = 0.43;
|
|
127
|
+
}
|
|
128
|
+
if (nDotL > 0.08) {
|
|
129
|
+
lightBand = 0.70;
|
|
130
|
+
}
|
|
131
|
+
if (nDotL > 0.68) {
|
|
132
|
+
lightBand = 1.0;
|
|
133
|
+
}
|
|
134
|
+
var color = mix(material.shadowColor.rgb, surfaceColor, lightBand);
|
|
135
|
+
|
|
136
|
+
let shadowVisibility = evalDirectionalShadowFactor(normal, input.worldPos, input.viewZ);
|
|
137
|
+
if (nDotL > 0.08) {
|
|
138
|
+
// Move occluded faces toward their authored hue without multiplying the
|
|
139
|
+
// already-dark result toward black a second time.
|
|
140
|
+
let retainedLight = mix(0.48, 1.0, shadowVisibility);
|
|
141
|
+
color = mix(material.shadowColor.rgb, color, retainedLight);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
var planeShade = material.sideShade;
|
|
145
|
+
if (upFacing > 0.72) {
|
|
146
|
+
planeShade = 1.0;
|
|
147
|
+
}
|
|
148
|
+
if (upFacing < -0.72) {
|
|
149
|
+
planeShade = material.sideShade * 0.86;
|
|
150
|
+
}
|
|
151
|
+
color *= planeShade;
|
|
152
|
+
|
|
153
|
+
color += paintedSpecular(surfaceColor, normal, toLight, toCamera, material.surfaceRoughness,
|
|
154
|
+
material.surfaceMetallic, material.specularStrength, shadowVisibility);
|
|
155
|
+
let rim = paintedRim(normal, toCamera, material.surfaceRoughness, material.rimStrength, shadowVisibility);
|
|
156
|
+
color += material.rimColor.rgb * rim;
|
|
157
|
+
color += material.rimColor.rgb * material.emissionStrength;
|
|
158
|
+
|
|
159
|
+
return vec4<f32>(color, material.baseColor.a);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Opaque Toon depth entry shares this material's composed module and layout.
|
|
163
|
+
@vertex
|
|
164
|
+
fn vs_shadow(@location(0) position : vec3<f32>, @builtin(instance_index) idx : u32) -> @builtin(position) vec4<f32> {
|
|
165
|
+
let world = meshes[0].worldFromLocal * instances[idx].localFromInstance * vec4<f32>(position, 1.0);
|
|
166
|
+
if (shadowCasterCascade.isSpot == 1u) {
|
|
167
|
+
return shadowCasterCascade.spotLightViewProj * world;
|
|
168
|
+
}
|
|
169
|
+
switch (shadowCasterCascade.index) {
|
|
170
|
+
case 0u: { return view.lightViewProj_A * world; }
|
|
171
|
+
case 1u: { return view.lightViewProj_B * world; }
|
|
172
|
+
case 2u: { return view.lightViewProj_C * world; }
|
|
173
|
+
default: { return view.lightViewProj_D * world; }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@fragment
|
|
178
|
+
fn fs_shadow() {}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "material",
|
|
3
|
+
"colorSpace": "srgb",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "baseColor",
|
|
7
|
+
"type": "color",
|
|
8
|
+
"default": [1, 1, 1, 1]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "shadowColor",
|
|
12
|
+
"type": "color",
|
|
13
|
+
"default": [0.34, 0.43, 0.56, 1]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "rimColor",
|
|
17
|
+
"type": "color",
|
|
18
|
+
"default": [0.72, 0.88, 0.84, 1]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "rimStrength",
|
|
22
|
+
"type": "f32",
|
|
23
|
+
"default": 0.018
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "specularStrength",
|
|
27
|
+
"type": "f32",
|
|
28
|
+
"default": 0.008
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "emissionStrength",
|
|
32
|
+
"type": "f32",
|
|
33
|
+
"default": 0
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "sideShade",
|
|
37
|
+
"type": "f32",
|
|
38
|
+
"default": 0.84
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "surfaceRoughness",
|
|
42
|
+
"type": "f32",
|
|
43
|
+
"default": 0.86
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "surfaceMetallic",
|
|
47
|
+
"type": "f32",
|
|
48
|
+
"default": 0
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "pigmentStrength",
|
|
52
|
+
"type": "f32",
|
|
53
|
+
"default": 0.08
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "pigmentScale",
|
|
57
|
+
"type": "f32",
|
|
58
|
+
"default": 3.2
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"passes": [
|
|
62
|
+
{
|
|
63
|
+
"name": "Forward",
|
|
64
|
+
"program": {
|
|
65
|
+
"module": "ai_weapon_spirit::low_poly_toon",
|
|
66
|
+
"vertexEntry": "vs_main",
|
|
67
|
+
"fragmentEntry": "fs_main"
|
|
68
|
+
},
|
|
69
|
+
"renderState": {
|
|
70
|
+
"tags": {
|
|
71
|
+
"LightMode": "Forward"
|
|
72
|
+
},
|
|
73
|
+
"queue": 2000
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "ShadowCaster",
|
|
78
|
+
"program": {
|
|
79
|
+
"module": "ai_weapon_spirit::low_poly_toon",
|
|
80
|
+
"vertexEntry": "vs_shadow",
|
|
81
|
+
"fragmentEntry": "fs_shadow"
|
|
82
|
+
},
|
|
83
|
+
"renderState": {
|
|
84
|
+
"tags": {
|
|
85
|
+
"LightMode": "ShadowCaster"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"values": {
|
|
91
|
+
"baseColor": [0.4, 0.65, 0.55, 1],
|
|
92
|
+
"emissionStrength": 0,
|
|
93
|
+
"pigmentStrength": 0,
|
|
94
|
+
"surfaceMetallic": 0,
|
|
95
|
+
"sideShade": 0.84
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#define_import_path ai_weapon_spirit::painterly_surface
|
|
2
|
+
|
|
3
|
+
fn pigmentHash(point : vec2<f32>) -> f32 {
|
|
4
|
+
var p = fract(vec3<f32>(point.x, point.y, point.x) * .1031);
|
|
5
|
+
p += vec3<f32>(dot(p, p.yzx + vec3<f32>(33.33)));
|
|
6
|
+
return fract((p.x + p.y) * p.z);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
fn pigmentNoise(point : vec2<f32>) -> f32 {
|
|
10
|
+
let cell = floor(point);
|
|
11
|
+
let f = fract(point);
|
|
12
|
+
let u = f * f * (vec2<f32>(3.0) - 2.0 * f);
|
|
13
|
+
return mix(mix(pigmentHash(cell), pigmentHash(cell + vec2<f32>(1.0, 0.0)), u.x),
|
|
14
|
+
mix(pigmentHash(cell + vec2<f32>(0.0, 1.0)), pigmentHash(cell + vec2<f32>(1.0, 1.0)), u.x), u.y);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn pigmentPlane(position : vec3<f32>, normal : vec3<f32>) -> vec2<f32> {
|
|
18
|
+
let axis = abs(normal);
|
|
19
|
+
if (axis.y >= max(axis.x, axis.z)) { return position.xz; }
|
|
20
|
+
if (axis.x > axis.z) { return position.zy; }
|
|
21
|
+
return position.xy;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Soft pigment pools, with no repeated stroke or bristle shapes. Rotate and
|
|
25
|
+
// gently warp the field so its broad transitions do not reveal the noise grid.
|
|
26
|
+
// Units are metres: moving actors use local coordinates, fixed terrain world coordinates.
|
|
27
|
+
fn applyPigment(base : vec3<f32>, position : vec3<f32>, normal : vec3<f32>, scale : f32, strength : f32) -> vec3<f32> {
|
|
28
|
+
let plane = pigmentPlane(position, normal) * scale;
|
|
29
|
+
let point = vec2<f32>(plane.x * .8 + plane.y * .6, plane.y * .8 - plane.x * .6);
|
|
30
|
+
let drift = vec2<f32>(
|
|
31
|
+
pigmentNoise(point * .11 + vec2<f32>(5.2, 11.7)),
|
|
32
|
+
pigmentNoise(point * .11 + vec2<f32>(19.3, -4.6)),
|
|
33
|
+
) - vec2<f32>(.5);
|
|
34
|
+
let field = point * .18 + drift * .65;
|
|
35
|
+
let wash = pigmentNoise(field + vec2<f32>(3.2, 8.1)) - .5;
|
|
36
|
+
let bloom = pigmentNoise(field * .47 + vec2<f32>(-7.4, 2.9)) - .5;
|
|
37
|
+
let pigment = (wash * .72 + bloom * .28) * strength;
|
|
38
|
+
// Pigment changes local reflectance; it never emits light or changes normals.
|
|
39
|
+
return max(vec3<f32>(0.0), base * (1.0 + pigment) + vec3<f32>(.08, .02, -.055) * pigment);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fn paintedSpecular(base : vec3<f32>, normal : vec3<f32>, light : vec3<f32>, camera : vec3<f32>,
|
|
43
|
+
roughness : f32, metallic : f32, strength : f32, visibility : f32) -> vec3<f32> {
|
|
44
|
+
let halfVector = normalize(light + camera);
|
|
45
|
+
let smoothness = 1.0 - clamp(roughness, .04, 1.0);
|
|
46
|
+
let lobe = pow(max(dot(normal, halfVector), 0.0), mix(12.0, 112.0, smoothness));
|
|
47
|
+
let reflection = strength * smoothness * smoothness * lobe
|
|
48
|
+
* max(dot(normal, light), 0.0) * visibility;
|
|
49
|
+
return mix(vec3<f32>(.88, .86, .81), base, metallic) * reflection;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn paintedRim(normal : vec3<f32>, camera : vec3<f32>, roughness : f32, strength : f32, visibility : f32) -> f32 {
|
|
53
|
+
let fresnel = pow(1.0 - clamp(dot(normal, camera), 0.0, 1.0), 4.0);
|
|
54
|
+
return fresnel * strength * mix(1.0, .18, roughness) * mix(.35, 1.0, visibility);
|
|
55
|
+
}
|
|
@@ -61,7 +61,9 @@ export interface GpuDrivenViewLifecycleEvidence {
|
|
|
61
61
|
readonly candidateCapacity: number;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export async function runGpuDrivenViewLifecycleEvidence(
|
|
64
|
+
export async function runGpuDrivenViewLifecycleEvidence(
|
|
65
|
+
frames = 300,
|
|
66
|
+
): Promise<GpuDrivenViewLifecycleEvidence> {
|
|
65
67
|
const adapter = (await rhi.requestAdapter()).unwrap();
|
|
66
68
|
const device = (await adapter.requestDevice()).unwrap();
|
|
67
69
|
const rawDevice = _internal_getRawDevice(device);
|
|
@@ -85,8 +87,6 @@ export async function runGpuDrivenViewLifecycleEvidence(): Promise<GpuDrivenView
|
|
|
85
87
|
const retirements: Array<Promise<unknown>> = [];
|
|
86
88
|
let activeCount = 0;
|
|
87
89
|
let previous: CompiledRenderGraph<{ readonly encoder: RhiCommandEncoder }> | undefined;
|
|
88
|
-
const frames = 300;
|
|
89
|
-
|
|
90
90
|
for (let frame = 0; frame < frames; frame += 1) {
|
|
91
91
|
const targetCount = frame < 4 ? 2 ** frame : frame % 2 === 0 ? 1 : 8;
|
|
92
92
|
const operations: Array<
|
|
@@ -5,6 +5,14 @@ import {
|
|
|
5
5
|
} from './gpu-driven-view-gpu-evidence';
|
|
6
6
|
|
|
7
7
|
const browserReady = typeof navigator !== 'undefined' && navigator.gpu !== undefined;
|
|
8
|
+
const lifecycleFrames =
|
|
9
|
+
(
|
|
10
|
+
import.meta as ImportMeta & {
|
|
11
|
+
readonly env?: { readonly FORGEAX_BROWSER_CI_LIGHTWEIGHT?: string };
|
|
12
|
+
}
|
|
13
|
+
).env?.FORGEAX_BROWSER_CI_LIGHTWEIGHT === '1'
|
|
14
|
+
? 60
|
|
15
|
+
: 300;
|
|
8
16
|
|
|
9
17
|
describe.skipIf(!browserReady)('GPU-driven View Browser WebGPU', () => {
|
|
10
18
|
it('produces compact visible IDs and portable indirect args on the real browser device', async () => {
|
|
@@ -20,9 +28,9 @@ describe.skipIf(!browserReady)('GPU-driven View Browser WebGPU', () => {
|
|
|
20
28
|
});
|
|
21
29
|
});
|
|
22
30
|
|
|
23
|
-
it(
|
|
24
|
-
await expect(runGpuDrivenViewLifecycleEvidence()).resolves.toEqual({
|
|
25
|
-
frames:
|
|
31
|
+
it(`survives ${lifecycleFrames} frames of spawn/despawn capacity crossings without stale buffers`, async () => {
|
|
32
|
+
await expect(runGpuDrivenViewLifecycleEvidence(lifecycleFrames)).resolves.toEqual({
|
|
33
|
+
frames: lifecycleFrames,
|
|
26
34
|
bufferRebuilds: 4,
|
|
27
35
|
candidateCapacity: 8,
|
|
28
36
|
});
|
|
@@ -120,9 +120,17 @@ describe('GpuScene', () => {
|
|
|
120
120
|
expect(created.scene.inspect().uploadBytes).toBe(bytesBefore);
|
|
121
121
|
|
|
122
122
|
created.scene.commitTemporalFrame(true).unwrap();
|
|
123
|
-
expect(queue.writes).toHaveLength(writesBefore
|
|
123
|
+
expect(queue.writes).toHaveLength(writesBefore);
|
|
124
|
+
expect(created.scene.inspect().uploadBytes).toBe(bytesBefore);
|
|
125
|
+
|
|
126
|
+
const dirty = projection.apply([
|
|
127
|
+
{ kind: 'update-transform', worldId: 0, entityKey: 0, world: snapshot(0, 3).transform.world },
|
|
128
|
+
]);
|
|
129
|
+
created.scene.sync(dirty).unwrap();
|
|
130
|
+
created.scene.commitTemporalFrame(true).unwrap();
|
|
131
|
+
expect(queue.writes).toHaveLength(writesBefore + 2);
|
|
124
132
|
expect(created.scene.inspect().uploadBytes).toBe(
|
|
125
|
-
bytesBefore +
|
|
133
|
+
bytesBefore + 2 * GPU_SCENE_LAYOUTS.transform.stride,
|
|
126
134
|
);
|
|
127
135
|
});
|
|
128
136
|
|
|
@@ -200,4 +208,32 @@ describe('GpuScene', () => {
|
|
|
200
208
|
gpuSceneFieldOffset(GPU_SCENE_LAYOUTS.transform, 'previousWorld') + 12 * 4;
|
|
201
209
|
expect(new DataView(transformWrite.bytes.buffer).getFloat32(previousTranslation, true)).toBe(9);
|
|
202
210
|
});
|
|
211
|
+
|
|
212
|
+
it('keeps a recycled slot allocated for the replacement identity', () => {
|
|
213
|
+
const queue = new RecordingQueue();
|
|
214
|
+
const created = GpuScene.create(createDevice(queue), 1).unwrap();
|
|
215
|
+
if (created.status !== 'available') return;
|
|
216
|
+
const projection = new RenderScene();
|
|
217
|
+
created.scene.sync(projection.apply([{ kind: 'create', snapshot: snapshot(1, 2) }])).unwrap();
|
|
218
|
+
|
|
219
|
+
const recycled = projection.apply([
|
|
220
|
+
{ kind: 'remove', worldId: 0, entityKey: 1 },
|
|
221
|
+
{ kind: 'create', snapshot: snapshot(2, 7) },
|
|
222
|
+
]);
|
|
223
|
+
expect(recycled.removedSlots[0]?.slot).toBe(recycled.createdSlots[0]?.slot);
|
|
224
|
+
created.scene.sync(recycled).unwrap();
|
|
225
|
+
|
|
226
|
+
expect(() =>
|
|
227
|
+
created.scene.sync(
|
|
228
|
+
projection.apply([
|
|
229
|
+
{
|
|
230
|
+
kind: 'update-transform',
|
|
231
|
+
worldId: 0,
|
|
232
|
+
entityKey: 2,
|
|
233
|
+
world: snapshot(2, 11).transform.world,
|
|
234
|
+
},
|
|
235
|
+
]),
|
|
236
|
+
),
|
|
237
|
+
).not.toThrow();
|
|
238
|
+
});
|
|
203
239
|
});
|