@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
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { deriveVertexLayoutProjection } from '@forgeax/engine-geometry';
|
|
16
16
|
import { box3, frustum, type Mat4, mat4, type Vec3, vec3 } from '@forgeax/engine-math';
|
|
17
17
|
import { AssetGuid } from '@forgeax/engine-pack/guid';
|
|
18
|
+
import type { MaterialCookProgramContext } from '@forgeax/engine-pack/material-cook';
|
|
18
19
|
import { RhiError } from '@forgeax/engine-rhi';
|
|
19
20
|
import { GlobalTransform, MorphWeights, Transform } from '@forgeax/engine-scene';
|
|
20
21
|
import type { MaterialShaderArtifact } from '@forgeax/engine-shader';
|
|
@@ -88,7 +89,8 @@ import type {
|
|
|
88
89
|
} from './features/types';
|
|
89
90
|
import { ensureGlyphMeshMaterialSlots } from './glyph-text-layout-system';
|
|
90
91
|
import type { GpuDrivenGeometryReceipt } from './gpu-driven/prepared-draw';
|
|
91
|
-
import {
|
|
92
|
+
import type { InstanceProjectionStore } from './instances';
|
|
93
|
+
import { deriveInstancesUnionBounds, fingerprintNumericArray } from './instances-derived-bounds';
|
|
92
94
|
import {
|
|
93
95
|
type MeshMaterialBindingDiagnostic,
|
|
94
96
|
type MeshMaterialBindingSource,
|
|
@@ -147,6 +149,7 @@ import {
|
|
|
147
149
|
materialColorParameterSchema,
|
|
148
150
|
materialNormalScale,
|
|
149
151
|
materialParametersToParamSchema,
|
|
152
|
+
materialProgramKeysForMaterial,
|
|
150
153
|
materialTextureFields,
|
|
151
154
|
materialTextureRef,
|
|
152
155
|
pipelineRenderState,
|
|
@@ -156,7 +159,7 @@ import {
|
|
|
156
159
|
readStablePersistentMaterialSnapshot,
|
|
157
160
|
resolveMaterialSnapshot,
|
|
158
161
|
resolveVideoFieldHandle,
|
|
159
|
-
|
|
162
|
+
runtimeMaterialShaderIdForMaterial,
|
|
160
163
|
Severity,
|
|
161
164
|
selectCameraRoles,
|
|
162
165
|
selectFogFrame,
|
|
@@ -173,11 +176,15 @@ export function extractFrames(
|
|
|
173
176
|
pipelineState?: ExtractPipelineSurface | null,
|
|
174
177
|
materialSnapshotCachesByWorld?: MaterialSnapshotCachesByWorld,
|
|
175
178
|
options: {
|
|
179
|
+
readonly materialContext?: MaterialCookProgramContext;
|
|
176
180
|
readonly cull?: 'normal' | 'none';
|
|
177
181
|
readonly renderables?: 'full' | 'none';
|
|
182
|
+
readonly renderableEntitiesByWorld?: readonly (ReadonlySet<number> | undefined)[];
|
|
183
|
+
readonly retainHidden?: boolean;
|
|
178
184
|
readonly getMaterialShaderArtifact?: (
|
|
179
185
|
materialShaderId: string,
|
|
180
186
|
) => MaterialShaderArtifact | undefined;
|
|
187
|
+
readonly instanceCollections?: InstanceProjectionStore;
|
|
181
188
|
} = {},
|
|
182
189
|
): ExtractedFrame {
|
|
183
190
|
// w4: normalize the owner argument. A bare number is the legacy single-owner
|
|
@@ -247,11 +254,21 @@ export function extractFrames(
|
|
|
247
254
|
return cache;
|
|
248
255
|
})(),
|
|
249
256
|
}),
|
|
257
|
+
...(options.materialContext === undefined
|
|
258
|
+
? {}
|
|
259
|
+
: { materialContext: options.materialContext }),
|
|
250
260
|
cull: options.cull === 'none' ? 'none' : isCameraOwner ? 'self' : 'external',
|
|
251
261
|
renderables: options.renderables ?? 'full',
|
|
262
|
+
...(options.renderableEntitiesByWorld?.[wi] === undefined
|
|
263
|
+
? {}
|
|
264
|
+
: { renderableEntities: options.renderableEntitiesByWorld[wi] }),
|
|
265
|
+
retainHidden: options.retainHidden ?? false,
|
|
252
266
|
...(options.getMaterialShaderArtifact === undefined
|
|
253
267
|
? {}
|
|
254
268
|
: { getMaterialShaderArtifact: options.getMaterialShaderArtifact }),
|
|
269
|
+
...(options.instanceCollections === undefined
|
|
270
|
+
? {}
|
|
271
|
+
: { instanceCollections: options.instanceCollections }),
|
|
255
272
|
...(cameraOwnerFrame === undefined ? {} : { cullCameras: cameraOwnerFrame.cameras }),
|
|
256
273
|
});
|
|
257
274
|
const frame = extractFrame(world, prepared);
|
|
@@ -495,6 +512,30 @@ export function extractFrames(
|
|
|
495
512
|
return (f.reflectionProbes ?? []).map((probe) => ({ ...probe, worldId }));
|
|
496
513
|
});
|
|
497
514
|
|
|
515
|
+
if (options.renderables !== 'none' && options.renderableEntitiesByWorld === undefined) {
|
|
516
|
+
options.instanceCollections?.retain(
|
|
517
|
+
new Set(
|
|
518
|
+
renderables.flatMap((row) =>
|
|
519
|
+
row.instances?.collectionId === undefined ? [] : [row.instances.collectionId],
|
|
520
|
+
),
|
|
521
|
+
),
|
|
522
|
+
);
|
|
523
|
+
if (
|
|
524
|
+
skinPaletteAllocator !== null &&
|
|
525
|
+
typeof skinPaletteAllocator.retainSliceKeys === 'function'
|
|
526
|
+
) {
|
|
527
|
+
skinPaletteAllocator.retainSliceKeys(
|
|
528
|
+
new Set(
|
|
529
|
+
renderables.flatMap((row) =>
|
|
530
|
+
row.skin === undefined
|
|
531
|
+
? []
|
|
532
|
+
: [`${worlds[row.worldId]?.identity ?? row.worldId}:${row.entityKey}`],
|
|
533
|
+
),
|
|
534
|
+
),
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
498
539
|
return {
|
|
499
540
|
cameras,
|
|
500
541
|
auxiliaryCameras,
|
|
@@ -604,6 +645,9 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
604
645
|
cull: cullMode,
|
|
605
646
|
resourceOwnerFog,
|
|
606
647
|
getMaterialShaderArtifact,
|
|
648
|
+
instanceCollections,
|
|
649
|
+
renderableEntities,
|
|
650
|
+
retainHidden,
|
|
607
651
|
} = context;
|
|
608
652
|
// Environment reads are owned by the retained resource projection and are
|
|
609
653
|
// established at the frame boundary; record never revisits World state.
|
|
@@ -1521,22 +1565,18 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1521
1565
|
// extraction. Shared handles are immutable inputs for the frame, while
|
|
1522
1566
|
// dispatch entries still need to be rebuilt for each entity.
|
|
1523
1567
|
const materialSnapshotCache: MaterialSnapshotCache = new Map();
|
|
1568
|
+
const skinnedMaterialSnapshotCache: MaterialSnapshotCache = new Map();
|
|
1524
1569
|
// tweak-20260611 M1: MeshRenderer renderable archetype walk routes
|
|
1525
1570
|
// through one World-owned Query. K-2 sniffing scheme B
|
|
1526
1571
|
// (`row.get(X) !== undefined` edge sniff) replaces the prior
|
|
1527
1572
|
// `arch.components.some` row-internal back-door. K-3 invariant: the
|
|
1528
|
-
// variable-length array reads (`MeshRenderer.materials`,
|
|
1529
|
-
//
|
|
1530
|
-
//
|
|
1531
|
-
// `row.entity`.
|
|
1573
|
+
// variable-length array reads (`MeshRenderer.materials`, SpriteInstances
|
|
1574
|
+
// arrays) still flow through `_getArrayView`; explicit Instances bytes also come
|
|
1575
|
+
// from World, before projection into renderer-owned snapshots.
|
|
1532
1576
|
//
|
|
1533
|
-
// archVersion
|
|
1534
|
-
//
|
|
1535
|
-
//
|
|
1536
|
-
// QueryRow does not surface this number, so a single archetype
|
|
1537
|
-
// graph access is retained for instance-bearing rows -- match by entity
|
|
1538
|
-
// packed handle. AC-01 grep ≤ current - 1 still holds: the stale
|
|
1539
|
-
// archetype-graph traversal commentary at the prior call site is gone.
|
|
1577
|
+
// archVersion remains the content fingerprint for SpriteInstances' managed
|
|
1578
|
+
// arrays; explicit Instances use the collection revision below and never
|
|
1579
|
+
// need an archetype graph access for their matrix bytes.
|
|
1540
1580
|
// feat-20260521-sprite-atlas-animation M3 / T-16: SpriteRegionOverride
|
|
1541
1581
|
// column id for the sprite-bucket per-entity region override read
|
|
1542
1582
|
void SpriteRegionOverride;
|
|
@@ -1564,11 +1604,10 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1564
1604
|
})
|
|
1565
1605
|
.unwrap();
|
|
1566
1606
|
// QueryRow deliberately exposes component data, not an archetype version.
|
|
1567
|
-
//
|
|
1568
|
-
//
|
|
1607
|
+
// SpriteInstances still uses a content fingerprint for its managed arrays;
|
|
1608
|
+
// explicit Instances use the renderer-owned collection revision below.
|
|
1569
1609
|
const resolveArchVersion = (entity: EntityHandle): number => {
|
|
1570
1610
|
const values = [
|
|
1571
|
-
worldInternal._getArrayView(entity, Instances, 'transforms'),
|
|
1572
1611
|
worldInternal._getArrayView(entity, SpriteInstances, 'transforms'),
|
|
1573
1612
|
worldInternal._getArrayView(entity, SpriteInstances, 'regions'),
|
|
1574
1613
|
];
|
|
@@ -1591,6 +1630,13 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1591
1630
|
for (const entry of pending) dispatch.push(entry);
|
|
1592
1631
|
};
|
|
1593
1632
|
for (const row of meshRendererQuery) {
|
|
1633
|
+
if (
|
|
1634
|
+
context.renderables === 'full' &&
|
|
1635
|
+
renderableEntities !== undefined &&
|
|
1636
|
+
!renderableEntities.has(row.entity)
|
|
1637
|
+
) {
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1594
1640
|
// K-2 archetype-edge sniff (scheme B): a missing optional component
|
|
1595
1641
|
// surfaces as an absent bundle key, not a row-internal optional chain.
|
|
1596
1642
|
// Presence-only checks use QueryRow.has so large array-bearing components
|
|
@@ -1687,8 +1733,9 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1687
1733
|
{
|
|
1688
1734
|
// feat-20260608 M2 / w11: read materials array via _getArrayView
|
|
1689
1735
|
const entity = row.entity;
|
|
1690
|
-
|
|
1691
|
-
|
|
1736
|
+
const authorVisible = !(isRenderable && visibility?.effective(entity) === 'hidden');
|
|
1737
|
+
if (!authorVisible) explicitlyHidden.add(entity);
|
|
1738
|
+
if (!authorVisible && !retainHidden) {
|
|
1692
1739
|
continue;
|
|
1693
1740
|
}
|
|
1694
1741
|
const layerVal = fLayerValue ?? 0;
|
|
@@ -1886,6 +1933,8 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1886
1933
|
renderables.length,
|
|
1887
1934
|
layerVal,
|
|
1888
1935
|
materialSnap.paramSnapshot,
|
|
1936
|
+
0,
|
|
1937
|
+
materialSnap.materialProgramKeys,
|
|
1889
1938
|
);
|
|
1890
1939
|
}
|
|
1891
1940
|
} else if (handleRaw === 0 || assets === undefined || assets === null) {
|
|
@@ -1913,6 +1962,8 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1913
1962
|
renderables.length,
|
|
1914
1963
|
layerVal,
|
|
1915
1964
|
materialSnap.paramSnapshot,
|
|
1965
|
+
0,
|
|
1966
|
+
materialSnap.materialProgramKeys,
|
|
1916
1967
|
);
|
|
1917
1968
|
}
|
|
1918
1969
|
} else {
|
|
@@ -1976,10 +2027,26 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
1976
2027
|
}
|
|
1977
2028
|
const resolved = resolvedResult.value;
|
|
1978
2029
|
const allPasses = resolved.passes;
|
|
1979
|
-
const
|
|
1980
|
-
|
|
1981
|
-
?
|
|
1982
|
-
:
|
|
2030
|
+
const materialContext =
|
|
2031
|
+
context.materialContext === undefined
|
|
2032
|
+
? undefined
|
|
2033
|
+
: {
|
|
2034
|
+
...context.materialContext,
|
|
2035
|
+
geometry: hasSkin ? ('skinned' as const) : context.materialContext.geometry,
|
|
2036
|
+
};
|
|
2037
|
+
const materialProgramKeys = materialProgramKeysForMaterial(
|
|
2038
|
+
asset,
|
|
2039
|
+
assets,
|
|
2040
|
+
materialContext,
|
|
2041
|
+
);
|
|
2042
|
+
const authoredFirstPassShader = runtimeMaterialShaderIdForMaterial(
|
|
2043
|
+
allPasses,
|
|
2044
|
+
undefined,
|
|
2045
|
+
);
|
|
2046
|
+
const firstPassShader = runtimeMaterialShaderIdForMaterial(
|
|
2047
|
+
allPasses,
|
|
2048
|
+
materialProgramKeys,
|
|
2049
|
+
);
|
|
1983
2050
|
const pv = materialValuesToLinearRuntime(
|
|
1984
2051
|
resolved.values,
|
|
1985
2052
|
materialColorParameterSchema(resolved.parameters ?? [], firstPassShader, assets),
|
|
@@ -2008,7 +2075,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2008
2075
|
|
|
2009
2076
|
const materialParamSchema = materialParametersToParamSchema(
|
|
2010
2077
|
resolved.parameters ?? [],
|
|
2011
|
-
|
|
2078
|
+
authoredFirstPassShader,
|
|
2012
2079
|
);
|
|
2013
2080
|
// feat-20260611-fox-skinning-vertex-attribute-chain M4 / w17 (D-5):
|
|
2014
2081
|
// bidirectional Skin <-> pbr-skin material fail-fast at extract.
|
|
@@ -2297,6 +2364,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2297
2364
|
}),
|
|
2298
2365
|
normalScale: normalScalePv,
|
|
2299
2366
|
materialShaderId: firstPassShader,
|
|
2367
|
+
materialProgramKeys,
|
|
2300
2368
|
materialHandle: handleRaw,
|
|
2301
2369
|
renderState: pipelineRenderState(allPasses[0]?.renderState),
|
|
2302
2370
|
paramSnapshot: paramSnap,
|
|
@@ -2357,6 +2425,8 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2357
2425
|
renderables.length,
|
|
2358
2426
|
layerVal,
|
|
2359
2427
|
paramSnap,
|
|
2428
|
+
0,
|
|
2429
|
+
materialProgramKeys,
|
|
2360
2430
|
);
|
|
2361
2431
|
}
|
|
2362
2432
|
}
|
|
@@ -2512,7 +2582,18 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2512
2582
|
// surface is absent (test fixtures that pass undefined) the
|
|
2513
2583
|
// hasSkin segment is skipped silently — bind-pose equivalent.
|
|
2514
2584
|
if (skinPaletteAllocator !== null) {
|
|
2515
|
-
|
|
2585
|
+
// Keep the narrow extraction seam compatible with older test or
|
|
2586
|
+
// host-owned allocator doubles while the real renderer uses the
|
|
2587
|
+
// stable-key path. The fallback is frame-local and therefore
|
|
2588
|
+
// cannot affect production allocators that implement the new
|
|
2589
|
+
// method.
|
|
2590
|
+
const slice =
|
|
2591
|
+
typeof skinPaletteAllocator.allocateSliceFor === 'function'
|
|
2592
|
+
? skinPaletteAllocator.allocateSliceFor(
|
|
2593
|
+
`${world.identity}:${entity}`,
|
|
2594
|
+
skeleton.jointCount,
|
|
2595
|
+
)
|
|
2596
|
+
: skinPaletteAllocator.allocateSlice(skeleton.jointCount);
|
|
2516
2597
|
skinPaletteAllocator.writeJointPalette(slice, ibms, jointWorlds);
|
|
2517
2598
|
skinSlice = {
|
|
2518
2599
|
jointCount: slice.jointCount,
|
|
@@ -2556,15 +2637,22 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2556
2637
|
if (assets !== undefined && assets !== null) {
|
|
2557
2638
|
for (let mi = 1; mi < materialHandles.length; mi++) {
|
|
2558
2639
|
const subHandle = materialHandles[mi] ?? 0;
|
|
2559
|
-
const
|
|
2640
|
+
const subCache = hasSkin ? skinnedMaterialSnapshotCache : materialSnapshotCache;
|
|
2641
|
+
const cachedSubmaterial = subCache.get(subHandle);
|
|
2560
2642
|
materialsArr.push(
|
|
2561
2643
|
cachedSubmaterial?.snapshot ??
|
|
2562
2644
|
resolveMaterialSnapshot(
|
|
2563
2645
|
subHandle,
|
|
2564
2646
|
world,
|
|
2565
2647
|
assets,
|
|
2566
|
-
|
|
2567
|
-
persistentMaterialSnapshotCache,
|
|
2648
|
+
subCache,
|
|
2649
|
+
hasSkin ? undefined : persistentMaterialSnapshotCache,
|
|
2650
|
+
context.materialContext === undefined
|
|
2651
|
+
? undefined
|
|
2652
|
+
: {
|
|
2653
|
+
...context.materialContext,
|
|
2654
|
+
geometry: hasSkin ? 'skinned' : context.materialContext.geometry,
|
|
2655
|
+
},
|
|
2568
2656
|
),
|
|
2569
2657
|
);
|
|
2570
2658
|
}
|
|
@@ -2574,8 +2662,14 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2574
2662
|
const subHandle = materialHandles[mi] ?? 0;
|
|
2575
2663
|
if (subHandle === handleRaw) continue;
|
|
2576
2664
|
const subEntry =
|
|
2577
|
-
materialSnapshotCache.get(subHandle) ??
|
|
2578
|
-
|
|
2665
|
+
(hasSkin ? skinnedMaterialSnapshotCache : materialSnapshotCache).get(subHandle) ??
|
|
2666
|
+
(hasSkin
|
|
2667
|
+
? undefined
|
|
2668
|
+
: readPersistentMaterialSnapshot(
|
|
2669
|
+
persistentMaterialSnapshotCache,
|
|
2670
|
+
subHandle,
|
|
2671
|
+
assets,
|
|
2672
|
+
));
|
|
2579
2673
|
appendMaterialDispatchEntries(
|
|
2580
2674
|
pendingDispatch,
|
|
2581
2675
|
subEntry?.passes ?? (subHandle === 0 ? [DEFAULT_FORWARD_PASS] : []),
|
|
@@ -2584,6 +2678,8 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2584
2678
|
renderables.length,
|
|
2585
2679
|
layerVal,
|
|
2586
2680
|
materialsArr[mi]?.paramSnapshot,
|
|
2681
|
+
0,
|
|
2682
|
+
materialsArr[mi]?.materialProgramKeys,
|
|
2587
2683
|
);
|
|
2588
2684
|
}
|
|
2589
2685
|
}
|
|
@@ -2727,39 +2823,35 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2727
2823
|
// Instances are snapshotted before the CPU visibility decision so the
|
|
2728
2824
|
// culling owner can derive the union of every instance's transformed
|
|
2729
2825
|
// mesh bounds. The same detached snapshot is then carried to record;
|
|
2730
|
-
// do not re-read the
|
|
2731
|
-
//
|
|
2826
|
+
// do not re-read the collection after culling (a mutation must not
|
|
2827
|
+
// make the cull and draw disagree within one frame).
|
|
2732
2828
|
let instancesSnap: InstancesSnapshot | undefined;
|
|
2733
2829
|
if (hasInstances) {
|
|
2734
|
-
const transforms =
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
instancesSnap = {
|
|
2741
|
-
transforms: new Float32Array(),
|
|
2742
|
-
instanceCount: 0,
|
|
2743
|
-
cacheKey: entity,
|
|
2744
|
-
archVersion,
|
|
2745
|
-
};
|
|
2746
|
-
} else {
|
|
2747
|
-
const actualLength = transforms.length;
|
|
2748
|
-
if (actualLength % 16 !== 0) {
|
|
2749
|
-
worldInternal._routeError(new InstanceTransformsStrideMismatchError(actualLength), {
|
|
2830
|
+
const transforms =
|
|
2831
|
+
worldInternal._getArrayView(entity, Instances, 'transforms') ?? new Float32Array();
|
|
2832
|
+
if (transforms.length % 16 !== 0) {
|
|
2833
|
+
worldInternal._routeError(
|
|
2834
|
+
new InstanceTransformsStrideMismatchError(transforms.length),
|
|
2835
|
+
{
|
|
2750
2836
|
severity: Severity.Error,
|
|
2751
2837
|
systemName: 'RenderSystem.extract (Instances stride)',
|
|
2752
|
-
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
const snapshotCopy = new Float32Array(transforms);
|
|
2756
|
-
instancesSnap = {
|
|
2757
|
-
transforms: snapshotCopy,
|
|
2758
|
-
instanceCount: actualLength / 16,
|
|
2759
|
-
cacheKey: entity,
|
|
2760
|
-
archVersion,
|
|
2761
|
-
};
|
|
2838
|
+
},
|
|
2839
|
+
);
|
|
2840
|
+
continue;
|
|
2762
2841
|
}
|
|
2842
|
+
const projected = instanceCollections?.project(world, entity, transforms);
|
|
2843
|
+
instancesSnap = {
|
|
2844
|
+
transforms: projected?.transforms ?? new Float32Array(transforms),
|
|
2845
|
+
instanceCount: transforms.length / 16,
|
|
2846
|
+
cacheKey: entity,
|
|
2847
|
+
archVersion: projected === undefined ? fingerprintNumericArray(transforms) : 0,
|
|
2848
|
+
...(projected === undefined
|
|
2849
|
+
? {}
|
|
2850
|
+
: {
|
|
2851
|
+
collectionId: projected.collectionId,
|
|
2852
|
+
revision: projected.revision,
|
|
2853
|
+
}),
|
|
2854
|
+
};
|
|
2763
2855
|
}
|
|
2764
2856
|
|
|
2765
2857
|
const baseRenderable: RenderableSnapshot = {
|
|
@@ -2774,7 +2866,11 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
|
|
|
2774
2866
|
materialBindingDiagnostics,
|
|
2775
2867
|
worldId: 0,
|
|
2776
2868
|
entityKey: entity,
|
|
2869
|
+
...(authorVisible ? {} : { authorVisible: false }),
|
|
2777
2870
|
...(skinSlice !== undefined ? { skin: skinSlice } : {}),
|
|
2871
|
+
...(skin?.joints === undefined
|
|
2872
|
+
? {}
|
|
2873
|
+
: { skinJointEntities: Array.from(skin.joints, (joint) => Number(joint)) }),
|
|
2778
2874
|
...(morph !== undefined ? { morph } : {}),
|
|
2779
2875
|
...(instancesSnap !== undefined ? { instances: instancesSnap } : {}),
|
|
2780
2876
|
...(spriteInstancesSnap !== undefined ? { spriteInstances: spriteInstancesSnap } : {}),
|