@forgeax/engine-shader 0.1.21 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +14 -5
  2. package/dist/ShaderRegistry.d.ts.map +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.mjs +33042 -55
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/ltc/provenance.d.ts +17 -0
  8. package/dist/ltc/provenance.d.ts.map +1 -0
  9. package/dist/ltc/tables.d.ts +22 -0
  10. package/dist/ltc/tables.d.ts.map +1 -0
  11. package/dist/material/artifact-types.d.ts +52 -0
  12. package/dist/material/artifact-types.d.ts.map +1 -1
  13. package/dist/material-schemas.d.ts +36 -0
  14. package/dist/material-schemas.d.ts.map +1 -1
  15. package/dist/register-default-sprite-lit.d.ts +3 -6
  16. package/dist/register-default-sprite-lit.d.ts.map +1 -1
  17. package/dist/types.d.ts +2 -1
  18. package/dist/types.d.ts.map +1 -1
  19. package/package.json +4 -4
  20. package/src/ShaderRegistry.ts +0 -17
  21. package/src/__tests__/default-standard-pbr-alpha.unit.test.ts +9 -3
  22. package/src/__tests__/default-standard-pbr-transmission.unit.test.ts +67 -122
  23. package/src/__tests__/deferred-lighting-ssao.test.ts +3 -3
  24. package/src/__tests__/direct-light-layout.unit.test.ts +40 -0
  25. package/src/__tests__/ibl-irradiance.unit.test.ts +16 -4
  26. package/src/__tests__/ibl-sampling.unit.test.ts +3 -4
  27. package/src/__tests__/lighting-directional.unit.test.ts +36 -0
  28. package/src/__tests__/lighting-point-spot-volume.unit.test.ts +8 -2
  29. package/src/__tests__/lighting-punctual.unit.test.ts +40 -5
  30. package/src/__tests__/lighting-spot-volume-attenuation.unit.test.ts +1 -1
  31. package/src/__tests__/ltc-provenance.unit.test.ts +33 -0
  32. package/src/__tests__/manifest.fixture.json +33 -0
  33. package/src/__tests__/material-builtins.unit.test.ts +21 -3
  34. package/src/__tests__/material-contract.unit.test.ts +188 -14
  35. package/src/__tests__/physical-clearcoat.unit.test.ts +65 -0
  36. package/src/__tests__/probe-lighting-composition.unit.test.ts +39 -0
  37. package/src/__tests__/rect-area-brdf.unit.test.ts +36 -0
  38. package/src/__tests__/reflection-probe-sampling.unit.test.ts +24 -2
  39. package/src/__tests__/shader-manifest-transmission.unit.test.ts +8 -10
  40. package/src/__tests__/shader.unit.test.ts +54 -85
  41. package/src/__tests__/spot-cookie-composition.unit.test.ts +58 -0
  42. package/src/__tests__/spot-modifier-composition.unit.test.ts +19 -0
  43. package/src/__tests__/sprite-variants.unit.test.ts +4 -1
  44. package/src/__tests__/standard-webgl2-varying-budget.unit.test.ts +17 -0
  45. package/src/__tests__/surface-v1-negative.unit.test.ts +37 -0
  46. package/src/__tests__/surface-v1.unit.test.ts +83 -0
  47. package/src/__tests__/transmission-thickness-scale.unit.test.ts +2 -6
  48. package/src/__tests__/vertex-color-variant.unit.test.ts +16 -5
  49. package/src/brdf.wgsl +115 -1
  50. package/src/common.wgsl +53 -79
  51. package/src/default-standard-pbr-skin.wgsl +687 -144
  52. package/src/default-standard-pbr.wgsl +600 -247
  53. package/src/default_standard_surface.wgsl +88 -0
  54. package/src/hdrp-cluster-forward.wgsl +225 -0
  55. package/src/ibl-irradiance.wgsl +47 -9
  56. package/src/ibl-prefilter.wgsl +13 -3
  57. package/src/ibl-sampling.wgsl +2 -2
  58. package/src/ibl-shared.wgsl +9 -2
  59. package/src/index.ts +23 -0
  60. package/src/lighting-directional.wgsl +9 -117
  61. package/src/lighting-probe.wgsl +51 -0
  62. package/src/lighting-punctual.wgsl +21 -11
  63. package/src/lighting-rect-area.wgsl +162 -0
  64. package/src/lighting-spot-modifiers.wgsl +100 -0
  65. package/src/lighting-spot-projector.wgsl +31 -0
  66. package/src/ltc/provenance.ts +19 -0
  67. package/src/ltc/tables.ts +2831 -0
  68. package/src/material/artifact-types.ts +137 -0
  69. package/src/material/physical/anisotropy.wgsl +26 -0
  70. package/src/material/physical/clearcoat.wgsl +24 -0
  71. package/src/material/physical/iridescence.wgsl +23 -0
  72. package/src/material/physical/sheen.wgsl +17 -0
  73. package/src/material-schemas.ts +77 -30
  74. package/src/register-default-sprite-lit.ts +3 -6
  75. package/src/register-default-standard-pbr-skin.ts +2 -2
  76. package/src/sprite-lit.wgsl +3 -3
  77. package/src/sprite.wgsl +1 -1
  78. package/src/standard-cluster.wgsl +80 -78
  79. package/src/surface_v1.wgsl +26 -0
  80. package/src/types.ts +2 -1
  81. package/src/volume/volume-inject.wgsl +34 -36
  82. package/src/volume/volume-integrate.wgsl +48 -38
  83. package/dist/.tsbuildinfo +0 -1
package/src/brdf.wgsl CHANGED
@@ -21,5 +21,119 @@ fn v_smith(nDotV : f32, nDotL : f32, a : f32) -> f32 {
21
21
  }
22
22
 
23
23
  fn f_schlick(vDotH : f32, f0 : vec3<f32>) -> vec3<f32> {
24
- return f0 + (vec3<f32>(1.0) - f0) * pow(1.0 - vDotH, 5.0);
24
+ let fresnel = exp2((-5.55473 * vDotH - 6.98316) * vDotH);
25
+ return f0 * (vec3<f32>(1.0) - fresnel) + vec3<f32>(fresnel);
26
+ }
27
+
28
+
29
+ // Source: Three.js r184 src/nodes/functions/BSDF/DFGLUT.js. The full 16x16
30
+ // RG16F table is decoded to exact f32 constants here; the lookup below mirrors
31
+ // the source DataTexture's linear filtering and clamp-to-edge sampling without
32
+ // adding a host binding or coupling direct light to the engine IBL LUT.
33
+ const THREE_R184_DFG_LUT_SIZE : u32 = 16u;
34
+ const THREE_R184_DFG_LUT : array<vec2<f32>, 256> = array<vec2<f32>, 256>(
35
+ vec2<f32>(0.1470947265625, 0.85205078125), vec2<f32>(0.16552734375, 0.78759765625), vec2<f32>(0.244384765625, 0.638671875), vec2<f32>(0.370849609375, 0.51953125),
36
+ vec2<f32>(0.496826171875, 0.41552734375), vec2<f32>(0.60205078125, 0.326416015625), vec2<f32>(0.68408203125, 0.25390625), vec2<f32>(0.74609375, 0.197509765625),
37
+ vec2<f32>(0.79052734375, 0.154296875), vec2<f32>(0.822265625, 0.12164306640625), vec2<f32>(0.84326171875, 0.09698486328125), vec2<f32>(0.8564453125, 0.07843017578125),
38
+ vec2<f32>(0.86328125, 0.06439208984375), vec2<f32>(0.86572265625, 0.0537109375), vec2<f32>(0.8642578125, 0.045440673828125), vec2<f32>(0.85986328125, 0.039031982421875),
39
+ vec2<f32>(0.388671875, 0.611328125), vec2<f32>(0.39306640625, 0.6005859375), vec2<f32>(0.412353515625, 0.5458984375), vec2<f32>(0.45654296875, 0.4482421875),
40
+ vec2<f32>(0.52783203125, 0.3525390625), vec2<f32>(0.607421875, 0.27392578125), vec2<f32>(0.6787109375, 0.21142578125), vec2<f32>(0.7333984375, 0.16259765625),
41
+ vec2<f32>(0.77099609375, 0.1253662109375), vec2<f32>(0.79345703125, 0.0972900390625), vec2<f32>(0.80322265625, 0.07623291015625), vec2<f32>(0.8037109375, 0.06036376953125),
42
+ vec2<f32>(0.79638671875, 0.048431396484375), vec2<f32>(0.78564453125, 0.03936767578125), vec2<f32>(0.77197265625, 0.03240966796875), vec2<f32>(0.7548828125, 0.0269775390625),
43
+ vec2<f32>(0.572265625, 0.427490234375), vec2<f32>(0.57373046875, 0.424072265625), vec2<f32>(0.57958984375, 0.403564453125), vec2<f32>(0.591796875, 0.3544921875),
44
+ vec2<f32>(0.6162109375, 0.2880859375), vec2<f32>(0.6552734375, 0.224853515625), vec2<f32>(0.69873046875, 0.172607421875), vec2<f32>(0.7353515625, 0.1318359375),
45
+ vec2<f32>(0.75927734375, 0.10089111328125), vec2<f32>(0.77001953125, 0.07745361328125), vec2<f32>(0.77197265625, 0.0599365234375), vec2<f32>(0.76611328125, 0.046844482421875),
46
+ vec2<f32>(0.751953125, 0.0369873046875), vec2<f32>(0.732421875, 0.029541015625), vec2<f32>(0.70947265625, 0.023834228515625), vec2<f32>(0.68359375, 0.019439697265625),
47
+ vec2<f32>(0.708984375, 0.291015625), vec2<f32>(0.708984375, 0.289794921875), vec2<f32>(0.7099609375, 0.28125), vec2<f32>(0.7099609375, 0.258544921875),
48
+ vec2<f32>(0.71142578125, 0.220458984375), vec2<f32>(0.7197265625, 0.1768798828125), vec2<f32>(0.734375, 0.1370849609375), vec2<f32>(0.748046875, 0.10479736328125),
49
+ vec2<f32>(0.755859375, 0.07989501953125), vec2<f32>(0.759765625, 0.061004638671875), vec2<f32>(0.75341796875, 0.046844482421875), vec2<f32>(0.73876953125, 0.036224365234375),
50
+ vec2<f32>(0.7177734375, 0.02825927734375), vec2<f32>(0.69189453125, 0.0222625732421875), vec2<f32>(0.6611328125, 0.0177001953125), vec2<f32>(0.62841796875, 0.01419830322265625),
51
+ vec2<f32>(0.80810546875, 0.1917724609375), vec2<f32>(0.8076171875, 0.1912841796875), vec2<f32>(0.80615234375, 0.18798828125), vec2<f32>(0.8017578125, 0.1781005859375),
52
+ vec2<f32>(0.79296875, 0.15869140625), vec2<f32>(0.78369140625, 0.1322021484375), vec2<f32>(0.775390625, 0.1048583984375), vec2<f32>(0.7685546875, 0.08111572265625),
53
+ vec2<f32>(0.7646484375, 0.061981201171875), vec2<f32>(0.75537109375, 0.047271728515625), vec2<f32>(0.740234375, 0.036163330078125), vec2<f32>(0.71875, 0.0277557373046875),
54
+ vec2<f32>(0.69091796875, 0.021484375), vec2<f32>(0.658203125, 0.0167388916015625), vec2<f32>(0.6220703125, 0.01316070556640625), vec2<f32>(0.583984375, 0.01041412353515625),
55
+ vec2<f32>(0.87841796875, 0.1217041015625), vec2<f32>(0.8779296875, 0.1217041015625), vec2<f32>(0.875, 0.12060546875), vec2<f32>(0.869140625, 0.116943359375),
56
+ vec2<f32>(0.85693359375, 0.1080322265625), vec2<f32>(0.837890625, 0.09375), vec2<f32>(0.81494140625, 0.076904296875), vec2<f32>(0.7958984375, 0.060699462890625),
57
+ vec2<f32>(0.7763671875, 0.046875), vec2<f32>(0.75634765625, 0.035919189453125), vec2<f32>(0.732421875, 0.0274505615234375), vec2<f32>(0.703125, 0.021026611328125),
58
+ vec2<f32>(0.6689453125, 0.01617431640625), vec2<f32>(0.63037109375, 0.01251220703125), vec2<f32>(0.58935546875, 0.00974273681640625), vec2<f32>(0.54638671875, 0.007633209228515625),
59
+ vec2<f32>(0.92626953125, 0.07379150390625), vec2<f32>(0.92578125, 0.07391357421875), vec2<f32>(0.9228515625, 0.07391357421875), vec2<f32>(0.9169921875, 0.0731201171875),
60
+ vec2<f32>(0.90380859375, 0.06982421875), vec2<f32>(0.88134765625, 0.0631103515625), vec2<f32>(0.85107421875, 0.053802490234375), vec2<f32>(0.8212890625, 0.043701171875),
61
+ vec2<f32>(0.791015625, 0.034393310546875), vec2<f32>(0.76123046875, 0.026611328125), vec2<f32>(0.72802734375, 0.02044677734375), vec2<f32>(0.69189453125, 0.015655517578125),
62
+ vec2<f32>(0.65087890625, 0.0120086669921875), vec2<f32>(0.607421875, 0.00925445556640625), vec2<f32>(0.56103515625, 0.0071563720703125), vec2<f32>(0.51416015625, 0.005565643310546875),
63
+ vec2<f32>(0.95751953125, 0.042327880859375), vec2<f32>(0.95703125, 0.042449951171875), vec2<f32>(0.95458984375, 0.042816162109375), vec2<f32>(0.94921875, 0.043182373046875),
64
+ vec2<f32>(0.93701171875, 0.04266357421875), vec2<f32>(0.9130859375, 0.040252685546875), vec2<f32>(0.8818359375, 0.035797119140625), vec2<f32>(0.8447265625, 0.0301361083984375),
65
+ vec2<f32>(0.80615234375, 0.0243377685546875), vec2<f32>(0.76708984375, 0.0191497802734375), vec2<f32>(0.7265625, 0.01485443115234375), vec2<f32>(0.6826171875, 0.01142120361328125),
66
+ vec2<f32>(0.63623046875, 0.0087738037109375), vec2<f32>(0.5869140625, 0.006740570068359375), vec2<f32>(0.53662109375, 0.005199432373046875), vec2<f32>(0.486083984375, 0.00402069091796875),
67
+ vec2<f32>(0.9775390625, 0.0226287841796875), vec2<f32>(0.97705078125, 0.0227508544921875), vec2<f32>(0.97509765625, 0.023193359375), vec2<f32>(0.9697265625, 0.0239105224609375),
68
+ vec2<f32>(0.95947265625, 0.0244903564453125), vec2<f32>(0.93603515625, 0.0241241455078125), vec2<f32>(0.9052734375, 0.02252197265625), vec2<f32>(0.865234375, 0.0197601318359375),
69
+ vec2<f32>(0.82177734375, 0.016510009765625), vec2<f32>(0.7744140625, 0.0132904052734375), vec2<f32>(0.7265625, 0.01045989990234375), vec2<f32>(0.67626953125, 0.0081329345703125),
70
+ vec2<f32>(0.6240234375, 0.00627899169921875), vec2<f32>(0.56982421875, 0.004825592041015625), vec2<f32>(0.51513671875, 0.0037136077880859375), vec2<f32>(0.46142578125, 0.0028629302978515625),
71
+ vec2<f32>(0.98876953125, 0.01107025146484375), vec2<f32>(0.98876953125, 0.01116180419921875), vec2<f32>(0.98681640625, 0.01151275634765625), vec2<f32>(0.98291015625, 0.01221466064453125),
72
+ vec2<f32>(0.97314453125, 0.01299285888671875), vec2<f32>(0.953125, 0.013519287109375), vec2<f32>(0.9228515625, 0.01328277587890625), vec2<f32>(0.88232421875, 0.01226043701171875),
73
+ vec2<f32>(0.8349609375, 0.01065826416015625), vec2<f32>(0.783203125, 0.00885009765625), vec2<f32>(0.728515625, 0.007114410400390625), vec2<f32>(0.671875, 0.00560760498046875),
74
+ vec2<f32>(0.61376953125, 0.004360198974609375), vec2<f32>(0.5546875, 0.0033721923828125), vec2<f32>(0.496337890625, 0.0025997161865234375), vec2<f32>(0.439453125, 0.0020046234130859375),
75
+ vec2<f32>(0.9951171875, 0.00479888916015625), vec2<f32>(0.9951171875, 0.004863739013671875), vec2<f32>(0.99365234375, 0.005096435546875), vec2<f32>(0.990234375, 0.005603790283203125),
76
+ vec2<f32>(0.9814453125, 0.0063323974609375), vec2<f32>(0.96435546875, 0.006977081298828125), vec2<f32>(0.93603515625, 0.007297515869140625), vec2<f32>(0.896484375, 0.0071258544921875),
77
+ vec2<f32>(0.8466796875, 0.00649261474609375), vec2<f32>(0.79150390625, 0.005596160888671875), vec2<f32>(0.7314453125, 0.004627227783203125), vec2<f32>(0.6689453125, 0.0037174224853515625),
78
+ vec2<f32>(0.60546875, 0.0029296875), vec2<f32>(0.54150390625, 0.00228118896484375), vec2<f32>(0.479248046875, 0.001766204833984375), vec2<f32>(0.419677734375, 0.00136566162109375),
79
+ vec2<f32>(0.998046875, 0.0017604827880859375), vec2<f32>(0.998046875, 0.0017938613891601562), vec2<f32>(0.99658203125, 0.0019292831420898438), vec2<f32>(0.994140625, 0.002239227294921875),
80
+ vec2<f32>(0.986328125, 0.0027294158935546875), vec2<f32>(0.9716796875, 0.0032501220703125), vec2<f32>(0.94580078125, 0.00366973876953125), vec2<f32>(0.90771484375, 0.003818511962890625),
81
+ vec2<f32>(0.8583984375, 0.003681182861328125), vec2<f32>(0.79931640625, 0.0033206939697265625), vec2<f32>(0.7353515625, 0.0028438568115234375), vec2<f32>(0.66748046875, 0.0023441314697265625),
82
+ vec2<f32>(0.5986328125, 0.0018796920776367188), vec2<f32>(0.5302734375, 0.0014829635620117188), vec2<f32>(0.464111328125, 0.0011587142944335938), vec2<f32>(0.402099609375, 0.0008993148803710938),
83
+ vec2<f32>(0.99951171875, 0.0005011558532714844), vec2<f32>(0.99951171875, 0.0005154609680175781), vec2<f32>(0.998046875, 0.000583648681640625), vec2<f32>(0.99658203125, 0.0007505416870117188),
84
+ vec2<f32>(0.9892578125, 0.00101470947265625), vec2<f32>(0.97607421875, 0.001346588134765625), vec2<f32>(0.95263671875, 0.0016527175903320312), vec2<f32>(0.916015625, 0.0018558502197265625),
85
+ vec2<f32>(0.8671875, 0.0019054412841796875), vec2<f32>(0.8076171875, 0.0018167495727539062), vec2<f32>(0.7392578125, 0.001621246337890625), vec2<f32>(0.6669921875, 0.0013799667358398438),
86
+ vec2<f32>(0.59326171875, 0.0011358261108398438), vec2<f32>(0.52001953125, 0.0009121894836425781), vec2<f32>(0.450439453125, 0.0007219314575195312), vec2<f32>(0.385986328125, 0.0005650520324707031),
87
+ vec2<f32>(1.0, 0.00009316205978393555), vec2<f32>(1.0, 0.0000978708267211914), vec2<f32>(0.9990234375, 0.00012540817260742188), vec2<f32>(0.9970703125, 0.00019216537475585938),
88
+ vec2<f32>(0.99072265625, 0.0003104209899902344), vec2<f32>(0.97900390625, 0.0004699230194091797), vec2<f32>(0.95751953125, 0.0006470680236816406), vec2<f32>(0.92333984375, 0.0007915496826171875),
89
+ vec2<f32>(0.87548828125, 0.0008769035339355469), vec2<f32>(0.81494140625, 0.0008869171142578125), vec2<f32>(0.744140625, 0.0008325576782226562), vec2<f32>(0.66748046875, 0.0007386207580566406),
90
+ vec2<f32>(0.58837890625, 0.0006265640258789062), vec2<f32>(0.51123046875, 0.0005168914794921875), vec2<f32>(0.438232421875, 0.0004165172576904297), vec2<f32>(0.37109375, 0.0003311634063720703),
91
+ vec2<f32>(1.0, 0.000007271766662597656), vec2<f32>(1.0, 0.000008165836334228516), vec2<f32>(0.9990234375, 0.000016987323760986328), vec2<f32>(0.99755859375, 0.00003790855407714844),
92
+ vec2<f32>(0.9921875, 0.00007593631744384766), vec2<f32>(0.9814453125, 0.00013744831085205078), vec2<f32>(0.96142578125, 0.00020754337310791016), vec2<f32>(0.92919921875, 0.00028014183044433594),
93
+ vec2<f32>(0.8828125, 0.0003345012664794922), vec2<f32>(0.82177734375, 0.00036263465881347656), vec2<f32>(0.7490234375, 0.00036215782165527344), vec2<f32>(0.66845703125, 0.0003380775451660156),
94
+ vec2<f32>(0.58544921875, 0.00029969215393066406), vec2<f32>(0.50390625, 0.00025582313537597656), vec2<f32>(0.427001953125, 0.0002117156982421875), vec2<f32>(0.357666015625, 0.00017201900482177734),
95
+ 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),
96
+ vec2<f32>(0.9931640625, 0.000015079975128173828), vec2<f32>(0.98291015625, 0.00002855062484741211), vec2<f32>(0.96435546875, 0.00004744529724121094), vec2<f32>(0.93408203125, 0.00006842613220214844),
97
+ vec2<f32>(0.88916015625, 0.00008893013000488281), vec2<f32>(0.828125, 0.0001042485237121582), vec2<f32>(0.75390625, 0.00011217594146728516), vec2<f32>(0.67041015625, 0.00011241436004638672),
98
+ vec2<f32>(0.5830078125, 0.00010627508163452148), vec2<f32>(0.4970703125, 0.00009584426879882812), vec2<f32>(0.4169921875, 0.0000833272933959961), vec2<f32>(0.34521484375, 0.00007051229476928711),
99
+ );
100
+
101
+ fn sampleThreeR184DfgLut(roughness : f32, dotNV : f32) -> vec2<f32> {
102
+ let uv = clamp(vec2<f32>(roughness, dotNV), vec2<f32>(0.0), vec2<f32>(1.0));
103
+ let samplePosition = uv * f32(THREE_R184_DFG_LUT_SIZE) - vec2<f32>(0.5);
104
+ let base = vec2<i32>(floor(samplePosition));
105
+ let weight = fract(samplePosition);
106
+ let last = i32(THREE_R184_DFG_LUT_SIZE - 1u);
107
+ let lo = clamp(base, vec2<i32>(0), vec2<i32>(last));
108
+ let hi = clamp(base + vec2<i32>(1), vec2<i32>(0), vec2<i32>(last));
109
+ let rowLo = mix(
110
+ THREE_R184_DFG_LUT[u32(lo.y) * THREE_R184_DFG_LUT_SIZE + u32(lo.x)],
111
+ THREE_R184_DFG_LUT[u32(lo.y) * THREE_R184_DFG_LUT_SIZE + u32(hi.x)],
112
+ weight.x,
113
+ );
114
+ let rowHi = mix(
115
+ THREE_R184_DFG_LUT[u32(hi.y) * THREE_R184_DFG_LUT_SIZE + u32(lo.x)],
116
+ THREE_R184_DFG_LUT[u32(hi.y) * THREE_R184_DFG_LUT_SIZE + u32(hi.x)],
117
+ weight.x,
118
+ );
119
+ return mix(rowLo, rowHi, weight.y);
120
+ }
121
+
122
+ fn threeR184DirectMultiScatter(
123
+ roughness : f32,
124
+ nDotV : f32,
125
+ nDotL : f32,
126
+ F0 : vec3<f32>,
127
+ ) -> vec3<f32> {
128
+ let dfgV = sampleThreeR184DfgLut(roughness, nDotV);
129
+ let dfgL = sampleThreeR184DfgLut(roughness, nDotL);
130
+ let fssEssV = F0 * dfgV.x + vec3<f32>(dfgV.y);
131
+ let fssEssL = F0 * dfgL.x + vec3<f32>(dfgL.y);
132
+ let emsV = 1.0 - dfgV.x - dfgV.y;
133
+ let emsL = 1.0 - dfgL.x - dfgL.y;
134
+ let favg = F0 + (vec3<f32>(1.0) - F0) * 0.047619;
135
+ let energyLoss = emsV * emsL;
136
+ let fms = fssEssV * fssEssL * favg
137
+ / (vec3<f32>(1.0) - energyLoss * favg * favg + vec3<f32>(1e-6));
138
+ return fms * energyLoss;
25
139
  }
package/src/common.wgsl CHANGED
@@ -142,13 +142,10 @@ fn ditherUnorm8(value : vec3<f32>, pixelPosition : vec2<f32>) -> vec3<f32> {
142
142
  // the per-spot perspective `spotLightViewProj` matrices (4 lanes, fragment-read)
143
143
  // fold into the View UBO tail instead of a standalone @group(0) binding 9
144
144
  // uniform buffer. The standalone binding pushed the fragment-stage uniform
145
- // buffer count to 12 (view + pointLights + spotLights + shadowParams +
146
- // shadowCasterCascade + spotLightViewProj on the WebGL2 fallback path),
147
- // exceeding GLES 3.0's `max_uniform_buffers_per_shader_stage = 11` so the
148
- // WebGL2 fallback (mobile / WebKit this feat's compat target) crashed
149
- // pipeline-layout creation. Folding into the View UBO costs zero new bindings
150
- // (the count drops back to 11). D-1 rejected the View UBO for the CASTER vertex
151
- // channel (binding 7) because directional + spot casters both need a light-view
145
+ // buffer count to 12 before the local-light arrays were removed. The current
146
+ // view declares no point/spot light arrays; the spot matrices remain folded
147
+ // into the View UBO with no standalone binding. D-1 rejected the View UBO for
148
+ // the CASTER vertex channel (binding 7) because directional + spot casters both need a light-view
152
149
  // matrix in the same frame (same-frame write contention); the FRAGMENT read
153
150
  // channel has no such contention — the host writes all <=4 spot matrices once
154
151
  // per frame before the forward pass, so the fold is safe. mat4 array align=16:
@@ -207,12 +204,22 @@ struct Mesh {
207
204
  #endif
208
205
  };
209
206
 
207
+ // Retained CPU ProbeBlendRecord ABI: 4 scalar lanes plus 9 vec4 lanes = 160 B.
208
+ // The last lane carries padding for the 27 f32 SH coefficients. Sky residual
209
+ // is derived in lighting-probe.wgsl, never stored as a second fraction.
210
+ struct ProbeBlendRecord {
211
+ objectKey : f32,
212
+ generation : f32,
213
+ localBlendFraction : f32,
214
+ flags : f32,
215
+ shPreblend : array<vec4<f32>, 9>,
216
+ };
217
+
210
218
  // feat-20260519-light-casters-point-spot-pbr M4 / w21 (D-S1 + D-S2 +
211
219
  // AC-04 b/c + AC-05 binding declaration). Punctual-light std430 storage
212
- // types byte-for-byte mirror packPointLight / packSpotLight in
213
- // `packages/runtime/src/light-buffer-layout.ts`:
220
+ // types use the shared five-row host ABI in `light-buffer-layout.ts`:
214
221
  //
215
- // PointLight (32 B / 8 floats):
222
+ // Point/Spot/Rect direct slot (80 B / 20 u32-or-float lanes):
216
223
  // [ 0..2 ] position vec3<f32>
217
224
  // [ 3 ] invRangeSquared f32 (Bevy color_inverse_square_range.w; 0
218
225
  // collapses range falloff to a pure 1/d^2 inverse-square law)
@@ -220,7 +227,7 @@ struct Mesh {
220
227
  // color * intensity so the shader avoids the per-fragment mul)
221
228
  // [ 7 ] pad f32 = 0
222
229
  //
223
- // SpotLight (80 B / 20 floats):
230
+ // The metadata row carries kind, shadow, IES, and Cookie identities.
224
231
  // [ 0..2 ] position vec3<f32>
225
232
  // [ 3 ] invRangeSquared f32
226
233
  // [ 4..6 ] colorTimesIntensity vec3<f32>
@@ -229,81 +236,31 @@ struct Mesh {
229
236
  // [ 8..10] direction vec3<f32> (raw outgoing vector; shader reads
230
237
  // via dot(L, -direction) for cone angle test)
231
238
  // [ 11 ] cosOuter f32
232
- // [12] depthBias f32, [13] normalBias f32, [14] pcfKernelSize f32
233
- // [ 15 ] shadowAtlasTile i32 (sentinel -1 = unassigned/clipped,
234
- // 0..3 = spot atlas tile index; feat-20260625 M2/M3 D-4)
235
- // [ 16 ] shadowIntensity f32 (fraction of sampled shadow to apply)
236
- // [17..19] alignment tail padding
239
+ // Spot row 3: [12] depthBias, [13] normalBias, [14] shadowIntensity,
240
+ // [15] rollDeg. The unified slot has no separate pcf lane; the current
241
+ // surface and volume receivers use the stable PCF3 profile.
242
+ // Rect row 1/2/3: halfWidth, axisY + halfHeight, axisX + zero pad. The
243
+ // final metadata row carries the kind,
244
+ // shadow, IES, and Cookie identities.
237
245
  //
238
246
  // WGSL std430 alignment audit: vec3<f32> alignof=16 / sizeof=12. The
239
247
  // f32 lane wedged immediately after each vec3 fills the 4 B remainder
240
248
  // (WGSL struct member rule: next.offset = roundUp(prev.offset +
241
249
  // prev.size, this.alignof) - for f32 alignof=4 the round-up is a
242
250
  // no-op, so position[3] / color[3] / direction[3] sit at byte
243
- // offsets 12 / 28 / 44 with zero internal padding). PointLight stays
244
- // 32 B; SpotLight grows from 64 B (feat-20260625 M2/M3 D-4) for the three
245
- // receiver controls plus `shadowAtlasTile: i32`, then to 80 B for the
246
- // parity-only `shadowIntensity` lane at byte 64. These struct sizes match the
247
- // host packers (packPointLight 32 B / packSpotLight 80 B) exactly.
251
+ // offsets 12 / 28 / 44 with zero internal padding). Point, Spot, and Rect all
252
+ // use the unified 80 B host packer; this shared slot is the sole local-light
253
+ // carrier.
248
254
  //
249
- // Header `count: u32` lives in a wrapper struct with the trailing
250
- // runtime-sized array. Array-of-vec4-aligned-struct alignof = 16, so
251
- // `slots` starts at byte 16 (count u32 occupies 0..4; bytes 4..16 are
252
- // implicit padding). This matches `packLightArrayHeader`'s 16 B
253
- // (count u32 + 12 B pad) layout in light-buffer-layout.ts.
254
-
255
- struct PointLight {
256
- position : vec3<f32>,
257
- invRangeSquared : f32,
258
- colorTimesIntensity : vec3<f32>,
259
- // feat-20260612-point-light-shadows-urp-hdrp M1 / T-M1-8 (plan-strategy §D-2):
260
- // Repurposes the prior `pointPadW` (f32 zero-pad) lane as `shadowAtlasLayer`
261
- // (i32 sentinel, -1 = no shadow, 0..3 = cube_array atlas layer index for
262
- // shadow-casting point lights). Cap = 4 enforced by the PointLightShadow
263
- // ECS component cardinality. The shader path samples the cube_array atlas
264
- // (binding 5) only when `shadowAtlasLayer >= 0`. Field name is unique to
265
- // this struct (no `pad0`/`pad1` collision with the pbr Material struct
266
- // under naga_oil writeback substitution).
267
- shadowAtlasLayer : i32,
268
- };
269
-
270
- struct SpotLight {
271
- position : vec3<f32>,
272
- invRangeSquared : f32,
273
- colorTimesIntensity : vec3<f32>,
274
- cosInner : f32,
275
- direction : vec3<f32>,
276
- cosOuter : f32,
277
- // feat-20260625-spot-light-shadow-mapping M3 / w13 (plan-strategy D-4):
278
- // The trailing vec4 transports receiver controls and the tile identity.
279
- // Host packSpotLight writes slots 12..14 from the same snapshot; slot 15 is
280
- // the i32 shadow tile sentinel and slot 16 carries shadowIntensity.
281
- depthBias : f32,
282
- normalBias : f32,
283
- pcfKernelSize : f32,
284
- shadowAtlasTile : i32,
285
- shadowIntensity : f32,
286
- };
287
-
288
- struct PointLightsArray {
289
- count : u32,
290
- slots : array<PointLight, 4>,
291
- };
292
-
293
- struct SpotLightsArray {
294
- count : u32,
295
- slots : array<SpotLight, 4>,
255
+ struct DirectLightSlot {
256
+ position : vec4<f32>, // row0: position + inverse range
257
+ colorTimesIntensity : vec4<f32>, // row1: color + first angular fact
258
+ direction : vec4<f32>, // row2: primary axis + second angular fact
259
+ auxiliary : vec4<f32>, // row3: auxiliary Rect axis
260
+ metadata : vec4<u32>,
296
261
  };
297
262
 
298
263
  @group(0) @binding(0) var<uniform> view : View;
299
-
300
- #if STORAGE_BUFFER_AVAILABLE == true
301
- @group(0) @binding(1) var<storage, read> pointLightsBuffer : PointLightsArray;
302
- @group(0) @binding(2) var<storage, read> spotLightsBuffer : SpotLightsArray;
303
- #else
304
- @group(0) @binding(1) var<uniform> pointLightsBuffer : PointLightsArray;
305
- @group(0) @binding(2) var<uniform> spotLightsBuffer : SpotLightsArray;
306
- #endif
307
264
  // feat-20260520-directional-light-shadow-mapping M3 / w16 (D-1 / plan-strategy §8.1):
308
265
  // shadowMap + shadowSampler consume @group(0) bindings 3/4 (smallest unused
309
266
  // slots adjacent to view UBO at 0). M3 uses 3x3 PCF with textureLoad on
@@ -314,7 +271,7 @@ struct SpotLightsArray {
314
271
  // layers=4, depth32float; one cube per shadow-casting point light, cap=4).
315
272
  // Binding 6 declares the per-light shadow params buffer (URP only — proj
316
273
  // constants for cube depth-ref reconstruction); HDRP rides the same constants
317
- // on LightSlot pad lanes (.kind_and_pad.wyz) so binding 6 stays unbound on
274
+ // on direct-light metadata so binding 6 stays unbound on
318
275
  // the HDRP path. Sample-time gating by PointLight.shadowAtlasLayer >= 0.
319
276
  @group(0) @binding(3) var shadowMap : texture_depth_2d;
320
277
  @group(0) @binding(4) var shadowSampler : sampler_comparison;
@@ -337,7 +294,7 @@ struct SpotLightsArray {
337
294
  // depth-ref reconstruction (research L0.5 + L1.13). Each lane stores the
338
295
  // shader-side reconstruction constants for one shadow-casting point light;
339
296
  // slot N matches `PointLight.shadowAtlasLayer = N`. HDRP rides the same
340
- // constants on `LightSlot.kind_and_pad.wyz` so binding 6 stays unbound on
297
+ // constants on direct-light metadata so binding 6 stays unbound on
341
298
  // the HDRP path.
342
299
  #ifdef POINT_SHADOW_AVAILABLE
343
300
  @group(0) @binding(5) var shadowAtlas : texture_depth_cube_array;
@@ -410,6 +367,23 @@ struct ShadowCasterCascade {
410
367
  // — folded there in feat-20260625 w25 (scope-amend) to keep the WebGL2 fallback
411
368
  // fragment uniform-buffer count <= 11; binding 8 is the last view-BG binding.
412
369
  @group(0) @binding(8) var spotShadowMap : texture_depth_2d;
370
+ // Extended-lighting resources are a real optional view topology. The
371
+ // renderer selects the matching material variant and BGL together; keeping
372
+ // these declarations behind the same axis prevents a no-extension variant
373
+ // from consuming texture budget or requiring absent bindings.
374
+ #ifdef EXTENDED_LIGHTING_AVAILABLE
375
+ @group(0) @binding(9) var spotModifierSampler : sampler;
376
+ @group(0) @binding(11) var iesProfileTexture : texture_2d_array<f32>;
377
+ @group(0) @binding(12) var cookieTexture : texture_2d_array<f32>;
378
+ @group(0) @binding(13) var ltcLambertTexture : texture_2d<f32>;
379
+ @group(0) @binding(14) var ltcGgxTexture : texture_2d<f32>;
380
+ // One aspect-correction matrix per Cookie array slice. The matrix is kept in
381
+ // the shared view group so the same projected Cookie semantics are available
382
+ // to both the ordinary and clustered Standard PBR consumers.
383
+ @group(0) @binding(15) var<uniform> cookieMatrices : array<mat4x4<f32>, 32>;
384
+ #endif
385
+ #ifdef PROJECTOR_AVAILABLE
386
+ #ifndef EXTENDED_LIGHTING_AVAILABLE
413
387
  // Optional authored SpotLight projector. Surface and volume bind the same
414
388
  // accepted TextureAsset view and linear-clamp sampler; an unprojected spot
415
389
  // receives the renderer-owned white fallback. The declaration is capability
@@ -417,10 +391,10 @@ struct ShadowCasterCascade {
417
391
  // minimum of 16 sampled textures without this optional cookie. Devices that
418
392
  // cannot expose the 17th sampled texture select the matching white-projector
419
393
  // shader variant and omit these resources from the view BGL.
420
- #ifdef PROJECTOR_AVAILABLE
421
394
  @group(0) @binding(11) var projectorTexture : texture_2d<f32>;
422
395
  @group(0) @binding(12) var projectorSampler : sampler;
423
396
  #endif
397
+ #endif
424
398
  #if STORAGE_BUFFER_AVAILABLE == true
425
399
  @group(2) @binding(0) var<storage, read> meshes : array<Mesh>;
426
400
  #else