@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.
- package/README.md +14 -5
- package/dist/ShaderRegistry.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +33042 -55
- package/dist/index.mjs.map +1 -1
- package/dist/ltc/provenance.d.ts +17 -0
- package/dist/ltc/provenance.d.ts.map +1 -0
- package/dist/ltc/tables.d.ts +22 -0
- package/dist/ltc/tables.d.ts.map +1 -0
- package/dist/material/artifact-types.d.ts +52 -0
- package/dist/material/artifact-types.d.ts.map +1 -1
- package/dist/material-schemas.d.ts +36 -0
- package/dist/material-schemas.d.ts.map +1 -1
- package/dist/register-default-sprite-lit.d.ts +3 -6
- package/dist/register-default-sprite-lit.d.ts.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ShaderRegistry.ts +0 -17
- package/src/__tests__/default-standard-pbr-alpha.unit.test.ts +9 -3
- package/src/__tests__/default-standard-pbr-transmission.unit.test.ts +67 -122
- package/src/__tests__/deferred-lighting-ssao.test.ts +3 -3
- package/src/__tests__/direct-light-layout.unit.test.ts +40 -0
- package/src/__tests__/ibl-irradiance.unit.test.ts +16 -4
- package/src/__tests__/ibl-sampling.unit.test.ts +3 -4
- package/src/__tests__/lighting-directional.unit.test.ts +36 -0
- package/src/__tests__/lighting-point-spot-volume.unit.test.ts +8 -2
- package/src/__tests__/lighting-punctual.unit.test.ts +40 -5
- package/src/__tests__/lighting-spot-volume-attenuation.unit.test.ts +1 -1
- package/src/__tests__/ltc-provenance.unit.test.ts +33 -0
- package/src/__tests__/manifest.fixture.json +33 -0
- package/src/__tests__/material-builtins.unit.test.ts +21 -3
- package/src/__tests__/material-contract.unit.test.ts +188 -14
- package/src/__tests__/physical-clearcoat.unit.test.ts +65 -0
- package/src/__tests__/probe-lighting-composition.unit.test.ts +39 -0
- package/src/__tests__/rect-area-brdf.unit.test.ts +36 -0
- package/src/__tests__/reflection-probe-sampling.unit.test.ts +24 -2
- package/src/__tests__/shader-manifest-transmission.unit.test.ts +8 -10
- package/src/__tests__/shader.unit.test.ts +54 -85
- package/src/__tests__/spot-cookie-composition.unit.test.ts +58 -0
- package/src/__tests__/spot-modifier-composition.unit.test.ts +19 -0
- package/src/__tests__/sprite-variants.unit.test.ts +4 -1
- package/src/__tests__/standard-webgl2-varying-budget.unit.test.ts +17 -0
- package/src/__tests__/surface-v1-negative.unit.test.ts +37 -0
- package/src/__tests__/surface-v1.unit.test.ts +83 -0
- package/src/__tests__/transmission-thickness-scale.unit.test.ts +2 -6
- package/src/__tests__/vertex-color-variant.unit.test.ts +16 -5
- package/src/brdf.wgsl +115 -1
- package/src/common.wgsl +53 -79
- package/src/default-standard-pbr-skin.wgsl +687 -144
- package/src/default-standard-pbr.wgsl +600 -247
- package/src/default_standard_surface.wgsl +88 -0
- package/src/hdrp-cluster-forward.wgsl +225 -0
- package/src/ibl-irradiance.wgsl +47 -9
- package/src/ibl-prefilter.wgsl +13 -3
- package/src/ibl-sampling.wgsl +2 -2
- package/src/ibl-shared.wgsl +9 -2
- package/src/index.ts +23 -0
- package/src/lighting-directional.wgsl +9 -117
- package/src/lighting-probe.wgsl +51 -0
- package/src/lighting-punctual.wgsl +21 -11
- package/src/lighting-rect-area.wgsl +162 -0
- package/src/lighting-spot-modifiers.wgsl +100 -0
- package/src/lighting-spot-projector.wgsl +31 -0
- package/src/ltc/provenance.ts +19 -0
- package/src/ltc/tables.ts +2831 -0
- package/src/material/artifact-types.ts +137 -0
- package/src/material/physical/anisotropy.wgsl +26 -0
- package/src/material/physical/clearcoat.wgsl +24 -0
- package/src/material/physical/iridescence.wgsl +23 -0
- package/src/material/physical/sheen.wgsl +17 -0
- package/src/material-schemas.ts +77 -30
- package/src/register-default-sprite-lit.ts +3 -6
- package/src/register-default-standard-pbr-skin.ts +2 -2
- package/src/sprite-lit.wgsl +3 -3
- package/src/sprite.wgsl +1 -1
- package/src/standard-cluster.wgsl +80 -78
- package/src/surface_v1.wgsl +26 -0
- package/src/types.ts +2 -1
- package/src/volume/volume-inject.wgsl +34 -36
- package/src/volume/volume-integrate.wgsl +48 -38
- 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
|
+
}
|
package/src/material-schemas.ts
CHANGED
|
@@ -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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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`
|
|
60
|
-
*
|
|
61
|
-
*
|
|
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 {
|
|
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:
|
|
72
|
+
paramSchema: STANDARD_PIPELINE_PARAM_SCHEMA,
|
|
73
73
|
});
|
|
74
74
|
}
|
package/src/sprite-lit.wgsl
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
//
|
|
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
|
//
|