@forgeax/engine-render 0.1.25 → 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 (86) hide show
  1. package/README.md +18 -0
  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.map +1 -1
  8. package/dist/assembly/webgpu-renderer.d.ts +0 -1
  9. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  10. package/dist/authoring.mjs +1 -1
  11. package/dist/{chunk-JSEDTZYS.mjs → chunk-GF523LHF.mjs} +6 -6
  12. package/dist/chunk-GF523LHF.mjs.map +1 -0
  13. package/dist/{chunk-TCLDX7SZ.mjs → chunk-TMIASV2N.mjs} +403 -457
  14. package/dist/chunk-TMIASV2N.mjs.map +1 -0
  15. package/dist/{chunk-N3RT2EUR.mjs → chunk-YUQXSEHG.mjs} +87 -53
  16. package/dist/chunk-YUQXSEHG.mjs.map +1 -0
  17. package/dist/construct-renderer.mjs +153 -13
  18. package/dist/construct-renderer.mjs.map +1 -1
  19. package/dist/extract/contracts.d.ts +6 -6
  20. package/dist/extract/contracts.d.ts.map +1 -1
  21. package/dist/index.mjs +1 -1
  22. package/dist/internal.mjs +1 -1
  23. package/dist/pipeline-spec-types.d.ts +2 -0
  24. package/dist/pipeline-spec-types.d.ts.map +1 -1
  25. package/dist/pipeline-spec.d.ts.map +1 -1
  26. package/dist/record/frame.d.ts.map +1 -1
  27. package/dist/record/main-pass-geometry.d.ts +2 -2
  28. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  29. package/dist/record/main-pass-material.d.ts +20 -2
  30. package/dist/record/main-pass-material.d.ts.map +1 -1
  31. package/dist/record/main-pass-sprite-draws.d.ts +3 -3
  32. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  33. package/dist/record/main-pass.d.ts.map +1 -1
  34. package/dist/record/material-uniforms.d.ts +4 -0
  35. package/dist/record/material-uniforms.d.ts.map +1 -0
  36. package/dist/record/render-context.d.ts +2 -2
  37. package/dist/record/render-context.d.ts.map +1 -1
  38. package/dist/record/shadow-pass.d.ts +2 -3
  39. package/dist/record/shadow-pass.d.ts.map +1 -1
  40. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  41. package/dist/render-system-extract-tail.d.ts +2 -0
  42. package/dist/render-system-extract-tail.d.ts.map +1 -1
  43. package/dist/render-system-extract.d.ts +21 -10
  44. package/dist/render-system-extract.d.ts.map +1 -1
  45. package/dist/render-system.d.ts.map +1 -1
  46. package/dist/temporal/index.mjs +2 -2
  47. package/package.json +20 -20
  48. package/src/__tests__/fixtures/ai-weapon-spirit/README.md +20 -0
  49. package/src/__tests__/fixtures/ai-weapon-spirit/low-poly-toon.wgsl +178 -0
  50. package/src/__tests__/fixtures/ai-weapon-spirit/material.json +97 -0
  51. package/src/__tests__/fixtures/ai-weapon-spirit/painterly-surface.wgsl +55 -0
  52. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +3 -3
  53. package/src/__tests__/gpu-driven-view.browser.test.ts +11 -3
  54. package/src/__tests__/material-contract-inventory.unit.test.ts +43 -0
  55. package/src/__tests__/{material-static-dynamic-route.unit.test.ts → material-layer-projection.unit.test.ts} +30 -47
  56. package/src/__tests__/material-program-dispatch.unit.test.ts +48 -0
  57. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +2 -2
  58. package/src/__tests__/skinned-shadow-caster.test.ts +14 -14
  59. package/src/__tests__/surface-variant-provenance.integration.test.ts +1 -1
  60. package/src/assembly/factory.ts +0 -3
  61. package/src/assembly/material/assembly.ts +8 -40
  62. package/src/assembly/material/standard-layer-projection.ts +3 -1
  63. package/src/assembly/material/surface-projection.ts +2 -1
  64. package/src/assembly/webgpu-renderer.ts +17 -9
  65. package/src/extract/contracts.ts +6 -6
  66. package/src/materials.ts +3 -3
  67. package/src/pipeline-spec-types.ts +2 -0
  68. package/src/pipeline-spec.ts +7 -3
  69. package/src/record/frame.ts +7 -1
  70. package/src/record/main-pass-geometry.ts +340 -279
  71. package/src/record/main-pass-material.ts +87 -2
  72. package/src/record/main-pass-sprite-draws.ts +65 -168
  73. package/src/record/main-pass.ts +24 -246
  74. package/src/record/material-uniforms.ts +186 -0
  75. package/src/record/render-context.ts +4 -0
  76. package/src/record/shadow-pass.ts +86 -28
  77. package/src/recovery/render-system-candidate.ts +5 -1
  78. package/src/render-system-extract-tail.ts +51 -11
  79. package/src/render-system-extract.ts +73 -63
  80. package/src/render-system.ts +19 -0
  81. package/dist/assembly/material/pipeline-projection.d.ts +0 -30
  82. package/dist/assembly/material/pipeline-projection.d.ts.map +0 -1
  83. package/dist/chunk-JSEDTZYS.mjs.map +0 -1
  84. package/dist/chunk-N3RT2EUR.mjs.map +0 -1
  85. package/dist/chunk-TCLDX7SZ.mjs.map +0 -1
  86. package/src/assembly/material/pipeline-projection.ts +0 -63
@@ -1,10 +1,10 @@
1
1
  import { GlyphText, selectActiveCameraIndex, getActiveCamera } from './chunk-FJ6P52EE.mjs';
2
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-HKXTW355.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
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,6 +1639,7 @@ 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",
1644
1645
  ...options.renderableEntitiesByWorld?.[wi] === void 0 ? {} : { renderableEntities: options.renderableEntitiesByWorld[wi] },
@@ -2563,6 +2564,7 @@ function extractFrame(world, context) {
2563
2564
  const explicitlyHidden = /* @__PURE__ */ new Set();
2564
2565
  let dispatch = [];
2565
2566
  const materialSnapshotCache = /* @__PURE__ */ new Map();
2567
+ const skinnedMaterialSnapshotCache = /* @__PURE__ */ new Map();
2566
2568
  const meshRendererQuery = context.renderables === "none" ? [] : world.query({
2567
2569
  read: [MeshRenderer],
2568
2570
  optional: [
@@ -2777,7 +2779,7 @@ function extractFrame(world, context) {
2777
2779
  layerVal,
2778
2780
  materialSnap.paramSnapshot,
2779
2781
  0,
2780
- materialSnap.materialShaderId
2782
+ materialSnap.materialProgramKeys
2781
2783
  );
2782
2784
  }
2783
2785
  } else if (handleRaw === 0 || assets === void 0 || assets === null) {
@@ -2802,7 +2804,7 @@ function extractFrame(world, context) {
2802
2804
  layerVal,
2803
2805
  materialSnap.paramSnapshot,
2804
2806
  0,
2805
- materialSnap.materialShaderId
2807
+ materialSnap.materialProgramKeys
2806
2808
  );
2807
2809
  }
2808
2810
  } else {
@@ -2856,7 +2858,23 @@ function extractFrame(world, context) {
2856
2858
  }
2857
2859
  const resolved = resolvedResult.value;
2858
2860
  const allPasses = resolved.passes;
2859
- const firstPassShader = runtimeMaterialShaderIdForMaterial(asset, allPasses, assets);
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
+ );
2860
2878
  const pv = materialValuesToLinearRuntime(
2861
2879
  resolved.values,
2862
2880
  materialColorParameterSchema(resolved.parameters ?? [], firstPassShader, assets),
@@ -2882,7 +2900,7 @@ function extractFrame(world, context) {
2882
2900
  }
2883
2901
  const materialParamSchema = materialParametersToParamSchema(
2884
2902
  resolved.parameters ?? [],
2885
- firstPassShader
2903
+ authoredFirstPassShader
2886
2904
  );
2887
2905
  {
2888
2906
  const hasSkinSkel = hasSkin && skinSkeletonView !== void 0 && skinSkeletonView !== void 0 && skinSkeletonView !== 0;
@@ -3044,6 +3062,7 @@ function extractFrame(world, context) {
3044
3062
  },
3045
3063
  normalScale: normalScalePv,
3046
3064
  materialShaderId: firstPassShader,
3065
+ materialProgramKeys,
3047
3066
  materialHandle: handleRaw,
3048
3067
  renderState: pipelineRenderState(allPasses[0]?.renderState),
3049
3068
  paramSnapshot: paramSnap,
@@ -3098,7 +3117,7 @@ function extractFrame(world, context) {
3098
3117
  layerVal,
3099
3118
  paramSnap,
3100
3119
  0,
3101
- firstPassShader
3120
+ materialProgramKeys
3102
3121
  );
3103
3122
  }
3104
3123
  }
@@ -3220,14 +3239,19 @@ function extractFrame(world, context) {
3220
3239
  if (assets !== void 0 && assets !== null) {
3221
3240
  for (let mi = 1; mi < materialHandles.length; mi++) {
3222
3241
  const subHandle = materialHandles[mi] ?? 0;
3223
- const cachedSubmaterial = materialSnapshotCache.get(subHandle);
3242
+ const subCache = hasSkin ? skinnedMaterialSnapshotCache : materialSnapshotCache;
3243
+ const cachedSubmaterial = subCache.get(subHandle);
3224
3244
  materialsArr.push(
3225
3245
  cachedSubmaterial?.snapshot ?? resolveMaterialSnapshot(
3226
3246
  subHandle,
3227
3247
  world,
3228
3248
  assets,
3229
- materialSnapshotCache,
3230
- 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
+ }
3231
3255
  )
3232
3256
  );
3233
3257
  }
@@ -3236,7 +3260,11 @@ function extractFrame(world, context) {
3236
3260
  for (let mi = 1; mi < materialHandles.length; mi++) {
3237
3261
  const subHandle = materialHandles[mi] ?? 0;
3238
3262
  if (subHandle === handleRaw) continue;
3239
- 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
+ ));
3240
3268
  appendMaterialDispatchEntries(
3241
3269
  pendingDispatch,
3242
3270
  subEntry?.passes ?? (subHandle === 0 ? [DEFAULT_FORWARD_PASS] : []),
@@ -3246,7 +3274,7 @@ function extractFrame(world, context) {
3246
3274
  layerVal,
3247
3275
  materialsArr[mi]?.paramSnapshot,
3248
3276
  0,
3249
- materialsArr[mi]?.materialShaderId
3277
+ materialsArr[mi]?.materialProgramKeys
3250
3278
  );
3251
3279
  }
3252
3280
  }
@@ -3553,14 +3581,16 @@ var DEFAULT_FORWARD_PASS = {
3553
3581
  program: { module: "forgeax::default-unlit", vertexEntry: "vs_main", fragmentEntry: "fs_main" },
3554
3582
  renderState: { tags: { LightMode: "Forward" }, queue: 2e3 }
3555
3583
  };
3556
- function appendMaterialDispatchEntries(pendingDispatch, passes, entity, materialHandle, renderableIndex, layer, paramSnapshot, passIndexOffset = 0, materialShaderIdOverride) {
3584
+ function appendMaterialDispatchEntries(pendingDispatch, passes, entity, materialHandle, renderableIndex, layer, paramSnapshot, passIndexOffset = 0, materialProgramKeys) {
3557
3585
  const matchedPasses = selectPasses(passes, {});
3558
3586
  for (let pIdx = 0; pIdx < matchedPasses.length; pIdx++) {
3559
3587
  const pass = matchedPasses[pIdx];
3560
3588
  if (pass === void 0) continue;
3561
3589
  const passState = pass.renderState ?? {};
3562
3590
  const authoredShaderId = runtimeMaterialShaderId(pass.program.module, pass.name);
3563
- const dispatchShaderId = authoredShaderId === "forgeax::default-shadow-caster" ? authoredShaderId : materialShaderIdOverride ?? authoredShaderId;
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}`);
3564
3594
  pendingDispatch.push({
3565
3595
  entityIndex: entity,
3566
3596
  materialHandle,
@@ -3575,13 +3605,6 @@ function appendMaterialDispatchEntries(pendingDispatch, passes, entity, material
3575
3605
  defines: void 0,
3576
3606
  vertexEntry: pass.program.vertexEntry,
3577
3607
  fragmentEntry: pass.program.fragmentEntry,
3578
- // A cooked Standard publication supplies one specialization key for its
3579
- // forward/deferred artifact, but its ShadowCaster pass still owns the
3580
- // engine depth-only shader. Keep the pass-local canonical identity so a
3581
- // specialized Standard source (which only declares fs_main/fs_gbuffer)
3582
- // is never asked to build an fs_shadow pipeline. Authored non-Standard
3583
- // ShadowCaster modules retain the publication override and continue to
3584
- // use their producer-owned source.
3585
3608
  materialShaderId: dispatchShaderId,
3586
3609
  paramSnapshot,
3587
3610
  ...passState.stencilReference !== void 0 && {
@@ -3678,9 +3701,38 @@ function runtimeMaterialShaderId(module, passName) {
3678
3701
  return module;
3679
3702
  }
3680
3703
  }
3681
- function runtimeMaterialShaderIdForMaterial(material, passes, assets) {
3682
- const authored = runtimeMaterialShaderId(passes[0]?.program.module, passes[0]?.name);
3683
- return assets.getMaterialProjectionForPayload(material)?.specializationKey ?? authored;
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];
3684
3736
  }
3685
3737
  function pipelineRenderState(renderState) {
3686
3738
  if (renderState === void 0) return void 0;
@@ -3819,30 +3871,8 @@ function isEngineInjectedTextureField(shaderId, fieldName) {
3819
3871
  return isStandardPbrMaterialShader(shaderId) && ENGINE_INJECTED_TEXTURE_FIELDS.has(fieldName);
3820
3872
  }
3821
3873
  function materialParametersToParamSchema(parameters, shaderId) {
3822
- if (isCanonicalStandardPbrMaterialShader(shaderId)) {
3823
- return STANDARD_PIPELINE_PARAM_SCHEMA;
3824
- }
3825
- const engineInjectedTextureFields = isStandardPbrMaterialShader(shaderId) ? ENGINE_INJECTED_TEXTURE_FIELDS : void 0;
3826
- return parameters.flatMap((parameter) => {
3827
- if (parameter.type === "bool") return [];
3828
- if (parameter.type === "texture" || parameter.type === "texture_cube") {
3829
- if (engineInjectedTextureFields?.has(parameter.name) === true) return [];
3830
- return [
3831
- {
3832
- name: parameter.name,
3833
- type: parameter.type === "texture_cube" ? "texture_cube" : "texture2d",
3834
- default: parameter.default
3835
- }
3836
- ];
3837
- }
3838
- const numericDefault = typeof parameter.default === "number" ? parameter.default : Array.isArray(parameter.default) && parameter.default.every((entry) => typeof entry === "number") ? parameter.default : void 0;
3839
- const numericEntry = {
3840
- name: parameter.name,
3841
- type: parameter.type,
3842
- ...parameter.colorSpace === void 0 ? {} : { colorSpace: parameter.colorSpace }
3843
- };
3844
- return numericDefault === void 0 ? [numericEntry] : [{ ...numericEntry, default: numericDefault }];
3845
- });
3874
+ if (isCanonicalStandardPbrMaterialShader(shaderId)) return STANDARD_PIPELINE_PARAM_SCHEMA;
3875
+ return materialParametersToParamSchema$1(parameters);
3846
3876
  }
3847
3877
  function materialColorParameterSchema(parameters, shaderId, assets) {
3848
3878
  if (shaderId === void 0) return parameters;
@@ -3907,7 +3937,7 @@ function storeMaterialSnapshot(cache, handleRaw, snapshot, passes, root, assets)
3907
3937
  cache.set(handleRaw, entry);
3908
3938
  return entry;
3909
3939
  }
3910
- function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCache, persistentMaterialSnapshotCache) {
3940
+ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCache, persistentMaterialSnapshotCache, materialContext) {
3911
3941
  if (handleRaw === 0) return defaultMaterialSnapshot(handleRaw);
3912
3942
  const cached = materialSnapshotCache?.get(handleRaw);
3913
3943
  if (cached !== void 0) return cached.snapshot;
@@ -3938,7 +3968,9 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
3938
3968
  if (!resolvedResult.ok) return defaultMaterialSnapshot(handleRaw);
3939
3969
  const resolved = resolvedResult.value;
3940
3970
  const allPasses = resolved.passes;
3941
- const firstPassShader = runtimeMaterialShaderIdForMaterial(asset, allPasses, assetsRef);
3971
+ const materialProgramKeys = materialProgramKeysForMaterial(asset, assetsRef, materialContext);
3972
+ const authoredFirstPassShader = runtimeMaterialShaderIdForMaterial(allPasses, void 0);
3973
+ const firstPassShader = runtimeMaterialShaderIdForMaterial(allPasses, materialProgramKeys);
3942
3974
  const pv = materialValuesToLinearRuntime(
3943
3975
  resolved.values,
3944
3976
  materialColorParameterSchema(resolved.parameters ?? [], firstPassShader, assetsRef),
@@ -3964,7 +3996,7 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
3964
3996
  }
3965
3997
  const materialParamSchema = materialParametersToParamSchema(
3966
3998
  resolved.parameters ?? [],
3967
- firstPassShader
3999
+ authoredFirstPassShader
3968
4000
  );
3969
4001
  const resolveTexLike = (value, brand) => {
3970
4002
  if (typeof value === "number") return toShared(value);
@@ -4014,6 +4046,7 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
4014
4046
  },
4015
4047
  normalScale: normalScalePv,
4016
4048
  materialShaderId: firstPassShader,
4049
+ materialProgramKeys,
4017
4050
  materialHandle: handleRaw,
4018
4051
  renderState: pipelineRenderState(allPasses[0]?.renderState),
4019
4052
  paramSnapshot: paramSnap,
@@ -4402,6 +4435,7 @@ function tonemapParams(camera) {
4402
4435
  function prepareExtractContext(world, options = {}) {
4403
4436
  const renderables = options.renderables ?? "full";
4404
4437
  return {
4438
+ materialContext: options.materialContext,
4405
4439
  assets: options.assets,
4406
4440
  pipelineState: options.pipelineState,
4407
4441
  materialSnapshotCache: options.materialSnapshotCache,
@@ -5131,5 +5165,5 @@ var ProbeBlendSceneProjection = class {
5131
5165
  };
5132
5166
 
5133
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 };
5134
- //# sourceMappingURL=chunk-N3RT2EUR.mjs.map
5135
- //# sourceMappingURL=chunk-N3RT2EUR.mjs.map
5168
+ //# sourceMappingURL=chunk-YUQXSEHG.mjs.map
5169
+ //# sourceMappingURL=chunk-YUQXSEHG.mjs.map