@driftengine/core 4.11.1 → 4.12.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 (46) hide show
  1. package/CHANGELOG.json +36 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +2 -0
  4. package/dist/render/backend/webgl2/renderer.d.ts +16 -1
  5. package/dist/render/backend/webgl2/renderer.js +41 -2
  6. package/dist/render/backend/webgpu/renderer.d.ts +2 -0
  7. package/dist/render/backend/webgpu/renderer.js +9 -0
  8. package/dist/render/shaders/flat/areaLight.d.ts +1 -1
  9. package/dist/render/shaders/flat/areaLight.js +1 -1
  10. package/dist/render/shaders/flat/glassTint.d.ts +1 -1
  11. package/dist/render/shaders/flat/glassTint.js +1 -0
  12. package/dist/render/shaders/flat/index.d.ts +5 -0
  13. package/dist/render/shaders/flat/index.js +1 -1
  14. package/dist/render/shaders/flat/layerLooks.d.ts +16 -0
  15. package/dist/render/shaders/flat/layerLooks.js +116 -0
  16. package/dist/render/shaders/flat/layered.d.ts +6 -4
  17. package/dist/render/shaders/flat/layered.js +62 -13
  18. package/dist/render/shaders/flat/main.d.ts +1 -1
  19. package/dist/render/shaders/flat/main.js +7 -2
  20. package/dist/render/shaders/flat/models.js +1 -1
  21. package/dist/render/shaders/flat/preamble.js +6 -0
  22. package/dist/render/shaders/generated/flat.wgsl.d.ts +144 -16
  23. package/dist/render/shaders/generated/flat.wgsl.js +183 -55
  24. package/dist/render/surfaceLayerLooks.d.ts +80 -0
  25. package/dist/render/surfaceLayerLooks.js +83 -0
  26. package/dist/render/surfaceLayers.d.ts +47 -6
  27. package/dist/render/surfaceLayers.js +5 -1
  28. package/package.json +6 -6
  29. package/scripts/browser.d.mts +5 -0
  30. package/scripts/browser.mjs +68 -14
  31. package/scripts/look.d.mts +81 -0
  32. package/scripts/look.mjs +380 -0
  33. package/src/index.ts +2 -0
  34. package/src/render/backend/webgl2/renderer.ts +40 -2
  35. package/src/render/backend/webgpu/renderer.ts +8 -0
  36. package/src/render/shaders/flat/areaLight.ts +1 -1
  37. package/src/render/shaders/flat/glassTint.ts +3 -1
  38. package/src/render/shaders/flat/index.ts +6 -1
  39. package/src/render/shaders/flat/layerLooks.ts +116 -0
  40. package/src/render/shaders/flat/layered.ts +63 -13
  41. package/src/render/shaders/flat/main.ts +7 -2
  42. package/src/render/shaders/flat/models.ts +1 -1
  43. package/src/render/shaders/flat/preamble.ts +6 -0
  44. package/src/render/shaders/generated/flat.wgsl.ts +183 -55
  45. package/src/render/surfaceLayerLooks.ts +155 -0
  46. package/src/render/surfaceLayers.ts +52 -7
@@ -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,12 @@ 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
+ /* What an occlusion read at the mesh's coordinates leaves of this point, 1 where none: layeredBegin. */
64
+ float lMeshOcclusion;
58
65
 
59
66
  bool layered() {
60
67
  return uLayers[1].y > 0.5;
@@ -71,14 +78,15 @@ vec2 layerPlace() {
71
78
  }
72
79
 
73
80
  vec3 layerAt(int i) {
74
- return vec3(layerPlace() * layerRepeat(i), float(i));
81
+ float across = layerRepeat(i);
82
+ return vec3(layerPlace() * vec2(across, layerRepeatDown(i, across)), layerArray(i));
75
83
  }
76
84
 
77
85
  /* The weights as the material keeps them: the mask's channels, at the mesh's own coordinates. */
78
86
  vec4 layerWeights() {
79
87
  float source = uLayers[1].w;
80
88
  if (source > 1.5) return vec4(vColor, 0.0);
81
- if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy, uLayers[1].y));
89
+ if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy, layerExtras()));
82
90
  return texture(uModelMap, vec3(vUv.xy, 0.0));
83
91
  }
84
92
 
@@ -92,10 +100,22 @@ vec4 layerPick(float layer) {
92
100
  * Under a branch on uniforms, as its reads are.
93
101
  */
94
102
  void layeredBegin() {
103
+ /*
104
+ * The occlusion at the mesh's coordinates, once: the ORM array's layer past the layers and past
105
+ * any mask and added mask it carries, spread over its range and taken at its strength.
106
+ */
107
+ lMeshOcclusion = 1.0;
108
+ float strength = layerOcclusionStrength();
109
+ if (strength > 0.0) {
110
+ float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0) + (uLayers[2].z > 0.5 ? 1.0 : 0.0);
111
+ vec2 range = layerOcclusionRange();
112
+ float occlusion = mix(range.x, range.y, texture(uOrmMap, vec3(vUv.xy, at)).r);
113
+ lMeshOcclusion = mix(1.0, occlusion, strength);
114
+ }
95
115
  vec4 m = layerWeights();
96
116
  if (uLayers[2].z > 0.5) {
97
117
  /* 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);
118
+ float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0);
99
119
  float added = texture(uOrmMap, vec3(layerPlace() * uLayers[2].w, at)).r * uLayers[3].x;
100
120
  m = mix(m, clamp(m + added, 0.0, 1.0), layerPick(uLayers[2].z));
101
121
  }
@@ -135,23 +155,52 @@ vec3 layeredColor(vec3 color) {
135
155
  return uLayers[1].w > 1.5 ? vec3(1.0) : color;
136
156
  }
137
157
 
138
- /* Colour by the shares, and the base layer's coverage, which a cutout reads. */
158
+ /*
159
+ * Colour by the shares, each layer's tinted, and the base layer's coverage, which a cutout reads;
160
+ * then darkened by the occlusion at the mesh's coordinates, where it is the colour that takes it.
161
+ */
139
162
  vec4 layeredAlbedo() {
140
163
  vec4 sum = vec4(0.0);
141
164
  for (int i = 0; i < 5; i++) {
142
165
  if (float(i) >= uLayers[1].y) break;
143
166
  vec4 t = texture(uAlbedo, layerAt(i));
144
- sum.rgb += t.rgb * layerShare(i);
167
+ sum.rgb += t.rgb * layerTint(i) * layerShare(i);
145
168
  if (i == 0) sum.a = t.a;
146
169
  }
170
+ if (!layerOcclusionAmbient()) sum.rgb *= lMeshOcclusion;
147
171
  return sum;
148
172
  }
149
173
 
174
+ /* What the ambient light keeps: the occlusion at the mesh's coordinates, where it takes it. */
175
+ float layeredAmbient() {
176
+ return layerOcclusionAmbient() ? lMeshOcclusion : 1.0;
177
+ }
178
+
179
+ /*
180
+ * The specular by the shares, each layer's own or the surface's where it names none. The surface's
181
+ * own, untouched, where no material has asked for looks: shares summing to one in floating point
182
+ * are not quite one, and a layered material that names nothing must draw exactly as before.
183
+ */
184
+ float layeredSpecular(float own) {
185
+ if (LAYER_LOOKS) {
186
+ float sum = 0.0;
187
+ for (int i = 0; i < 5; i++) {
188
+ if (float(i) >= uLayers[1].y) break;
189
+ sum += layerSpecular(i, own) * layerShare(i);
190
+ }
191
+ return sum;
192
+ }
193
+ return own;
194
+ }
195
+
196
+ /* Occlusion, roughness and metalness by the shares, each layer's spread over its own ranges. */
150
197
  vec3 layeredOrm() {
151
198
  vec3 sum = vec3(0.0);
152
199
  for (int i = 0; i < 5; i++) {
153
200
  if (float(i) >= uLayers[1].y) break;
154
- sum += texture(uOrmMap, layerAt(i)).rgb * layerShare(i);
201
+ vec3 t = texture(uOrmMap, layerAt(i)).rgb;
202
+ t.yz = layerRanges(i, t.yz);
203
+ sum += t * layerShare(i);
155
204
  }
156
205
  return sum;
157
206
  }
@@ -168,7 +217,7 @@ vec3 layeredTexel() {
168
217
  vec3 sum = vec3(0.0);
169
218
  for (int i = 0; i < 5; i++) {
170
219
  if (float(i) >= uLayers[1].y) break;
171
- sum += layerNormalTexel(layerAt(i)) * layerShare(i);
220
+ sum += layerStrengthen(i, layerNormalTexel(layerAt(i))) * layerShare(i);
172
221
  }
173
222
  float len = length(sum);
174
223
  return len > 1e-5 ? sum / len : vec3(0.0, 0.0, 1.0);
@@ -181,7 +230,7 @@ bool layeredMeshNormal() {
181
230
 
182
231
  /* That normal's texel: the normal array's layer past the layers, at the mesh's coordinates. */
183
232
  vec3 layeredMeshTexel() {
184
- return layerNormalTexel(vec3(vUv.xy, uLayers[1].y));
233
+ return layerNormalTexel(vec3(vUv.xy, layerExtras()));
185
234
  }
186
235
 
187
236
  /* Whether the emissive map belongs to one layer rather than to the whole surface. */