@forgeax/engine-shader 0.1.21 → 0.1.24

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 (83) hide show
  1. package/README.md +14 -5
  2. package/dist/ShaderRegistry.d.ts.map +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.mjs +33042 -55
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/ltc/provenance.d.ts +17 -0
  8. package/dist/ltc/provenance.d.ts.map +1 -0
  9. package/dist/ltc/tables.d.ts +22 -0
  10. package/dist/ltc/tables.d.ts.map +1 -0
  11. package/dist/material/artifact-types.d.ts +52 -0
  12. package/dist/material/artifact-types.d.ts.map +1 -1
  13. package/dist/material-schemas.d.ts +36 -0
  14. package/dist/material-schemas.d.ts.map +1 -1
  15. package/dist/register-default-sprite-lit.d.ts +3 -6
  16. package/dist/register-default-sprite-lit.d.ts.map +1 -1
  17. package/dist/types.d.ts +2 -1
  18. package/dist/types.d.ts.map +1 -1
  19. package/package.json +4 -4
  20. package/src/ShaderRegistry.ts +0 -17
  21. package/src/__tests__/default-standard-pbr-alpha.unit.test.ts +9 -3
  22. package/src/__tests__/default-standard-pbr-transmission.unit.test.ts +67 -122
  23. package/src/__tests__/deferred-lighting-ssao.test.ts +3 -3
  24. package/src/__tests__/direct-light-layout.unit.test.ts +40 -0
  25. package/src/__tests__/ibl-irradiance.unit.test.ts +16 -4
  26. package/src/__tests__/ibl-sampling.unit.test.ts +3 -4
  27. package/src/__tests__/lighting-directional.unit.test.ts +36 -0
  28. package/src/__tests__/lighting-point-spot-volume.unit.test.ts +8 -2
  29. package/src/__tests__/lighting-punctual.unit.test.ts +40 -5
  30. package/src/__tests__/lighting-spot-volume-attenuation.unit.test.ts +1 -1
  31. package/src/__tests__/ltc-provenance.unit.test.ts +33 -0
  32. package/src/__tests__/manifest.fixture.json +33 -0
  33. package/src/__tests__/material-builtins.unit.test.ts +21 -3
  34. package/src/__tests__/material-contract.unit.test.ts +188 -14
  35. package/src/__tests__/physical-clearcoat.unit.test.ts +65 -0
  36. package/src/__tests__/probe-lighting-composition.unit.test.ts +39 -0
  37. package/src/__tests__/rect-area-brdf.unit.test.ts +36 -0
  38. package/src/__tests__/reflection-probe-sampling.unit.test.ts +24 -2
  39. package/src/__tests__/shader-manifest-transmission.unit.test.ts +8 -10
  40. package/src/__tests__/shader.unit.test.ts +54 -85
  41. package/src/__tests__/spot-cookie-composition.unit.test.ts +58 -0
  42. package/src/__tests__/spot-modifier-composition.unit.test.ts +19 -0
  43. package/src/__tests__/sprite-variants.unit.test.ts +4 -1
  44. package/src/__tests__/standard-webgl2-varying-budget.unit.test.ts +17 -0
  45. package/src/__tests__/surface-v1-negative.unit.test.ts +37 -0
  46. package/src/__tests__/surface-v1.unit.test.ts +83 -0
  47. package/src/__tests__/transmission-thickness-scale.unit.test.ts +2 -6
  48. package/src/__tests__/vertex-color-variant.unit.test.ts +16 -5
  49. package/src/brdf.wgsl +115 -1
  50. package/src/common.wgsl +53 -79
  51. package/src/default-standard-pbr-skin.wgsl +687 -144
  52. package/src/default-standard-pbr.wgsl +600 -247
  53. package/src/default_standard_surface.wgsl +88 -0
  54. package/src/hdrp-cluster-forward.wgsl +225 -0
  55. package/src/ibl-irradiance.wgsl +47 -9
  56. package/src/ibl-prefilter.wgsl +13 -3
  57. package/src/ibl-sampling.wgsl +2 -2
  58. package/src/ibl-shared.wgsl +9 -2
  59. package/src/index.ts +23 -0
  60. package/src/lighting-directional.wgsl +9 -117
  61. package/src/lighting-probe.wgsl +51 -0
  62. package/src/lighting-punctual.wgsl +21 -11
  63. package/src/lighting-rect-area.wgsl +162 -0
  64. package/src/lighting-spot-modifiers.wgsl +100 -0
  65. package/src/lighting-spot-projector.wgsl +31 -0
  66. package/src/ltc/provenance.ts +19 -0
  67. package/src/ltc/tables.ts +2831 -0
  68. package/src/material/artifact-types.ts +137 -0
  69. package/src/material/physical/anisotropy.wgsl +26 -0
  70. package/src/material/physical/clearcoat.wgsl +24 -0
  71. package/src/material/physical/iridescence.wgsl +23 -0
  72. package/src/material/physical/sheen.wgsl +17 -0
  73. package/src/material-schemas.ts +77 -30
  74. package/src/register-default-sprite-lit.ts +3 -6
  75. package/src/register-default-standard-pbr-skin.ts +2 -2
  76. package/src/sprite-lit.wgsl +3 -3
  77. package/src/sprite.wgsl +1 -1
  78. package/src/standard-cluster.wgsl +80 -78
  79. package/src/surface_v1.wgsl +26 -0
  80. package/src/types.ts +2 -1
  81. package/src/volume/volume-inject.wgsl +34 -36
  82. package/src/volume/volume-integrate.wgsl +48 -38
  83. package/dist/.tsbuildinfo +0 -1
@@ -1,14 +1,151 @@
1
1
  import type { BindGroupLayoutDescriptor } from '@forgeax/engine-types';
2
2
 
3
+ export interface MaterialShaderResourceSlot {
4
+ readonly name: string;
5
+ readonly parameter: string;
6
+ readonly kind: 'sampler' | 'texture';
7
+ readonly group: number;
8
+ readonly binding: number;
9
+ }
10
+
11
+ export interface MaterialShaderVertexInput {
12
+ readonly semantic: string;
13
+ readonly location: number;
14
+ readonly format: string;
15
+ }
16
+
17
+ export interface MaterialShaderArtifactReceipt {
18
+ readonly directEntry: string;
19
+ readonly sceneIndexEntry: string;
20
+ readonly materialRow: {
21
+ readonly byteLength: number;
22
+ readonly fields: readonly string[];
23
+ };
24
+ readonly resourceSlots: readonly MaterialShaderResourceSlot[];
25
+ readonly uvSets: readonly { readonly parameter: string; readonly set: number }[];
26
+ readonly vertexInputs: readonly MaterialShaderVertexInput[];
27
+ readonly alphaMask: { readonly cutoff: string; readonly source: string };
28
+ readonly skinPaletteAddress?: {
29
+ readonly group: number;
30
+ readonly binding: number;
31
+ readonly stride: number;
32
+ };
33
+ readonly reflection: {
34
+ readonly layoutIdentity: string;
35
+ readonly resourceSlots: readonly MaterialShaderResourceSlot[];
36
+ readonly vertexInputs: readonly MaterialShaderVertexInput[];
37
+ };
38
+ readonly receiptIdentity: string;
39
+ readonly generation: number;
40
+ }
41
+
3
42
  export interface MaterialShaderArtifact {
4
43
  readonly material: string;
5
44
  readonly pass: string;
6
45
  readonly wgsl: string;
7
46
  readonly layoutIdentity: string;
47
+ /** Naga-reflected UV set count used to derive clamp-to-last vertex aliases. */
48
+ readonly uvSetCount?: number;
8
49
  readonly bindings: readonly BindGroupLayoutDescriptor[];
9
50
  readonly deps: readonly string[];
10
51
  readonly vertexInputs: readonly Readonly<Record<string, unknown>>[];
11
52
  readonly specializationKey?: string;
53
+ /** Producer-owned ABI facts shared by direct and scene-index consumers. */
54
+ readonly receipt?: MaterialShaderArtifactReceipt;
55
+ }
56
+
57
+ const STANDARD_PBR_TEXTURES = [
58
+ 'baseColorTexture',
59
+ 'metallicRoughnessTexture',
60
+ 'normalTexture',
61
+ 'specularColorTexture',
62
+ 'emissiveTexture',
63
+ 'occlusionTexture',
64
+ 'transmissionTexture',
65
+ 'thicknessTexture',
66
+ ] as const;
67
+
68
+ const STANDARD_PBR_NUMERIC_FIELDS = [
69
+ 'baseColor',
70
+ 'metallic',
71
+ 'roughness',
72
+ 'metallicChannel',
73
+ 'roughnessChannel',
74
+ 'aoChannel',
75
+ 'extraChannel',
76
+ 'emissive',
77
+ 'emissiveIntensity',
78
+ 'occlusionStrength',
79
+ 'alphaCutoff',
80
+ 'clearcoat',
81
+ 'clearcoatRoughness',
82
+ 'specularColor',
83
+ 'normalScale',
84
+ 'transmission',
85
+ 'ior',
86
+ 'thickness',
87
+ 'attenuationColor',
88
+ 'attenuationDistance',
89
+ ] as const;
90
+
91
+ const STANDARD_PBR_VERTEX_INPUTS: readonly MaterialShaderVertexInput[] = [
92
+ { semantic: 'position', location: 0, format: 'float32x3' },
93
+ { semantic: 'normal', location: 1, format: 'float32x3' },
94
+ { semantic: 'uv', location: 2, format: 'float32x2' },
95
+ { semantic: 'tangent', location: 3, format: 'float32x4' },
96
+ ];
97
+
98
+ function standardPbrResourceSlots(): MaterialShaderResourceSlot[] {
99
+ return STANDARD_PBR_TEXTURES.flatMap((parameter, index) => [
100
+ {
101
+ name: `${parameter}_sampler`,
102
+ parameter,
103
+ kind: 'sampler' as const,
104
+ group: 1,
105
+ binding: index * 2 + 1,
106
+ },
107
+ {
108
+ name: parameter,
109
+ parameter,
110
+ kind: 'texture' as const,
111
+ group: 1,
112
+ binding: index * 2 + 2,
113
+ },
114
+ ]);
115
+ }
116
+
117
+ /**
118
+ * Builds the one Standard PBR ABI receipt consumed by both material lanes.
119
+ * The skinned module uses the same material producer and only adds its palette
120
+ * address; it must retain the same receipt identity for material compatibility.
121
+ */
122
+ export function createStandardPbrArtifactReceipt(skinned = false): MaterialShaderArtifactReceipt {
123
+ const resourceSlots = standardPbrResourceSlots();
124
+ const uvSets = STANDARD_PBR_TEXTURES.map((parameter) => ({ parameter, set: 0 }));
125
+ const vertexInputs = skinned
126
+ ? [
127
+ ...STANDARD_PBR_VERTEX_INPUTS,
128
+ { semantic: 'skinIndex', location: 4, format: 'uint16x4' },
129
+ { semantic: 'skinWeight', location: 5, format: 'float32x4' },
130
+ ]
131
+ : [...STANDARD_PBR_VERTEX_INPUTS];
132
+ return {
133
+ directEntry: 'vs_main',
134
+ sceneIndexEntry: 'vs_scene_index',
135
+ materialRow: { byteLength: 384, fields: [...STANDARD_PBR_NUMERIC_FIELDS] },
136
+ resourceSlots,
137
+ uvSets,
138
+ vertexInputs,
139
+ alphaMask: { cutoff: 'alphaCutoff', source: 'baseColor.a' },
140
+ ...(skinned ? { skinPaletteAddress: { group: 2, binding: 1, stride: 64 } } : {}),
141
+ reflection: {
142
+ layoutIdentity: 'standard-pbr/material-row-v1',
143
+ resourceSlots,
144
+ vertexInputs,
145
+ },
146
+ receiptIdentity: 'standard-pbr/material-row-v1',
147
+ generation: 1,
148
+ };
12
149
  }
13
150
 
14
151
  export function isMaterialShaderArtifact(value: unknown): value is MaterialShaderArtifact {
@@ -0,0 +1,26 @@
1
+ #define_import_path forgeax_pbr::anisotropy
2
+
3
+ // Engine-owned anisotropy helpers. The root contract supplies strength and
4
+ // rotation; the map (when present) supplies tangent direction in RG and a
5
+ // strength multiplier in B. Keeping the frame operation here means the
6
+ // Standard evaluator and custom Surface share one deterministic seam.
7
+ fn evaluateAnisotropicNormal(
8
+ normal : vec3<f32>,
9
+ tangent : vec4<f32>,
10
+ strength : f32,
11
+ rotation : f32,
12
+ direction : vec2<f32>,
13
+ ) -> vec3<f32> {
14
+ let frameTangent = normalize(tangent.xyz);
15
+ let handedBitangent = normalize(cross(normal, frameTangent)) * select(-1.0, 1.0, tangent.w >= 0.0);
16
+ var mapDirection = vec2<f32>(1.0, 0.0);
17
+ if (dot(direction, direction) >= 1e-6) {
18
+ mapDirection = normalize(direction);
19
+ }
20
+ let mappedTangent = normalize(frameTangent * mapDirection.x + handedBitangent * mapDirection.y);
21
+ let mappedBitangent = normalize(cross(normal, mappedTangent)) * select(-1.0, 1.0, tangent.w >= 0.0);
22
+ let axis = normalize(mappedTangent * cos(rotation) + mappedBitangent * sin(rotation));
23
+ // A bounded bent normal preserves the zero-strength isotropic path while
24
+ // moving only the base specular highlight for non-zero anisotropy.
25
+ return normalize(normal + axis * clamp(strength, -0.999, 0.999) * 0.35);
26
+ }
@@ -0,0 +1,24 @@
1
+ #define_import_path forgeax_pbr::clearcoat
2
+
3
+ // Clearcoat is the terminal physical layer. Its Fresnel term owns both the
4
+ // attenuation of lower layers and the weight of the coat radiance.
5
+ // The root supplies clearcoatRoughness and clearcoatNormalScale after their
6
+ // texture projections; this module deliberately owns only layer energy.
7
+ fn evaluateClearcoatFresnel(viewCosine : f32, clearcoatFactor : f32) -> f32 {
8
+ let cosine = clamp(viewCosine, 0.0, 1.0);
9
+ let oneMinusCosine = 1.0 - cosine;
10
+ let dielectricFresnel = 0.04 + 0.96 * oneMinusCosine * oneMinusCosine *
11
+ oneMinusCosine * oneMinusCosine * oneMinusCosine;
12
+ return clamp(clearcoatFactor, 0.0, 1.0) * dielectricFresnel;
13
+ }
14
+
15
+ fn evaluateClearcoatLayer(
16
+ baseRadiance : vec3<f32>,
17
+ coatRadiance : vec3<f32>,
18
+ viewCosine : f32,
19
+ clearcoatFactor : f32,
20
+ ) -> vec3<f32> {
21
+ let fresnel = evaluateClearcoatFresnel(viewCosine, clearcoatFactor);
22
+ let attenuatedBase = baseRadiance * (1.0 - fresnel);
23
+ return attenuatedBase + coatRadiance * fresnel;
24
+ }
@@ -0,0 +1,23 @@
1
+ #define_import_path forgeax_pbr::iridescence
2
+
3
+ // Bounded RGB thin-film Fresnel approximation. Thickness is deliberately
4
+ // not clamped to min/max order: the glTF contract permits inverted bounds and
5
+ // the caller supplies the authored interval verbatim.
6
+ fn evaluateIridescenceFresnel(
7
+ baseF0 : vec3<f32>,
8
+ strength : f32,
9
+ filmIor : f32,
10
+ thicknessNanometres : f32,
11
+ ) -> vec3<f32> {
12
+ let safeStrength = clamp(strength, 0.0, 1.0);
13
+ let safeIor = max(filmIor, 1.0);
14
+ let base = clamp((safeIor - 1.0) / (safeIor + 1.0), 0.0, 1.0);
15
+ let phase = thicknessNanometres * 0.018;
16
+ let spectral = vec3<f32>(
17
+ 0.5 + 0.5 * cos(phase),
18
+ 0.5 + 0.5 * cos(phase + 2.0943952),
19
+ 0.5 + 0.5 * cos(phase + 4.1887903),
20
+ );
21
+ let film = clamp(vec3<f32>(base) * spectral, vec3<f32>(0.0), vec3<f32>(1.0));
22
+ return clamp(mix(baseF0, film, safeStrength), vec3<f32>(0.0), vec3<f32>(1.0));
23
+ }
@@ -0,0 +1,17 @@
1
+ #define_import_path forgeax_pbr::sheen
2
+
3
+ // Charlie-like grazing lobe approximation with explicit energy compensation.
4
+ // It is evaluated below clearcoat, so the caller attenuates this result when
5
+ // the top coat Fresnel is applied.
6
+ fn evaluateSheenLayer(
7
+ baseRadiance : vec3<f32>,
8
+ sheenColor : vec3<f32>,
9
+ sheenRoughness : f32,
10
+ viewCosine : f32,
11
+ ) -> vec3<f32> {
12
+ let roughness = clamp(sheenRoughness, 0.04, 1.0);
13
+ let grazing = pow(1.0 - clamp(viewCosine, 0.0, 1.0), 2.0);
14
+ let lobe = grazing * (1.0 - 0.5 * roughness);
15
+ let energy = clamp(max(max(sheenColor.r, sheenColor.g), sheenColor.b), 0.0, 1.0);
16
+ return baseRadiance * (1.0 - energy * lobe * 0.5) + sheenColor * lobe;
17
+ }
@@ -1,38 +1,85 @@
1
1
  import type { ParamSchemaEntry } from '@forgeax/engine-types';
2
+ import {
3
+ STANDARD_MATERIAL_PARAM_SCHEMA,
4
+ STANDARD_PHYSICAL_PARAMETER_NAMES,
5
+ } from '@forgeax/engine-types';
6
+ import {
7
+ createStandardPbrArtifactReceipt,
8
+ type MaterialShaderArtifactReceipt,
9
+ } from './material/artifact-types.js';
2
10
 
3
11
  export const STANDARD_PBR_ALPHA_CUTOFF_DEFAULT = 0;
4
12
 
5
13
  /** Shared material contract for the standard PBR and skinned PBR shaders. */
6
- export const DEFAULT_STANDARD_PBR_PARAM_SCHEMA: readonly ParamSchemaEntry[] = [
7
- { name: 'baseColor', type: 'color', default: [1, 1, 1, 1] },
8
- { name: 'metallic', type: 'f32', default: 0 },
9
- { name: 'roughness', type: 'f32', default: 0.5 },
10
- { name: 'metallicChannel', type: 'f32', default: 2 },
11
- { name: 'roughnessChannel', type: 'f32', default: 1 },
12
- { name: 'aoChannel', type: 'f32', default: 0 },
13
- { name: 'extraChannel', type: 'f32', default: 0 },
14
- { name: 'emissive', type: 'vec3', colorSpace: 'srgb', default: [0, 0, 0] },
15
- { name: 'emissiveIntensity', type: 'f32', default: 0 },
16
- { name: 'occlusionStrength', type: 'f32', default: 1 },
17
- { name: 'alphaCutoff', type: 'f32', default: STANDARD_PBR_ALPHA_CUTOFF_DEFAULT },
18
- { name: 'clearcoat', type: 'f32', default: 0 },
19
- { name: 'clearcoatRoughness', type: 'f32', default: 0.5 },
20
- { name: 'specularTint', type: 'vec3', colorSpace: 'srgb', default: [1, 1, 1] },
21
- { name: 'normalScale', type: 'f32', default: 1 },
22
- { name: 'transmission', type: 'f32', default: 0 },
23
- { name: 'ior', type: 'f32', default: 1.5 },
24
- { name: 'thickness', type: 'f32', default: 0 },
25
- { name: 'attenuationColor', type: 'vec3', colorSpace: 'linear', default: [1, 1, 1] },
26
- { name: 'attenuationDistance', type: 'f32' },
27
- { name: 'baseColorTexture', type: 'texture2d' },
28
- { name: 'metallicRoughnessTexture', type: 'texture2d' },
29
- { name: 'normalTexture', type: 'texture2d' },
30
- { name: 'specularTintTexture', type: 'texture2d' },
31
- { name: 'emissiveTexture', type: 'texture2d' },
32
- { name: 'occlusionTexture', type: 'texture2d' },
33
- { name: 'transmissionTexture', type: 'texture2d' },
34
- { name: 'thicknessTexture', type: 'texture2d' },
35
- ];
14
+ export const DEFAULT_STANDARD_PBR_PARAM_SCHEMA = STANDARD_MATERIAL_PARAM_SCHEMA;
15
+
16
+ export type { StandardPhysicalTextureField } from '@forgeax/engine-types';
17
+ /**
18
+ * Backward-compatible export name for callers that need the physical
19
+ * projection. Every entry is selected from the Standard root schema above;
20
+ * no independent defaults or binding inventory can drift from it.
21
+ */
22
+ /**
23
+ * Stable physical texture injection order. The order is part of the
24
+ * Standard template's resource ABI and is derived from the root schema by
25
+ * `standardPhysicalTextureFields`; render/cook must not maintain another
26
+ * field inventory.
27
+ */
28
+ export {
29
+ STANDARD_PHYSICAL_TEXTURE_FIELDS,
30
+ standardPhysicalTextureFields,
31
+ } from '@forgeax/engine-types';
32
+
33
+ export const STANDARD_PHYSICAL_LAYER_PARAM_SCHEMA: readonly ParamSchemaEntry[] =
34
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter((entry) =>
35
+ STANDARD_PHYSICAL_PARAMETER_NAMES.has(entry.name),
36
+ );
37
+
38
+ /**
39
+ * Canonical static Standard entry. It deliberately contains only the base
40
+ * contract (including the specular extension) so a base-only material keeps
41
+ * its Deferred path and carries no second-stage physical resources.
42
+ */
43
+ export const STANDARD_BASE_PARAM_SCHEMA: readonly ParamSchemaEntry[] =
44
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter(
45
+ (entry) =>
46
+ !STANDARD_PHYSICAL_PARAMETER_NAMES.has(entry.name) &&
47
+ ![
48
+ 'transmission',
49
+ 'thickness',
50
+ 'attenuationColor',
51
+ 'attenuationDistance',
52
+ 'transmissionTexture',
53
+ 'thicknessTexture',
54
+ ].includes(entry.name),
55
+ );
56
+
57
+ /**
58
+ * Canonical boot-time user region for the shared Standard material BGL.
59
+ *
60
+ * It is still a projection of the root schema, but unlike the author-facing
61
+ * base-only projection it retains the pre-existing transmission texture pair.
62
+ * The template reserves those two pairs before the IBL/backdrop injection so
63
+ * a base-only shader and a transmissive shader can share one boot layout;
64
+ * physical texture pairs are never included here and are appended only for a
65
+ * root contract that declares them.
66
+ */
67
+ export const STANDARD_PIPELINE_PARAM_SCHEMA: readonly ParamSchemaEntry[] =
68
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter(
69
+ // The canonical Standard UBO keeps every numeric root coordinate,
70
+ // including the physical-layer tail. Physical map pairs are engine-owned
71
+ // resources and are injected after the stable user region.
72
+ (entry) =>
73
+ !(STANDARD_PHYSICAL_PARAMETER_NAMES.has(entry.name) && entry.type.startsWith('texture')),
74
+ );
75
+
76
+ /** The single producer receipt shared by direct and scene-index Standard PBR. */
77
+ export const STANDARD_PBR_ARTIFACT_RECEIPT: MaterialShaderArtifactReceipt =
78
+ createStandardPbrArtifactReceipt();
79
+
80
+ /** Skinned Standard PBR keeps the material receipt identity and adds palette ABI. */
81
+ export const STANDARD_PBR_SKIN_ARTIFACT_RECEIPT: MaterialShaderArtifactReceipt =
82
+ createStandardPbrArtifactReceipt(true);
36
83
 
37
84
  export const DEFAULT_UNLIT_PARAM_SCHEMA: readonly ParamSchemaEntry[] = [
38
85
  { name: 'baseColor', type: 'color', default: [1, 1, 1, 1] },
@@ -56,12 +56,9 @@ export interface SpriteLitCaps {
56
56
  * compiled by @forgeax/engine-vite-plugin-shader at build time and surfaced
57
57
  * in manifest.json. The caller reads it from the manifest entries.
58
58
  *
59
- * `caps.storageBuffer` switches the runtime BGL buffer types for
60
- * @group(0) bindings 1+2 (pointLightsBuffer / spotLightsBuffer):
61
- * `false` -> uniform fallback (AC-10 WebGL2 path); `true` -> read-only-storage.
62
- * The BGL itself is built downstream in runtime/pbr-pipeline.ts (sprite-lit
63
- * reuses pbr-view / pbr-mesh-array / pbr-instances unchanged; AC-07
64
- * BGL byte-identical).
59
+ * `caps.storageBuffer` is retained for the shared mesh/instance layout
60
+ * selection. Sprite-lit local lighting reads the same Standard Cluster group
61
+ * as PBR; the view group has no direct point/spot arrays.
65
62
  *
66
63
  * @param registry ShaderRegistry instance (engine boot path).
67
64
  * @param composedWgsl Post-naga_oil composed WGSL source string.
@@ -13,7 +13,7 @@
13
13
  // - R-10: paramSchema reuses default-standard-pbr schema (same params)
14
14
 
15
15
  import type { ShaderRegistry } from './index.js';
16
- import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA } from './material-schemas.js';
16
+ import { STANDARD_PIPELINE_PARAM_SCHEMA } from './material-schemas.js';
17
17
 
18
18
  /**
19
19
  * paramSchema for forgeax::pbr-skin — mirrors default-standard-pbr 8 fields.
@@ -69,6 +69,6 @@ export function registerDefaultStandardPbrSkin(
69
69
  void caps;
70
70
  registry.installMaterialArtifact(RESERVED_ID, {
71
71
  source: composedWgsl,
72
- paramSchema: DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
72
+ paramSchema: STANDARD_PIPELINE_PARAM_SCHEMA,
73
73
  });
74
74
  }
@@ -2,7 +2,7 @@
2
2
  #pragma variant_axis CLUSTER_FORWARD_AVAILABLE
3
3
  #define_import_path forgeax_material::sprite-lit
4
4
 
5
- #import forgeax_view::common::{View, Mesh, InstanceData, view, meshes, instances, sampleMaterialTexture}
5
+ #import forgeax_view::common::{View, Mesh, InstanceData, view, meshes, instances, sampleMaterialTexture, packSceneTemporal}
6
6
  #import forgeax_scene_temporal::{packSceneTemporalV1, sceneViewZ}
7
7
  #ifdef CLUSTER_FORWARD_AVAILABLE
8
8
  #import forgeax_standard::cluster::{evaluateStandardClusterLights}
@@ -39,11 +39,11 @@
39
39
  // 1 string change in MaterialAsset.passes[0].shader).
40
40
  //
41
41
  // Bindings (byte-identical to sprite.wgsl so the 4 BindGroupLayout chain is
42
- // reused without a per-pipeline BGL; the 4 PBR-unused entries 3..6 bind
42
+ // reused without a per-pipeline BGL; the PBR-unused entries 3..6 bind
43
43
  // pipelineState.defaultSampler + .defaultWhiteTextureView on the host side):
44
44
  //
45
45
  // @group(0) @binding(0) view uniform
46
- // @group(0) @binding(1..2) Standard Cluster storage (selected variant)
46
+ // @group(2) @binding(3..6) Standard Cluster storage (selected variant)
47
47
  // @group(1) @binding(0) material uniform (sprite layout
48
48
  // colorTint /
49
49
  // region /
package/src/sprite.wgsl CHANGED
@@ -152,7 +152,7 @@ fn resolveSpriteVertex(in : VsIn, idx : u32, vertex_index : u32) -> SpriteVertex
152
152
  // pivotAndSize.zw scaled the local quad AND the world matrix also scaled
153
153
  // it, producing the scale^2 visual size debt that research F-4 flagged.
154
154
  // Post-w11 there is one and only one scale source: the entity's
155
- // Transform.world. The mesh's built-in vertex.pos is NOT consumed (sprite
155
+ // GlobalTransform.world. The mesh's built-in vertex.pos is NOT consumed (sprite
156
156
  // geometry is fully re-derived from uv + pivot) so HANDLE_QUAD's mesh.pos
157
157
  // remains a placeholder driving vertex count (4) and topology only.
158
158
  //