@forgeax/engine-shader 0.1.2
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/LICENSE +202 -0
- package/README.md +99 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/ShaderRegistry.d.ts +208 -0
- package/dist/ShaderRegistry.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-background.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-background.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-cubemap-orientation.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-cubemap-orientation.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-preetham-numeric.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-preetham-numeric.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-preetham-red.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-preetham-red.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-preetham.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-preetham.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-three-r184-reference.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-three-r184-reference.test.d.ts.map +1 -0
- package/dist/__tests__/bloom-fxaa-tonemap.unit.test.d.ts +2 -0
- package/dist/__tests__/bloom-fxaa-tonemap.unit.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-texture-sampling-contract.test.d.ts +2 -0
- package/dist/__tests__/builtin-texture-sampling-contract.test.d.ts.map +1 -0
- package/dist/__tests__/default-standard-pbr-alpha.unit.test.d.ts +2 -0
- package/dist/__tests__/default-standard-pbr-alpha.unit.test.d.ts.map +1 -0
- package/dist/__tests__/deferred-lighting-ssao.test.d.ts +2 -0
- package/dist/__tests__/deferred-lighting-ssao.test.d.ts.map +1 -0
- package/dist/__tests__/fog-oracle.unit.test.d.ts +2 -0
- package/dist/__tests__/fog-oracle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fog-orthographic-ray.unit.test.d.ts +2 -0
- package/dist/__tests__/fog-orthographic-ray.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-matrix.integration.test.d.ts +2 -0
- package/dist/__tests__/fog-producer-matrix.integration.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-ssao-compile.test.d.ts +2 -0
- package/dist/__tests__/hdrp-ssao-compile.test.d.ts.map +1 -0
- package/dist/__tests__/ibl-irradiance.unit.test.d.ts +2 -0
- package/dist/__tests__/ibl-irradiance.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ibl-sampling.unit.test.d.ts +2 -0
- package/dist/__tests__/ibl-sampling.unit.test.d.ts.map +1 -0
- package/dist/__tests__/lighting-punctual.unit.test.d.ts +2 -0
- package/dist/__tests__/lighting-punctual.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-artifact-dedup.unit.test.d.ts +2 -0
- package/dist/__tests__/material-artifact-dedup.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-builtins.unit.test.d.ts +2 -0
- package/dist/__tests__/material-builtins.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/material-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-derived-builtins.integration.test.d.ts +2 -0
- package/dist/__tests__/material-derived-builtins.integration.test.d.ts.map +1 -0
- package/dist/__tests__/public-surface.unit.test.d.ts +2 -0
- package/dist/__tests__/public-surface.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-temporal.unit.test.d.ts +2 -0
- package/dist/__tests__/scene-temporal.unit.test.d.ts.map +1 -0
- package/dist/__tests__/shader-registry-transaction.unit.test.d.ts +2 -0
- package/dist/__tests__/shader-registry-transaction.unit.test.d.ts.map +1 -0
- package/dist/__tests__/shader.unit.test.d.ts +2 -0
- package/dist/__tests__/shader.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-lit-shader.test.d.ts +2 -0
- package/dist/__tests__/sprite-lit-shader.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-variants.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-variants.unit.test.d.ts.map +1 -0
- package/dist/__tests__/taa-resolve.unit.test.d.ts +2 -0
- package/dist/__tests__/taa-resolve.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transparent-pbr.unit.test.d.ts +2 -0
- package/dist/__tests__/transparent-pbr.unit.test.d.ts.map +1 -0
- package/dist/__tests__/vertex-color-variant.unit.test.d.ts +2 -0
- package/dist/__tests__/vertex-color-variant.unit.test.d.ts.map +1 -0
- package/dist/errors.d.ts +96 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +560 -0
- package/dist/index.mjs.map +1 -0
- package/dist/material/artifact-registry.d.ts +31 -0
- package/dist/material/artifact-registry.d.ts.map +1 -0
- package/dist/material/artifact-types.d.ts +13 -0
- package/dist/material/artifact-types.d.ts.map +1 -0
- package/dist/material-schemas.d.ts +8 -0
- package/dist/material-schemas.d.ts.map +1 -0
- package/dist/register-default-sprite-lit.d.ts +40 -0
- package/dist/register-default-sprite-lit.d.ts.map +1 -0
- package/dist/register-default-standard-pbr-skin.d.ts +34 -0
- package/dist/register-default-standard-pbr-skin.d.ts.map +1 -0
- package/dist/tonemap.d.ts +13 -0
- package/dist/tonemap.d.ts.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +58 -0
- package/src/ShaderRegistry.ts +519 -0
- package/src/__tests__/atmosphere-background.test.ts +33 -0
- package/src/__tests__/atmosphere-cubemap-orientation.test.ts +68 -0
- package/src/__tests__/atmosphere-preetham-numeric.test.ts +122 -0
- package/src/__tests__/atmosphere-preetham-red.test.ts +52 -0
- package/src/__tests__/atmosphere-preetham.test.ts +132 -0
- package/src/__tests__/atmosphere-three-r184-reference.test.ts +122 -0
- package/src/__tests__/bloom-fxaa-tonemap.unit.test.ts +31 -0
- package/src/__tests__/builtin-texture-sampling-contract.test.ts +56 -0
- package/src/__tests__/default-standard-pbr-alpha.unit.test.ts +19 -0
- package/src/__tests__/deferred-lighting-ssao.test.ts +114 -0
- package/src/__tests__/fog-oracle.unit.test.ts +132 -0
- package/src/__tests__/fog-orthographic-ray.unit.test.ts +62 -0
- package/src/__tests__/fog-producer-matrix.integration.test.ts +77 -0
- package/src/__tests__/hdrp-ssao-compile.test.ts +185 -0
- package/src/__tests__/ibl-irradiance.unit.test.ts +43 -0
- package/src/__tests__/ibl-sampling.unit.test.ts +40 -0
- package/src/__tests__/lighting-punctual.unit.test.ts +66 -0
- package/src/__tests__/manifest.fixture.json +22 -0
- package/src/__tests__/material-artifact-dedup.unit.test.ts +21 -0
- package/src/__tests__/material-builtins.unit.test.ts +111 -0
- package/src/__tests__/material-contract.unit.test.ts +79 -0
- package/src/__tests__/material-derived-builtins.integration.test.ts +30 -0
- package/src/__tests__/public-surface.unit.test.ts +9 -0
- package/src/__tests__/scene-temporal.unit.test.ts +32 -0
- package/src/__tests__/shader-registry-transaction.unit.test.ts +116 -0
- package/src/__tests__/shader.unit.test.ts +1909 -0
- package/src/__tests__/sprite-lit-shader.test.ts +240 -0
- package/src/__tests__/sprite-variants.unit.test.ts +209 -0
- package/src/__tests__/taa-resolve.unit.test.ts +32 -0
- package/src/__tests__/transparent-pbr.unit.test.ts +21 -0
- package/src/__tests__/vertex-color-variant.unit.test.ts +52 -0
- package/src/atmosphere-background.wgsl +80 -0
- package/src/atmosphere-cubemap.wgsl +72 -0
- package/src/atmosphere-ibl.wgsl +127 -0
- package/src/atmosphere-preetham.wgsl +214 -0
- package/src/bloom-blur.wgsl +89 -0
- package/src/bloom-bright.wgsl +50 -0
- package/src/bloom-composite.wgsl +54 -0
- package/src/brdf.wgsl +25 -0
- package/src/common.wgsl +523 -0
- package/src/default-standard-pbr-skin.wgsl +538 -0
- package/src/default-standard-pbr.wgsl +794 -0
- package/src/errors.ts +169 -0
- package/src/fog.wgsl +27 -0
- package/src/fxaa.wgsl +259 -0
- package/src/hdrp-cluster-forward.wgsl +186 -0
- package/src/hdrp-deferred-lighting.wgsl +69 -0
- package/src/hdrp-ssao.wgsl +174 -0
- package/src/ibl-brdf-lut.wgsl +92 -0
- package/src/ibl-equirect-to-cube.wgsl +56 -0
- package/src/ibl-irradiance.wgsl +89 -0
- package/src/ibl-prefilter.wgsl +101 -0
- package/src/ibl-sampling.wgsl +58 -0
- package/src/ibl-shared.wgsl +118 -0
- package/src/index.ts +166 -0
- package/src/lighting-directional.wgsl +471 -0
- package/src/lighting-punctual.wgsl +274 -0
- package/src/material/artifact-registry.ts +78 -0
- package/src/material/artifact-types.ts +26 -0
- package/src/material-schemas.ts +48 -0
- package/src/msdf-text.wgsl +208 -0
- package/src/pbr-temporal.wgsl +73 -0
- package/src/register-default-sprite-lit.ts +87 -0
- package/src/register-default-standard-pbr-skin.ts +74 -0
- package/src/shadow-pcf.wgsl +120 -0
- package/src/shadow_caster.wgsl +54 -0
- package/src/skybox.wgsl +75 -0
- package/src/sprite-lit.wgsl +307 -0
- package/src/sprite.wgsl +365 -0
- package/src/taa-resolve.wgsl +129 -0
- package/src/tbn.wgsl +54 -0
- package/src/tonemap.ts +13 -0
- package/src/tonemap.wgsl +177 -0
- package/src/types.ts +59 -0
- package/src/unlit.wgsl +186 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
#define_import_path forgeax_pbr::lighting_directional
|
|
2
|
+
|
|
3
|
+
// @forgeax/engine-shader - lighting-directional.wgsl
|
|
4
|
+
// (feat-20260523-shader-template-instance-split M5 / T02;
|
|
5
|
+
// feat-20260613-csm-cascaded-shadow-maps-unique-shadow-path M5 / w18 rewrite).
|
|
6
|
+
//
|
|
7
|
+
// Directional-light evaluator extracted from pbr.wgsl. Cook-Torrance
|
|
8
|
+
// (D_GGX + V_Smith + F_Schlick) microfacet specular + Lambertian diffuse,
|
|
9
|
+
// modulated by a slope-scaled-bias 3x3 PCF shadow lookup against the
|
|
10
|
+
// host's CSM shadow atlas (LearnOpenGL 3.1.3 PCF model + Bevy-style
|
|
11
|
+
// cascaded shadow maps).
|
|
12
|
+
//
|
|
13
|
+
// Cascade selection (feat-20260613 AC-03 / AC-06 / AC-10):
|
|
14
|
+
// 1. Pick layer in 0..cascadeCount-1 based on viewZ vs splitPlanes[i].
|
|
15
|
+
// The same code path covers a 1-layer config (single tile) and a
|
|
16
|
+
// 4-layer config (Bevy default) -- AC-03 forbids any single-cascade
|
|
17
|
+
// fallback branch.
|
|
18
|
+
// 2. Project worldPos through the matching lightViewProj. The host emits
|
|
19
|
+
// pure clip-space matrices (orthoProj * lightView with no tile-UV
|
|
20
|
+
// pre-bake); this helper performs atlas tile UV placement on the
|
|
21
|
+
// fragment side so shadow_caster can keep gl_Position in clip space
|
|
22
|
+
// (w28 split-of-roles -- writer and reader share one matrix shape).
|
|
23
|
+
// 3. textureSampleCompareLevel against shadowMap (the atlas) with a
|
|
24
|
+
// slope-scaled bias (LO 3.1.3) and 3x3 PCF tap kernel.
|
|
25
|
+
// 4. When cascadeBlend > 0 and the fragment lies near the cascade
|
|
26
|
+
// boundary, mix(shadow_curr, shadow_next, t) where t walks 0->1
|
|
27
|
+
// across a band of width splitPlanes[layer] * cascadeBlend.
|
|
28
|
+
//
|
|
29
|
+
// feat-20260612-point-light-shadows-urp-hdrp M2 / T-M2-2 (plan-strategy D-4):
|
|
30
|
+
// 9-tap PCF taps come from shared sample_shadow_2d in forgeax_pbr::shadow_pcf.
|
|
31
|
+
// Bias formula and 9-tap kernel are byte-equivalent to the prior inline
|
|
32
|
+
// version (research L1.5 lines 47-81); the shared core is the single SSOT
|
|
33
|
+
// for directional + point-light PCF.
|
|
34
|
+
//
|
|
35
|
+
// Pulls View + shadowMap from forgeax_view::common -- the helper inherits
|
|
36
|
+
// the group(0) binding namespace from the host material shader (every
|
|
37
|
+
// consumer already imports forgeax_view::common). Shadow PCF taps use
|
|
38
|
+
// textureSampleCompareLevel against the comparison sampler so the path
|
|
39
|
+
// is portable across WebGPU + GLES.
|
|
40
|
+
//
|
|
41
|
+
// Exports:
|
|
42
|
+
// - evalDirectional(...) -> vec3<f32> (Cook-Torrance + CSM shadow mod)
|
|
43
|
+
// - evalDirectionalNoShadow(...) -> vec3<f32> (Cook-Torrance, no shadow;
|
|
44
|
+
// sprite-lit M1' / w3 D-1; also the inner brdf body of evalDirectional)
|
|
45
|
+
// - evalDirectionalShadowFactor(...) -> f32 (one reusable CSM sample for
|
|
46
|
+
// layered BRDFs such as base + clearcoat)
|
|
47
|
+
|
|
48
|
+
#import forgeax_view::common::{view, shadowMap, shadowSampler}
|
|
49
|
+
#import forgeax_pbr::brdf::{f_schlick, v_smith, d_ggx}
|
|
50
|
+
#import forgeax_pbr::shadow_pcf::{sample_shadow_2d}
|
|
51
|
+
|
|
52
|
+
// feat-20260621-learn-render-5-3-production-shadow-demos M0 / AC-14:
|
|
53
|
+
// compile-time upper bound on the PCF half-extent so the WGSL tap loops keep
|
|
54
|
+
// a constant trip count (no dynamic loop bounds / shader variants). half=2
|
|
55
|
+
// covers pcfKernelSize in {1,3,5} -> {1,9,25} taps; view.pcfKernelSize selects
|
|
56
|
+
// the runtime radius via a per-iteration clip (plan-strategy D-1).
|
|
57
|
+
const MAX_PCF_HALF : u32 = 2u;
|
|
58
|
+
|
|
59
|
+
// Source: Three.js r184 src/nodes/functions/BSDF/DFGLUT.js. The full 16x16
|
|
60
|
+
// RG16F table is decoded to exact f32 constants here; the lookup below mirrors
|
|
61
|
+
// the source DataTexture's linear filtering and clamp-to-edge sampling without
|
|
62
|
+
// adding a host binding or coupling direct light to the engine IBL LUT.
|
|
63
|
+
const THREE_R184_DFG_LUT_SIZE : u32 = 16u;
|
|
64
|
+
const THREE_R184_DFG_LUT : array<vec2<f32>, 256> = array<vec2<f32>, 256>(
|
|
65
|
+
vec2<f32>(0.1470947265625, 0.85205078125), vec2<f32>(0.16552734375, 0.78759765625), vec2<f32>(0.244384765625, 0.638671875), vec2<f32>(0.370849609375, 0.51953125),
|
|
66
|
+
vec2<f32>(0.496826171875, 0.41552734375), vec2<f32>(0.60205078125, 0.326416015625), vec2<f32>(0.68408203125, 0.25390625), vec2<f32>(0.74609375, 0.197509765625),
|
|
67
|
+
vec2<f32>(0.79052734375, 0.154296875), vec2<f32>(0.822265625, 0.12164306640625), vec2<f32>(0.84326171875, 0.09698486328125), vec2<f32>(0.8564453125, 0.07843017578125),
|
|
68
|
+
vec2<f32>(0.86328125, 0.06439208984375), vec2<f32>(0.86572265625, 0.0537109375), vec2<f32>(0.8642578125, 0.045440673828125), vec2<f32>(0.85986328125, 0.039031982421875),
|
|
69
|
+
vec2<f32>(0.388671875, 0.611328125), vec2<f32>(0.39306640625, 0.6005859375), vec2<f32>(0.412353515625, 0.5458984375), vec2<f32>(0.45654296875, 0.4482421875),
|
|
70
|
+
vec2<f32>(0.52783203125, 0.3525390625), vec2<f32>(0.607421875, 0.27392578125), vec2<f32>(0.6787109375, 0.21142578125), vec2<f32>(0.7333984375, 0.16259765625),
|
|
71
|
+
vec2<f32>(0.77099609375, 0.1253662109375), vec2<f32>(0.79345703125, 0.0972900390625), vec2<f32>(0.80322265625, 0.07623291015625), vec2<f32>(0.8037109375, 0.06036376953125),
|
|
72
|
+
vec2<f32>(0.79638671875, 0.048431396484375), vec2<f32>(0.78564453125, 0.03936767578125), vec2<f32>(0.77197265625, 0.03240966796875), vec2<f32>(0.7548828125, 0.0269775390625),
|
|
73
|
+
vec2<f32>(0.572265625, 0.427490234375), vec2<f32>(0.57373046875, 0.424072265625), vec2<f32>(0.57958984375, 0.403564453125), vec2<f32>(0.591796875, 0.3544921875),
|
|
74
|
+
vec2<f32>(0.6162109375, 0.2880859375), vec2<f32>(0.6552734375, 0.224853515625), vec2<f32>(0.69873046875, 0.172607421875), vec2<f32>(0.7353515625, 0.1318359375),
|
|
75
|
+
vec2<f32>(0.75927734375, 0.10089111328125), vec2<f32>(0.77001953125, 0.07745361328125), vec2<f32>(0.77197265625, 0.0599365234375), vec2<f32>(0.76611328125, 0.046844482421875),
|
|
76
|
+
vec2<f32>(0.751953125, 0.0369873046875), vec2<f32>(0.732421875, 0.029541015625), vec2<f32>(0.70947265625, 0.023834228515625), vec2<f32>(0.68359375, 0.019439697265625),
|
|
77
|
+
vec2<f32>(0.708984375, 0.291015625), vec2<f32>(0.708984375, 0.289794921875), vec2<f32>(0.7099609375, 0.28125), vec2<f32>(0.7099609375, 0.258544921875),
|
|
78
|
+
vec2<f32>(0.71142578125, 0.220458984375), vec2<f32>(0.7197265625, 0.1768798828125), vec2<f32>(0.734375, 0.1370849609375), vec2<f32>(0.748046875, 0.10479736328125),
|
|
79
|
+
vec2<f32>(0.755859375, 0.07989501953125), vec2<f32>(0.759765625, 0.061004638671875), vec2<f32>(0.75341796875, 0.046844482421875), vec2<f32>(0.73876953125, 0.036224365234375),
|
|
80
|
+
vec2<f32>(0.7177734375, 0.02825927734375), vec2<f32>(0.69189453125, 0.0222625732421875), vec2<f32>(0.6611328125, 0.0177001953125), vec2<f32>(0.62841796875, 0.01419830322265625),
|
|
81
|
+
vec2<f32>(0.80810546875, 0.1917724609375), vec2<f32>(0.8076171875, 0.1912841796875), vec2<f32>(0.80615234375, 0.18798828125), vec2<f32>(0.8017578125, 0.1781005859375),
|
|
82
|
+
vec2<f32>(0.79296875, 0.15869140625), vec2<f32>(0.78369140625, 0.1322021484375), vec2<f32>(0.775390625, 0.1048583984375), vec2<f32>(0.7685546875, 0.08111572265625),
|
|
83
|
+
vec2<f32>(0.7646484375, 0.061981201171875), vec2<f32>(0.75537109375, 0.047271728515625), vec2<f32>(0.740234375, 0.036163330078125), vec2<f32>(0.71875, 0.0277557373046875),
|
|
84
|
+
vec2<f32>(0.69091796875, 0.021484375), vec2<f32>(0.658203125, 0.0167388916015625), vec2<f32>(0.6220703125, 0.01316070556640625), vec2<f32>(0.583984375, 0.01041412353515625),
|
|
85
|
+
vec2<f32>(0.87841796875, 0.1217041015625), vec2<f32>(0.8779296875, 0.1217041015625), vec2<f32>(0.875, 0.12060546875), vec2<f32>(0.869140625, 0.116943359375),
|
|
86
|
+
vec2<f32>(0.85693359375, 0.1080322265625), vec2<f32>(0.837890625, 0.09375), vec2<f32>(0.81494140625, 0.076904296875), vec2<f32>(0.7958984375, 0.060699462890625),
|
|
87
|
+
vec2<f32>(0.7763671875, 0.046875), vec2<f32>(0.75634765625, 0.035919189453125), vec2<f32>(0.732421875, 0.0274505615234375), vec2<f32>(0.703125, 0.021026611328125),
|
|
88
|
+
vec2<f32>(0.6689453125, 0.01617431640625), vec2<f32>(0.63037109375, 0.01251220703125), vec2<f32>(0.58935546875, 0.00974273681640625), vec2<f32>(0.54638671875, 0.007633209228515625),
|
|
89
|
+
vec2<f32>(0.92626953125, 0.07379150390625), vec2<f32>(0.92578125, 0.07391357421875), vec2<f32>(0.9228515625, 0.07391357421875), vec2<f32>(0.9169921875, 0.0731201171875),
|
|
90
|
+
vec2<f32>(0.90380859375, 0.06982421875), vec2<f32>(0.88134765625, 0.0631103515625), vec2<f32>(0.85107421875, 0.053802490234375), vec2<f32>(0.8212890625, 0.043701171875),
|
|
91
|
+
vec2<f32>(0.791015625, 0.034393310546875), vec2<f32>(0.76123046875, 0.026611328125), vec2<f32>(0.72802734375, 0.02044677734375), vec2<f32>(0.69189453125, 0.015655517578125),
|
|
92
|
+
vec2<f32>(0.65087890625, 0.0120086669921875), vec2<f32>(0.607421875, 0.00925445556640625), vec2<f32>(0.56103515625, 0.0071563720703125), vec2<f32>(0.51416015625, 0.005565643310546875),
|
|
93
|
+
vec2<f32>(0.95751953125, 0.042327880859375), vec2<f32>(0.95703125, 0.042449951171875), vec2<f32>(0.95458984375, 0.042816162109375), vec2<f32>(0.94921875, 0.043182373046875),
|
|
94
|
+
vec2<f32>(0.93701171875, 0.04266357421875), vec2<f32>(0.9130859375, 0.040252685546875), vec2<f32>(0.8818359375, 0.035797119140625), vec2<f32>(0.8447265625, 0.0301361083984375),
|
|
95
|
+
vec2<f32>(0.80615234375, 0.0243377685546875), vec2<f32>(0.76708984375, 0.0191497802734375), vec2<f32>(0.7265625, 0.01485443115234375), vec2<f32>(0.6826171875, 0.01142120361328125),
|
|
96
|
+
vec2<f32>(0.63623046875, 0.0087738037109375), vec2<f32>(0.5869140625, 0.006740570068359375), vec2<f32>(0.53662109375, 0.005199432373046875), vec2<f32>(0.486083984375, 0.00402069091796875),
|
|
97
|
+
vec2<f32>(0.9775390625, 0.0226287841796875), vec2<f32>(0.97705078125, 0.0227508544921875), vec2<f32>(0.97509765625, 0.023193359375), vec2<f32>(0.9697265625, 0.0239105224609375),
|
|
98
|
+
vec2<f32>(0.95947265625, 0.0244903564453125), vec2<f32>(0.93603515625, 0.0241241455078125), vec2<f32>(0.9052734375, 0.02252197265625), vec2<f32>(0.865234375, 0.0197601318359375),
|
|
99
|
+
vec2<f32>(0.82177734375, 0.016510009765625), vec2<f32>(0.7744140625, 0.0132904052734375), vec2<f32>(0.7265625, 0.01045989990234375), vec2<f32>(0.67626953125, 0.0081329345703125),
|
|
100
|
+
vec2<f32>(0.6240234375, 0.00627899169921875), vec2<f32>(0.56982421875, 0.004825592041015625), vec2<f32>(0.51513671875, 0.0037136077880859375), vec2<f32>(0.46142578125, 0.0028629302978515625),
|
|
101
|
+
vec2<f32>(0.98876953125, 0.01107025146484375), vec2<f32>(0.98876953125, 0.01116180419921875), vec2<f32>(0.98681640625, 0.01151275634765625), vec2<f32>(0.98291015625, 0.01221466064453125),
|
|
102
|
+
vec2<f32>(0.97314453125, 0.01299285888671875), vec2<f32>(0.953125, 0.013519287109375), vec2<f32>(0.9228515625, 0.01328277587890625), vec2<f32>(0.88232421875, 0.01226043701171875),
|
|
103
|
+
vec2<f32>(0.8349609375, 0.01065826416015625), vec2<f32>(0.783203125, 0.00885009765625), vec2<f32>(0.728515625, 0.007114410400390625), vec2<f32>(0.671875, 0.00560760498046875),
|
|
104
|
+
vec2<f32>(0.61376953125, 0.004360198974609375), vec2<f32>(0.5546875, 0.0033721923828125), vec2<f32>(0.496337890625, 0.0025997161865234375), vec2<f32>(0.439453125, 0.0020046234130859375),
|
|
105
|
+
vec2<f32>(0.9951171875, 0.00479888916015625), vec2<f32>(0.9951171875, 0.004863739013671875), vec2<f32>(0.99365234375, 0.005096435546875), vec2<f32>(0.990234375, 0.005603790283203125),
|
|
106
|
+
vec2<f32>(0.9814453125, 0.0063323974609375), vec2<f32>(0.96435546875, 0.006977081298828125), vec2<f32>(0.93603515625, 0.007297515869140625), vec2<f32>(0.896484375, 0.0071258544921875),
|
|
107
|
+
vec2<f32>(0.8466796875, 0.00649261474609375), vec2<f32>(0.79150390625, 0.005596160888671875), vec2<f32>(0.7314453125, 0.004627227783203125), vec2<f32>(0.6689453125, 0.0037174224853515625),
|
|
108
|
+
vec2<f32>(0.60546875, 0.0029296875), vec2<f32>(0.54150390625, 0.00228118896484375), vec2<f32>(0.479248046875, 0.001766204833984375), vec2<f32>(0.419677734375, 0.00136566162109375),
|
|
109
|
+
vec2<f32>(0.998046875, 0.0017604827880859375), vec2<f32>(0.998046875, 0.0017938613891601562), vec2<f32>(0.99658203125, 0.0019292831420898438), vec2<f32>(0.994140625, 0.002239227294921875),
|
|
110
|
+
vec2<f32>(0.986328125, 0.0027294158935546875), vec2<f32>(0.9716796875, 0.0032501220703125), vec2<f32>(0.94580078125, 0.00366973876953125), vec2<f32>(0.90771484375, 0.003818511962890625),
|
|
111
|
+
vec2<f32>(0.8583984375, 0.003681182861328125), vec2<f32>(0.79931640625, 0.0033206939697265625), vec2<f32>(0.7353515625, 0.0028438568115234375), vec2<f32>(0.66748046875, 0.0023441314697265625),
|
|
112
|
+
vec2<f32>(0.5986328125, 0.0018796920776367188), vec2<f32>(0.5302734375, 0.0014829635620117188), vec2<f32>(0.464111328125, 0.0011587142944335938), vec2<f32>(0.402099609375, 0.0008993148803710938),
|
|
113
|
+
vec2<f32>(0.99951171875, 0.0005011558532714844), vec2<f32>(0.99951171875, 0.0005154609680175781), vec2<f32>(0.998046875, 0.000583648681640625), vec2<f32>(0.99658203125, 0.0007505416870117188),
|
|
114
|
+
vec2<f32>(0.9892578125, 0.00101470947265625), vec2<f32>(0.97607421875, 0.001346588134765625), vec2<f32>(0.95263671875, 0.0016527175903320312), vec2<f32>(0.916015625, 0.0018558502197265625),
|
|
115
|
+
vec2<f32>(0.8671875, 0.0019054412841796875), vec2<f32>(0.8076171875, 0.0018167495727539062), vec2<f32>(0.7392578125, 0.001621246337890625), vec2<f32>(0.6669921875, 0.0013799667358398438),
|
|
116
|
+
vec2<f32>(0.59326171875, 0.0011358261108398438), vec2<f32>(0.52001953125, 0.0009121894836425781), vec2<f32>(0.450439453125, 0.0007219314575195312), vec2<f32>(0.385986328125, 0.0005650520324707031),
|
|
117
|
+
vec2<f32>(1.0, 0.00009316205978393555), vec2<f32>(1.0, 0.0000978708267211914), vec2<f32>(0.9990234375, 0.00012540817260742188), vec2<f32>(0.9970703125, 0.00019216537475585938),
|
|
118
|
+
vec2<f32>(0.99072265625, 0.0003104209899902344), vec2<f32>(0.97900390625, 0.0004699230194091797), vec2<f32>(0.95751953125, 0.0006470680236816406), vec2<f32>(0.92333984375, 0.0007915496826171875),
|
|
119
|
+
vec2<f32>(0.87548828125, 0.0008769035339355469), vec2<f32>(0.81494140625, 0.0008869171142578125), vec2<f32>(0.744140625, 0.0008325576782226562), vec2<f32>(0.66748046875, 0.0007386207580566406),
|
|
120
|
+
vec2<f32>(0.58837890625, 0.0006265640258789062), vec2<f32>(0.51123046875, 0.0005168914794921875), vec2<f32>(0.438232421875, 0.0004165172576904297), vec2<f32>(0.37109375, 0.0003311634063720703),
|
|
121
|
+
vec2<f32>(1.0, 0.000007271766662597656), vec2<f32>(1.0, 0.000008165836334228516), vec2<f32>(0.9990234375, 0.000016987323760986328), vec2<f32>(0.99755859375, 0.00003790855407714844),
|
|
122
|
+
vec2<f32>(0.9921875, 0.00007593631744384766), vec2<f32>(0.9814453125, 0.00013744831085205078), vec2<f32>(0.96142578125, 0.00020754337310791016), vec2<f32>(0.92919921875, 0.00028014183044433594),
|
|
123
|
+
vec2<f32>(0.8828125, 0.0003345012664794922), vec2<f32>(0.82177734375, 0.00036263465881347656), vec2<f32>(0.7490234375, 0.00036215782165527344), vec2<f32>(0.66845703125, 0.0003380775451660156),
|
|
124
|
+
vec2<f32>(0.58544921875, 0.00029969215393066406), vec2<f32>(0.50390625, 0.00025582313537597656), vec2<f32>(0.427001953125, 0.0002117156982421875), vec2<f32>(0.357666015625, 0.00017201900482177734),
|
|
125
|
+
vec2<f32>(1.0, 0.0), vec2<f32>(1.0, 5.960464477539063e-8), vec2<f32>(0.99951171875, 0.0000012516975402832031), vec2<f32>(0.99755859375, 0.000005304813385009766),
|
|
126
|
+
vec2<f32>(0.9931640625, 0.000015079975128173828), vec2<f32>(0.98291015625, 0.00002855062484741211), vec2<f32>(0.96435546875, 0.00004744529724121094), vec2<f32>(0.93408203125, 0.00006842613220214844),
|
|
127
|
+
vec2<f32>(0.88916015625, 0.00008893013000488281), vec2<f32>(0.828125, 0.0001042485237121582), vec2<f32>(0.75390625, 0.00011217594146728516), vec2<f32>(0.67041015625, 0.00011241436004638672),
|
|
128
|
+
vec2<f32>(0.5830078125, 0.00010627508163452148), vec2<f32>(0.4970703125, 0.00009584426879882812), vec2<f32>(0.4169921875, 0.0000833272933959961), vec2<f32>(0.34521484375, 0.00007051229476928711),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
fn _sampleThreeR184DfgLut(roughness : f32, dotNV : f32) -> vec2<f32> {
|
|
132
|
+
let uv = clamp(vec2<f32>(roughness, dotNV), vec2<f32>(0.0), vec2<f32>(1.0));
|
|
133
|
+
let samplePosition = uv * f32(THREE_R184_DFG_LUT_SIZE) - vec2<f32>(0.5);
|
|
134
|
+
let base = vec2<i32>(floor(samplePosition));
|
|
135
|
+
let weight = fract(samplePosition);
|
|
136
|
+
let last = i32(THREE_R184_DFG_LUT_SIZE - 1u);
|
|
137
|
+
let lo = clamp(base, vec2<i32>(0), vec2<i32>(last));
|
|
138
|
+
let hi = clamp(base + vec2<i32>(1), vec2<i32>(0), vec2<i32>(last));
|
|
139
|
+
let rowLo = mix(
|
|
140
|
+
THREE_R184_DFG_LUT[u32(lo.y) * THREE_R184_DFG_LUT_SIZE + u32(lo.x)],
|
|
141
|
+
THREE_R184_DFG_LUT[u32(lo.y) * THREE_R184_DFG_LUT_SIZE + u32(hi.x)],
|
|
142
|
+
weight.x,
|
|
143
|
+
);
|
|
144
|
+
let rowHi = mix(
|
|
145
|
+
THREE_R184_DFG_LUT[u32(hi.y) * THREE_R184_DFG_LUT_SIZE + u32(lo.x)],
|
|
146
|
+
THREE_R184_DFG_LUT[u32(hi.y) * THREE_R184_DFG_LUT_SIZE + u32(hi.x)],
|
|
147
|
+
weight.x,
|
|
148
|
+
);
|
|
149
|
+
return mix(rowLo, rowHi, weight.y);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
fn _threeR184DirectMultiScatter(
|
|
153
|
+
roughness : f32,
|
|
154
|
+
nDotV : f32,
|
|
155
|
+
nDotL : f32,
|
|
156
|
+
F0 : vec3<f32>,
|
|
157
|
+
) -> vec3<f32> {
|
|
158
|
+
let dfgV = _sampleThreeR184DfgLut(roughness, nDotV);
|
|
159
|
+
let dfgL = _sampleThreeR184DfgLut(roughness, nDotL);
|
|
160
|
+
let fssEssV = F0 * dfgV.x + vec3<f32>(dfgV.y);
|
|
161
|
+
let fssEssL = F0 * dfgL.x + vec3<f32>(dfgL.y);
|
|
162
|
+
let emsV = 1.0 - dfgV.x - dfgV.y;
|
|
163
|
+
let emsL = 1.0 - dfgL.x - dfgL.y;
|
|
164
|
+
let favg = F0 + (vec3<f32>(1.0) - F0) * 0.047619;
|
|
165
|
+
let energyLoss = emsV * emsL;
|
|
166
|
+
let fms = fssEssV * fssEssL * favg
|
|
167
|
+
/ (vec3<f32>(1.0) - energyLoss * favg * favg + vec3<f32>(1e-6));
|
|
168
|
+
return fms * energyLoss;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Pick the cascade layer for a positive view-space depth -- walks
|
|
172
|
+
// splitPlanes in order, returns the first split the depth falls below. Last
|
|
173
|
+
// layer (count - 1) catches everything beyond splits[count-2]. cascadeCount=1
|
|
174
|
+
// returns 0 unconditionally without a special branch (count - 1u == 0
|
|
175
|
+
// short-circuits the loop trip count).
|
|
176
|
+
//
|
|
177
|
+
// NOTE the sign: the vertex stage emits `viewZ = -clipPos.w` (NEGATIVE in
|
|
178
|
+
// front of the camera -- the deliberate convention the cluster Z-slice path
|
|
179
|
+
// also relies on), but `pssmSplit` host-side produces POSITIVE view-space
|
|
180
|
+
// split depths. The caller therefore passes `viewDepth = -viewZ` so this
|
|
181
|
+
// comparison is positive-vs-positive. Comparing the raw negative viewZ against
|
|
182
|
+
// positive splits collapsed every visible fragment to layer 0 (its near slab),
|
|
183
|
+
// projecting far geometry out of the tile -> shadowFactor always 1.0 (no
|
|
184
|
+
// occlusion). (downstream template integration #1.)
|
|
185
|
+
fn _pickCascadeLayer(viewDepth : f32, count : u32) -> u32 {
|
|
186
|
+
var layer : u32 = count - 1u;
|
|
187
|
+
for (var i : u32 = 0u; i < count - 1u; i = i + 1u) {
|
|
188
|
+
let sp = view.splitPlanes[i].x;
|
|
189
|
+
if (viewDepth < sp) {
|
|
190
|
+
layer = i;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return layer;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Look up the lightViewProj matrix for layer index. View UBO carries 4
|
|
198
|
+
// distinct fields (lightViewProj_A..D); WGSL has no addressable mat4
|
|
199
|
+
// array on a uniform, so a manual switch keeps the path uniform.
|
|
200
|
+
fn _cascadeLightViewProj(layer : u32) -> mat4x4<f32> {
|
|
201
|
+
switch (layer) {
|
|
202
|
+
case 0u: { return view.lightViewProj_A; }
|
|
203
|
+
case 1u: { return view.lightViewProj_B; }
|
|
204
|
+
case 2u: { return view.lightViewProj_C; }
|
|
205
|
+
default: { return view.lightViewProj_D; }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Match the host's compact atlas exactly: 1 -> 1x1, 2 -> 2x1, 3/4 -> 2x2.
|
|
210
|
+
// A square-only scale halves Y for the common two-cascade case even though
|
|
211
|
+
// each raster viewport spans the atlas's full height, so receivers sample a
|
|
212
|
+
// different region than casters wrote.
|
|
213
|
+
fn _atlasTileGrid(count : u32) -> vec2<u32> {
|
|
214
|
+
let columns : u32 = select(2u, 1u, count <= 1u);
|
|
215
|
+
let rows : u32 = (count + columns - 1u) / columns;
|
|
216
|
+
return vec2<u32>(columns, rows);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fn _atlasTileScale(count : u32) -> vec2<f32> {
|
|
220
|
+
return vec2<f32>(1.0) / vec2<f32>(_atlasTileGrid(count));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fn _atlasTileOrigin(layer : u32, count : u32) -> vec2<f32> {
|
|
224
|
+
let grid = _atlasTileGrid(count);
|
|
225
|
+
let tile = vec2<u32>(layer % grid.x, layer / grid.x);
|
|
226
|
+
return vec2<f32>(tile) / vec2<f32>(grid);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Sample the shadow atlas with the LO 3.1.3 slope-scaled bias + dynamic PCF
|
|
230
|
+
// kernel (driven by view.pcfKernelSize, MAX_PCF_HALF=2),
|
|
231
|
+
// against the lightViewProj for the chosen cascade. The shader maps NDC
|
|
232
|
+
// xy to that cascade's atlas tile in fragment space (matrix carries
|
|
233
|
+
// clip-space; tile placement happens here so shadow_caster.gl_Position
|
|
234
|
+
// stays in the WGSL clip-space contract).
|
|
235
|
+
fn _sampleShadowForCascade(
|
|
236
|
+
worldPos : vec3<f32>,
|
|
237
|
+
layer : u32,
|
|
238
|
+
count : u32,
|
|
239
|
+
normal : vec3<f32>,
|
|
240
|
+
l : vec3<f32>,
|
|
241
|
+
) -> f32 {
|
|
242
|
+
let lvp = _cascadeLightViewProj(layer);
|
|
243
|
+
let lightClip = lvp * vec4<f32>(worldPos, 1.0);
|
|
244
|
+
let projCoords = lightClip.xyz / lightClip.w;
|
|
245
|
+
let tileScale = _atlasTileScale(count);
|
|
246
|
+
let tileOrigin = _atlasTileOrigin(layer, count);
|
|
247
|
+
// NDC [-1,1] -> tile-local UV -> compact atlas UV.
|
|
248
|
+
let tileUv = vec2<f32>(projCoords.x * 0.5 + 0.5, -projCoords.y * 0.5 + 0.5);
|
|
249
|
+
let uv = tileUv * tileScale + tileOrigin;
|
|
250
|
+
let currentDepth = projCoords.z;
|
|
251
|
+
// feat-20260621-merge-directionallightshadow-into-directionallight M3 / m3-t4
|
|
252
|
+
// (D-1): the slope-scaled bias is driven by the merged DirectionalLight's
|
|
253
|
+
// shadow fields carried in the View UBO -- normalBias scales the
|
|
254
|
+
// (1 - N.L) slope term, depthBias is the constant floor. Replaces the prior
|
|
255
|
+
// hardcoded max(0.05*(1-N.L), 0.005).
|
|
256
|
+
let bias = max(view.normalBias * (1.0 - dot(normal, l)), view.depthBias);
|
|
257
|
+
let adjustedDepth = currentDepth - bias;
|
|
258
|
+
// NaN-safe bounds: relational < and > do not reject NaN (NaN < 0 is
|
|
259
|
+
// false), so a zero / degenerate lightViewProj matrix that produces
|
|
260
|
+
// 0/0 = NaN would slip through. Use x >= 0 && x <= 1 instead -- NaN
|
|
261
|
+
// makes the conjunction false and the early-return fires (shadow=1.0).
|
|
262
|
+
// Matches the main-line pattern that survived the transform-hierarchy
|
|
263
|
+
// dawn regression test (AC-08 parent-move pixel-diff on main).
|
|
264
|
+
if (!(tileUv.x >= 0.0 && tileUv.x <= 1.0 && tileUv.y >= 0.0 && tileUv.y <= 1.0 && currentDepth <= 1.0)) {
|
|
265
|
+
return 1.0;
|
|
266
|
+
}
|
|
267
|
+
let texelDims = vec2<f32>(textureDimensions(shadowMap, 0));
|
|
268
|
+
let texel = vec2<f32>(1.0 / texelDims.x, 1.0 / texelDims.y);
|
|
269
|
+
// AC-07 (bug-20260619): the OOB guard above is in tile-local space, but the
|
|
270
|
+
// PCF tap offset is applied in atlas space. For count>1 (inv<1) a fragment
|
|
271
|
+
// within one texel of a tile edge would sample into a NEIGHBOURING cascade's
|
|
272
|
+
// tile, reading the wrong depth and producing a 1-texel seam at cascade
|
|
273
|
+
// boundaries. Clamp every tap to this cascade's tile rect
|
|
274
|
+
// [tileOrigin, tileOrigin+tileScale) (one texel inset) so taps stay in-tile.
|
|
275
|
+
let tileLo = tileOrigin + texel;
|
|
276
|
+
let tileHi = tileOrigin + tileScale - texel;
|
|
277
|
+
// Variable-width PCF kernel driven by view.pcfKernelSize (feat-20260621
|
|
278
|
+
// 5.3-production-shadow-demos AC-14 merged with the DirectionalLightShadow
|
|
279
|
+
// merge). Constant trip count to MAX_PCF_HALF with a per-iteration clip to the
|
|
280
|
+
// runtime radius keeps the shader variant-free (no dynamic loop bound, legal
|
|
281
|
+
// for textureSampleCompareLevel uniform control flow). Host clamps
|
|
282
|
+
// view.pcfKernelSize to {1,3,5}; divisor = actual tap count, so pcfKernelSize=3
|
|
283
|
+
// -> half=1 -> 9 taps / 9.0 (result-identical to the prior hard-coded 3x3);
|
|
284
|
+
// pcfKernelSize=1 -> half=0 -> single centre tap (hard edge); pcfKernelSize=5
|
|
285
|
+
// -> half=2 -> 25-tap soft penumbra.
|
|
286
|
+
let requestedKernel = clamp(u32(round(view.pcfKernelSize)), 1u, 2u * MAX_PCF_HALF + 1u);
|
|
287
|
+
// Preserve the previous radius mapping for malformed even values:
|
|
288
|
+
// 1 -> 1x1, 2/3/4 -> 3x3, 5 -> 5x5. The authored component accepts only
|
|
289
|
+
// {1,3,5}, but keeping this normalization makes the refactor output-stable
|
|
290
|
+
// for raw UBO callers too.
|
|
291
|
+
let kernel = select(select(5u, 3u, requestedKernel <= 4u), 1u, requestedKernel == 1u);
|
|
292
|
+
if (kernel == 1u) {
|
|
293
|
+
let lit = textureSampleCompareLevel(shadowMap, shadowSampler, clamp(uv, tileLo, tileHi), adjustedDepth);
|
|
294
|
+
return lit;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
var blocked = 0.0;
|
|
298
|
+
if (kernel == 3u) {
|
|
299
|
+
// A linear comparison sample is already the bilinear average of four
|
|
300
|
+
// depth comparisons. Three adjacent samples on one axis therefore have
|
|
301
|
+
// the separable texel weights [1-f, 1, 1, f]. Pairing those four weights
|
|
302
|
+
// into two bilinear samples is exact, reducing the 3x3 path from 9 samples
|
|
303
|
+
// to 4. Keep the original 9-sample form at cascade-tile edges where the
|
|
304
|
+
// per-tap clamp intentionally duplicates edge samples.
|
|
305
|
+
let interior = all(uv >= tileLo + texel) && all(uv <= tileHi - texel);
|
|
306
|
+
if (interior) {
|
|
307
|
+
let pcfFraction = fract(uv / texel - vec2<f32>(0.5));
|
|
308
|
+
let loWeight = vec2<f32>(2.0) - pcfFraction;
|
|
309
|
+
let hiWeight = vec2<f32>(1.0) + pcfFraction;
|
|
310
|
+
let loOffset = vec2<f32>(-1.0) - pcfFraction + vec2<f32>(1.0) / loWeight;
|
|
311
|
+
let hiOffset = vec2<f32>(1.0) - pcfFraction + pcfFraction / hiWeight;
|
|
312
|
+
let litLoLo = textureSampleCompareLevel(
|
|
313
|
+
shadowMap, shadowSampler, uv + vec2<f32>(loOffset.x, loOffset.y) * texel, adjustedDepth,
|
|
314
|
+
);
|
|
315
|
+
let litHiLo = textureSampleCompareLevel(
|
|
316
|
+
shadowMap, shadowSampler, uv + vec2<f32>(hiOffset.x, loOffset.y) * texel, adjustedDepth,
|
|
317
|
+
);
|
|
318
|
+
let litLoHi = textureSampleCompareLevel(
|
|
319
|
+
shadowMap, shadowSampler, uv + vec2<f32>(loOffset.x, hiOffset.y) * texel, adjustedDepth,
|
|
320
|
+
);
|
|
321
|
+
let litHiHi = textureSampleCompareLevel(
|
|
322
|
+
shadowMap, shadowSampler, uv + vec2<f32>(hiOffset.x, hiOffset.y) * texel, adjustedDepth,
|
|
323
|
+
);
|
|
324
|
+
return (
|
|
325
|
+
litLoLo * loWeight.x * loWeight.y +
|
|
326
|
+
litHiLo * hiWeight.x * loWeight.y +
|
|
327
|
+
litLoHi * loWeight.x * hiWeight.y +
|
|
328
|
+
litHiHi * hiWeight.x * hiWeight.y
|
|
329
|
+
) / 9.0;
|
|
330
|
+
}
|
|
331
|
+
for (var x = -1; x <= 1; x++) {
|
|
332
|
+
for (var y = -1; y <= 1; y++) {
|
|
333
|
+
let offsetUv = clamp(uv + vec2<f32>(f32(x), f32(y)) * texel, tileLo, tileHi);
|
|
334
|
+
let lit = textureSampleCompareLevel(shadowMap, shadowSampler, offsetUv, adjustedDepth);
|
|
335
|
+
blocked = blocked + (1.0 - lit);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return 1.0 - blocked / 9.0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
for (var x = -i32(MAX_PCF_HALF); x <= i32(MAX_PCF_HALF); x++) {
|
|
342
|
+
for (var y = -i32(MAX_PCF_HALF); y <= i32(MAX_PCF_HALF); y++) {
|
|
343
|
+
let offsetUv = clamp(uv + vec2<f32>(f32(x), f32(y)) * texel, tileLo, tileHi);
|
|
344
|
+
let lit = textureSampleCompareLevel(shadowMap, shadowSampler, offsetUv, adjustedDepth);
|
|
345
|
+
blocked = blocked + (1.0 - lit);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return 1.0 - blocked / 25.0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// `evalDirectionalNoShadow` evaluates the GGX direct-lighting term for the
|
|
352
|
+
// single directional light carried in `view.lightDir / view.lightColor`
|
|
353
|
+
// WITHOUT applying any shadow factor — pure Cook-Torrance (D_GGX + V_Smith
|
|
354
|
+
// + F_Schlick) microfacet specular + Lambertian diffuse, returned scaled
|
|
355
|
+
// by `lightColor * nDotL`.
|
|
356
|
+
//
|
|
357
|
+
// feat-20260624-sprite-lit-shading-model-pure-2d-lighting M1' / w3 (D-1):
|
|
358
|
+
// extracted from evalDirectional so the brdf body matches the
|
|
359
|
+
// `evalPoint` / `evalSpot` pattern (no shadow tap inside the brdf
|
|
360
|
+
// function — caller multiplies the shadow factor afterwards). Industry
|
|
361
|
+
// alignment: Bevy / glTF Sample Renderer / Three.js all keep their
|
|
362
|
+
// directional brdf shadow-free; forgeax was the outlier with
|
|
363
|
+
// `_sampleShadowForCascade` hard-coded inside the body. Sprite-lit and
|
|
364
|
+
// future per-light variants get a clean shadow-free reuse target while
|
|
365
|
+
// mesh PBR keeps calling the wrapping `evalDirectional` (mathematically
|
|
366
|
+
// equivalent — see plan-strategy R-3D-mesh-PBR-output-shift).
|
|
367
|
+
//
|
|
368
|
+
// @internal — exported for sprite-lit re-use inside the engine; external
|
|
369
|
+
// material shaders should keep calling `evalDirectional` for backward
|
|
370
|
+
// compat with the cascaded-shadow pipeline.
|
|
371
|
+
fn evalDirectionalNoShadow(
|
|
372
|
+
normal : vec3<f32>,
|
|
373
|
+
viewDir : vec3<f32>,
|
|
374
|
+
baseColor : vec3<f32>,
|
|
375
|
+
metallic : f32,
|
|
376
|
+
alphaSq : f32,
|
|
377
|
+
F0 : vec3<f32>,
|
|
378
|
+
) -> vec3<f32> {
|
|
379
|
+
let l = normalize(-view.lightDir);
|
|
380
|
+
let h = normalize(viewDir + l);
|
|
381
|
+
let nDotL = max(dot(normal, l), 0.0);
|
|
382
|
+
let nDotV = max(dot(normal, viewDir), 1e-5);
|
|
383
|
+
let nDotH = max(dot(normal, h), 0.0);
|
|
384
|
+
let vDotH = max(dot(viewDir, h), 0.0);
|
|
385
|
+
let fresnel = exp2((-5.55473 * vDotH - 6.98316) * vDotH);
|
|
386
|
+
let f = F0 * (vec3<f32>(1.0) - fresnel) + vec3<f32>(fresnel);
|
|
387
|
+
let roughness = sqrt(max(alphaSq, 0.0));
|
|
388
|
+
let multiScatter = _threeR184DirectMultiScatter(roughness, nDotV, nDotL, F0);
|
|
389
|
+
let specular = d_ggx(nDotH, alphaSq) * v_smith(nDotV, nDotL, alphaSq) * f + multiScatter;
|
|
390
|
+
let diffuse = (1.0 - metallic) * baseColor / 3.14159265;
|
|
391
|
+
return (diffuse + specular) * view.lightColor * nDotL;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
fn evalDirectionalShadowFactor(
|
|
395
|
+
normal : vec3<f32>,
|
|
396
|
+
worldPos : vec3<f32>,
|
|
397
|
+
viewZ : f32,
|
|
398
|
+
) -> f32 {
|
|
399
|
+
// `cascadeCount == 0` is the host-side sentinel for DirectionalLight
|
|
400
|
+
// `castShadow:false`. A non-shadow-casting light must stay fully lit: the
|
|
401
|
+
// fallback depth view and zeroed light matrices only satisfy the bind-group
|
|
402
|
+
// shape and are not a valid CSM sample. Do this before the count clamp so
|
|
403
|
+
// the disabled path cannot accidentally project through cascade zero.
|
|
404
|
+
if (view.cascadeCount < 1.0) {
|
|
405
|
+
return 1.0;
|
|
406
|
+
}
|
|
407
|
+
let l = normalize(-view.lightDir);
|
|
408
|
+
let count = u32(max(view.cascadeCount, 1.0));
|
|
409
|
+
let viewDepth = -viewZ;
|
|
410
|
+
// `pssmSplit` stores the authored shadowDistance in the last active split.
|
|
411
|
+
// Geometry beyond that distance is intentionally unshadowed; reject it
|
|
412
|
+
// before cascade projection, atlas dimension queries, and the PCF loop.
|
|
413
|
+
if (viewDepth > view.splitPlanes[count - 1u].x) {
|
|
414
|
+
return 1.0;
|
|
415
|
+
}
|
|
416
|
+
let layer = _pickCascadeLayer(viewDepth, count);
|
|
417
|
+
let shadowCurr = _sampleShadowForCascade(worldPos, layer, count, normal, l);
|
|
418
|
+
|
|
419
|
+
var shadow = shadowCurr;
|
|
420
|
+
if (view.cascadeBlend > 0.0 && layer + 1u < count) {
|
|
421
|
+
let spCurr = view.splitPlanes[layer].x;
|
|
422
|
+
let blendWidth = spCurr * view.cascadeBlend;
|
|
423
|
+
if (blendWidth > 0.0) {
|
|
424
|
+
let dist = spCurr - viewDepth;
|
|
425
|
+
let t = clamp(1.0 - dist / blendWidth, 0.0, 1.0);
|
|
426
|
+
if (t > 0.0) {
|
|
427
|
+
let shadowNext = _sampleShadowForCascade(worldPos, layer + 1u, count, normal, l);
|
|
428
|
+
shadow = mix(shadowCurr, shadowNext, t);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return shadow;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// `evalDirectional` evaluates the GGX direct-lighting term for the single
|
|
436
|
+
// directional light carried in `view.lightDir / view.lightColor`. CSM
|
|
437
|
+
// pathway: pick cascade layer from viewZ + splitPlanes, sample the atlas
|
|
438
|
+
// tile via the matching lightViewProj, optionally blend with the next
|
|
439
|
+
// cascade across a `cascadeBlend`-wide boundary band.
|
|
440
|
+
//
|
|
441
|
+
// feat-20260624 M1' / w3 (D-1): body now delegates the brdf math to
|
|
442
|
+
// `evalDirectionalNoShadow` and multiplies the cascade shadow factor at
|
|
443
|
+
// the call site (mirrors `evalPoint` / `evalSpot` shape). Output is
|
|
444
|
+
// mathematically equivalent to the pre-refactor inline form — mesh PBR
|
|
445
|
+
// pixel-parity bench is the regression guard (w8).
|
|
446
|
+
fn evalDirectional(
|
|
447
|
+
normal : vec3<f32>,
|
|
448
|
+
viewDir : vec3<f32>,
|
|
449
|
+
baseColor : vec3<f32>,
|
|
450
|
+
metallic : f32,
|
|
451
|
+
alphaSq : f32,
|
|
452
|
+
F0 : vec3<f32>,
|
|
453
|
+
worldPos : vec3<f32>,
|
|
454
|
+
viewZ : f32,
|
|
455
|
+
) -> vec3<f32> {
|
|
456
|
+
// No-shadow brdf body (factored out — same expression as the prior
|
|
457
|
+
// inline form, multiplied by shadow factor below). Reuse keeps the
|
|
458
|
+
// mesh PBR output byte-equivalent and gives sprite-lit a shared
|
|
459
|
+
// shadow-free entry point.
|
|
460
|
+
let lit = evalDirectionalNoShadow(normal, viewDir, baseColor, metallic, alphaSq, F0);
|
|
461
|
+
|
|
462
|
+
// Cascade selection + atlas sampling (AC-03 / AC-05 / AC-06 / AC-10).
|
|
463
|
+
// feat-20260613-csm-cascaded-shadow-maps M5 / w18: uses inline 9-tap PCF
|
|
464
|
+
// inside `_sampleShadowForCascade` rather than the shared sample_shadow_2d
|
|
465
|
+
// (forgeax_pbr::shadow_pcf used by point-light) — the cascade dispatch
|
|
466
|
+
// wraps the kernel per-tile so the shared core's `(uv, currentDepth)`
|
|
467
|
+
// entry shape doesn't fit (it expects pre-projected light-space coords;
|
|
468
|
+
// CSM derives them per-cascade after dispatch). F-J-1 future-tracks the
|
|
469
|
+
// dedup once `forgeax_view::cascade` lands as its own module (post-#387).
|
|
470
|
+
return lit * evalDirectionalShadowFactor(normal, worldPos, viewZ);
|
|
471
|
+
}
|