@forgeax/engine-shader 0.1.27 → 0.1.29

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 (73) hide show
  1. package/NOTICE +35 -0
  2. package/README.md +39 -0
  3. package/dist/ShaderRegistry.d.ts +8 -0
  4. package/dist/ShaderRegistry.d.ts.map +1 -1
  5. package/dist/index.d.ts +6 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.mjs +312 -71
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/material/artifact-types.d.ts +12 -2
  10. package/dist/material/artifact-types.d.ts.map +1 -1
  11. package/dist/material-schemas.d.ts +5 -0
  12. package/dist/material-schemas.d.ts.map +1 -1
  13. package/package.json +5 -4
  14. package/src/ShaderRegistry.ts +10 -0
  15. package/src/__tests__/auto-exposure-graph.unit.test.ts +59 -0
  16. package/src/__tests__/bloom-fxaa-tonemap.unit.test.ts +30 -15
  17. package/src/__tests__/builtin-texture-sampling-contract.test.ts +1 -1
  18. package/src/__tests__/default-standard-pbr-alpha.unit.test.ts +2 -1
  19. package/src/__tests__/default-standard-pbr-transmission.unit.test.ts +167 -6
  20. package/src/__tests__/direct-light-layout.unit.test.ts +1 -1
  21. package/src/__tests__/lighting-punctual.unit.test.ts +29 -1
  22. package/src/__tests__/ltc-provenance.unit.test.ts +13 -2
  23. package/src/__tests__/material-builtins.unit.test.ts +1 -0
  24. package/src/__tests__/material-contract.unit.test.ts +42 -9
  25. package/src/__tests__/material-derived-builtins.integration.test.ts +18 -2
  26. package/src/__tests__/probe-lighting-composition.unit.test.ts +1 -1
  27. package/src/__tests__/reflection-probe-sampling.unit.test.ts +23 -2
  28. package/src/__tests__/scene-temporal.unit.test.ts +10 -0
  29. package/src/__tests__/shader.unit.test.ts +1 -0
  30. package/src/__tests__/sprite-variants.unit.test.ts +1 -0
  31. package/src/__tests__/ssr-artifact.unit.test.ts +141 -0
  32. package/src/__tests__/ssr-bgl.integration.test.ts +185 -0
  33. package/src/__tests__/standard-output-domain.unit.test.ts +36 -0
  34. package/src/__tests__/standard-pbr-artifact-receipt.unit.test.ts +93 -0
  35. package/src/__tests__/standard-surface-pass-evaluation.integration.test.ts +16 -4
  36. package/src/__tests__/surface-v1.unit.test.ts +6 -0
  37. package/src/__tests__/taa-resolve.unit.test.ts +20 -9
  38. package/src/__tests__/transmission-thickness-scale.unit.test.ts +6 -1
  39. package/src/__tests__/transparent-pbr.unit.test.ts +1 -1
  40. package/src/__tests__/vertex-color-variant.unit.test.ts +4 -1
  41. package/src/atmosphere-background.wgsl +3 -3
  42. package/src/auto-exposure-meter.wgsl +179 -0
  43. package/src/color-lut.wgsl +17 -0
  44. package/src/common.wgsl +7 -5
  45. package/src/default-standard-pbr-skin.wgsl +142 -40
  46. package/src/default-standard-pbr.wgsl +198 -82
  47. package/src/default_standard_surface.wgsl +56 -19
  48. package/src/fxaa.wgsl +9 -5
  49. package/src/ibl-sampling.wgsl +30 -6
  50. package/src/index.ts +189 -0
  51. package/src/lighting-punctual.wgsl +5 -6
  52. package/src/material/artifact-types.ts +109 -63
  53. package/src/material-schemas.ts +84 -8
  54. package/src/output-encoding.wgsl +10 -0
  55. package/src/pbr-temporal.wgsl +9 -1
  56. package/src/scene-temporal.wgsl +2 -0
  57. package/src/shadow-pcf.wgsl +6 -8
  58. package/src/shadow-surface.wgsl +16 -0
  59. package/src/shadow_caster.wgsl +99 -61
  60. package/src/sprite-lit.wgsl +4 -4
  61. package/src/sprite.wgsl +3 -3
  62. package/src/ssr-compose.wgsl +129 -0
  63. package/src/ssr-hiz-reduce.wgsl +53 -0
  64. package/src/ssr-hiz.wgsl +66 -0
  65. package/src/ssr-temporal.wgsl +305 -0
  66. package/src/ssr-trace.wgsl +784 -0
  67. package/src/standard-cluster.wgsl +6 -4
  68. package/src/standard-surface.wgsl +696 -0
  69. package/src/surface_v1.wgsl +6 -0
  70. package/src/taa-resolve.wgsl +222 -28
  71. package/src/tbn.wgsl +1 -1
  72. package/src/tonemap.wgsl +37 -18
  73. package/src/unlit.wgsl +3 -3
package/NOTICE ADDED
@@ -0,0 +1,35 @@
1
+ forgeax-engine
2
+ Copyright 2026 ForgeaXGame Contributors
3
+
4
+ This is part of the ForgeaX project, an open-source AI-native game
5
+ development toolchain (https://github.com/ForgeaXGame).
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ see the LICENSE file in this repository or at
9
+ http://www.apache.org/licenses/LICENSE-2.0 for details.
10
+
11
+ The projected-space SSR tracing implementation in
12
+ packages/shader/src/ssr-trace.wgsl is adapted from the algorithms in Three.js
13
+ SSRShader and SSRNode at 4457aa3c5de4a05bbae4e0bee2d99d994c38a2bb.
14
+
15
+ The MIT License
16
+
17
+ Copyright © 2010-2026 three.js authors
18
+
19
+ Permission is hereby granted, free of charge, to any person obtaining a copy
20
+ of this software and associated documentation files (the "Software"), to deal
21
+ in the Software without restriction, including without limitation the rights
22
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23
+ copies of the Software, and to permit persons to whom the Software is
24
+ furnished to do so, subject to the following conditions:
25
+
26
+ The above copyright notice and this permission notice shall be included in
27
+ all copies or substantial portions of the Software.
28
+
29
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35
+ THE SOFTWARE.
package/README.md CHANGED
@@ -33,6 +33,12 @@ BRDF 的输入,不是最终颜色;Engine-owned Standard pass family 负责
33
33
 
34
34
  ### Minimal authoring shape
35
35
 
36
+ `SurfaceInput` exposes `uv0` through `uv7`, matching the geometry coordinate
37
+ inputs. Every texture slot selects its own set, scale, rotation and offset.
38
+ The default Surface evaluator is shared by CPU, GPU scene-index and shadow
39
+ passes; no shadow-only sampling formula may discard those authored coordinates.
40
+ Changes to the engine-owned input ABI require re-cooking authored materials.
41
+
36
42
  `SurfaceData` is deliberately base-only. Its frozen field order is:
37
43
 
38
44
  | Order | Field | Meaning |
@@ -111,6 +117,13 @@ not import this accessor. The canonical source is `src/standard-cluster.wgsl`;
111
117
  all Standard lit variants compose this one module, so there is no second
112
118
  implementation to maintain.
113
119
 
120
+ `src/standard-surface.wgsl` owns the Standard material/fragment evaluation shared
121
+ by ordinary Mesh and the VFX Mesh vertex adapter. Geometry adapters supply world
122
+ position, normal, tangent, UVs and color; they do not fork BRDF, shadow reception
123
+ or IBL formulas. Render supplies the corresponding lighting resources. The
124
+ single-level BRDF LUT uses explicit-LOD sampling, including when per-particle
125
+ surface factors make fragment control flow non-uniform.
126
+
114
127
  ## MaterialAsset and shader route
115
128
 
116
129
  The recovery route is to inspect the structured code, detail, and hint, then
@@ -134,6 +147,22 @@ const materialHandle = world.allocSharedRef('MaterialAsset', result.value);
134
147
 
135
148
  The custom-shader demo is the executable reference: [`apps/hello/custom-shader`](../../apps/hello/custom-shader). It loads the root and derived GUIDs, validates their cooked records, checks the manifest artifact, and only then draws.
136
149
 
150
+ ## GPU-driven PBR / shadow / skin navigation
151
+
152
+ This package is the producer entry: author `paramSchema` and WGSL, then inspect
153
+ the cooked receipt before the render owner admits a draw. The consumer route is
154
+ [`packages/render/README.md`](../render/README.md#gpu-driven-pbr--shadow--skin-navigation); host
155
+ assembly and recovery are documented in
156
+ [`packages/runtime/README.md`](../runtime/README.md#gpu-driven-pbr--shadow--skin-navigation).
157
+ An Alpha Mask cutoff, texture/sampler slot, or skin palette mismatch is a
158
+ structured producer failure, not a CPU duplicate-draw request.
159
+
160
+ Offline recovery is always `inspect -> repair this producer -> retry`:
161
+
162
+ ```text
163
+ shader source/schema -> cook + reflection receipt -> runtime catalog -> render prepare
164
+ ```
165
+
137
166
  ## Shader module catalog
138
167
 
139
168
  `ShaderRegistry` owns the content-addressed build manifest. It is a runtime
@@ -165,6 +194,16 @@ must agree with that derived shape before a record is published. Per-slot
165
194
  texture coordinates are data in `MaterialTextureValue`, not a global shader
166
195
  switch.
167
196
 
197
+ Standard texture availability comes from authored parameter declarations, not
198
+ GPU residency. Cooked materials omit unavailable texture declarations and
199
+ sampling code. Shared built-in Standard modules retain a fixed binding layout
200
+ and specialize sampling with one pipeline override, `STANDARD_TEXTURE_MASK_OVERRIDE`.
201
+ `standardTextureMask()` derives its bits from the canonical texture-field order;
202
+ the renderer carries the authored mask separately from the canonical UBO schema
203
+ and includes it in pipeline identity. Runtime selects published WGSL and GPU
204
+ pipeline constants; it does not compose or cook WGSL. A declared but nonresident
205
+ texture remains enabled and follows the existing resource recovery route.
206
+
168
207
  ## Error recovery
169
208
 
170
209
  Material and shader errors are closed. Switch on `error.code`, then use the
@@ -33,6 +33,14 @@ export interface ShaderRegistryDevice {
33
33
  * (UUIDv5/v7) shape and not `forgeax::*`.
34
34
  */
35
35
  export declare const FORGEAX_RESERVED_PATH_PREFIX: "forgeax::";
36
+ /** Stable build-time module ids for the M1 spatial SSR artifact set. */
37
+ export declare const SSR_SHADER_MODULES: Readonly<{
38
+ readonly hiz: "forgeax_ssr::hiz";
39
+ readonly hizReduce: "forgeax_ssr::hiz_reduce";
40
+ readonly trace: "forgeax_ssr::trace";
41
+ readonly temporal: "forgeax_ssr::temporal";
42
+ }>;
43
+ export type SsrShaderModule = (typeof SSR_SHADER_MODULES)[keyof typeof SSR_SHADER_MODULES];
36
44
  /**
37
45
  * Material shader admission input accepted by
38
46
  * `installMaterialArtifact(identifier, entry)`. `findMaterialArtifact`
@@ -1 +1 @@
1
- {"version":3,"file":"ShaderRegistry.d.ts","sourceRoot":"","sources":["../src/ShaderRegistry.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EACV,8BAA8B,EAC9B,aAAa,EACb,gBAAgB,EAChB,+BAA+B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,MAAM,IAAI,YAAY,EAE5B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAI9D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,CAAC,IAAI,EAAE;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACrC,GAAG,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;CACpC;AAID;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,EAAG,WAAoB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACnD;AAED,+EAA+E;AAC/E,MAAM,WAAW,6BAA8B,SAAQ,mBAAmB;IACxE,QAAQ,CAAC,qBAAqB,EAAE,8BAA8B,CAAC;CAChE;AAID,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAc;;gBAcb,IAAI,EAAE,qBAAqB;IAKvC;;;;;;;;;;;;;;;OAeG;IACG,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAyK9D;;;;;;;;;;OAUG;IACH,OAAO,IAAI,gBAAgB,CAAC,aAAa,CAAC;IAI1C;;;;;;;;;;;;;OAaG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,WAAW,CAAC;IA2C/D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAsC7E;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAClB,UAAU,EAAE,MAAM,GACjB,YAAY,CAAC,6BAA6B,EAAE,WAAW,CAAC;IAc3D;;;;OAIG;IACH,yBAAyB,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAIrD,uEAAuE;IACvE,0BAA0B,IAAI,+BAA+B;IAI7D;;;;;;;;;;;OAWG;IACH,6BAA6B,IAAI,gBAAgB,CAAC,2BAA2B,CAAC;CAG/E"}
1
+ {"version":3,"file":"ShaderRegistry.d.ts","sourceRoot":"","sources":["../src/ShaderRegistry.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EACV,8BAA8B,EAC9B,aAAa,EACb,gBAAgB,EAChB,+BAA+B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,MAAM,IAAI,YAAY,EAE5B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAI9D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,CAAC,IAAI,EAAE;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACrC,GAAG,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;CACpC;AAID;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,EAAG,WAAoB,CAAC;AAEjE,wEAAwE;AACxE,eAAO,MAAM,kBAAkB;;;;;EAKpB,CAAC;AAEZ,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,OAAO,kBAAkB,CAAC,CAAC;AAE3F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACnD;AAED,+EAA+E;AAC/E,MAAM,WAAW,6BAA8B,SAAQ,mBAAmB;IACxE,QAAQ,CAAC,qBAAqB,EAAE,8BAA8B,CAAC;CAChE;AAID,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAc;;gBAcb,IAAI,EAAE,qBAAqB;IAKvC;;;;;;;;;;;;;;;OAeG;IACG,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAyK9D;;;;;;;;;;OAUG;IACH,OAAO,IAAI,gBAAgB,CAAC,aAAa,CAAC;IAI1C;;;;;;;;;;;;;OAaG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,WAAW,CAAC;IA2C/D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAsC7E;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAClB,UAAU,EAAE,MAAM,GACjB,YAAY,CAAC,6BAA6B,EAAE,WAAW,CAAC;IAc3D;;;;OAIG;IACH,yBAAyB,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAIrD,uEAAuE;IACvE,0BAA0B,IAAI,+BAA+B;IAI7D;;;;;;;;;;;OAWG;IACH,6BAA6B,IAAI,gBAAgB,CAAC,2BAA2B,CAAC;CAG/E"}
package/dist/index.d.ts CHANGED
@@ -5,11 +5,11 @@ export { err, manifestMalformed, materialShaderNotFound, ok, type Result, type R
5
5
  export { generateLtcTables, hashLtcTable, LTC_SOURCE_PROVENANCE, LTC_TABLE_HASHES, LTC_TABLE_HEIGHT, LTC_TABLE_INPUT_HASHES, LTC_TABLE_WIDTH, LTC_TABLES, } from './ltc/tables.js';
6
6
  export { type MaterialArtifactConflictError, type MaterialArtifactInspection, MaterialArtifactRegistry, type MaterialRuntimeArtifact, } from './material/artifact-registry.js';
7
7
  export { createStandardPbrArtifactReceipt, isMaterialShaderArtifact, type MaterialShaderArtifact, type MaterialShaderArtifactReceipt, type MaterialShaderResourceSlot, type MaterialShaderVertexInput, } from './material/artifact-types.js';
8
- export { DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_UNLIT_PARAM_SCHEMA, STANDARD_BASE_PARAM_SCHEMA, STANDARD_PBR_ALPHA_CUTOFF_DEFAULT, STANDARD_PBR_ARTIFACT_RECEIPT, STANDARD_PBR_SKIN_ARTIFACT_RECEIPT, STANDARD_PHYSICAL_LAYER_PARAM_SCHEMA, STANDARD_PHYSICAL_TEXTURE_FIELDS, STANDARD_PIPELINE_PARAM_SCHEMA, type StandardPhysicalTextureField, standardPhysicalTextureFields, } from './material-schemas.js';
8
+ export { DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_UNLIT_PARAM_SCHEMA, PARTICLE_MESH_SURFACE_PARAM_SCHEMA, STANDARD_BASE_PARAM_SCHEMA, STANDARD_PBR_ALPHA_CUTOFF_DEFAULT, STANDARD_PBR_ARTIFACT_RECEIPT, STANDARD_PBR_SKIN_ARTIFACT_RECEIPT, STANDARD_PHYSICAL_LAYER_PARAM_SCHEMA, STANDARD_PHYSICAL_TEXTURE_FIELDS, STANDARD_PIPELINE_PARAM_SCHEMA, STANDARD_TEXTURE_MASK_OVERRIDE, type StandardPhysicalTextureField, standardPhysicalTextureFields, standardTextureMask, } from './material-schemas.js';
9
9
  export { registerDefaultSpriteLit, type SpriteLitCaps, } from './register-default-sprite-lit.js';
10
10
  export { registerDefaultStandardPbrSkin } from './register-default-standard-pbr-skin.js';
11
11
  export declare const RECT_AREA_LTC_SHADER_MODULE: "forgeax::lighting-rect-area";
12
- export { FORGEAX_RESERVED_PATH_PREFIX, type MaterialShaderEntry, type RegisteredMaterialShaderEntry, ShaderRegistry, ShaderRegistry as ShaderCatalog, type ShaderRegistryDevice, type ShaderRegistryDevice as ShaderCatalogDevice, type ShaderRegistryOptions, type ShaderRegistryOptions as ShaderCatalogOptions, } from './ShaderRegistry.js';
12
+ export { FORGEAX_RESERVED_PATH_PREFIX, type MaterialShaderEntry, type RegisteredMaterialShaderEntry, ShaderRegistry, ShaderRegistry as ShaderCatalog, type ShaderRegistryDevice, type ShaderRegistryDevice as ShaderCatalogDevice, type ShaderRegistryOptions, type ShaderRegistryOptions as ShaderCatalogOptions, SSR_SHADER_MODULES, type SsrShaderModule, } from './ShaderRegistry.js';
13
13
  export { findVariantByKey, type MaterialShaderManifestEntry, type MaterialShaderManifestVariant, } from './types.js';
14
14
  export declare const BUILTIN_MATERIAL_MODULES: {
15
15
  readonly standard: "forgeax_material::standard";
@@ -24,6 +24,10 @@ export declare const BUILTIN_MATERIAL_MODULES: {
24
24
  export declare const DEFAULT_STANDARD_SURFACE_MODULE: "forgeax_material::default_standard_surface";
25
25
  /** Stable build-time module id for the temporal-v1 accessor owner. */
26
26
  export declare const SCENE_DATA_TEMPORAL_V1_SHADER_MODULE: "forgeax_scene_temporal";
27
+ /** Stable build-time module id for the single Standard output encoder. */
28
+ export declare const STANDARD_OUTPUT_ENCODING_SHADER_MODULE: "forgeax_view::output_encoding";
29
+ /** Runtime WGSL for the fixed-cohort, same-frame auto exposure meter. */
30
+ export declare const AUTO_EXPOSURE_METER_WGSL = "\nstruct AutoExposureParameters {\n compensationEv: f32,\n rangeMinEv: f32,\n rangeMaxEv: f32,\n upRate: f32,\n downRate: f32,\n deltaTime: f32,\n fallback: f32,\n generation: f32,\n};\n@group(0) @binding(0) var source: texture_2d<f32>;\n@group(0) @binding(1) var<storage, read_write> histogram: array<atomic<u32>>;\n@group(0) @binding(2) var<storage, read_write> state: array<vec4<f32>>;\n@group(0) @binding(3) var<storage, read_write> candidate: array<vec4<f32>>;\n@group(0) @binding(4) var<storage, read> parameters: AutoExposureParameters;\n\nvar<workgroup> localHistogram: array<atomic<u32>, 256>;\nvar<workgroup> totals: array<u32, 64>;\nvar<workgroup> sampleTotal: u32;\n\nfn finite(value: f32) -> bool {\n // Equality rejects NaN; the magnitude bound rejects +/-infinity.\n return value == value && abs(value) <= 3.402823e+37;\n}\n\nfn centerWeight(\n block: vec2<u32>,\n center: vec2<f32>,\n inverseExtentSquared: vec2<f32>,\n) -> u32 {\n let delta = vec2<f32>(block) - center;\n let distanceSquared =\n delta.x * delta.x * inverseExtentSquared.x +\n delta.y * delta.y * inverseExtentSquared.y;\n if (distanceSquared <= 0.25) { return 3u; }\n if (distanceSquared <= 0.75) { return 2u; }\n return 1u;\n}\n\nfn accumulateSample(\n block: vec2<u32>,\n sampleGrid: vec2<u32>,\n dimensions: vec2<u32>,\n center: vec2<f32>,\n extent: vec2<f32>,\n) {\n if (block.x >= sampleGrid.x || block.y >= sampleGrid.y) { return; }\n let pixel = min(block * vec2<u32>(4u) + vec2<u32>(2u), dimensions - vec2<u32>(1u));\n let sample = textureLoad(source, vec2<i32>(pixel), 0);\n if (!finite(sample.r) || !finite(sample.g) || !finite(sample.b)) { return; }\n let luminance = dot(sample.rgb, vec3<f32>(0.2126, 0.7152, 0.0722));\n if (!finite(luminance) || luminance <= 0.0) { return; }\n let bin = min(u32(clamp(log2(luminance) + 12.0, 0.0, 23.999) * (256.0 / 24.0)), 255u);\n atomicAdd(&localHistogram[bin], centerWeight(block, center, extent));\n}\n\n@compute @workgroup_size(256, 1, 1)\nfn auto_exposure_clear(@builtin(local_invocation_index) localIndex: u32) {\n atomicStore(&histogram[localIndex], 0u);\n}\n\n@compute @workgroup_size(256, 1, 1)\nfn auto_exposure_histogram(\n @builtin(local_invocation_index) localIndex: u32,\n @builtin(workgroup_id) workgroupId: vec3<u32>,\n @builtin(num_workgroups) numWorkgroups: vec3<u32>,\n) {\n let dimensions = textureDimensions(source);\n let sampleGrid = (dimensions.xy + vec2<u32>(3u)) / vec2<u32>(4u);\n let grid = vec2<f32>(sampleGrid);\n let center = (grid - vec2<f32>(1.0)) * 0.5;\n let extent = max(center, vec2<f32>(1.0));\n let inverseExtent = 1.0 / extent;\n let inverseExtentSquared = inverseExtent * inverseExtent;\n\n // Map the 256 lanes to a 16x16 logical tile. The fixed 4x8 dispatch grid\n // then uses a two-dimensional tile stride to cover every 4x4 sample block.\n atomicStore(&localHistogram[localIndex], 0u);\n workgroupBarrier();\n let localGrid = vec2<u32>(localIndex % 16u, localIndex / 16u);\n let tileSize = vec2<u32>(16u);\n let blockStart = workgroupId.xy * tileSize + localGrid;\n let blockStride = numWorkgroups.xy * tileSize;\n for (var blockY = blockStart.y; blockY < sampleGrid.y; blockY += blockStride.y) {\n for (var blockX = blockStart.x; blockX < sampleGrid.x; blockX += blockStride.x) {\n accumulateSample(\n vec2<u32>(blockX, blockY),\n sampleGrid,\n dimensions,\n center,\n inverseExtentSquared,\n );\n }\n }\n workgroupBarrier();\n\n // Every lane owns one bin. All local accumulation is complete before the\n // owners atomically publish their finite result to the one global 1KiB map.\n let localCount = atomicLoad(&localHistogram[localIndex]);\n if (localCount > 0u) {\n atomicAdd(&histogram[localIndex], localCount);\n }\n}\n\n@compute @workgroup_size(64, 1, 1)\nfn auto_exposure_adapt(@builtin(local_invocation_index) localIndex: u32) {\n var total = 0u;\n for (var index = localIndex; index < 256u; index += 64u) {\n total += atomicLoad(&histogram[index]);\n }\n totals[localIndex] = total;\n workgroupBarrier();\n if (localIndex == 0u) {\n var reducedTotal = 0u;\n for (var lane = 0u; lane < 64u; lane += 1u) {\n reducedTotal += totals[lane];\n }\n sampleTotal = reducedTotal;\n }\n workgroupBarrier();\n if (localIndex == 0u) {\n let validParameters =\n finite(parameters.compensationEv) &&\n finite(parameters.rangeMinEv) &&\n finite(parameters.rangeMaxEv) &&\n parameters.rangeMinEv <= parameters.rangeMaxEv &&\n finite(parameters.upRate) &&\n finite(parameters.downRate) &&\n finite(parameters.deltaTime) &&\n parameters.deltaTime >= 0.0 &&\n finite(parameters.fallback) &&\n parameters.fallback > 0.0 &&\n finite(parameters.generation);\n let safeFallback = select(\n 1.0,\n parameters.fallback,\n finite(parameters.fallback) && parameters.fallback > 0.0,\n );\n let safeGeneration = select(0.0, parameters.generation, finite(parameters.generation));\n let lowRank = min(sampleTotal, u32(f32(sampleTotal) * 0.05));\n let highRank = min(sampleTotal, max(lowRank + 1u, u32(ceil(f32(sampleTotal) * 0.95))));\n var cumulative = 0u;\n var clippedWeightedLog = 0.0;\n var clippedTotal = 0u;\n for (var index = 0u; index < 256u; index += 1u) {\n let count = atomicLoad(&histogram[index]);\n let begin = cumulative;\n cumulative += count;\n let keptBegin = max(begin, lowRank);\n let keptEnd = min(cumulative, highRank);\n if (keptEnd > keptBegin) {\n let kept = keptEnd - keptBegin;\n clippedTotal += kept;\n clippedWeightedLog += f32(kept) * (-12.0 + (f32(index) + 0.5) * (24.0 / 256.0));\n }\n }\n let averageLog = select(0.0, clippedWeightedLog / f32(clippedTotal), clippedTotal > 0u);\n let measuredExposure = exp2(-averageLog) * 0.18;\n let targetExposure = select(\n safeFallback,\n exp2(clamp(log2(max(measuredExposure, 1e-6)) + parameters.compensationEv, parameters.rangeMinEv, parameters.rangeMaxEv)),\n validParameters && clippedTotal > 0u && finite(measuredExposure),\n );\n let previous = state[0];\n let hasPrevious = validParameters && previous.y > 0.5 && previous.z == safeGeneration && previous.w == safeFallback && finite(previous.x) && previous.x > 0.0;\n let current = select(safeFallback, previous.x, hasPrevious);\n let rate = select(parameters.downRate, parameters.upRate, targetExposure > current);\n let safeRate = select(0.0, rate, finite(rate) && rate >= 0.0);\n let dt = select(0.0, parameters.deltaTime, finite(parameters.deltaTime) && parameters.deltaTime >= 0.0);\n let amount = 1.0 - exp(-safeRate * dt);\n let adapted = select(current, current + (targetExposure - current) * amount, validParameters && finite(targetExposure) && finite(current) && dt > 0.0 && safeRate > 0.0);\n let exposure = select(safeFallback, adapted, finite(adapted) && adapted > 0.0);\n candidate[0] = vec4<f32>(exposure, 1.0, safeGeneration, safeFallback);\n state[0] = candidate[0];\n }\n}\n";
27
31
  /**
28
32
  * Material modules whose shader source and parameter contract are owned by
29
33
  * the Engine. They live in the runtime ShaderRegistry, so a Pack containing
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAsBA,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE7E,OAAO,KAAK,EAAE,aAAa,EAAoC,MAAM,uBAAuB,CAAC;AAI7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EACL,GAAG,EACH,iBAAiB,EACjB,sBAAsB,EACtB,EAAE,EACF,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,wBAAwB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,gCAAgC,EAChC,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,GAC/B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,iCAAiC,EACjC,0BAA0B,EAC1B,0BAA0B,EAC1B,iCAAiC,EACjC,6BAA6B,EAC7B,kCAAkC,EAClC,oCAAoC,EACpC,gCAAgC,EAChC,8BAA8B,EAC9B,KAAK,4BAA4B,EACjC,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,wBAAwB,EACxB,KAAK,aAAa,GACnB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AACzF,eAAO,MAAM,2BAA2B,EAAG,6BAAsC,CAAC;AAClF,OAAO,EACL,4BAA4B,EAC5B,KAAK,mBAAmB,EACxB,KAAK,6BAA6B,EAClC,cAAc,EACd,cAAc,IAAI,aAAa,EAC/B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,IAAI,mBAAmB,EAChD,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,IAAI,oBAAoB,GACnD,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,GACnC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,wBAAwB;;;;CAI3B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAC1C,4CAAqD,CAAC;AAExD,sEAAsE;AACtE,eAAO,MAAM,oCAAoC,EAAG,wBAAiC,CAAC;AAEtF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,wVAa1B,CAAC;AAEX,0EAA0E;AAC1E,eAAO,MAAM,+BAA+B,2DAGjC,CAAC;AAEZ,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,GAAG,OAAO,CAWjF;AAED,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,wBAAwB,CAAC;AA0BxE,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,mBAAmB,GAAG,aAAa,CAoBnF;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,UAAO,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,43 +1,32 @@
1
- import { STANDARD_MATERIAL_PARAM_SCHEMA, STANDARD_PHYSICAL_PARAMETER_NAMES, ok, err, ParamSchemaProjectionOwner, findUndeclaredSampledTextures, standardSurfaceParameters } from '@forgeax/engine-types';
1
+ import { STANDARD_MATERIAL_PARAM_SCHEMA, STANDARD_PHYSICAL_TEXTURE_FIELDS, derive, STANDARD_PHYSICAL_PARAMETER_NAMES, ok, err, ParamSchemaProjectionOwner, findUndeclaredSampledTextures, standardSurfaceParameters } from '@forgeax/engine-types';
2
2
  export { MATERIAL_PARAM_TYPES, STANDARD_PHYSICAL_TEXTURE_FIELDS, standardPhysicalTextureFields } from '@forgeax/engine-types';
3
3
  import { ok as ok$1, err as err$1 } from '@forgeax/engine-rhi';
4
4
  export { err, ok } from '@forgeax/engine-rhi';
5
5
 
6
6
  // src/index.ts
7
-
8
- // src/material/artifact-types.ts
9
- var STANDARD_PBR_TEXTURES = [
10
- "baseColorTexture",
11
- "metallicRoughnessTexture",
12
- "normalTexture",
13
- "specularColorTexture",
14
- "emissiveTexture",
15
- "occlusionTexture",
16
- "transmissionTexture",
17
- "thicknessTexture"
18
- ];
19
- var STANDARD_PBR_NUMERIC_FIELDS = [
20
- "baseColor",
21
- "metallic",
22
- "roughness",
23
- "metallicChannel",
24
- "roughnessChannel",
25
- "aoChannel",
26
- "extraChannel",
27
- "emissive",
28
- "emissiveIntensity",
29
- "occlusionStrength",
30
- "alphaCutoff",
31
- "clearcoat",
32
- "clearcoatRoughness",
33
- "specularColor",
34
- "normalScale",
35
- "transmission",
36
- "ior",
37
- "thickness",
38
- "attenuationColor",
39
- "attenuationDistance"
40
- ];
7
+ var STANDARD_PIPELINE_PARAM_SCHEMA = STANDARD_MATERIAL_PARAM_SCHEMA.filter(
8
+ (entry) => !(entry.type.startsWith("texture") && STANDARD_PHYSICAL_TEXTURE_FIELDS.includes(
9
+ entry.name
10
+ ))
11
+ );
12
+ var STANDARD_PIPELINE_DERIVED = derive(STANDARD_PIPELINE_PARAM_SCHEMA);
13
+ function isNumericParam(entry) {
14
+ return entry.type === "f32" || entry.type === "i32" || entry.type === "u32" || entry.type === "vec2" || entry.type === "vec3" || entry.type === "vec4" || entry.type === "color";
15
+ }
16
+ function standardPbrMaterialRowFields() {
17
+ const coordinates = new Map(
18
+ STANDARD_PIPELINE_DERIVED.coordinateRecords.map((record) => [record.parameter, record])
19
+ );
20
+ return STANDARD_PIPELINE_PARAM_SCHEMA.flatMap((entry) => {
21
+ if (isNumericParam(entry)) return [entry.name];
22
+ if (entry.type.startsWith("texture")) {
23
+ const record = coordinates.get(entry.name);
24
+ if (record === void 0) throw new Error(`missing coordinate record for ${entry.name}`);
25
+ return [record.transformMember, record.metadataMember];
26
+ }
27
+ return [];
28
+ });
29
+ }
41
30
  var STANDARD_PBR_VERTEX_INPUTS = [
42
31
  { semantic: "position", location: 0, format: "float32x3" },
43
32
  { semantic: "normal", location: 1, format: "float32x3" },
@@ -45,56 +34,79 @@ var STANDARD_PBR_VERTEX_INPUTS = [
45
34
  { semantic: "tangent", location: 3, format: "float32x4" }
46
35
  ];
47
36
  function standardPbrResourceSlots() {
48
- return STANDARD_PBR_TEXTURES.flatMap((parameter, index) => [
49
- {
50
- name: `${parameter}_sampler`,
51
- parameter,
52
- kind: "sampler",
53
- group: 1,
54
- binding: index * 2 + 1
55
- },
56
- {
57
- name: parameter,
58
- parameter,
59
- kind: "texture",
60
- group: 1,
61
- binding: index * 2 + 2
62
- }
63
- ]);
37
+ return STANDARD_PIPELINE_DERIVED.resourceBindings.flatMap((resource) => {
38
+ if (resource.kind !== "sampler" && resource.kind !== "texture") return [];
39
+ return [
40
+ {
41
+ name: resource.name,
42
+ parameter: resource.parameter ?? resource.name,
43
+ kind: resource.kind,
44
+ group: 1,
45
+ binding: resource.binding
46
+ }
47
+ ];
48
+ });
64
49
  }
65
- function createStandardPbrArtifactReceipt(skinned = false) {
50
+ function createStandardPbrArtifactReceipt(skinned = false, vertexColorAvailable = false) {
66
51
  const resourceSlots = standardPbrResourceSlots();
67
- const uvSets = STANDARD_PBR_TEXTURES.map((parameter) => ({ parameter, set: 0 }));
68
- const vertexInputs = skinned ? [
52
+ const uvSets = STANDARD_PIPELINE_DERIVED.coordinateRecords.map((record) => ({
53
+ parameter: record.parameter,
54
+ set: 0
55
+ }));
56
+ const vertexInputs = [
69
57
  ...STANDARD_PBR_VERTEX_INPUTS,
70
- { semantic: "skinIndex", location: 4, format: "uint16x4" },
71
- { semantic: "skinWeight", location: 5, format: "float32x4" }
72
- ] : [...STANDARD_PBR_VERTEX_INPUTS];
58
+ ...skinned ? [
59
+ { semantic: "skinIndex", location: 4, format: "uint16x4" },
60
+ { semantic: "skinWeight", location: 5, format: "float32x4" }
61
+ ] : [],
62
+ ...vertexColorAvailable ? [{ semantic: "color", location: 13, format: "float32x4" }] : []
63
+ ];
64
+ const layoutIdentity = `standard-pbr/material-row-v2${vertexColorAvailable ? "/vertex-color" : ""}`;
73
65
  return {
74
66
  directEntry: "vs_main",
75
67
  sceneIndexEntry: "vs_scene_index",
76
- materialRow: { byteLength: 384, fields: [...STANDARD_PBR_NUMERIC_FIELDS] },
68
+ materialRow: {
69
+ byteLength: STANDARD_PIPELINE_DERIVED.totalBytes,
70
+ fields: [...standardPbrMaterialRowFields()]
71
+ },
77
72
  resourceSlots,
78
73
  uvSets,
79
74
  vertexInputs,
80
75
  alphaMask: { cutoff: "alphaCutoff", source: "baseColor.a" },
81
76
  ...skinned ? { skinPaletteAddress: { group: 2, binding: 1, stride: 64 } } : {},
82
77
  reflection: {
83
- layoutIdentity: "standard-pbr/material-row-v1",
78
+ layoutIdentity,
84
79
  resourceSlots,
85
80
  vertexInputs
86
81
  },
87
- receiptIdentity: "standard-pbr/material-row-v1",
88
- generation: 1
82
+ receiptIdentity: layoutIdentity,
83
+ generation: 2
89
84
  };
90
85
  }
91
86
  function isMaterialShaderArtifact(value) {
92
87
  if (value === null || typeof value !== "object") return false;
93
88
  const artifact = value;
94
- return typeof artifact.material === "string" && typeof artifact.pass === "string" && typeof artifact.wgsl === "string" && typeof artifact.layoutIdentity === "string" && Array.isArray(artifact.bindings) && Array.isArray(artifact.deps) && Array.isArray(artifact.vertexInputs);
89
+ const particleInputs = artifact.particleInputs;
90
+ const particleInputsValid = particleInputs === void 0 || Array.isArray(particleInputs) && particleInputs.every(
91
+ (input) => input !== null && typeof input === "object" && typeof input.name === "string" && typeof input.type === "string" && typeof input.visibility === "string" && Number.isInteger(input.lane) && input.lane >= 0
92
+ );
93
+ return typeof artifact.material === "string" && typeof artifact.pass === "string" && typeof artifact.wgsl === "string" && typeof artifact.layoutIdentity === "string" && Array.isArray(artifact.bindings) && Array.isArray(artifact.deps) && Array.isArray(artifact.vertexInputs) && particleInputsValid;
95
94
  }
96
95
  var STANDARD_PBR_ALPHA_CUTOFF_DEFAULT = 0;
97
96
  var DEFAULT_STANDARD_PBR_PARAM_SCHEMA = STANDARD_MATERIAL_PARAM_SCHEMA;
97
+ var STANDARD_TEXTURE_MASK_OVERRIDE = "64000";
98
+ var standardTextureBits = new Map(
99
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter((entry) => entry.type === "texture2d").map(
100
+ (entry, index) => [entry.name, 2 ** index]
101
+ )
102
+ );
103
+ function standardTextureMask(schema) {
104
+ let mask = 0;
105
+ for (const entry of schema) {
106
+ if (entry.type === "texture2d") mask |= standardTextureBits.get(entry.name) ?? 0;
107
+ }
108
+ return mask;
109
+ }
98
110
  var STANDARD_PHYSICAL_LAYER_PARAM_SCHEMA = DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter(
99
111
  (entry) => STANDARD_PHYSICAL_PARAMETER_NAMES.has(entry.name)
100
112
  );
@@ -108,12 +120,52 @@ var STANDARD_BASE_PARAM_SCHEMA = DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter(
108
120
  "thicknessTexture"
109
121
  ].includes(entry.name)
110
122
  );
111
- var STANDARD_PIPELINE_PARAM_SCHEMA = DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter(
112
- // The canonical Standard UBO keeps every numeric root coordinate,
113
- // including the physical-layer tail. Physical map pairs are engine-owned
114
- // resources and are injected after the stable user region.
115
- (entry) => !(STANDARD_PHYSICAL_PARAMETER_NAMES.has(entry.name) && entry.type.startsWith("texture"))
116
- );
123
+ var STANDARD_PIPELINE_PARAM_SCHEMA2 = STANDARD_PIPELINE_PARAM_SCHEMA;
124
+ var PARTICLE_SURFACE_NUMERIC_FIELDS = [
125
+ "baseColor",
126
+ "metallic",
127
+ "roughness",
128
+ "metallicChannel",
129
+ "roughnessChannel",
130
+ "aoChannel",
131
+ "extraChannel",
132
+ "emissive",
133
+ "emissiveIntensity",
134
+ "occlusionStrength",
135
+ "alphaCutoff",
136
+ "clearcoat",
137
+ "clearcoatRoughness",
138
+ "specularTint",
139
+ "normalScale",
140
+ "transmission",
141
+ "ior",
142
+ "thickness",
143
+ "attenuationColor",
144
+ "attenuationDistance"
145
+ ];
146
+ var PARTICLE_SURFACE_TEXTURE_FIELDS = [
147
+ "baseColorTexture",
148
+ "metallicRoughnessTexture",
149
+ "normalTexture",
150
+ "specularTintTexture",
151
+ "emissiveTexture",
152
+ "occlusionTexture",
153
+ "transmissionTexture",
154
+ "thicknessTexture"
155
+ ];
156
+ function particleSurfaceSchemaEntry(name) {
157
+ const entry = DEFAULT_STANDARD_PBR_PARAM_SCHEMA.find((candidate) => candidate.name === name);
158
+ if (entry !== void 0) return entry;
159
+ if (name === "specularTint") {
160
+ return { name, type: "vec3", colorSpace: "srgb", default: [1, 1, 1] };
161
+ }
162
+ if (name === "specularTintTexture") return { name, type: "texture2d" };
163
+ throw new Error(`Particle Standard Surface schema field is missing: ${name}`);
164
+ }
165
+ var PARTICLE_MESH_SURFACE_PARAM_SCHEMA = Object.freeze([
166
+ ...PARTICLE_SURFACE_NUMERIC_FIELDS.map(particleSurfaceSchemaEntry),
167
+ ...PARTICLE_SURFACE_TEXTURE_FIELDS.map(particleSurfaceSchemaEntry)
168
+ ]);
117
169
  var STANDARD_PBR_ARTIFACT_RECEIPT = createStandardPbrArtifactReceipt();
118
170
  var STANDARD_PBR_SKIN_ARTIFACT_RECEIPT = createStandardPbrArtifactReceipt(true);
119
171
  var DEFAULT_UNLIT_PARAM_SCHEMA = [
@@ -33173,10 +33225,16 @@ var RESERVED_ID2 = "forgeax::pbr-skin";
33173
33225
  function registerDefaultStandardPbrSkin(registry, composedWgsl, caps) {
33174
33226
  registry.installMaterialArtifact(RESERVED_ID2, {
33175
33227
  source: composedWgsl,
33176
- paramSchema: STANDARD_PIPELINE_PARAM_SCHEMA
33228
+ paramSchema: STANDARD_PIPELINE_PARAM_SCHEMA2
33177
33229
  });
33178
33230
  }
33179
33231
  var FORGEAX_RESERVED_PATH_PREFIX = "forgeax::";
33232
+ var SSR_SHADER_MODULES = Object.freeze({
33233
+ hiz: "forgeax_ssr::hiz",
33234
+ hizReduce: "forgeax_ssr::hiz_reduce",
33235
+ trace: "forgeax_ssr::trace",
33236
+ temporal: "forgeax_ssr::temporal"
33237
+ });
33180
33238
  function markShaderManifestStage(name, detail = {}) {
33181
33239
  if (typeof globalThis === "undefined") return;
33182
33240
  const host = globalThis;
@@ -33604,6 +33662,188 @@ var BUILTIN_MATERIAL_MODULES = {
33604
33662
  };
33605
33663
  var DEFAULT_STANDARD_SURFACE_MODULE = "forgeax_material::default_standard_surface";
33606
33664
  var SCENE_DATA_TEMPORAL_V1_SHADER_MODULE = "forgeax_scene_temporal";
33665
+ var STANDARD_OUTPUT_ENCODING_SHADER_MODULE = "forgeax_view::output_encoding";
33666
+ var AUTO_EXPOSURE_METER_WGSL = (
33667
+ /* wgsl */
33668
+ `
33669
+ struct AutoExposureParameters {
33670
+ compensationEv: f32,
33671
+ rangeMinEv: f32,
33672
+ rangeMaxEv: f32,
33673
+ upRate: f32,
33674
+ downRate: f32,
33675
+ deltaTime: f32,
33676
+ fallback: f32,
33677
+ generation: f32,
33678
+ };
33679
+ @group(0) @binding(0) var source: texture_2d<f32>;
33680
+ @group(0) @binding(1) var<storage, read_write> histogram: array<atomic<u32>>;
33681
+ @group(0) @binding(2) var<storage, read_write> state: array<vec4<f32>>;
33682
+ @group(0) @binding(3) var<storage, read_write> candidate: array<vec4<f32>>;
33683
+ @group(0) @binding(4) var<storage, read> parameters: AutoExposureParameters;
33684
+
33685
+ var<workgroup> localHistogram: array<atomic<u32>, 256>;
33686
+ var<workgroup> totals: array<u32, 64>;
33687
+ var<workgroup> sampleTotal: u32;
33688
+
33689
+ fn finite(value: f32) -> bool {
33690
+ // Equality rejects NaN; the magnitude bound rejects +/-infinity.
33691
+ return value == value && abs(value) <= 3.402823e+37;
33692
+ }
33693
+
33694
+ fn centerWeight(
33695
+ block: vec2<u32>,
33696
+ center: vec2<f32>,
33697
+ inverseExtentSquared: vec2<f32>,
33698
+ ) -> u32 {
33699
+ let delta = vec2<f32>(block) - center;
33700
+ let distanceSquared =
33701
+ delta.x * delta.x * inverseExtentSquared.x +
33702
+ delta.y * delta.y * inverseExtentSquared.y;
33703
+ if (distanceSquared <= 0.25) { return 3u; }
33704
+ if (distanceSquared <= 0.75) { return 2u; }
33705
+ return 1u;
33706
+ }
33707
+
33708
+ fn accumulateSample(
33709
+ block: vec2<u32>,
33710
+ sampleGrid: vec2<u32>,
33711
+ dimensions: vec2<u32>,
33712
+ center: vec2<f32>,
33713
+ extent: vec2<f32>,
33714
+ ) {
33715
+ if (block.x >= sampleGrid.x || block.y >= sampleGrid.y) { return; }
33716
+ let pixel = min(block * vec2<u32>(4u) + vec2<u32>(2u), dimensions - vec2<u32>(1u));
33717
+ let sample = textureLoad(source, vec2<i32>(pixel), 0);
33718
+ if (!finite(sample.r) || !finite(sample.g) || !finite(sample.b)) { return; }
33719
+ let luminance = dot(sample.rgb, vec3<f32>(0.2126, 0.7152, 0.0722));
33720
+ if (!finite(luminance) || luminance <= 0.0) { return; }
33721
+ let bin = min(u32(clamp(log2(luminance) + 12.0, 0.0, 23.999) * (256.0 / 24.0)), 255u);
33722
+ atomicAdd(&localHistogram[bin], centerWeight(block, center, extent));
33723
+ }
33724
+
33725
+ @compute @workgroup_size(256, 1, 1)
33726
+ fn auto_exposure_clear(@builtin(local_invocation_index) localIndex: u32) {
33727
+ atomicStore(&histogram[localIndex], 0u);
33728
+ }
33729
+
33730
+ @compute @workgroup_size(256, 1, 1)
33731
+ fn auto_exposure_histogram(
33732
+ @builtin(local_invocation_index) localIndex: u32,
33733
+ @builtin(workgroup_id) workgroupId: vec3<u32>,
33734
+ @builtin(num_workgroups) numWorkgroups: vec3<u32>,
33735
+ ) {
33736
+ let dimensions = textureDimensions(source);
33737
+ let sampleGrid = (dimensions.xy + vec2<u32>(3u)) / vec2<u32>(4u);
33738
+ let grid = vec2<f32>(sampleGrid);
33739
+ let center = (grid - vec2<f32>(1.0)) * 0.5;
33740
+ let extent = max(center, vec2<f32>(1.0));
33741
+ let inverseExtent = 1.0 / extent;
33742
+ let inverseExtentSquared = inverseExtent * inverseExtent;
33743
+
33744
+ // Map the 256 lanes to a 16x16 logical tile. The fixed 4x8 dispatch grid
33745
+ // then uses a two-dimensional tile stride to cover every 4x4 sample block.
33746
+ atomicStore(&localHistogram[localIndex], 0u);
33747
+ workgroupBarrier();
33748
+ let localGrid = vec2<u32>(localIndex % 16u, localIndex / 16u);
33749
+ let tileSize = vec2<u32>(16u);
33750
+ let blockStart = workgroupId.xy * tileSize + localGrid;
33751
+ let blockStride = numWorkgroups.xy * tileSize;
33752
+ for (var blockY = blockStart.y; blockY < sampleGrid.y; blockY += blockStride.y) {
33753
+ for (var blockX = blockStart.x; blockX < sampleGrid.x; blockX += blockStride.x) {
33754
+ accumulateSample(
33755
+ vec2<u32>(blockX, blockY),
33756
+ sampleGrid,
33757
+ dimensions,
33758
+ center,
33759
+ inverseExtentSquared,
33760
+ );
33761
+ }
33762
+ }
33763
+ workgroupBarrier();
33764
+
33765
+ // Every lane owns one bin. All local accumulation is complete before the
33766
+ // owners atomically publish their finite result to the one global 1KiB map.
33767
+ let localCount = atomicLoad(&localHistogram[localIndex]);
33768
+ if (localCount > 0u) {
33769
+ atomicAdd(&histogram[localIndex], localCount);
33770
+ }
33771
+ }
33772
+
33773
+ @compute @workgroup_size(64, 1, 1)
33774
+ fn auto_exposure_adapt(@builtin(local_invocation_index) localIndex: u32) {
33775
+ var total = 0u;
33776
+ for (var index = localIndex; index < 256u; index += 64u) {
33777
+ total += atomicLoad(&histogram[index]);
33778
+ }
33779
+ totals[localIndex] = total;
33780
+ workgroupBarrier();
33781
+ if (localIndex == 0u) {
33782
+ var reducedTotal = 0u;
33783
+ for (var lane = 0u; lane < 64u; lane += 1u) {
33784
+ reducedTotal += totals[lane];
33785
+ }
33786
+ sampleTotal = reducedTotal;
33787
+ }
33788
+ workgroupBarrier();
33789
+ if (localIndex == 0u) {
33790
+ let validParameters =
33791
+ finite(parameters.compensationEv) &&
33792
+ finite(parameters.rangeMinEv) &&
33793
+ finite(parameters.rangeMaxEv) &&
33794
+ parameters.rangeMinEv <= parameters.rangeMaxEv &&
33795
+ finite(parameters.upRate) &&
33796
+ finite(parameters.downRate) &&
33797
+ finite(parameters.deltaTime) &&
33798
+ parameters.deltaTime >= 0.0 &&
33799
+ finite(parameters.fallback) &&
33800
+ parameters.fallback > 0.0 &&
33801
+ finite(parameters.generation);
33802
+ let safeFallback = select(
33803
+ 1.0,
33804
+ parameters.fallback,
33805
+ finite(parameters.fallback) && parameters.fallback > 0.0,
33806
+ );
33807
+ let safeGeneration = select(0.0, parameters.generation, finite(parameters.generation));
33808
+ let lowRank = min(sampleTotal, u32(f32(sampleTotal) * 0.05));
33809
+ let highRank = min(sampleTotal, max(lowRank + 1u, u32(ceil(f32(sampleTotal) * 0.95))));
33810
+ var cumulative = 0u;
33811
+ var clippedWeightedLog = 0.0;
33812
+ var clippedTotal = 0u;
33813
+ for (var index = 0u; index < 256u; index += 1u) {
33814
+ let count = atomicLoad(&histogram[index]);
33815
+ let begin = cumulative;
33816
+ cumulative += count;
33817
+ let keptBegin = max(begin, lowRank);
33818
+ let keptEnd = min(cumulative, highRank);
33819
+ if (keptEnd > keptBegin) {
33820
+ let kept = keptEnd - keptBegin;
33821
+ clippedTotal += kept;
33822
+ clippedWeightedLog += f32(kept) * (-12.0 + (f32(index) + 0.5) * (24.0 / 256.0));
33823
+ }
33824
+ }
33825
+ let averageLog = select(0.0, clippedWeightedLog / f32(clippedTotal), clippedTotal > 0u);
33826
+ let measuredExposure = exp2(-averageLog) * 0.18;
33827
+ let targetExposure = select(
33828
+ safeFallback,
33829
+ exp2(clamp(log2(max(measuredExposure, 1e-6)) + parameters.compensationEv, parameters.rangeMinEv, parameters.rangeMaxEv)),
33830
+ validParameters && clippedTotal > 0u && finite(measuredExposure),
33831
+ );
33832
+ let previous = state[0];
33833
+ let hasPrevious = validParameters && previous.y > 0.5 && previous.z == safeGeneration && previous.w == safeFallback && finite(previous.x) && previous.x > 0.0;
33834
+ let current = select(safeFallback, previous.x, hasPrevious);
33835
+ let rate = select(parameters.downRate, parameters.upRate, targetExposure > current);
33836
+ let safeRate = select(0.0, rate, finite(rate) && rate >= 0.0);
33837
+ let dt = select(0.0, parameters.deltaTime, finite(parameters.deltaTime) && parameters.deltaTime >= 0.0);
33838
+ let amount = 1.0 - exp(-safeRate * dt);
33839
+ let adapted = select(current, current + (targetExposure - current) * amount, validParameters && finite(targetExposure) && finite(current) && dt > 0.0 && safeRate > 0.0);
33840
+ let exposure = select(safeFallback, adapted, finite(adapted) && adapted > 0.0);
33841
+ candidate[0] = vec4<f32>(exposure, 1.0, safeGeneration, safeFallback);
33842
+ state[0] = candidate[0];
33843
+ }
33844
+ }
33845
+ `
33846
+ );
33607
33847
  var ENGINE_MATERIAL_MODULES = [
33608
33848
  "forgeax::default-standard-pbr",
33609
33849
  "forgeax::pbr-skin",
@@ -33660,7 +33900,8 @@ function createBuiltinMaterialAsset(kind) {
33660
33900
  program: {
33661
33901
  module: BUILTIN_MATERIAL_MODULES[kind],
33662
33902
  ...kind === "standard" ? { moduleSlots: { surface: DEFAULT_STANDARD_SURFACE_MODULE } } : {}
33663
- }
33903
+ },
33904
+ renderState: { tags: { LightMode: "Forward" } }
33664
33905
  }
33665
33906
  ],
33666
33907
  parameters: kind === "standard" ? standardSurfaceParameters(BUILTIN_PARAMETERS[kind]) : BUILTIN_PARAMETERS[kind],
@@ -33669,6 +33910,6 @@ function createBuiltinMaterialAsset(kind) {
33669
33910
  }
33670
33911
  var TONEMAP_LUMINANCE_EPSILON = 1e-5;
33671
33912
 
33672
- export { BUILTIN_MATERIAL_MODULES, DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_STANDARD_SURFACE_MODULE, DEFAULT_UNLIT_PARAM_SCHEMA, ENGINE_MATERIAL_MODULES, FORGEAX_RESERVED_PATH_PREFIX, LTC_SOURCE_PROVENANCE, LTC_TABLES, LTC_TABLE_HASHES, LTC_TABLE_HEIGHT, LTC_TABLE_INPUT_HASHES, LTC_TABLE_WIDTH, MaterialArtifactRegistry, RECT_AREA_LTC_SHADER_MODULE, REFLECTION_PROBE_SHADER_HELPERS, SCENE_DATA_TEMPORAL_V1_SHADER_MODULE, STANDARD_BASE_PARAM_SCHEMA, STANDARD_PBR_ALPHA_CUTOFF_DEFAULT, STANDARD_PBR_ARTIFACT_RECEIPT, STANDARD_PBR_SKIN_ARTIFACT_RECEIPT, STANDARD_PHYSICAL_LAYER_PARAM_SCHEMA, STANDARD_PIPELINE_PARAM_SCHEMA, ShaderRegistry as ShaderCatalog, ShaderError, ShaderRegistry, TONEMAP_LUMINANCE_EPSILON, TONEMAP_SHADER_MODE, createBuiltinMaterialAsset, createStandardPbrArtifactReceipt, findVariantByKey, generateLtcTables, hashLtcTable, isEngineMaterial, isEngineMaterialModule, isMaterialShaderArtifact, manifestMalformed, materialShaderNotFound, registerDefaultSpriteLit, registerDefaultStandardPbrSkin, shaderNotFound };
33913
+ export { AUTO_EXPOSURE_METER_WGSL, BUILTIN_MATERIAL_MODULES, DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_STANDARD_SURFACE_MODULE, DEFAULT_UNLIT_PARAM_SCHEMA, ENGINE_MATERIAL_MODULES, FORGEAX_RESERVED_PATH_PREFIX, LTC_SOURCE_PROVENANCE, LTC_TABLES, LTC_TABLE_HASHES, LTC_TABLE_HEIGHT, LTC_TABLE_INPUT_HASHES, LTC_TABLE_WIDTH, MaterialArtifactRegistry, PARTICLE_MESH_SURFACE_PARAM_SCHEMA, RECT_AREA_LTC_SHADER_MODULE, REFLECTION_PROBE_SHADER_HELPERS, SCENE_DATA_TEMPORAL_V1_SHADER_MODULE, SSR_SHADER_MODULES, STANDARD_BASE_PARAM_SCHEMA, STANDARD_OUTPUT_ENCODING_SHADER_MODULE, STANDARD_PBR_ALPHA_CUTOFF_DEFAULT, STANDARD_PBR_ARTIFACT_RECEIPT, STANDARD_PBR_SKIN_ARTIFACT_RECEIPT, STANDARD_PHYSICAL_LAYER_PARAM_SCHEMA, STANDARD_PIPELINE_PARAM_SCHEMA2 as STANDARD_PIPELINE_PARAM_SCHEMA, STANDARD_TEXTURE_MASK_OVERRIDE, ShaderRegistry as ShaderCatalog, ShaderError, ShaderRegistry, TONEMAP_LUMINANCE_EPSILON, TONEMAP_SHADER_MODE, createBuiltinMaterialAsset, createStandardPbrArtifactReceipt, findVariantByKey, generateLtcTables, hashLtcTable, isEngineMaterial, isEngineMaterialModule, isMaterialShaderArtifact, manifestMalformed, materialShaderNotFound, registerDefaultSpriteLit, registerDefaultStandardPbrSkin, shaderNotFound, standardTextureMask };
33673
33914
  //# sourceMappingURL=index.mjs.map
33674
33915
  //# sourceMappingURL=index.mjs.map