@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.
Files changed (167) hide show
  1. package/README.md +118 -1
  2. package/dist/assembly/factory.d.ts +1 -1
  3. package/dist/assembly/factory.d.ts.map +1 -1
  4. package/dist/assembly/material/assembly.d.ts +4 -17
  5. package/dist/assembly/material/assembly.d.ts.map +1 -1
  6. package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -1
  7. package/dist/assembly/material/surface-projection.d.ts +24 -0
  8. package/dist/assembly/material/surface-projection.d.ts.map +1 -0
  9. package/dist/assembly/material-shader-policy.d.ts +20 -0
  10. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  11. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  12. package/dist/assembly/webgpu-renderer.d.ts +1 -2
  13. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  14. package/dist/assembly/webgpu-vertex-layouts.d.ts +89 -0
  15. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -0
  16. package/dist/assets/asset-decoders.d.ts.map +1 -1
  17. package/dist/authoring.mjs +1 -1
  18. package/dist/{chunk-Q752SHI5.mjs → chunk-ADHHVYLW.mjs} +3 -3
  19. package/dist/chunk-ADHHVYLW.mjs.map +1 -0
  20. package/dist/{chunk-TFH5I7JJ.mjs → chunk-E34VL5VI.mjs} +3 -3
  21. package/dist/{chunk-TFH5I7JJ.mjs.map → chunk-E34VL5VI.mjs.map} +1 -1
  22. package/dist/{chunk-YKB5DQV7.mjs → chunk-GF523LHF.mjs} +89 -21
  23. package/dist/chunk-GF523LHF.mjs.map +1 -0
  24. package/dist/{chunk-KZFTK6DO.mjs → chunk-HKXTW355.mjs} +7 -4
  25. package/dist/chunk-HKXTW355.mjs.map +1 -0
  26. package/dist/{chunk-UQYS7FRM.mjs → chunk-KM2NOX2I.mjs} +4 -4
  27. package/dist/{chunk-UQYS7FRM.mjs.map → chunk-KM2NOX2I.mjs.map} +1 -1
  28. package/dist/{chunk-YRUYGA4A.mjs → chunk-TMIASV2N.mjs} +944 -577
  29. package/dist/chunk-TMIASV2N.mjs.map +1 -0
  30. package/dist/{chunk-Z3YYH2MB.mjs → chunk-YUQXSEHG.mjs} +160 -73
  31. package/dist/chunk-YUQXSEHG.mjs.map +1 -0
  32. package/dist/{chunk-RR5L4SRS.mjs → chunk-ZZ4YQ474.mjs} +2 -2
  33. package/dist/{chunk-RR5L4SRS.mjs.map → chunk-ZZ4YQ474.mjs.map} +1 -1
  34. package/dist/components/instances.d.ts +13 -31
  35. package/dist/components/instances.d.ts.map +1 -1
  36. package/dist/construct-renderer.mjs +1012 -149
  37. package/dist/construct-renderer.mjs.map +1 -1
  38. package/dist/extract/contracts.d.ts +6 -6
  39. package/dist/extract/contracts.d.ts.map +1 -1
  40. package/dist/gpu-driven/production-raster.d.ts +6 -1
  41. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  42. package/dist/gpu-scene.d.ts +4 -0
  43. package/dist/gpu-scene.d.ts.map +1 -1
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.mjs +27 -9
  47. package/dist/index.mjs.map +1 -1
  48. package/dist/instance-buffer-cache.d.ts +7 -1
  49. package/dist/instance-buffer-cache.d.ts.map +1 -1
  50. package/dist/instances.d.ts +101 -0
  51. package/dist/instances.d.ts.map +1 -0
  52. package/dist/internal.mjs +5 -5
  53. package/dist/materials.d.ts +63 -2
  54. package/dist/materials.d.ts.map +1 -1
  55. package/dist/pipeline-builder.d.ts.map +1 -1
  56. package/dist/pipeline-spec-types.d.ts +2 -0
  57. package/dist/pipeline-spec-types.d.ts.map +1 -1
  58. package/dist/pipeline-spec.d.ts.map +1 -1
  59. package/dist/record/frame-snapshot.d.ts +13 -2
  60. package/dist/record/frame-snapshot.d.ts.map +1 -1
  61. package/dist/record/frame.d.ts.map +1 -1
  62. package/dist/record/main-pass-geometry.d.ts +23 -4
  63. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  64. package/dist/record/main-pass-material.d.ts +20 -2
  65. package/dist/record/main-pass-material.d.ts.map +1 -1
  66. package/dist/record/main-pass-sprite-draws.d.ts +3 -3
  67. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  68. package/dist/record/main-pass.d.ts.map +1 -1
  69. package/dist/record/material-uniforms.d.ts +4 -0
  70. package/dist/record/material-uniforms.d.ts.map +1 -0
  71. package/dist/record/render-context.d.ts +4 -3
  72. package/dist/record/render-context.d.ts.map +1 -1
  73. package/dist/record/shadow-pass.d.ts +10 -1
  74. package/dist/record/shadow-pass.d.ts.map +1 -1
  75. package/dist/recovery/render-system-candidate.d.ts +1 -1
  76. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  77. package/dist/render-contract.d.ts +4 -0
  78. package/dist/render-contract.d.ts.map +1 -1
  79. package/dist/render-system-extract-tail.d.ts +6 -0
  80. package/dist/render-system-extract-tail.d.ts.map +1 -1
  81. package/dist/render-system-extract.d.ts +44 -9
  82. package/dist/render-system-extract.d.ts.map +1 -1
  83. package/dist/render-system.d.ts +4 -1
  84. package/dist/render-system.d.ts.map +1 -1
  85. package/dist/scene/render-scene-types.d.ts +2 -0
  86. package/dist/scene/render-scene-types.d.ts.map +1 -1
  87. package/dist/scene/render-scene.d.ts +12 -1
  88. package/dist/scene/render-scene.d.ts.map +1 -1
  89. package/dist/systems/skin-palette-allocator.d.ts +6 -0
  90. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  91. package/dist/temporal/index.mjs +5 -5
  92. package/package.json +20 -20
  93. package/src/__tests__/fixtures/ai-weapon-spirit/README.md +20 -0
  94. package/src/__tests__/fixtures/ai-weapon-spirit/low-poly-toon.wgsl +178 -0
  95. package/src/__tests__/fixtures/ai-weapon-spirit/material.json +97 -0
  96. package/src/__tests__/fixtures/ai-weapon-spirit/painterly-surface.wgsl +55 -0
  97. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +3 -3
  98. package/src/__tests__/gpu-driven-view.browser.test.ts +11 -3
  99. package/src/__tests__/gpu-scene.unit.test.ts +38 -2
  100. package/src/__tests__/instances-store.unit.test.ts +46 -0
  101. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  102. package/src/__tests__/material-contract-inventory.unit.test.ts +48 -13
  103. package/src/__tests__/{material-static-dynamic-route.unit.test.ts → material-layer-projection.unit.test.ts} +30 -47
  104. package/src/__tests__/material-pass-policy.unit.test.ts +69 -0
  105. package/src/__tests__/material-program-dispatch.unit.test.ts +48 -0
  106. package/src/__tests__/material-snapshot-mutation.integration.test.ts +69 -0
  107. package/src/__tests__/material-surface-authoring.test-d.ts +62 -0
  108. package/src/__tests__/materials-transmission-validation.unit.test.ts +24 -0
  109. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +0 -4
  110. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +44 -2
  111. package/src/__tests__/skin-motion-regression.unit.test.ts +33 -0
  112. package/src/__tests__/skinned-shadow-caster.test.ts +30 -2
  113. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +60 -0
  114. package/src/__tests__/surface-standard-pipeline.browser.test.ts +20 -0
  115. package/src/__tests__/surface-standard-pipeline.dawn.test.ts +20 -0
  116. package/src/__tests__/surface-standard-pipeline.fixture.ts +132 -0
  117. package/src/__tests__/surface-variant-provenance.integration.test.ts +33 -0
  118. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +1 -1
  119. package/src/assembly/factory.ts +2 -3
  120. package/src/assembly/material/__tests__/standard-layer-plan-projection.integration.test.ts +18 -0
  121. package/src/assembly/material/__tests__/surface-pass-projection.integration.test.ts +62 -0
  122. package/src/assembly/material/assembly.ts +8 -40
  123. package/src/assembly/material/standard-layer-projection.ts +3 -1
  124. package/src/assembly/material/surface-projection.ts +91 -0
  125. package/src/assembly/material-shader-policy.ts +88 -10
  126. package/src/assembly/recovery/renderer-recover.ts +1 -1
  127. package/src/assembly/webgpu-ready.ts +3 -16
  128. package/src/assembly/webgpu-renderer.ts +106 -166
  129. package/src/assembly/webgpu-vertex-layouts.ts +132 -0
  130. package/src/assets/asset-decoders.ts +27 -4
  131. package/src/components/instances.ts +14 -197
  132. package/src/extract/contracts.ts +6 -6
  133. package/src/gpu-driven/production-raster.ts +34 -1
  134. package/src/gpu-scene.ts +84 -29
  135. package/src/index.ts +1 -0
  136. package/src/instance-buffer-cache.ts +14 -1
  137. package/src/instances.ts +288 -0
  138. package/src/materials.ts +109 -14
  139. package/src/pipeline-builder.ts +14 -10
  140. package/src/pipeline-spec-types.ts +2 -0
  141. package/src/pipeline-spec.ts +13 -17
  142. package/src/record/frame-snapshot.ts +19 -2
  143. package/src/record/frame.ts +38 -3
  144. package/src/record/main-pass-geometry.ts +837 -337
  145. package/src/record/main-pass-material.ts +87 -2
  146. package/src/record/main-pass-sprite-draws.ts +66 -169
  147. package/src/record/main-pass.ts +24 -246
  148. package/src/record/material-uniforms.ts +186 -0
  149. package/src/record/render-context.ts +8 -0
  150. package/src/record/shadow-pass.ts +120 -115
  151. package/src/recovery/render-system-candidate.ts +46 -5
  152. package/src/render-contract.ts +4 -0
  153. package/src/render-system-extract-tail.ts +153 -57
  154. package/src/render-system-extract.ts +110 -73
  155. package/src/render-system.ts +59 -5
  156. package/src/scene/render-scene-types.ts +2 -0
  157. package/src/scene/render-scene.ts +579 -36
  158. package/src/systems/skin-palette-allocator.ts +129 -7
  159. package/src/transmission/__tests__/surface-compatibility.integration.test.ts +32 -0
  160. package/dist/assembly/material/pipeline-projection.d.ts +0 -30
  161. package/dist/assembly/material/pipeline-projection.d.ts.map +0 -1
  162. package/dist/chunk-KZFTK6DO.mjs.map +0 -1
  163. package/dist/chunk-Q752SHI5.mjs.map +0 -1
  164. package/dist/chunk-YKB5DQV7.mjs.map +0 -1
  165. package/dist/chunk-YRUYGA4A.mjs.map +0 -1
  166. package/dist/chunk-Z3YYH2MB.mjs.map +0 -1
  167. package/src/assembly/material/pipeline-projection.ts +0 -63
@@ -1,10 +1,10 @@
1
1
  import { GlyphText, selectActiveCameraIndex, getActiveCamera } from './chunk-FJ6P52EE.mjs';
2
- import { MeshRenderer, MeshFilter, DirectionalLight, validateDirectionalLightData, PointLight, computeInvRangeSquared, SpotLight, degToCos, RectAreaLight, validateRectAreaLightData, directionalShadowQualityFromF32, PointLightShadow, Skylight, LightProbe, validateLightProbeData, SkyboxBackground, Atmosphere, Instances, Layer, Points, Lines, SortKey, resolveMeshMaterialBindings, pointShapeFromU32, PostProcessParams, CubeCamera, cubeCameraUpdateIntentFromF32, ReflectionProbe, reflectionProbeUpdateIntentFromF32, tonemapToU32, resolveVisibility, Fog, VolumetricFog, resolveSelectedVolumetricLight, extractVolumetricFog, MotionBlur, Camera, bloomEnabledFromF32, antialiasFromF32, tonemapFromF32, cameraProjectionFromF32 } from './chunk-Q752SHI5.mjs';
2
+ import { MeshRenderer, MeshFilter, DirectionalLight, validateDirectionalLightData, PointLight, computeInvRangeSquared, SpotLight, degToCos, RectAreaLight, validateRectAreaLightData, directionalShadowQualityFromF32, PointLightShadow, Skylight, LightProbe, validateLightProbeData, SkyboxBackground, Atmosphere, Instances, Layer, Points, Lines, SortKey, resolveMeshMaterialBindings, pointShapeFromU32, PostProcessParams, CubeCamera, cubeCameraUpdateIntentFromF32, ReflectionProbe, reflectionProbeUpdateIntentFromF32, tonemapToU32, resolveVisibility, Fog, VolumetricFog, resolveSelectedVolumetricLight, extractVolumetricFog, MotionBlur, Camera, bloomEnabledFromF32, antialiasFromF32, tonemapFromF32, cameraProjectionFromF32 } from './chunk-ADHHVYLW.mjs';
3
3
  import { SpriteRegionOverride, SpriteInstances } from './chunk-JDWARUOI.mjs';
4
- import { PROBE_BLEND_RECORD_CAPACITY, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_COPY_DST, IES_SLICE_CAPACITY, COOKIE_SLICE_CAPACITY, isStandardPbrSkinMaterialShader, selectPasses, resolveRenderTargetMaterialSource, isCanonicalStandardPbrMaterialShader, isStandardPbrMaterialShader, PROBE_BLEND_RECORD_BYTE_SIZE, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, COOKIE_SLICE_SIZE } from './chunk-KZFTK6DO.mjs';
5
- import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, SHADOW_ATLAS_DEFAULT_LAYERS, SkinMaterialMismatchError, MaterialSkinAttrMissingError, ShadowInvalidConfigError, EnvironmentSourceConflictError, FogCardinalityError, AtmosphereInvalidParameterError } from './chunk-RR5L4SRS.mjs';
4
+ import { PROBE_BLEND_RECORD_CAPACITY, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_COPY_DST, IES_SLICE_CAPACITY, COOKIE_SLICE_CAPACITY, isStandardPbrSkinMaterialShader, selectPasses, resolveRenderTargetMaterialSource, isCanonicalStandardPbrMaterialShader, PROBE_BLEND_RECORD_BYTE_SIZE, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, COOKIE_SLICE_SIZE, isStandardPbrMaterialShader } from './chunk-HKXTW355.mjs';
5
+ import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, SHADOW_ATLAS_DEFAULT_LAYERS, SkinMaterialMismatchError, MaterialSkinAttrMissingError, ShadowInvalidConfigError, EnvironmentSourceConflictError, FogCardinalityError, AtmosphereInvalidParameterError } from './chunk-ZZ4YQ474.mjs';
6
6
  import { err, ok, RhiError } from '@forgeax/engine-rhi';
7
- import { resolveAssetHandle, walkMaterialPassesOverSharedRefs } from '@forgeax/engine-assets-runtime';
7
+ import { resolveAssetHandle, walkMaterialPassesOverSharedRefs, selectMaterialPassProgram, materialParametersToParamSchema as materialParametersToParamSchema$1 } from '@forgeax/engine-assets-runtime';
8
8
  import { SpawnLightInvalidBoundsError, routeWorldError, SpriteInstancesMutuallyExclusiveWithInstancesError, SpriteInstancesRequiresSpriteShaderError, SpriteInstancesCountMismatchError, InstanceTransformsStrideMismatchError, readRenderArrayView } from '@forgeax/engine-ecs/projection';
9
9
  import { vec3, mat4, frustum, box3 } from '@forgeax/engine-math';
10
10
  import { AssetGuid } from '@forgeax/engine-pack/guid';
@@ -1639,9 +1639,13 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1639
1639
  return cache;
1640
1640
  })()
1641
1641
  },
1642
+ ...options.materialContext === void 0 ? {} : { materialContext: options.materialContext },
1642
1643
  cull: options.cull === "none" ? "none" : isCameraOwner ? "self" : "external",
1643
1644
  renderables: options.renderables ?? "full",
1645
+ ...options.renderableEntitiesByWorld?.[wi] === void 0 ? {} : { renderableEntities: options.renderableEntitiesByWorld[wi] },
1646
+ retainHidden: options.retainHidden ?? false,
1644
1647
  ...options.getMaterialShaderArtifact === void 0 ? {} : { getMaterialShaderArtifact: options.getMaterialShaderArtifact },
1648
+ ...options.instanceCollections === void 0 ? {} : { instanceCollections: options.instanceCollections },
1645
1649
  ...cameraOwnerFrame2 === void 0 ? {} : { cullCameras: cameraOwnerFrame2.cameras }
1646
1650
  });
1647
1651
  const frame = extractFrame(world, prepared);
@@ -1814,6 +1818,24 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1814
1818
  const worldId = succeededIndices[index] ?? 0;
1815
1819
  return (f.reflectionProbes ?? []).map((probe) => ({ ...probe, worldId }));
1816
1820
  });
1821
+ if (options.renderables !== "none" && options.renderableEntitiesByWorld === void 0) {
1822
+ options.instanceCollections?.retain(
1823
+ new Set(
1824
+ renderables.flatMap(
1825
+ (row) => row.instances?.collectionId === void 0 ? [] : [row.instances.collectionId]
1826
+ )
1827
+ )
1828
+ );
1829
+ if (skinPaletteAllocator !== null && typeof skinPaletteAllocator.retainSliceKeys === "function") {
1830
+ skinPaletteAllocator.retainSliceKeys(
1831
+ new Set(
1832
+ renderables.flatMap(
1833
+ (row) => row.skin === void 0 ? [] : [`${worlds[row.worldId]?.identity ?? row.worldId}:${row.entityKey}`]
1834
+ )
1835
+ )
1836
+ );
1837
+ }
1838
+ }
1817
1839
  return {
1818
1840
  cameras,
1819
1841
  auxiliaryCameras,
@@ -1885,7 +1907,10 @@ function extractFrame(world, context) {
1885
1907
  materialSnapshotCache: persistentMaterialSnapshotCache,
1886
1908
  cull: cullMode,
1887
1909
  resourceOwnerFog,
1888
- getMaterialShaderArtifact
1910
+ getMaterialShaderArtifact,
1911
+ instanceCollections,
1912
+ renderableEntities,
1913
+ retainHidden
1889
1914
  } = context;
1890
1915
  const fog = resourceOwnerFog === void 0 ? selectFogFrame(world) : resourceOwnerFog ?? void 0;
1891
1916
  const fogFailure = fogState(world).failure;
@@ -2539,6 +2564,7 @@ function extractFrame(world, context) {
2539
2564
  const explicitlyHidden = /* @__PURE__ */ new Set();
2540
2565
  let dispatch = [];
2541
2566
  const materialSnapshotCache = /* @__PURE__ */ new Map();
2567
+ const skinnedMaterialSnapshotCache = /* @__PURE__ */ new Map();
2542
2568
  const meshRendererQuery = context.renderables === "none" ? [] : world.query({
2543
2569
  read: [MeshRenderer],
2544
2570
  optional: [
@@ -2558,7 +2584,6 @@ function extractFrame(world, context) {
2558
2584
  }).unwrap();
2559
2585
  const resolveArchVersion = (entity) => {
2560
2586
  const values = [
2561
- worldInternal._getArrayView(entity, Instances, "transforms"),
2562
2587
  worldInternal._getArrayView(entity, SpriteInstances, "transforms"),
2563
2588
  worldInternal._getArrayView(entity, SpriteInstances, "regions")
2564
2589
  ];
@@ -2576,6 +2601,9 @@ function extractFrame(world, context) {
2576
2601
  for (const entry of pending) dispatch.push(entry);
2577
2602
  };
2578
2603
  for (const row of meshRendererQuery) {
2604
+ if (context.renderables === "full" && renderableEntities !== void 0 && !renderableEntities.has(row.entity)) {
2605
+ continue;
2606
+ }
2579
2607
  const hasTransform = row.has(Transform);
2580
2608
  const meshFilter = row.get(MeshFilter);
2581
2609
  const hasInstances = row.has(Instances);
@@ -2599,8 +2627,9 @@ function extractFrame(world, context) {
2599
2627
  }
2600
2628
  {
2601
2629
  const entity = row.entity;
2602
- if (isRenderable && visibility?.effective(entity) === "hidden") {
2603
- explicitlyHidden.add(entity);
2630
+ const authorVisible = !(isRenderable && visibility?.effective(entity) === "hidden");
2631
+ if (!authorVisible) explicitlyHidden.add(entity);
2632
+ if (!authorVisible && !retainHidden) {
2604
2633
  continue;
2605
2634
  }
2606
2635
  const layerVal = fLayerValue ?? 0;
@@ -2748,7 +2777,9 @@ function extractFrame(world, context) {
2748
2777
  handleRaw,
2749
2778
  renderables.length,
2750
2779
  layerVal,
2751
- materialSnap.paramSnapshot
2780
+ materialSnap.paramSnapshot,
2781
+ 0,
2782
+ materialSnap.materialProgramKeys
2752
2783
  );
2753
2784
  }
2754
2785
  } else if (handleRaw === 0 || assets === void 0 || assets === null) {
@@ -2771,7 +2802,9 @@ function extractFrame(world, context) {
2771
2802
  handleRaw,
2772
2803
  renderables.length,
2773
2804
  layerVal,
2774
- materialSnap.paramSnapshot
2805
+ materialSnap.paramSnapshot,
2806
+ 0,
2807
+ materialSnap.materialProgramKeys
2775
2808
  );
2776
2809
  }
2777
2810
  } else {
@@ -2825,7 +2858,23 @@ function extractFrame(world, context) {
2825
2858
  }
2826
2859
  const resolved = resolvedResult.value;
2827
2860
  const allPasses = resolved.passes;
2828
- const firstPassShader = allPasses.length > 0 ? runtimeMaterialShaderId(allPasses[0]?.program.module, allPasses[0]?.name) : void 0;
2861
+ const materialContext = context.materialContext === void 0 ? void 0 : {
2862
+ ...context.materialContext,
2863
+ geometry: hasSkin ? "skinned" : context.materialContext.geometry
2864
+ };
2865
+ const materialProgramKeys = materialProgramKeysForMaterial(
2866
+ asset,
2867
+ assets,
2868
+ materialContext
2869
+ );
2870
+ const authoredFirstPassShader = runtimeMaterialShaderIdForMaterial(
2871
+ allPasses,
2872
+ void 0
2873
+ );
2874
+ const firstPassShader = runtimeMaterialShaderIdForMaterial(
2875
+ allPasses,
2876
+ materialProgramKeys
2877
+ );
2829
2878
  const pv = materialValuesToLinearRuntime(
2830
2879
  resolved.values,
2831
2880
  materialColorParameterSchema(resolved.parameters ?? [], firstPassShader, assets),
@@ -2851,7 +2900,7 @@ function extractFrame(world, context) {
2851
2900
  }
2852
2901
  const materialParamSchema = materialParametersToParamSchema(
2853
2902
  resolved.parameters ?? [],
2854
- firstPassShader
2903
+ authoredFirstPassShader
2855
2904
  );
2856
2905
  {
2857
2906
  const hasSkinSkel = hasSkin && skinSkeletonView !== void 0 && skinSkeletonView !== void 0 && skinSkeletonView !== 0;
@@ -3013,6 +3062,7 @@ function extractFrame(world, context) {
3013
3062
  },
3014
3063
  normalScale: normalScalePv,
3015
3064
  materialShaderId: firstPassShader,
3065
+ materialProgramKeys,
3016
3066
  materialHandle: handleRaw,
3017
3067
  renderState: pipelineRenderState(allPasses[0]?.renderState),
3018
3068
  paramSnapshot: paramSnap,
@@ -3065,7 +3115,9 @@ function extractFrame(world, context) {
3065
3115
  handleRaw,
3066
3116
  renderables.length,
3067
3117
  layerVal,
3068
- paramSnap
3118
+ paramSnap,
3119
+ 0,
3120
+ materialProgramKeys
3069
3121
  );
3070
3122
  }
3071
3123
  }
@@ -3162,7 +3214,10 @@ function extractFrame(world, context) {
3162
3214
  ibms[jIdx] = ibmFlat.subarray(jIdx * 16, jIdx * 16 + 16);
3163
3215
  }
3164
3216
  if (skinPaletteAllocator !== null) {
3165
- const slice = skinPaletteAllocator.allocateSlice(skeleton.jointCount);
3217
+ const slice = typeof skinPaletteAllocator.allocateSliceFor === "function" ? skinPaletteAllocator.allocateSliceFor(
3218
+ `${world.identity}:${entity}`,
3219
+ skeleton.jointCount
3220
+ ) : skinPaletteAllocator.allocateSlice(skeleton.jointCount);
3166
3221
  skinPaletteAllocator.writeJointPalette(slice, ibms, jointWorlds);
3167
3222
  skinSlice = {
3168
3223
  jointCount: slice.jointCount,
@@ -3184,14 +3239,19 @@ function extractFrame(world, context) {
3184
3239
  if (assets !== void 0 && assets !== null) {
3185
3240
  for (let mi = 1; mi < materialHandles.length; mi++) {
3186
3241
  const subHandle = materialHandles[mi] ?? 0;
3187
- const cachedSubmaterial = materialSnapshotCache.get(subHandle);
3242
+ const subCache = hasSkin ? skinnedMaterialSnapshotCache : materialSnapshotCache;
3243
+ const cachedSubmaterial = subCache.get(subHandle);
3188
3244
  materialsArr.push(
3189
3245
  cachedSubmaterial?.snapshot ?? resolveMaterialSnapshot(
3190
3246
  subHandle,
3191
3247
  world,
3192
3248
  assets,
3193
- materialSnapshotCache,
3194
- persistentMaterialSnapshotCache
3249
+ subCache,
3250
+ hasSkin ? void 0 : persistentMaterialSnapshotCache,
3251
+ context.materialContext === void 0 ? void 0 : {
3252
+ ...context.materialContext,
3253
+ geometry: hasSkin ? "skinned" : context.materialContext.geometry
3254
+ }
3195
3255
  )
3196
3256
  );
3197
3257
  }
@@ -3200,7 +3260,11 @@ function extractFrame(world, context) {
3200
3260
  for (let mi = 1; mi < materialHandles.length; mi++) {
3201
3261
  const subHandle = materialHandles[mi] ?? 0;
3202
3262
  if (subHandle === handleRaw) continue;
3203
- const subEntry = materialSnapshotCache.get(subHandle) ?? readPersistentMaterialSnapshot(persistentMaterialSnapshotCache, subHandle, assets);
3263
+ const subEntry = (hasSkin ? skinnedMaterialSnapshotCache : materialSnapshotCache).get(subHandle) ?? (hasSkin ? void 0 : readPersistentMaterialSnapshot(
3264
+ persistentMaterialSnapshotCache,
3265
+ subHandle,
3266
+ assets
3267
+ ));
3204
3268
  appendMaterialDispatchEntries(
3205
3269
  pendingDispatch,
3206
3270
  subEntry?.passes ?? (subHandle === 0 ? [DEFAULT_FORWARD_PASS] : []),
@@ -3208,7 +3272,9 @@ function extractFrame(world, context) {
3208
3272
  subHandle,
3209
3273
  renderables.length,
3210
3274
  layerVal,
3211
- materialsArr[mi]?.paramSnapshot
3275
+ materialsArr[mi]?.paramSnapshot,
3276
+ 0,
3277
+ materialsArr[mi]?.materialProgramKeys
3212
3278
  );
3213
3279
  }
3214
3280
  }
@@ -3306,31 +3372,28 @@ function extractFrame(world, context) {
3306
3372
  };
3307
3373
  let instancesSnap;
3308
3374
  if (hasInstances) {
3309
- const transforms = worldInternal._getArrayView(entity, Instances, "transforms");
3310
- if (transforms === void 0) {
3311
- instancesSnap = {
3312
- transforms: new Float32Array(),
3313
- instanceCount: 0,
3314
- cacheKey: entity,
3315
- archVersion
3316
- };
3317
- } else {
3318
- const actualLength = transforms.length;
3319
- if (actualLength % 16 !== 0) {
3320
- worldInternal._routeError(new InstanceTransformsStrideMismatchError(actualLength), {
3375
+ const transforms = worldInternal._getArrayView(entity, Instances, "transforms") ?? new Float32Array();
3376
+ if (transforms.length % 16 !== 0) {
3377
+ worldInternal._routeError(
3378
+ new InstanceTransformsStrideMismatchError(transforms.length),
3379
+ {
3321
3380
  severity: Severity.Error,
3322
3381
  systemName: "RenderSystem.extract (Instances stride)"
3323
- });
3324
- continue;
3325
- }
3326
- const snapshotCopy = new Float32Array(transforms);
3327
- instancesSnap = {
3328
- transforms: snapshotCopy,
3329
- instanceCount: actualLength / 16,
3330
- cacheKey: entity,
3331
- archVersion
3332
- };
3382
+ }
3383
+ );
3384
+ continue;
3333
3385
  }
3386
+ const projected = instanceCollections?.project(world, entity, transforms);
3387
+ instancesSnap = {
3388
+ transforms: projected?.transforms ?? new Float32Array(transforms),
3389
+ instanceCount: transforms.length / 16,
3390
+ cacheKey: entity,
3391
+ archVersion: projected === void 0 ? fingerprintNumericArray(transforms) : 0,
3392
+ ...projected === void 0 ? {} : {
3393
+ collectionId: projected.collectionId,
3394
+ revision: projected.revision
3395
+ }
3396
+ };
3334
3397
  }
3335
3398
  const baseRenderable = {
3336
3399
  assetHandle: Math.round(fAssetHandle ?? 0),
@@ -3344,7 +3407,9 @@ function extractFrame(world, context) {
3344
3407
  materialBindingDiagnostics,
3345
3408
  worldId: 0,
3346
3409
  entityKey: entity,
3410
+ ...authorVisible ? {} : { authorVisible: false },
3347
3411
  ...skinSlice !== void 0 ? { skin: skinSlice } : {},
3412
+ ...skin?.joints === void 0 ? {} : { skinJointEntities: Array.from(skin.joints, (joint) => Number(joint)) },
3348
3413
  ...morph !== void 0 ? { morph } : {},
3349
3414
  ...instancesSnap !== void 0 ? { instances: instancesSnap } : {},
3350
3415
  ...spriteInstancesSnap !== void 0 ? { spriteInstances: spriteInstancesSnap } : {},
@@ -3516,12 +3581,16 @@ var DEFAULT_FORWARD_PASS = {
3516
3581
  program: { module: "forgeax::default-unlit", vertexEntry: "vs_main", fragmentEntry: "fs_main" },
3517
3582
  renderState: { tags: { LightMode: "Forward" }, queue: 2e3 }
3518
3583
  };
3519
- function appendMaterialDispatchEntries(pendingDispatch, passes, entity, materialHandle, renderableIndex, layer, paramSnapshot, passIndexOffset = 0) {
3584
+ function appendMaterialDispatchEntries(pendingDispatch, passes, entity, materialHandle, renderableIndex, layer, paramSnapshot, passIndexOffset = 0, materialProgramKeys) {
3520
3585
  const matchedPasses = selectPasses(passes, {});
3521
3586
  for (let pIdx = 0; pIdx < matchedPasses.length; pIdx++) {
3522
3587
  const pass = matchedPasses[pIdx];
3523
3588
  if (pass === void 0) continue;
3524
3589
  const passState = pass.renderState ?? {};
3590
+ const authoredShaderId = runtimeMaterialShaderId(pass.program.module, pass.name);
3591
+ const dispatchShaderId = materialProgramKeys === void 0 ? authoredShaderId : materialProgramKeys[pass.name];
3592
+ if (materialProgramKeys !== void 0 && dispatchShaderId === void 0)
3593
+ throw new Error(`Missing published material program for Pass ${pass.name}`);
3525
3594
  pendingDispatch.push({
3526
3595
  entityIndex: entity,
3527
3596
  materialHandle,
@@ -3536,7 +3605,7 @@ function appendMaterialDispatchEntries(pendingDispatch, passes, entity, material
3536
3605
  defines: void 0,
3537
3606
  vertexEntry: pass.program.vertexEntry,
3538
3607
  fragmentEntry: pass.program.fragmentEntry,
3539
- materialShaderId: runtimeMaterialShaderId(pass.program.module, pass.name),
3608
+ materialShaderId: dispatchShaderId,
3540
3609
  paramSnapshot,
3541
3610
  ...passState.stencilReference !== void 0 && {
3542
3611
  stencilReference: passState.stencilReference
@@ -3632,6 +3701,39 @@ function runtimeMaterialShaderId(module, passName) {
3632
3701
  return module;
3633
3702
  }
3634
3703
  }
3704
+ function materialProgramKeysForMaterial(material, assets, context) {
3705
+ const projection = assets.getMaterialProjectionForPayload(material);
3706
+ if (projection === void 0) return void 0;
3707
+ if (context === void 0)
3708
+ throw new Error("Published material selection requires renderer-owned compiler context");
3709
+ return Object.fromEntries(
3710
+ projection.passes.map((pass) => {
3711
+ const mode = String(
3712
+ pass.renderState?.tags?.LightMode ?? pass.name
3713
+ );
3714
+ const selectedContext = {
3715
+ ...context,
3716
+ pass: /shadow/i.test(mode) ? "shadow" : /depth/i.test(mode) ? "depth" : "forward",
3717
+ pipeline: /deferred|gbuffer/i.test(mode) ? "deferred" : context.pipeline
3718
+ };
3719
+ return [
3720
+ pass.name,
3721
+ selectMaterialPassProgram(projection, pass.name, selectedContext).specializationKey
3722
+ ];
3723
+ })
3724
+ );
3725
+ }
3726
+ function runtimeMaterialShaderIdForMaterial(passes, programs) {
3727
+ const pass = passes.find(
3728
+ (pass2) => !/shadow|depth/i.test(
3729
+ String(
3730
+ pass2.renderState?.tags?.LightMode ?? pass2.name
3731
+ )
3732
+ )
3733
+ ) ?? passes[0];
3734
+ if (pass === void 0) return void 0;
3735
+ return programs === void 0 ? runtimeMaterialShaderId(pass.program.module, pass.name) : programs[pass.name];
3736
+ }
3635
3737
  function pipelineRenderState(renderState) {
3636
3738
  if (renderState === void 0) return void 0;
3637
3739
  const {
@@ -3769,30 +3871,8 @@ function isEngineInjectedTextureField(shaderId, fieldName) {
3769
3871
  return isStandardPbrMaterialShader(shaderId) && ENGINE_INJECTED_TEXTURE_FIELDS.has(fieldName);
3770
3872
  }
3771
3873
  function materialParametersToParamSchema(parameters, shaderId) {
3772
- if (isCanonicalStandardPbrMaterialShader(shaderId)) {
3773
- return STANDARD_PIPELINE_PARAM_SCHEMA;
3774
- }
3775
- const engineInjectedTextureFields = isStandardPbrMaterialShader(shaderId) ? ENGINE_INJECTED_TEXTURE_FIELDS : void 0;
3776
- return parameters.flatMap((parameter) => {
3777
- if (parameter.type === "bool") return [];
3778
- if (parameter.type === "texture" || parameter.type === "texture_cube") {
3779
- if (engineInjectedTextureFields?.has(parameter.name) === true) return [];
3780
- return [
3781
- {
3782
- name: parameter.name,
3783
- type: parameter.type === "texture_cube" ? "texture_cube" : "texture2d",
3784
- default: parameter.default
3785
- }
3786
- ];
3787
- }
3788
- const numericDefault = typeof parameter.default === "number" ? parameter.default : Array.isArray(parameter.default) && parameter.default.every((entry) => typeof entry === "number") ? parameter.default : void 0;
3789
- const numericEntry = {
3790
- name: parameter.name,
3791
- type: parameter.type,
3792
- ...parameter.colorSpace === void 0 ? {} : { colorSpace: parameter.colorSpace }
3793
- };
3794
- return numericDefault === void 0 ? [numericEntry] : [{ ...numericEntry, default: numericDefault }];
3795
- });
3874
+ if (isCanonicalStandardPbrMaterialShader(shaderId)) return STANDARD_PIPELINE_PARAM_SCHEMA;
3875
+ return materialParametersToParamSchema$1(parameters);
3796
3876
  }
3797
3877
  function materialColorParameterSchema(parameters, shaderId, assets) {
3798
3878
  if (shaderId === void 0) return parameters;
@@ -3857,7 +3937,7 @@ function storeMaterialSnapshot(cache, handleRaw, snapshot, passes, root, assets)
3857
3937
  cache.set(handleRaw, entry);
3858
3938
  return entry;
3859
3939
  }
3860
- function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCache, persistentMaterialSnapshotCache) {
3940
+ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCache, persistentMaterialSnapshotCache, materialContext) {
3861
3941
  if (handleRaw === 0) return defaultMaterialSnapshot(handleRaw);
3862
3942
  const cached = materialSnapshotCache?.get(handleRaw);
3863
3943
  if (cached !== void 0) return cached.snapshot;
@@ -3888,7 +3968,9 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
3888
3968
  if (!resolvedResult.ok) return defaultMaterialSnapshot(handleRaw);
3889
3969
  const resolved = resolvedResult.value;
3890
3970
  const allPasses = resolved.passes;
3891
- const firstPassShader = allPasses.length > 0 ? runtimeMaterialShaderId(allPasses[0]?.program.module, allPasses[0]?.name) : void 0;
3971
+ const materialProgramKeys = materialProgramKeysForMaterial(asset, assetsRef, materialContext);
3972
+ const authoredFirstPassShader = runtimeMaterialShaderIdForMaterial(allPasses, void 0);
3973
+ const firstPassShader = runtimeMaterialShaderIdForMaterial(allPasses, materialProgramKeys);
3892
3974
  const pv = materialValuesToLinearRuntime(
3893
3975
  resolved.values,
3894
3976
  materialColorParameterSchema(resolved.parameters ?? [], firstPassShader, assetsRef),
@@ -3914,7 +3996,7 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
3914
3996
  }
3915
3997
  const materialParamSchema = materialParametersToParamSchema(
3916
3998
  resolved.parameters ?? [],
3917
- firstPassShader
3999
+ authoredFirstPassShader
3918
4000
  );
3919
4001
  const resolveTexLike = (value, brand) => {
3920
4002
  if (typeof value === "number") return toShared(value);
@@ -3964,6 +4046,7 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
3964
4046
  },
3965
4047
  normalScale: normalScalePv,
3966
4048
  materialShaderId: firstPassShader,
4049
+ materialProgramKeys,
3967
4050
  materialHandle: handleRaw,
3968
4051
  renderState: pipelineRenderState(allPasses[0]?.renderState),
3969
4052
  paramSnapshot: paramSnap,
@@ -4352,6 +4435,7 @@ function tonemapParams(camera) {
4352
4435
  function prepareExtractContext(world, options = {}) {
4353
4436
  const renderables = options.renderables ?? "full";
4354
4437
  return {
4438
+ materialContext: options.materialContext,
4355
4439
  assets: options.assets,
4356
4440
  pipelineState: options.pipelineState,
4357
4441
  materialSnapshotCache: options.materialSnapshotCache,
@@ -4359,8 +4443,11 @@ function prepareExtractContext(world, options = {}) {
4359
4443
  cull: options.cull ?? "self",
4360
4444
  cullCameras: options.cullCameras,
4361
4445
  renderables,
4446
+ renderableEntities: options.renderableEntities,
4447
+ retainHidden: options.retainHidden ?? false,
4362
4448
  visibility: renderables === "none" ? ALL_VISIBLE : resolveVisibility(world),
4363
- getMaterialShaderArtifact: options.getMaterialShaderArtifact
4449
+ getMaterialShaderArtifact: options.getMaterialShaderArtifact,
4450
+ instanceCollections: options.instanceCollections
4364
4451
  };
4365
4452
  }
4366
4453
  var fogQueries = /* @__PURE__ */ new WeakMap();
@@ -5078,5 +5165,5 @@ var ProbeBlendSceneProjection = class {
5078
5165
  };
5079
5166
 
5080
5167
  export { InstanceBoundsCache, OcclusionRenderRuntime, PROBE_MAX_CONTRIBUTORS, ProbeBlendSceneProjection, SKYLIGHT_RECOVERY_FALLBACK, admitProbeContributors, blendLightProbes, buildRectAreaWorldFrame, createCookieProjectionMatrixData, createExtendedLightingState, extractFrames, fingerprintNumericArray, glyphTextLayoutSystem, primitiveKey, primitiveKeyId, projectExtendedLightingInspection, promoteExtendedLightingCandidate, recordExtendedLightingFailure, rectAreaFacesPoint, scaledProbeWeight, setOcclusionRuntimeTestHooks, viewKey, viewKeyId };
5081
- //# sourceMappingURL=chunk-Z3YYH2MB.mjs.map
5082
- //# sourceMappingURL=chunk-Z3YYH2MB.mjs.map
5168
+ //# sourceMappingURL=chunk-YUQXSEHG.mjs.map
5169
+ //# sourceMappingURL=chunk-YUQXSEHG.mjs.map