@forgeax/engine-render 0.1.25 → 0.1.27

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 (87) 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-XDP6XE5V.mjs} +104 -56
  16. package/dist/chunk-XDP6XE5V.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 +27 -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/__tests__/standard-pbr-ubo-layout.unit.test.ts +68 -1
  70. package/src/record/frame.ts +7 -1
  71. package/src/record/main-pass-geometry.ts +340 -279
  72. package/src/record/main-pass-material.ts +87 -2
  73. package/src/record/main-pass-sprite-draws.ts +65 -168
  74. package/src/record/main-pass.ts +24 -246
  75. package/src/record/material-uniforms.ts +186 -0
  76. package/src/record/render-context.ts +4 -0
  77. package/src/record/shadow-pass.ts +86 -28
  78. package/src/recovery/render-system-candidate.ts +5 -1
  79. package/src/render-system-extract-tail.ts +54 -13
  80. package/src/render-system-extract.ts +103 -64
  81. package/src/render-system.ts +19 -0
  82. package/dist/assembly/material/pipeline-projection.d.ts +0 -30
  83. package/dist/assembly/material/pipeline-projection.d.ts.map +0 -1
  84. package/dist/chunk-JSEDTZYS.mjs.map +0 -1
  85. package/dist/chunk-N3RT2EUR.mjs.map +0 -1
  86. package/dist/chunk-TCLDX7SZ.mjs.map +0 -1
  87. package/src/assembly/material/pipeline-projection.ts +0 -63
@@ -248,7 +248,11 @@ export function cacheKeyOf(spec: PipelineSpec): string {
248
248
  stripSegment,
249
249
  `vl:${vlDigest}`,
250
250
  renderStateHash(renderState),
251
- ].join(':') + uvSetCountSegment
251
+ ].join(':') +
252
+ uvSetCountSegment +
253
+ (shader.vertexEntry === undefined && shader.fragmentEntry === undefined
254
+ ? ''
255
+ : `:entries:${JSON.stringify([shader.vertexEntry ?? null, shader.fragmentEntry ?? null])}`)
252
256
  );
253
257
  }
254
258
 
@@ -417,7 +421,7 @@ export function buildPipelineDescriptor(
417
421
  const descriptor: Record<string, unknown> = {
418
422
  vertex: {
419
423
  module: modules.vertex,
420
- entryPoint: modules.vertexEntryPoint ?? 'vs_main',
424
+ entryPoint: spec.shader.vertexEntry ?? modules.vertexEntryPoint ?? 'vs_main',
421
425
  buffers: vertexBuffers,
422
426
  },
423
427
  };
@@ -426,7 +430,7 @@ export function buildPipelineDescriptor(
426
430
  if (attachments.colorFormats.length > 0) {
427
431
  descriptor.fragment = {
428
432
  module: modules.fragment,
429
- entryPoint: modules.fragmentEntryPoint ?? 'fs_main',
433
+ entryPoint: spec.shader.fragmentEntry ?? modules.fragmentEntryPoint ?? 'fs_main',
430
434
  targets: attachments.colorFormats.map((fmt) => {
431
435
  const target: Record<string, unknown> = { format: fmt };
432
436
  if (renderState?.blend !== undefined) {
@@ -3,7 +3,8 @@ import { vec3 } from '@forgeax/engine-math';
3
3
  import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA } from '@forgeax/engine-shader';
4
4
  import { derive } from '@forgeax/engine-types';
5
5
  import { describe, expect, it } from 'vitest';
6
- import type { MaterialSnapshot } from '../../render-system-extract';
6
+ import { Materials } from '../../materials';
7
+ import { type MaterialSnapshot, materialParamSchemaForMaterial } from '../../render-system-extract';
7
8
  import { applyMaterialTextureUvScales, buildPbrMaterialUboPayload } from '../main-pass-material';
8
9
 
9
10
  describe('Standard PBR UBO layout', () => {
@@ -69,6 +70,72 @@ describe('Standard PBR UBO layout', () => {
69
70
  );
70
71
  });
71
72
 
73
+ it('writes custom Standard Surface parameters at their published offsets', () => {
74
+ const custom = Materials.standard({
75
+ surfaceModule: 'game_3d::rusted_iron_surface',
76
+ colorSpace: 'linear',
77
+ parameters: [
78
+ { name: 'ironColor', type: 'color' },
79
+ { name: 'rustDark', type: 'color' },
80
+ { name: 'rustBright', type: 'color' },
81
+ { name: 'noiseScale', type: 'f32' },
82
+ ],
83
+ values: {
84
+ ironColor: [0.4, 0.45, 0.47, 1],
85
+ rustDark: [0.42, 0.085, 0.018, 1],
86
+ rustBright: [0.95, 0.34, 0.055, 1],
87
+ noiseScale: 1.85,
88
+ },
89
+ });
90
+ const schema = materialParamSchemaForMaterial(
91
+ custom.parameters ?? [],
92
+ 'forgeax::default-standard-pbr',
93
+ custom.passes ?? [],
94
+ );
95
+ const material = {
96
+ baseColor: vec3.create(1, 1, 1),
97
+ metallic: 0,
98
+ roughness: 0.5,
99
+ materialShaderId: 'sha256:rusted-iron-forward',
100
+ materialParamSchema: schema,
101
+ paramSnapshot: {
102
+ ironColor: [0.4, 0.45, 0.47, 1],
103
+ rustDark: [0.42, 0.085, 0.018, 1],
104
+ rustBright: [0.95, 0.34, 0.055, 1],
105
+ noiseScale: 1.85,
106
+ },
107
+ } satisfies MaterialSnapshot;
108
+ const f32 = new Float32Array(buildPbrMaterialUboPayload(material).buffer);
109
+ const derived = derive(schema);
110
+ const numericOffsets = new Map(
111
+ derived.numericMembers.map((member) => [member.name, member.offset / 4]),
112
+ );
113
+
114
+ expect(numericOffsets.get('ironColor')).toBeDefined();
115
+ expect(numericOffsets.get('rustDark')).toBeDefined();
116
+ expect(numericOffsets.get('rustBright')).toBeDefined();
117
+ expect(numericOffsets.get('noiseScale')).toBeDefined();
118
+ const requireOffset = (name: string): number => {
119
+ const offset = numericOffsets.get(name);
120
+ if (offset === undefined) throw new Error(`missing numeric offset for ${name}`);
121
+ return offset;
122
+ };
123
+ const ironColorOffset = requireOffset('ironColor');
124
+ const rustDarkOffset = requireOffset('rustDark');
125
+ const rustBrightOffset = requireOffset('rustBright');
126
+ const noiseScaleOffset = requireOffset('noiseScale');
127
+ expect(f32.slice(ironColorOffset, ironColorOffset + 4)).toEqual(
128
+ new Float32Array([0.4, 0.45, 0.47, 1]),
129
+ );
130
+ expect(f32.slice(rustDarkOffset, rustDarkOffset + 4)).toEqual(
131
+ new Float32Array([0.42, 0.085, 0.018, 1]),
132
+ );
133
+ expect(f32.slice(rustBrightOffset, rustBrightOffset + 4)).toEqual(
134
+ new Float32Array([0.95, 0.34, 0.055, 1]),
135
+ );
136
+ expect(f32[noiseScaleOffset]).toBeCloseTo(1.85, 6);
137
+ });
138
+
72
139
  it('uses all seven user-region identity coordinate records in the no-snapshot fallback', () => {
73
140
  const material = {
74
141
  baseColor: vec3.create(0.7, 0.7, 0.7),
@@ -1,3 +1,4 @@
1
+ import { uploadMaterialUniforms } from './material-uniforms';
1
2
  // @forgeax/engine-runtime - RenderSystem record stage: frame.
2
3
  // Extracted from render-system-record.ts (feat-20260704 M3/w17, pure move).
3
4
 
@@ -1925,7 +1926,11 @@ export function recordFrame(
1925
1926
  // the swap-chain fallback uses its raw storage view. The encoder and
1926
1927
  // sprite PSO must use the same resolved format because WebGPU requires
1927
1928
  // attachment and pipeline target formats to match.
1928
- const splitLdrSprite = computeSplitLdrSprite(validatedOrdered, tonemapActive);
1929
+ const splitLdrSprite = computeSplitLdrSprite(
1930
+ validatedOrdered,
1931
+ tonemapActive,
1932
+ transparentDispatch,
1933
+ );
1929
1934
  let ldrSpritePassView: TextureView | null = null;
1930
1935
  if (splitLdrSprite) {
1931
1936
  const unormViewRes = internals.device.createTextureView(currentTexture, {});
@@ -2155,6 +2160,7 @@ export function recordFrame(
2155
2160
  directionalShadowCacheReuse: directionalShadowCache.reuse,
2156
2161
  ...(profilePhase !== undefined ? { profilePhase } : {}),
2157
2162
  };
2163
+ uploadMaterialUniforms(passCtx);
2158
2164
  const fallbackReadbackRequest = createReflectionFallbackReadbackRequest(internals, frameState);
2159
2165
  if (fallbackReadbackRequest !== undefined) {
2160
2166
  frameState.reflectionFallbackReadback = fallbackReadbackRequest;