@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,12 +1,12 @@
1
1
  import { inspectVolumetricFog, inspectLodOcclusion, resolveSsrAdmissionGeneration, projectSsrDependencies, inspectReflectionFallback, admitReflectionProbe, DEFAULT_REFLECTION_PROBE_LIMITS, buildReflectionProbeTable, advanceProbeFilter, buildCubeCameraFaceViews, commitProbeFilterStep, resolveReflectionFallbackSource, deriveReflectionFallbackProjection, reflectionFallbackCoverage, reflectionFallbackSourceKey, reflectionFallbackProjectionSignature, createProbeFilterState, ReflectionProbeProjection, admitPointsLines, inspectPointShadow } from './chunk-KM2NOX2I.mjs';
2
- import { createExtendedLightingState, promoteExtendedLightingCandidate, OcclusionRenderRuntime, extractFrames, viewKey, primitiveKey, glyphTextLayoutSystem, projectExtendedLightingInspection, viewKeyId, primitiveKeyId, ProbeBlendSceneProjection, SKYLIGHT_RECOVERY_FALLBACK, InstanceBoundsCache, fingerprintNumericArray, createCookieProjectionMatrixData } from './chunk-N3RT2EUR.mjs';
2
+ import { createExtendedLightingState, promoteExtendedLightingCandidate, OcclusionRenderRuntime, extractFrames, viewKey, primitiveKey, glyphTextLayoutSystem, projectExtendedLightingInspection, viewKeyId, primitiveKeyId, ProbeBlendSceneProjection, SKYLIGHT_RECOVERY_FALLBACK, InstanceBoundsCache, fingerprintNumericArray, createCookieProjectionMatrixData } from './chunk-YUQXSEHG.mjs';
3
3
  import './chunk-FJ6P52EE.mjs';
4
4
  import { MeshFilter, MeshRenderer, Instances, Layer, Visibility, Points, Lines, SortKey, Camera, MotionBlur, DirectionalLight, LightProbe, PointLight, PointLightShadow, SpotLight, Skylight, SkyboxBackground, PostProcessParams, ReflectionProbe, VolumetricFog, projectMeshMaterialBindingObservation, createVisibilityBudget, hasVolumetricFogCapability, CUBE_CAMERA_FACE_ORDER, CAMERA_PROJECTION_ORTHOGRAPHIC } from './chunk-ADHHVYLW.mjs';
5
5
  import { SpriteInstances, SpriteRegionOverride, TileLayer, decodeSortScope, Tilemap } from './chunk-JDWARUOI.mjs';
6
- import { assertStorageBufferCap, GpuBuffer, GpuTexture, deriveRenderDataTexture, deriveRenderDataMesh, deriveRenderDataCubemap, createIblPipelines, CUBEMAP_FACE_VERTICES, runIblPrecompute, InstanceProjectionStore, createClusterBinScratch, resetHdrpBuffers, retireTemporalGpuState, PostProcessError, entryHasDepthRead, DEPTH_MIN_PARAMS_BYTE_SIZE, postProcessShaderModuleLabel, resolveSsaoParameters, buildPerFrameBindGroups, postProcessShaderEntrySignature, PipelineSpecError, CAPTURE_VIEW_PROJS, PREFILTER_MIP_LEVELS, selectSwapChainFormat, setIblComposedShaders, POINTS_LINES_MATERIAL_SHADER_ID, createHdrpClusterMembershipBindGroupLayoutDescriptor, createSkylightFallback, buildSpecConstTable, buildLinearLdrMaterialSpecTable, getOrBuildPipeline, cacheKeyOf, REFLECTION_PROBE_VIEW_SLOT_BASE, VIEW_UNIFORM_SLOT_STRIDE, getOrCreateIblCache, postProcessShaderPipelineLabel, createPointsLinesLaneAdapter, computeViewMatrix, computeProjectionMatrix, prepareFrameLighting, warnMultiSkylight, warnMultiSkybox, selectLazyEquirectHandle, driveLazyEquirectProjection, warnZeroLightStandard, writeShadowParamsBuffer, writeSpotModifierTextures, writeHdrpClusterAndSsaoBuffers, resolveSkyboxActive, computeSplitLdrSprite, writeViewUbo, writePointsLinesViewUbo, writeShadowCasterUniforms, uploadMeshSsboBatch, passKindPolicyTable, colorFormatsForPassKind, configureSurface, VIEW_UNIFORM_BUFFER_SIZE, POINTS_LINES_VIEW_BUFFER_SIZE, SHADOW_CASTER_BUFFER_SIZE, FALLBACK_BYTES_PER_ROW, PREFILTER_SIZE, geometryRenderStateForTopology, assembleMaterialWithSkylightEntries, MESH_SSBO_BYTES, createPointsLinesLaneContract, foldDispatchBuckets, CUBE_CAPTURE_VIEW_SLOT_BASE, variantSetFromDefines, cleanPerEntityCache, ensureMeshSsboCapacity, buildFoldDispatchPlan, evaluateFoldBucketUniformCap, incrementFoldedDrawsMetric, resolveGeometryInstanceBuffer, buildFullscreenPostProcessPass, getTemporalGpuState, getTemporalParamsBuffer, getTemporalBindGroupResources, resolveSurfaceFormatPair, resolveSurfaceProfile, encodeMainPass, abortTemporalGpuSubmit, commitTemporalGpuSubmit, retireTemporalGpuStateAfterFence, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, DEFERRED_COLOR_FORMATS, aggregateTemporalDemand, standardTemporalLaneAdmission, addTypedScenePass, addTypedSsaoPasses, typedFrameClearColor, addTypedSkyboxPass, createStandardSceneDataTarget, addStandardSceneDataPass, addTypedFrameObservationPass, temporalReadIndex, temporalWriteIndex, addReflectionFallbackObservationPass, BYTES_PER_DIRECT_LIGHT_SLOT, createRenderPipelineTarget, resolveOutputDither, addTypedTemporalResolvePass, addTypedBloomPasses, addTypedOutputTransformPass, addTypedFullscreenPass, addTypedCompositePostEffects, standardTopologyVariantSet, geometryRenderStateForPass, standardStorageVariantSet, getOrCreateHdrpBuffers, encodeDirectionalShadowPass, encodePointShadowPass, encodeSpotShadowPass, VIEW_UNIFORM_BYTES, variantSetFromVertexLayoutProjection, MATERIAL_PER_ENTITY_STRIDE, isTemporalFullscreenBinding, createFullscreenBindGroup, applyParamSnapshotToUbo, residentTextureView, TYPED_BLOOM_PASS_NAMES } from './chunk-TCLDX7SZ.mjs';
6
+ import { assertStorageBufferCap, GpuBuffer, GpuTexture, deriveRenderDataTexture, deriveRenderDataMesh, deriveRenderDataCubemap, createIblPipelines, CUBEMAP_FACE_VERTICES, runIblPrecompute, InstanceProjectionStore, createClusterBinScratch, resetHdrpBuffers, retireTemporalGpuState, PostProcessError, entryHasDepthRead, DEPTH_MIN_PARAMS_BYTE_SIZE, postProcessShaderModuleLabel, resolveSsaoParameters, buildPerFrameBindGroups, postProcessShaderEntrySignature, PipelineSpecError, CAPTURE_VIEW_PROJS, PREFILTER_MIP_LEVELS, selectSwapChainFormat, setIblComposedShaders, POINTS_LINES_MATERIAL_SHADER_ID, createHdrpClusterMembershipBindGroupLayoutDescriptor, createSkylightFallback, buildSpecConstTable, buildLinearLdrMaterialSpecTable, getOrBuildPipeline, cacheKeyOf, REFLECTION_PROBE_VIEW_SLOT_BASE, VIEW_UNIFORM_SLOT_STRIDE, getOrCreateIblCache, postProcessShaderPipelineLabel, createPointsLinesLaneAdapter, computeViewMatrix, computeProjectionMatrix, prepareFrameLighting, warnMultiSkylight, warnMultiSkybox, selectLazyEquirectHandle, driveLazyEquirectProjection, warnZeroLightStandard, writeShadowParamsBuffer, writeSpotModifierTextures, writeHdrpClusterAndSsaoBuffers, resolveSkyboxActive, computeSplitLdrSprite, writeViewUbo, writePointsLinesViewUbo, writeShadowCasterUniforms, uploadMeshSsboBatch, passKindPolicyTable, colorFormatsForPassKind, configureSurface, VIEW_UNIFORM_BUFFER_SIZE, POINTS_LINES_VIEW_BUFFER_SIZE, SHADOW_CASTER_BUFFER_SIZE, FALLBACK_BYTES_PER_ROW, PREFILTER_SIZE, geometryRenderStateForTopology, assembleMaterialWithSkylightEntries, MESH_SSBO_BYTES, createPointsLinesLaneContract, foldDispatchBuckets, CUBE_CAPTURE_VIEW_SLOT_BASE, variantSetFromDefines, cleanPerEntityCache, ensureMeshSsboCapacity, buildFoldDispatchPlan, evaluateFoldBucketUniformCap, incrementFoldedDrawsMetric, writePbrMaterialUboPayload, applyParamSnapshotToUbo, applyMaterialTextureUvScales, residentTextureView, MATERIAL_PER_ENTITY_STRIDE, detectNineSliceScaleTooSmall, resolveGeometryInstanceBuffer, buildFullscreenPostProcessPass, getTemporalGpuState, getTemporalParamsBuffer, getTemporalBindGroupResources, resolveSurfaceFormatPair, resolveSurfaceProfile, encodeMainPass, STANDARD_PBR_UBO_SIZE, abortTemporalGpuSubmit, commitTemporalGpuSubmit, retireTemporalGpuStateAfterFence, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, DEFERRED_COLOR_FORMATS, aggregateTemporalDemand, standardTemporalLaneAdmission, addTypedScenePass, addTypedSsaoPasses, typedFrameClearColor, addTypedSkyboxPass, createStandardSceneDataTarget, addStandardSceneDataPass, addTypedFrameObservationPass, temporalReadIndex, temporalWriteIndex, addReflectionFallbackObservationPass, BYTES_PER_DIRECT_LIGHT_SLOT, createRenderPipelineTarget, resolveOutputDither, addTypedTemporalResolvePass, addTypedBloomPasses, addTypedOutputTransformPass, addTypedFullscreenPass, addTypedCompositePostEffects, standardTopologyVariantSet, geometryRenderStateForPass, standardStorageVariantSet, getOrCreateHdrpBuffers, encodeDirectionalShadowPass, encodePointShadowPass, encodeSpotShadowPass, VIEW_UNIFORM_BYTES, variantSetFromVertexLayoutProjection, isTemporalFullscreenBinding, createFullscreenBindGroup, TYPED_BLOOM_PASS_NAMES } from './chunk-TMIASV2N.mjs';
7
7
  import { getTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE, TRANSPARENT_SORT_MODE_LAYER_Z, TRANSPARENT_SORT_MODE_LAYER_Y, TRANSPARENT_SORT_MODE_LAYER_YZ } from './chunk-RXZ3RGOU.mjs';
8
8
  import { DEFAULT_STANDARD_PROFILE, DEFAULT_CLUSTER_GRID, createSceneDataCatalog, STANDARD_PIPELINE_ID, STANDARD_LIGHT_COUNTS, STANDARD_POST_STAGE_NAMES, resolveVolumetricFogProfile, isSceneDataTarget } from './chunk-E34VL5VI.mjs';
9
- import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-JSEDTZYS.mjs';
9
+ import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-GF523LHF.mjs';
10
10
  import { DeviceScope, SKIN_MATERIAL_SHADER_ID, EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_MAP_READ, resolveRenderTargetMaterialSource, createRenderTargetMaterialSource, deriveExtendedLightingCapability, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_INDEX, EXTENDED_LIGHTING_TOPOLOGY, GPU_BUFFER_USAGE_UNIFORM, getTextureIdentity, worldEntityKey, createHdrpBindGroupLayoutDescriptor, createHdrpSkinBindGroupLayoutDescriptor, IES_SLICE_WIDTH, IES_SLICE_HEIGHT, COOKIE_SLICE_SIZE, COOKIE_MATRIX_BYTES, makeZeroCameraFallbackSnapshot, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, buildPbrPipelineLayouts, buildPbrSkinLayouts, GPU_BUFFER_USAGE_STORAGE, resolvePipelineGroup2Contract, GPU_SHADER_STAGE_FRAGMENT, instanceCollectionCacheKey, validateGraphTargetCaptureReadback, isCanonicalStandardPbrMaterialShader, isStandardPbrMaterialShader, buildBindGroupLayoutDescriptor, GPU_BUFFER_USAGE_INDIRECT, buildPbrMaterialUserRegionEntries, extendedLightingSampledTextureCapacityAvailable, GPU_SHADER_STAGE_VERTEX, SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET, shadowCasterVariantSet, SHADOW_CASTER_SHADER_ID, LifecycleTransaction } from './chunk-HKXTW355.mjs';
11
11
  import { RendererContractFailureError, RendererOperationError, STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, RenderTargetStateInvalidError, RenderTargetOperationFailedError, RenderTargetCapabilityMissingError, RenderTargetDescriptorInvalidError, GPU_TEXTURE_USAGE_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_DST, RENDER_PHASE_CATALOG, FrameReceiptStaleError, RenderFeatureStageFailedError, RenderFeatureCapabilityMissingError, RenderFeatureRegistrationConflictError, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_SRC, EnvironmentGenerationFailedError, PointsLinesMaterialUnsupportedError, StandardProfileInvalidError, TransmissionCapabilityMissingError, SHADOW_ATLAS_DEFAULT_LAYERS, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, TemporalFrameSubmitError, ObservationUnavailableError, RenderFeaturePreparationFailedError, PointsLinesPrepareFailedError, SHADOW_ATLAS_DEFAULT_FACE_SIZE, SceneDataUnavailableError, RenderFeatureDrawRecordingFailedError, PointShadowAtlasUninitializedError, SkinPaletteOverflowError, RenderFeaturePreparedStateMismatchError, FXAA_POST_PROCESS_ID } from './chunk-ZZ4YQ474.mjs';
12
12
  import { ok, err, RhiError, validateDrawArgs } from '@forgeax/engine-rhi';
@@ -5904,7 +5904,7 @@ function pipelineCreationHint(error) {
5904
5904
  }
5905
5905
  function buildPipelineForMaterialShader(id, entry, ctx, renderState, geometry, vertexEntry, fragmentEntry, defines, passKind = "forward", sampleCount = 1) {
5906
5906
  const label = ctx.label ?? `pbr-pipeline-${id}`;
5907
- const vsEntry = (passKind === "temporal" ? "vs_temporal" : "vs_main");
5907
+ const vsEntry = vertexEntry ?? (passKind === "temporal" ? "vs_temporal" : "vs_main");
5908
5908
  const fsEntry = fragmentEntry ?? (passKind === "temporal" ? "fs_temporal" : passKind === "deferred" ? "fs_gbuffer" : passKind === "shadow-caster" ? "fs_shadow" : "fs_main");
5909
5909
  let source = entry.source;
5910
5910
  const moduleResult = ctx.shaderModuleFactory.createShaderModule({
@@ -11746,6 +11746,118 @@ function inspectStandardLighting(input) {
11746
11746
  }
11747
11747
  return inspectStandardClusterTransport(input.transport, input.prepared);
11748
11748
  }
11749
+ function uploadMaterialUniforms(c) {
11750
+ const {
11751
+ runtime,
11752
+ world,
11753
+ store,
11754
+ pipelineState,
11755
+ validatedOrdered,
11756
+ frameState,
11757
+ materialSlots,
11758
+ materialSlotOwners,
11759
+ materialSlotCount
11760
+ } = c;
11761
+ if (materialSlotCount === 0) return;
11762
+ const cachedMaterialUboPayload = c.materialUboPayloadCache;
11763
+ let materialUboPayload;
11764
+ if (cachedMaterialUboPayload?.materialSlots === materialSlots && cachedMaterialUboPayload.materialSlotCount === materialSlotCount) {
11765
+ materialUboPayload = cachedMaterialUboPayload.payload;
11766
+ } else {
11767
+ materialUboPayload = new Uint8Array(materialSlotCount * MATERIAL_PER_ENTITY_STRIDE);
11768
+ const slotPayload = new Uint8Array(STANDARD_PBR_UBO_SIZE);
11769
+ const slotPayloadF32 = new Float32Array(
11770
+ slotPayload.buffer,
11771
+ slotPayload.byteOffset,
11772
+ slotPayload.byteLength / 4
11773
+ );
11774
+ for (let materialSlot = 0; materialSlot < materialSlots.length; materialSlot += 1) {
11775
+ const mat = materialSlots[materialSlot];
11776
+ const entry = validatedOrdered[materialSlotOwners[materialSlot] ?? -1];
11777
+ if (mat === void 0 || entry === void 0) continue;
11778
+ writePbrMaterialUboPayload(slotPayloadF32, mat);
11779
+ const materialShaderId = mat.materialShaderId;
11780
+ const schema = mat.materialParamSchema ?? (materialShaderId !== void 0 ? runtime.getParamSchema?.(materialShaderId) : void 0);
11781
+ applyParamSnapshotToUbo(slotPayloadF32, schema, mat.paramSnapshot);
11782
+ const processValue = globalThis.process;
11783
+ if (processValue?.env?.FORGEAX_MATERIAL_PIPELINE_DIAGNOSTICS === "1" && (materialShaderId === "forgeax::default-standard-pbr" || materialShaderId === "forgeax::pbr-skin")) {
11784
+ console.error(
11785
+ `[render-material] UBO receipt: ${JSON.stringify({
11786
+ entityIndex: entry.renderableIndex,
11787
+ materialHandle: mat.materialHandle,
11788
+ materialShaderId,
11789
+ clearcoat: slotPayloadF32[32],
11790
+ clearcoatRoughness: slotPayloadF32[33],
11791
+ clearcoatNormalScale: slotPayloadF32[34],
11792
+ paramSnapshot: mat.paramSnapshot
11793
+ })}`
11794
+ );
11795
+ }
11796
+ applyMaterialTextureUvScales(slotPayloadF32, mat, world);
11797
+ {
11798
+ const matHandleRaw = mat.baseColorTexture;
11799
+ if (matHandleRaw !== void 0) {
11800
+ const view = residentTextureView(entry.world ?? world, store, runtime, matHandleRaw);
11801
+ if (view === void 0) {
11802
+ const rawId = matHandleRaw;
11803
+ if (!frameState.warnedMissingBaseColorTextureHandles.has(rawId)) {
11804
+ frameState.warnedMissingBaseColorTextureHandles.add(rawId);
11805
+ console.warn(
11806
+ `[forgeax] baseColor texture ${rawId} missing GPU view, rendering debug pink (shader=${materialShaderId ?? "<none>"} entityIndex=${entry.renderableIndex})`
11807
+ );
11808
+ }
11809
+ runtime.errorRegistry.fire(
11810
+ new RhiError({
11811
+ code: "asset-not-registered",
11812
+ expected: "material baseColor TextureAsset uploaded to GPU",
11813
+ hint: "register + uploadTexture the baseColor texture before draw([world], { cameraOwner: 0, resourceOwner: 0 }); rendering falls back to debug pink until then",
11814
+ detail: { assetHandle: rawId }
11815
+ })
11816
+ );
11817
+ slotPayloadF32[0] = 1;
11818
+ slotPayloadF32[1] = 0.4;
11819
+ slotPayloadF32[2] = 0.7;
11820
+ }
11821
+ }
11822
+ }
11823
+ materialUboPayload.set(slotPayload, materialSlot * MATERIAL_PER_ENTITY_STRIDE);
11824
+ }
11825
+ for (const entry of validatedOrdered) {
11826
+ const mat = entry.source.material;
11827
+ const materialShaderId = mat.materialShaderId;
11828
+ if (materialShaderId !== "forgeax::sprite" && materialShaderId !== "forgeax::sprite-lit")
11829
+ continue;
11830
+ const slicesAndMode = mat.paramSnapshot?.slicesAndMode;
11831
+ if (slicesAndMode === void 0 || slicesAndMode.length < 4) continue;
11832
+ const slicesArr = [
11833
+ slicesAndMode[0] ?? 0,
11834
+ slicesAndMode[1] ?? 0,
11835
+ slicesAndMode[2] ?? 0,
11836
+ slicesAndMode[3] ?? 0
11837
+ ];
11838
+ if (slicesArr[0] === 0 && slicesArr[1] === 0 && slicesArr[2] === 0 && slicesArr[3] === 0)
11839
+ continue;
11840
+ detectNineSliceScaleTooSmall(
11841
+ entry.source.transform.world,
11842
+ slicesArr,
11843
+ entry.renderableIndex,
11844
+ frameState.warnedNineSliceScaleEntities,
11845
+ runtime.metrics
11846
+ );
11847
+ }
11848
+ c.materialUboPayloadCache = {
11849
+ materialSlots,
11850
+ materialSlotCount,
11851
+ payload: materialUboPayload
11852
+ };
11853
+ }
11854
+ const materialUboUpload = runtime.device.queue.writeBuffer(
11855
+ pipelineState.materialUniformBuffer.buffer,
11856
+ 0,
11857
+ materialUboPayload
11858
+ );
11859
+ if (!materialUboUpload.ok) throw materialUboUpload.error;
11860
+ }
11749
11861
 
11750
11862
  // src/volume/temporal.ts
11751
11863
  function resolveVolumeTemporalReset(previous, next, options = {}) {
@@ -14934,7 +15046,11 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
14934
15046
  const materialSlots = dispatchPlan.materialSlots;
14935
15047
  const materialSlotOwners = dispatchPlan.materialSlotOwners;
14936
15048
  const materialSlotCount = dispatchPlan.materialSlotCount;
14937
- const splitLdrSprite = computeSplitLdrSprite(validatedOrdered, tonemapActive);
15049
+ const splitLdrSprite = computeSplitLdrSprite(
15050
+ validatedOrdered,
15051
+ tonemapActive,
15052
+ transparentDispatch
15053
+ );
14938
15054
  let ldrSpritePassView = null;
14939
15055
  if (splitLdrSprite) {
14940
15056
  const unormViewRes = internals.device.createTextureView(currentTexture, {});
@@ -15110,6 +15226,7 @@ function recordFrame(internals, world, cameras, lights, renderables, transparent
15110
15226
  directionalShadowCacheReuse: directionalShadowCache.reuse,
15111
15227
  ...profilePhase !== void 0 ? { profilePhase } : {}
15112
15228
  };
15229
+ uploadMaterialUniforms(passCtx);
15113
15230
  const fallbackReadbackRequest = createReflectionFallbackReadbackRequest(internals, frameState);
15114
15231
  if (fallbackReadbackRequest !== void 0) {
15115
15232
  frameState.reflectionFallbackReadback = fallbackReadbackRequest;
@@ -16685,7 +16802,11 @@ function createRenderSystemRecovery(deps) {
16685
16802
  validated: candidateValidated,
16686
16803
  dispatch: seed.frame.dispatch,
16687
16804
  shadowCastersActive: seed.frame.lights.pointShadow.length > 0 || seed.frame.lights.spot.some((spot) => spot.castShadow === true) || (seed.frame.lights.lightViewProj?.length ?? 0) > 0,
16688
- splitLdrSprite: computeSplitLdrSprite(candidateValidated, camera.tonemap !== "none"),
16805
+ splitLdrSprite: computeSplitLdrSprite(
16806
+ candidateValidated,
16807
+ camera.tonemap !== "none",
16808
+ seed.frame.dispatch
16809
+ ),
16689
16810
  reflectionFallbackAvailable: candidateFrameState.reflectionFallbackDemand === true
16690
16811
  });
16691
16812
  const candidatePostProcessIds = /* @__PURE__ */ new Set([
@@ -23039,6 +23160,18 @@ function createRenderSystem(internals) {
23039
23160
  internals.getPipelineState(),
23040
23161
  persistentRenderScene.materialSnapshotCacheStore(),
23041
23162
  {
23163
+ ...internals.device.caps.backendKind === "null" ? {} : {
23164
+ materialContext: {
23165
+ backend: internals.device.caps.backendKind === "wgpu-webgl2" ? "webgl2" : internals.device.caps.backendKind,
23166
+ capability: internals.device.caps.storageBuffer ? "storage-buffer" : "uniform-fallback",
23167
+ pipeline: "forward",
23168
+ geometry: "mesh",
23169
+ pass: "forward",
23170
+ profile: "forgeax-material-wgsl-v1",
23171
+ toolchain: "naga-oil",
23172
+ instrumentation: "none"
23173
+ }
23174
+ },
23042
23175
  cull: "none",
23043
23176
  renderables: request === "none" ? "none" : "full",
23044
23177
  ...request === "none" || request === "full" ? {} : { renderableEntitiesByWorld: request.entitiesByWorld },
@@ -32073,7 +32206,7 @@ async function makeWebGPURenderer(internals) {
32073
32206
  ...layoutKind === "pbr-skin" ? { layoutKind } : {}
32074
32207
  };
32075
32208
  };
32076
- const buildAndCachePipeline = (cacheKey, entry, label, moduleLabel, isHdr, renderState, topology, stripIndexFormat, variantSet, passKind = "forward", materialShaderId, meshAttributes, sampleCount = 1, colorFormatOverride, depthFormatOverride, vertexLayout, vertexLayoutProjection, shaderModuleMode, layoutKindOverride, additionalColorFormats) => {
32209
+ const buildAndCachePipeline = (cacheKey, entry, label, moduleLabel, isHdr, renderState, topology, stripIndexFormat, variantSet, passKind = "forward", materialShaderId, meshAttributes, sampleCount = 1, colorFormatOverride, depthFormatOverride, vertexLayout, vertexLayoutProjection, shaderModuleMode, layoutKindOverride, additionalColorFormats, vertexEntry, authoredFragmentEntry) => {
32077
32210
  const group2Contract = resolvePipelineGroup2Contract(entry.source);
32078
32211
  const ctx = buildPipelineContext(
32079
32212
  variantSet,
@@ -32089,7 +32222,7 @@ async function makeWebGPURenderer(internals) {
32089
32222
  const currentState = currentPipelineState();
32090
32223
  if (currentState === null) return null;
32091
32224
  const ldrColorFormat = colorFormatOverride ?? currentState.colorAttachmentFormat;
32092
- const fragmentEntry = isHdr && (materialShaderId === "forgeax::sprite" || materialShaderId === "forgeax::sprite-lit") ? "fs_main_hdr" : void 0;
32225
+ const fragmentEntry = authoredFragmentEntry ?? (isHdr && (materialShaderId === "forgeax::sprite" || materialShaderId === "forgeax::sprite-lit") ? "fs_main_hdr" : void 0);
32093
32226
  const built = buildPipelineForMaterialShader(
32094
32227
  cacheKey,
32095
32228
  // The catalog entry is projected into the material-shader entry shape.
@@ -32118,8 +32251,7 @@ async function makeWebGPURenderer(internals) {
32118
32251
  topology,
32119
32252
  ...topology === "line-strip" || topology === "triangle-strip" ? { stripIndexFormat: stripIndexFormat ?? "uint32" } : {}
32120
32253
  } : void 0,
32121
- void 0,
32122
- // vertexEntry — default vs_main
32254
+ vertexEntry,
32123
32255
  fragmentEntry,
32124
32256
  void 0,
32125
32257
  // defines — none
@@ -32139,7 +32271,7 @@ async function makeWebGPURenderer(internals) {
32139
32271
  );
32140
32272
  return built.value;
32141
32273
  };
32142
- const getMaterialShaderPipeline = (materialShaderId, isHdr, renderState, topology, indexFormat, variantSet, passKind = "forward", meshAttributes, sampleCount = 1, colorFormatOverride, shaderUvSetCount, depthFormatOverride, vertexLayout, vertexLayoutProjection, shaderModuleMode = "validated", layoutKindOverride, additionalColorFormats) => {
32274
+ const getMaterialShaderPipeline = (materialShaderId, isHdr, renderState, topology, indexFormat, variantSet, passKind = "forward", meshAttributes, sampleCount = 1, colorFormatOverride, shaderUvSetCount, depthFormatOverride, vertexLayout, vertexLayoutProjection, shaderModuleMode = "validated", layoutKindOverride, additionalColorFormats, vertexEntry, fragmentEntry) => {
32143
32275
  const currentState = currentPipelineState();
32144
32276
  const ldrColorFormat = colorFormatOverride ?? (currentState !== null ? currentState.colorAttachmentFormat : "bgra8unorm-srgb");
32145
32277
  const pipelineShaderId = resolveMaterialShaderBackendArtifactKey(
@@ -32188,7 +32320,13 @@ async function makeWebGPURenderer(internals) {
32188
32320
  const colorFormat = isHdr ? "rgba16float" : ldrColorFormat;
32189
32321
  const isDepthOnlyPass = passKindPolicyTable[passKind]?.shape === "depth-only";
32190
32322
  const spec = {
32191
- shader: { id: pipelineShaderId, passKind, variantSet: effectiveVariantSet },
32323
+ shader: {
32324
+ id: pipelineShaderId,
32325
+ passKind,
32326
+ variantSet: effectiveVariantSet,
32327
+ ...vertexEntry === void 0 ? {} : { vertexEntry },
32328
+ ...fragmentEntry === void 0 ? {} : { fragmentEntry }
32329
+ },
32192
32330
  attachments: {
32193
32331
  colorFormats: additionalColorFormats === void 0 ? colorFormatsForPassKind(passKind, colorFormat) : [colorFormat, ...additionalColorFormats],
32194
32332
  depthFormat: isDepthOnlyPass ? "depth32float" : depthFormatOverride === null ? void 0 : depthFormatOverride ?? "depth24plus-stencil8",
@@ -32365,7 +32503,9 @@ async function makeWebGPURenderer(internals) {
32365
32503
  vertexLayoutProjection,
32366
32504
  shaderModuleMode,
32367
32505
  layoutKindOverride,
32368
- additionalColorFormats
32506
+ additionalColorFormats,
32507
+ vertexEntry,
32508
+ fragmentEntry
32369
32509
  );
32370
32510
  };
32371
32511
  const getMaterialShaderPipelineEntry = (...args) => {