@driftengine/core 4.11.1 → 4.13.0

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 (231) hide show
  1. package/CHANGELOG.json +102 -0
  2. package/README.md +18 -9
  3. package/dist/geometry/meshBuilder.d.ts +10 -0
  4. package/dist/geometry/meshBuilder.js +11 -2
  5. package/dist/index.d.ts +5 -2
  6. package/dist/index.js +3 -2
  7. package/dist/math/color.d.ts +25 -0
  8. package/dist/math/color.js +37 -0
  9. package/dist/render/backend/webgl2/renderer.d.ts +33 -5
  10. package/dist/render/backend/webgl2/renderer.js +123 -49
  11. package/dist/render/backend/webgl2/skinScatter.d.ts +3 -1
  12. package/dist/render/backend/webgl2/skinScatter.js +5 -1
  13. package/dist/render/backend/webgpu/boltPass.d.ts +1 -1
  14. package/dist/render/backend/webgpu/causticsPass.d.ts +1 -1
  15. package/dist/render/backend/webgpu/filmPass.d.ts +1 -1
  16. package/dist/render/backend/webgpu/flockPass.d.ts +1 -1
  17. package/dist/render/backend/webgpu/giFieldPass.d.ts +3 -1
  18. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +10 -1
  19. package/dist/render/backend/webgpu/gpuDrivenPass.js +28 -11
  20. package/dist/render/backend/webgpu/panelPass.d.ts +1 -1
  21. package/dist/render/backend/webgpu/postPass.d.ts +2 -2
  22. package/dist/render/backend/webgpu/renderer.d.ts +21 -8
  23. package/dist/render/backend/webgpu/renderer.js +103 -38
  24. package/dist/render/backend/webgpu/scatterPass.d.ts +1 -1
  25. package/dist/render/backend/webgpu/skinScatterPass.d.ts +5 -1
  26. package/dist/render/backend/webgpu/skinScatterPass.js +9 -3
  27. package/dist/render/backend/webgpu/skyPass.d.ts +11 -1
  28. package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
  29. package/dist/render/backend/webgpu/windStreakPass.d.ts +1 -1
  30. package/dist/render/causticsRenderer.d.ts +3 -1
  31. package/dist/render/causticsRenderer.js +5 -1
  32. package/dist/render/decalPass.d.ts +3 -1
  33. package/dist/render/decalPass.js +4 -1
  34. package/dist/render/flockRenderer.d.ts +1 -1
  35. package/dist/render/flockRenderer.js +4 -1
  36. package/dist/render/globalMediumPass.d.ts +3 -1
  37. package/dist/render/globalMediumPass.js +5 -1
  38. package/dist/render/gradeColor.d.ts +21 -0
  39. package/dist/render/gradeColor.js +64 -0
  40. package/dist/render/lightMatrix.d.ts +13 -0
  41. package/dist/render/lightMatrix.js +17 -0
  42. package/dist/render/passGrade.d.ts +13 -0
  43. package/dist/render/passGrade.js +47 -0
  44. package/dist/render/plumeRenderer.d.ts +1 -1
  45. package/dist/render/plumeRenderer.js +4 -1
  46. package/dist/render/renderQuality.d.ts +57 -18
  47. package/dist/render/renderQuality.js +3 -3
  48. package/dist/render/sceneTarget.d.ts +2 -0
  49. package/dist/render/sceneTarget.js +1 -0
  50. package/dist/render/sdfTextRenderer.d.ts +1 -1
  51. package/dist/render/sdfTextRenderer.js +1 -1
  52. package/dist/render/shaders/arcane.d.ts +1 -1
  53. package/dist/render/shaders/arcane.js +5 -1
  54. package/dist/render/shaders/bolt.d.ts +1 -1
  55. package/dist/render/shaders/bolt.js +4 -1
  56. package/dist/render/shaders/caustics.d.ts +1 -1
  57. package/dist/render/shaders/caustics.js +4 -1
  58. package/dist/render/shaders/decalProject.js +12 -2
  59. package/dist/render/shaders/film.d.ts +1 -1
  60. package/dist/render/shaders/film.js +22 -9
  61. package/dist/render/shaders/fire.d.ts +1 -1
  62. package/dist/render/shaders/fire.js +4 -1
  63. package/dist/render/shaders/flat/areaLight.d.ts +1 -1
  64. package/dist/render/shaders/flat/areaLight.js +1 -1
  65. package/dist/render/shaders/flat/glassTint.d.ts +1 -1
  66. package/dist/render/shaders/flat/glassTint.js +1 -0
  67. package/dist/render/shaders/flat/index.d.ts +5 -0
  68. package/dist/render/shaders/flat/index.js +1 -1
  69. package/dist/render/shaders/flat/layerLooks.d.ts +16 -0
  70. package/dist/render/shaders/flat/layerLooks.js +108 -0
  71. package/dist/render/shaders/flat/layered.d.ts +6 -4
  72. package/dist/render/shaders/flat/layered.js +77 -13
  73. package/dist/render/shaders/flat/main.d.ts +1 -1
  74. package/dist/render/shaders/flat/main.js +7 -2
  75. package/dist/render/shaders/flat/models.js +1 -1
  76. package/dist/render/shaders/flat/preamble.js +6 -0
  77. package/dist/render/shaders/flock.d.ts +1 -1
  78. package/dist/render/shaders/flock.js +4 -1
  79. package/dist/render/shaders/generated/arcane.wgsl.d.ts +11 -1
  80. package/dist/render/shaders/generated/arcane.wgsl.js +11 -1
  81. package/dist/render/shaders/generated/bolt.wgsl.d.ts +12 -2
  82. package/dist/render/shaders/generated/bolt.wgsl.js +12 -2
  83. package/dist/render/shaders/generated/caustics.wgsl.d.ts +12 -2
  84. package/dist/render/shaders/generated/caustics.wgsl.js +12 -2
  85. package/dist/render/shaders/generated/decalProject.wgsl.d.ts +6 -1
  86. package/dist/render/shaders/generated/decalProject.wgsl.js +6 -1
  87. package/dist/render/shaders/generated/film.wgsl.d.ts +12 -2
  88. package/dist/render/shaders/generated/film.wgsl.js +12 -2
  89. package/dist/render/shaders/generated/fire.wgsl.d.ts +11 -1
  90. package/dist/render/shaders/generated/fire.wgsl.js +11 -1
  91. package/dist/render/shaders/generated/flat.wgsl.d.ts +144 -16
  92. package/dist/render/shaders/generated/flat.wgsl.js +183 -55
  93. package/dist/render/shaders/generated/flock.wgsl.d.ts +12 -2
  94. package/dist/render/shaders/generated/flock.wgsl.js +12 -2
  95. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +12 -2
  96. package/dist/render/shaders/generated/globalMedium.wgsl.js +12 -2
  97. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +36 -16
  98. package/dist/render/shaders/generated/lightVolume.wgsl.js +39 -19
  99. package/dist/render/shaders/generated/panel.wgsl.d.ts +12 -2
  100. package/dist/render/shaders/generated/panel.wgsl.js +12 -2
  101. package/dist/render/shaders/generated/rush.wgsl.d.ts +31 -26
  102. package/dist/render/shaders/generated/rush.wgsl.js +31 -26
  103. package/dist/render/shaders/generated/scatter.wgsl.d.ts +12 -2
  104. package/dist/render/shaders/generated/scatter.wgsl.js +12 -2
  105. package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +11 -1
  106. package/dist/render/shaders/generated/skinBlur.wgsl.js +11 -1
  107. package/dist/render/shaders/generated/sky.wgsl.d.ts +12 -2
  108. package/dist/render/shaders/generated/sky.wgsl.js +12 -2
  109. package/dist/render/shaders/generated/smoke.wgsl.d.ts +11 -1
  110. package/dist/render/shaders/generated/smoke.wgsl.js +11 -1
  111. package/dist/render/shaders/generated/text.wgsl.d.ts +11 -1
  112. package/dist/render/shaders/generated/text.wgsl.js +11 -1
  113. package/dist/render/shaders/generated/water.wgsl.d.ts +12 -2
  114. package/dist/render/shaders/generated/water.wgsl.js +12 -2
  115. package/dist/render/shaders/generated/windStreaks.wgsl.d.ts +12 -2
  116. package/dist/render/shaders/generated/windStreaks.wgsl.js +12 -2
  117. package/dist/render/shaders/globalMedium.js +14 -1
  118. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +15 -6
  119. package/dist/render/shaders/gpudriven/present.wgsl.js +71 -8
  120. package/dist/render/shaders/lightVolume.js +4 -1
  121. package/dist/render/shaders/line.d.ts +1 -1
  122. package/dist/render/shaders/outputTransform.d.ts +8 -2
  123. package/dist/render/shaders/outputTransform.js +18 -11
  124. package/dist/render/shaders/panel.d.ts +1 -1
  125. package/dist/render/shaders/panel.js +5 -1
  126. package/dist/render/shaders/particle.d.ts +3 -3
  127. package/dist/render/shaders/rush.js +8 -0
  128. package/dist/render/shaders/scatter.d.ts +1 -1
  129. package/dist/render/shaders/scatter.js +4 -1
  130. package/dist/render/shaders/sdfText.d.ts +1 -1
  131. package/dist/render/shaders/skinBlur.js +5 -1
  132. package/dist/render/shaders/sky.d.ts +1 -1
  133. package/dist/render/shaders/sky.js +5 -1
  134. package/dist/render/shaders/smoke.d.ts +1 -1
  135. package/dist/render/shaders/smoke.js +4 -1
  136. package/dist/render/shaders/text.d.ts +1 -1
  137. package/dist/render/shaders/text.js +4 -1
  138. package/dist/render/shaders/water.d.ts +1 -1
  139. package/dist/render/shaders/water.js +12 -2
  140. package/dist/render/shaders/windStreaks.d.ts +1 -1
  141. package/dist/render/shaders/windStreaks.js +4 -1
  142. package/dist/render/surfaceLayerLooks.d.ts +92 -0
  143. package/dist/render/surfaceLayerLooks.js +102 -0
  144. package/dist/render/surfaceLayers.d.ts +47 -6
  145. package/dist/render/surfaceLayers.js +5 -1
  146. package/dist/render/textRenderer.d.ts +3 -1
  147. package/dist/render/textRenderer.js +7 -1
  148. package/dist/render/vertexDefaults.d.ts +1 -1
  149. package/dist/render/vertexDefaults.js +1 -1
  150. package/dist/render/waterRenderer.d.ts +1 -1
  151. package/dist/render/waterRenderer.js +4 -1
  152. package/dist/render/windStreakRenderer.d.ts +3 -1
  153. package/dist/render/windStreakRenderer.js +5 -1
  154. package/package.json +6 -6
  155. package/scripts/browser.d.mts +5 -0
  156. package/scripts/browser.mjs +68 -14
  157. package/scripts/look.d.mts +81 -0
  158. package/scripts/look.mjs +380 -0
  159. package/src/geometry/meshBuilder.ts +21 -2
  160. package/src/index.ts +13 -2
  161. package/src/math/color.ts +39 -0
  162. package/src/render/backend/webgl2/renderer.ts +174 -46
  163. package/src/render/backend/webgl2/skinScatter.ts +5 -0
  164. package/src/render/backend/webgpu/giFieldPass.ts +3 -1
  165. package/src/render/backend/webgpu/gpuDrivenPass.ts +29 -13
  166. package/src/render/backend/webgpu/renderer.ts +112 -37
  167. package/src/render/backend/webgpu/skinScatterPass.ts +17 -1
  168. package/src/render/causticsRenderer.ts +5 -0
  169. package/src/render/decalPass.ts +3 -0
  170. package/src/render/flockRenderer.ts +5 -0
  171. package/src/render/globalMediumPass.ts +10 -1
  172. package/src/render/gradeColor.ts +90 -0
  173. package/src/render/lightMatrix.ts +32 -0
  174. package/src/render/passGrade.ts +58 -0
  175. package/src/render/plumeRenderer.ts +5 -0
  176. package/src/render/renderQuality.ts +60 -21
  177. package/src/render/sceneTarget.ts +3 -0
  178. package/src/render/sdfTextRenderer.ts +1 -1
  179. package/src/render/shaders/arcane.ts +5 -1
  180. package/src/render/shaders/bolt.ts +4 -1
  181. package/src/render/shaders/caustics.ts +4 -1
  182. package/src/render/shaders/decalProject.ts +12 -2
  183. package/src/render/shaders/film.ts +22 -9
  184. package/src/render/shaders/fire.ts +4 -1
  185. package/src/render/shaders/flat/areaLight.ts +1 -1
  186. package/src/render/shaders/flat/glassTint.ts +3 -1
  187. package/src/render/shaders/flat/index.ts +6 -1
  188. package/src/render/shaders/flat/layerLooks.ts +108 -0
  189. package/src/render/shaders/flat/layered.ts +78 -13
  190. package/src/render/shaders/flat/main.ts +7 -2
  191. package/src/render/shaders/flat/models.ts +1 -1
  192. package/src/render/shaders/flat/preamble.ts +6 -0
  193. package/src/render/shaders/flock.ts +4 -1
  194. package/src/render/shaders/generated/arcane.wgsl.ts +11 -1
  195. package/src/render/shaders/generated/bolt.wgsl.ts +12 -2
  196. package/src/render/shaders/generated/caustics.wgsl.ts +12 -2
  197. package/src/render/shaders/generated/decalProject.wgsl.ts +6 -1
  198. package/src/render/shaders/generated/film.wgsl.ts +12 -2
  199. package/src/render/shaders/generated/fire.wgsl.ts +11 -1
  200. package/src/render/shaders/generated/flat.wgsl.ts +183 -55
  201. package/src/render/shaders/generated/flock.wgsl.ts +12 -2
  202. package/src/render/shaders/generated/globalMedium.wgsl.ts +12 -2
  203. package/src/render/shaders/generated/lightVolume.wgsl.ts +39 -19
  204. package/src/render/shaders/generated/panel.wgsl.ts +12 -2
  205. package/src/render/shaders/generated/rush.wgsl.ts +31 -26
  206. package/src/render/shaders/generated/scatter.wgsl.ts +12 -2
  207. package/src/render/shaders/generated/skinBlur.wgsl.ts +11 -1
  208. package/src/render/shaders/generated/sky.wgsl.ts +12 -2
  209. package/src/render/shaders/generated/smoke.wgsl.ts +11 -1
  210. package/src/render/shaders/generated/text.wgsl.ts +11 -1
  211. package/src/render/shaders/generated/water.wgsl.ts +12 -2
  212. package/src/render/shaders/generated/windStreaks.wgsl.ts +12 -2
  213. package/src/render/shaders/globalMedium.ts +14 -1
  214. package/src/render/shaders/gpudriven/present.wgsl.ts +72 -8
  215. package/src/render/shaders/lightVolume.ts +4 -1
  216. package/src/render/shaders/outputTransform.ts +19 -11
  217. package/src/render/shaders/panel.ts +5 -1
  218. package/src/render/shaders/rush.ts +8 -0
  219. package/src/render/shaders/scatter.ts +4 -1
  220. package/src/render/shaders/skinBlur.ts +5 -1
  221. package/src/render/shaders/sky.ts +5 -1
  222. package/src/render/shaders/smoke.ts +4 -1
  223. package/src/render/shaders/text.ts +4 -1
  224. package/src/render/shaders/water.ts +12 -2
  225. package/src/render/shaders/windStreaks.ts +4 -1
  226. package/src/render/surfaceLayerLooks.ts +186 -0
  227. package/src/render/surfaceLayers.ts +52 -7
  228. package/src/render/textRenderer.ts +6 -0
  229. package/src/render/vertexDefaults.ts +1 -1
  230. package/src/render/waterRenderer.ts +5 -0
  231. package/src/render/windStreakRenderer.ts +5 -0
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Which layer of the shared arrays each of a layered material's layers reads, and how each looks:
3
+ * `uLayerLooks`, packed by `surfaceLayerLooks.ts`, read by `layered.ts`.
4
+ *
5
+ * **Every helper is the identity where the switch is off**, written as a branch on `LAYER_LOOKS`
6
+ * itself because the generated WGSL carries one string for both values of an override: layer `i`
7
+ * reads layer `i`, the maps beyond the layers start at the layer count, a tint is white, a range is
8
+ * 0 to 1, a normal is as stored, a specular is the surface's own, a repeat down is the repeat
9
+ * across, and nothing is occluded — exactly what `layered.ts` did before this existed, which is what
10
+ * a layered material that asks for none of it has to keep drawing.
11
+ *
12
+ * **A lit switch, `LAYER_LOOKS`**, off until a material first asks and declared after `LAYERED`, so
13
+ * every switch before it keeps its id. It is only ever compiled beside `LAYERED`, whose `uLayers`
14
+ * it reads.
15
+ */
16
+ export function layerLooksGlsl(on) {
17
+ if (!on) {
18
+ return /* glsl */ `
19
+ const bool LAYER_LOOKS = false; // wgsl:override
20
+ float layerArray(int i) { return float(i); }
21
+ float layerExtras() { return uLayers[1].y; }
22
+ vec3 layerTint(int i) { return vec3(1.0); }
23
+ vec2 layerRanges(int i, vec2 roughMetal) { return roughMetal; }
24
+ vec3 layerStrengthen(int i, vec3 texel) { return texel; }
25
+ float layerNamedSpecular(int i) { return -1.0; }
26
+ float layerRepeatDown(int i, float across) { return across; }
27
+ vec2 layerOcclusionStrengths() { return vec2(0.0); }
28
+ vec2 layerOcclusionRange() { return vec2(0.0, 1.0); }
29
+ `;
30
+ }
31
+ return /* glsl */ `
32
+ /* Whether layers are picked from shared arrays and given looks of their own: layerLooks.ts. */
33
+ const bool LAYER_LOOKS = true; // wgsl:override
34
+ /*
35
+ * Fifteen vectors, as surfaceLayerLooks.ts packs them: the array layer each of the five reads, base
36
+ * first (floats 0 to 4); where the maps beyond the layers start (5), the mesh occlusion's strength
37
+ * on the colour, from 0 up (6), and on the ambient light (7); then two vectors a
38
+ * layer, base first: its tint (x y z) and normal strength (w), then its roughness range (x to y)
39
+ * and metalness range (z to w); then each layer's specular, -1 for the surface's own (48 to 52), its
40
+ * repeat down (53 to 57), and the occlusion's range (58 to 59).
41
+ */
42
+ uniform vec4 uLayerLooks[15]; // wgsl:material
43
+
44
+ /* Float k of the fifteen vectors. */
45
+ float layerLook(int k) {
46
+ return uLayerLooks[k / 4][k % 4];
47
+ }
48
+
49
+ /* The layer of the albedo, normal and ORM arrays a material's layer i reads. */
50
+ float layerArray(int i) {
51
+ if (LAYER_LOOKS) return layerLook(i);
52
+ return float(i);
53
+ }
54
+
55
+ /* Where the maps beyond the layers start in each array. */
56
+ float layerExtras() {
57
+ if (LAYER_LOOKS) return uLayerLooks[1].y;
58
+ return uLayers[1].y;
59
+ }
60
+
61
+ vec3 layerTint(int i) {
62
+ if (LAYER_LOOKS) return uLayerLooks[2 + i * 2].xyz;
63
+ return vec3(1.0);
64
+ }
65
+
66
+ /* The ORM's roughness and metalness, each spread over the layer's own range. */
67
+ vec2 layerRanges(int i, vec2 roughMetal) {
68
+ if (LAYER_LOOKS) {
69
+ vec4 range = uLayerLooks[3 + i * 2];
70
+ return vec2(mix(range.x, range.y, roughMetal.x), mix(range.z, range.w, roughMetal.y));
71
+ }
72
+ return roughMetal;
73
+ }
74
+
75
+ /*
76
+ * A tangent-space texel bent further or less by the layer's strength: its x and y scaled, its z
77
+ * kept, so 0 lies flat and a strength above 1 steepens every slope the map holds. z is held above
78
+ * zero so a texel lying exactly flat on its surface cannot normalise to nothing at strength 0.
79
+ */
80
+ vec3 layerStrengthen(int i, vec3 texel) {
81
+ if (LAYER_LOOKS) return normalize(vec3(texel.xy * uLayerLooks[2 + i * 2].w, max(texel.z, 1e-4)));
82
+ return texel;
83
+ }
84
+
85
+ /* The specular the layer names, or -1 where it names none and the surface's own stands. */
86
+ float layerNamedSpecular(int i) {
87
+ if (LAYER_LOOKS) return layerLook(48 + i);
88
+ return -1.0;
89
+ }
90
+
91
+ /* The layer's repeat down, which is its repeat across unless it gave two. */
92
+ float layerRepeatDown(int i, float across) {
93
+ if (LAYER_LOOKS) return layerLook(53 + i);
94
+ return across;
95
+ }
96
+
97
+ /* The mesh occlusion's strength on the colour (x), from 0 up, and on the ambient light (y). */
98
+ vec2 layerOcclusionStrengths() {
99
+ if (LAYER_LOOKS) return uLayerLooks[1].zw;
100
+ return vec2(0.0);
101
+ }
102
+
103
+ vec2 layerOcclusionRange() {
104
+ if (LAYER_LOOKS) return uLayerLooks[14].zw;
105
+ return vec2(0.0, 1.0);
106
+ }
107
+ `;
108
+ }
@@ -2,7 +2,8 @@
2
2
  * A material blended from layers by a mask: `SurfaceMaterial.layers`, packed into `uLayers` by
3
3
  * `surfaceLayers.ts`.
4
4
  *
5
- * **Layer `i` is layer `i` of the material's arrays**, each read at its own repeat of where the
5
+ * **Layer `i` is layer `i` of the material's arrays** — or the layer `layerLooks.ts` picks, with the
6
+ * tint, ranges and normal strength it gives each — each read at its own repeat of where the
6
7
  * layers are laid: the mesh's coordinates, or the world's horizontal plane where the material has a
7
8
  * projection (`worldUv.ts`). The mask's channels weigh layers 1 to 4 — red, green, blue, alpha — and
8
9
  * come from a map read where a shading model's would be, from the ORM array's layer past the layers,
@@ -21,7 +22,8 @@
21
22
  * in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
22
23
  * uniform, and never skips on a share, which is the pixel's own.
23
24
  *
24
- * **A lit switch, `LAYERED`**, off until a material first asks, declared last so every switch before
25
- * it keeps its id. Compiled out, its four vectors are not declared and its calls are constants.
25
+ * **A lit switch, `LAYERED`**, off until a material first asks, declared after every switch before
26
+ * it so each keeps its id. Compiled out, its four vectors are not declared and its calls are
27
+ * constants. `looks` compiles `LAYER_LOOKS` in beside it, and means nothing without it.
26
28
  */
27
- export declare function layeredGlsl(on: boolean): string;
29
+ export declare function layeredGlsl(on: boolean, looks?: boolean): string;
@@ -1,8 +1,10 @@
1
+ import { layerLooksGlsl } from './layerLooks.js';
1
2
  /**
2
3
  * A material blended from layers by a mask: `SurfaceMaterial.layers`, packed into `uLayers` by
3
4
  * `surfaceLayers.ts`.
4
5
  *
5
- * **Layer `i` is layer `i` of the material's arrays**, each read at its own repeat of where the
6
+ * **Layer `i` is layer `i` of the material's arrays** — or the layer `layerLooks.ts` picks, with the
7
+ * tint, ranges and normal strength it gives each — each read at its own repeat of where the
6
8
  * layers are laid: the mesh's coordinates, or the world's horizontal plane where the material has a
7
9
  * projection (`worldUv.ts`). The mask's channels weigh layers 1 to 4 — red, green, blue, alpha — and
8
10
  * come from a map read where a shading model's would be, from the ORM array's layer past the layers,
@@ -21,10 +23,11 @@
21
23
  * in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
22
24
  * uniform, and never skips on a share, which is the pixel's own.
23
25
  *
24
- * **A lit switch, `LAYERED`**, off until a material first asks, declared last so every switch before
25
- * it keeps its id. Compiled out, its four vectors are not declared and its calls are constants.
26
+ * **A lit switch, `LAYERED`**, off until a material first asks, declared after every switch before
27
+ * it so each keeps its id. Compiled out, its four vectors are not declared and its calls are
28
+ * constants. `looks` compiles `LAYER_LOOKS` in beside it, and means nothing without it.
26
29
  */
27
- export function layeredGlsl(on) {
30
+ export function layeredGlsl(on, looks = false) {
28
31
  if (!on) {
29
32
  return /* glsl */ `
30
33
  const bool LAYERED = false; // wgsl:override
@@ -38,6 +41,8 @@ bool layeredMeshNormal() { return false; }
38
41
  vec3 layeredMeshTexel() { return vec3(0.0, 0.0, 1.0); }
39
42
  bool layeredGlows() { return false; }
40
43
  vec3 layeredEmissive() { return vec3(0.0); }
44
+ float layeredAmbient() { return 1.0; }
45
+ float layeredSpecular(float own) { return own; }
41
46
  `;
42
47
  }
43
48
  return /* glsl */ `
@@ -51,10 +56,16 @@ const bool LAYERED = true; // wgsl:override
51
56
  * layer or -1 (y), its bias (z) and its sharpness (w).
52
57
  */
53
58
  uniform vec4 uLayers[4]; // wgsl:material
54
-
59
+ ${layerLooksGlsl(looks)}
55
60
  /* Each layer's share of this point, the base's and layers 1 to 4's: worked out once, in layeredBegin. */
56
61
  float lShareBase;
57
62
  vec4 lShare;
63
+ /*
64
+ * What an occlusion read at the mesh's coordinates leaves of this point's colour and of its ambient
65
+ * light, 1 where none: layeredBegin.
66
+ */
67
+ float lColorOcclusion;
68
+ float lAmbientOcclusion;
58
69
 
59
70
  bool layered() {
60
71
  return uLayers[1].y > 0.5;
@@ -71,14 +82,15 @@ vec2 layerPlace() {
71
82
  }
72
83
 
73
84
  vec3 layerAt(int i) {
74
- return vec3(layerPlace() * layerRepeat(i), float(i));
85
+ float across = layerRepeat(i);
86
+ return vec3(layerPlace() * vec2(across, layerRepeatDown(i, across)), layerArray(i));
75
87
  }
76
88
 
77
89
  /* The weights as the material keeps them: the mask's channels, at the mesh's own coordinates. */
78
90
  vec4 layerWeights() {
79
91
  float source = uLayers[1].w;
80
92
  if (source > 1.5) return vec4(vColor, 0.0);
81
- if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy, uLayers[1].y));
93
+ if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy, layerExtras()));
82
94
  return texture(uModelMap, vec3(vUv.xy, 0.0));
83
95
  }
84
96
 
@@ -92,10 +104,25 @@ vec4 layerPick(float layer) {
92
104
  * Under a branch on uniforms, as its reads are.
93
105
  */
94
106
  void layeredBegin() {
107
+ /*
108
+ * The occlusion at the mesh's coordinates, once: the ORM array's layer past the layers and past
109
+ * any mask and added mask it carries, spread over its range and taken at each strength. The
110
+ * colour's may pass 1, darkening faster than the occlusion does, and is held at black.
111
+ */
112
+ lColorOcclusion = 1.0;
113
+ lAmbientOcclusion = 1.0;
114
+ vec2 strength = layerOcclusionStrengths();
115
+ if (strength.x > 0.0 || strength.y > 0.0) {
116
+ float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0) + (uLayers[2].z > 0.5 ? 1.0 : 0.0);
117
+ vec2 range = layerOcclusionRange();
118
+ float bare = 1.0 - mix(range.x, range.y, texture(uOrmMap, vec3(vUv.xy, at)).r);
119
+ lColorOcclusion = max(0.0, 1.0 - strength.x * bare);
120
+ lAmbientOcclusion = 1.0 - strength.y * bare;
121
+ }
95
122
  vec4 m = layerWeights();
96
123
  if (uLayers[2].z > 0.5) {
97
124
  /* The ORM array's layer past the layers, and past the mask where the array carries that too. */
98
- float at = uLayers[1].y + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0);
125
+ float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0);
99
126
  float added = texture(uOrmMap, vec3(layerPlace() * uLayers[2].w, at)).r * uLayers[3].x;
100
127
  m = mix(m, clamp(m + added, 0.0, 1.0), layerPick(uLayers[2].z));
101
128
  }
@@ -135,23 +162,60 @@ vec3 layeredColor(vec3 color) {
135
162
  return uLayers[1].w > 1.5 ? vec3(1.0) : color;
136
163
  }
137
164
 
138
- /* Colour by the shares, and the base layer's coverage, which a cutout reads. */
165
+ /*
166
+ * Colour by the shares, each layer's tinted, and the base layer's coverage, which a cutout reads;
167
+ * then darkened by the occlusion at the mesh's coordinates, at the colour's strength.
168
+ */
139
169
  vec4 layeredAlbedo() {
140
170
  vec4 sum = vec4(0.0);
141
171
  for (int i = 0; i < 5; i++) {
142
172
  if (float(i) >= uLayers[1].y) break;
143
173
  vec4 t = texture(uAlbedo, layerAt(i));
144
- sum.rgb += t.rgb * layerShare(i);
174
+ sum.rgb += t.rgb * layerTint(i) * layerShare(i);
145
175
  if (i == 0) sum.a = t.a;
146
176
  }
177
+ sum.rgb *= lColorOcclusion;
147
178
  return sum;
148
179
  }
149
180
 
181
+ /* What the ambient light keeps: the occlusion at the mesh's coordinates, at the ambient's strength. */
182
+ float layeredAmbient() {
183
+ return lAmbientOcclusion;
184
+ }
185
+
186
+ /*
187
+ * The specular by the shares: each layer's named one at its share, and the surface's own over the
188
+ * layers naming none, once at most. Under a summed blend the shares add past 1 where the weights
189
+ * do, and a surface whose layers leave the specular to it reflects its own, not its own times that
190
+ * sum; under a blend laid over, the shares never pass 1 and this is the sum it always was. What it
191
+ * gives up: named speculars still add as their colours do, so a summed blend that names them
192
+ * reflects their sum. The surface's own, untouched, where no material has asked for looks: shares
193
+ * summing to one in floating point are not quite one, and a layered material that names nothing
194
+ * must draw exactly as before.
195
+ */
196
+ float layeredSpecular(float own) {
197
+ if (LAYER_LOOKS) {
198
+ float named = 0.0;
199
+ float unnamed = 0.0;
200
+ for (int i = 0; i < 5; i++) {
201
+ if (float(i) >= uLayers[1].y) break;
202
+ float specular = layerNamedSpecular(i);
203
+ if (specular < 0.0) unnamed += layerShare(i);
204
+ else named += specular * layerShare(i);
205
+ }
206
+ return named + own * min(unnamed, 1.0);
207
+ }
208
+ return own;
209
+ }
210
+
211
+ /* Occlusion, roughness and metalness by the shares, each layer's spread over its own ranges. */
150
212
  vec3 layeredOrm() {
151
213
  vec3 sum = vec3(0.0);
152
214
  for (int i = 0; i < 5; i++) {
153
215
  if (float(i) >= uLayers[1].y) break;
154
- sum += texture(uOrmMap, layerAt(i)).rgb * layerShare(i);
216
+ vec3 t = texture(uOrmMap, layerAt(i)).rgb;
217
+ t.yz = layerRanges(i, t.yz);
218
+ sum += t * layerShare(i);
155
219
  }
156
220
  return sum;
157
221
  }
@@ -168,7 +232,7 @@ vec3 layeredTexel() {
168
232
  vec3 sum = vec3(0.0);
169
233
  for (int i = 0; i < 5; i++) {
170
234
  if (float(i) >= uLayers[1].y) break;
171
- sum += layerNormalTexel(layerAt(i)) * layerShare(i);
235
+ sum += layerStrengthen(i, layerNormalTexel(layerAt(i))) * layerShare(i);
172
236
  }
173
237
  float len = length(sum);
174
238
  return len > 1e-5 ? sum / len : vec3(0.0, 0.0, 1.0);
@@ -181,7 +245,7 @@ bool layeredMeshNormal() {
181
245
 
182
246
  /* That normal's texel: the normal array's layer past the layers, at the mesh's coordinates. */
183
247
  vec3 layeredMeshTexel() {
184
- return layerNormalTexel(vec3(vUv.xy, uLayers[1].y));
248
+ return layerNormalTexel(vec3(vUv.xy, layerExtras()));
185
249
  }
186
250
 
187
251
  /* Whether the emissive map belongs to one layer rather than to the whole surface. */