@driftengine/core 4.11.0 → 4.11.1

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 (56) hide show
  1. package/CHANGELOG.json +36 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +1 -1
  5. package/dist/render/ambientOcclusionPass.d.ts +3 -2
  6. package/dist/render/ambientOcclusionPass.js +4 -2
  7. package/dist/render/backend/api.d.ts +21 -1
  8. package/dist/render/backend/webgl2/renderer.d.ts +45 -4
  9. package/dist/render/backend/webgl2/renderer.js +112 -19
  10. package/dist/render/backend/webgpu/renderer.d.ts +52 -1
  11. package/dist/render/backend/webgpu/renderer.js +237 -89
  12. package/dist/render/instances.d.ts +13 -1
  13. package/dist/render/instances.js +10 -0
  14. package/dist/render/occlusionFade.d.ts +21 -0
  15. package/dist/render/occlusionFade.js +27 -0
  16. package/dist/render/sceneTarget.d.ts +2 -0
  17. package/dist/render/sceneTarget.js +1 -1
  18. package/dist/render/shaders/ambientOcclusion.js +12 -1
  19. package/dist/render/shaders/flat/index.js +9 -2
  20. package/dist/render/shaders/flat/layered.d.ts +15 -7
  21. package/dist/render/shaders/flat/layered.js +114 -31
  22. package/dist/render/shaders/flat/main.d.ts +1 -1
  23. package/dist/render/shaders/flat/main.js +10 -3
  24. package/dist/render/shaders/flat/normalMap.d.ts +1 -1
  25. package/dist/render/shaders/flat/normalMap.js +11 -2
  26. package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +6 -1
  27. package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +6 -1
  28. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -48
  29. package/dist/render/shaders/generated/flat.wgsl.js +71 -71
  30. package/dist/render/surfaceLayers.d.ts +83 -15
  31. package/dist/render/surfaceLayers.js +69 -13
  32. package/dist/render/surfaceTexture.d.ts +13 -4
  33. package/dist/render/transmission.d.ts +21 -0
  34. package/dist/render/transmission.js +21 -0
  35. package/dist/ui/splash.d.ts +42 -2
  36. package/dist/ui/splash.js +78 -13
  37. package/package.json +6 -6
  38. package/src/index.ts +2 -0
  39. package/src/render/ambientOcclusionPass.ts +4 -1
  40. package/src/render/backend/api.ts +31 -0
  41. package/src/render/backend/webgl2/renderer.ts +130 -20
  42. package/src/render/backend/webgpu/renderer.ts +371 -139
  43. package/src/render/instances.ts +18 -1
  44. package/src/render/occlusionFade.ts +29 -0
  45. package/src/render/sceneTarget.ts +3 -0
  46. package/src/render/shaders/ambientOcclusion.ts +12 -1
  47. package/src/render/shaders/flat/index.ts +9 -2
  48. package/src/render/shaders/flat/layered.ts +114 -31
  49. package/src/render/shaders/flat/main.ts +10 -3
  50. package/src/render/shaders/flat/normalMap.ts +11 -2
  51. package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +6 -1
  52. package/src/render/shaders/generated/flat.wgsl.ts +71 -71
  53. package/src/render/surfaceLayers.ts +138 -19
  54. package/src/render/surfaceTexture.ts +13 -4
  55. package/src/render/transmission.ts +27 -0
  56. package/src/ui/splash.ts +83 -14
@@ -2,18 +2,26 @@
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 the mesh's coordinates times its
6
- * own repeat; the mask is layer 0 of the map a shading model would read, at the mesh's coordinates.
7
- * Each channel lays a layer over everything before it — red layer 1, green 2, blue 3, alpha 4 — so a
8
- * layer's share is its channel times one less each later channel, and the base keeps what none of
9
- * them took. Colour, roughness and occlusion are blended by those shares, and the normal map's
10
- * tangent-space texels too, before the frame turns them into the world.
5
+ * **Layer `i` is layer `i` of the material's arrays**, each read at its own repeat of where the
6
+ * layers are laid: the mesh's coordinates, or the world's horizontal plane where the material has a
7
+ * projection (`worldUv.ts`). The mask's channels weigh layers 1 to 4 — red, green, blue, alpha — and
8
+ * come from a map read where a shading model's would be, from the ORM array's layer past the layers,
9
+ * or from the vertex colour; an added mask placed as the layers are raises one layer's weight, and
10
+ * one layer may be weighed by how much the surface faces up instead of by its channel.
11
+ *
12
+ * **Two ways to combine them.** Laid over, each layer covers everything before it, so a layer's
13
+ * share is its weight times one less each later weight, and the base keeps what none took. Summed,
14
+ * the base is mixed toward each layer times its weight by the weights' sum held to 1, so each
15
+ * layer's share is its weight times that and the base keeps the rest. The shares are worked out once
16
+ * a pixel, in `layeredBegin`; colour, roughness and occlusion are blended by them, and the normal
17
+ * map's tangent-space texels too, before the frame turns them into the world — around a normal read
18
+ * at the mesh's own coordinates, where the material lays one under the layers.
11
19
  *
12
20
  * **Every layer present is read, whatever its share.** A read whose level is implicit is legal only
13
21
  * in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
14
22
  * uniform, and never skips on a share, which is the pixel's own.
15
23
  *
16
24
  * **A lit switch, `LAYERED`**, off until a material first asks, declared last so every switch before
17
- * it keeps its id. Compiled out, its two vectors are not declared and its calls are constants.
25
+ * it keeps its id. Compiled out, its four vectors are not declared and its calls are constants.
18
26
  */
19
27
  export declare function layeredGlsl(on: boolean): string;
@@ -2,19 +2,27 @@
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 the mesh's coordinates times its
6
- * own repeat; the mask is layer 0 of the map a shading model would read, at the mesh's coordinates.
7
- * Each channel lays a layer over everything before it — red layer 1, green 2, blue 3, alpha 4 — so a
8
- * layer's share is its channel times one less each later channel, and the base keeps what none of
9
- * them took. Colour, roughness and occlusion are blended by those shares, and the normal map's
10
- * tangent-space texels too, before the frame turns them into the world.
5
+ * **Layer `i` is layer `i` of the material's arrays**, each read at its own repeat of where the
6
+ * layers are laid: the mesh's coordinates, or the world's horizontal plane where the material has a
7
+ * projection (`worldUv.ts`). The mask's channels weigh layers 1 to 4 — red, green, blue, alpha — and
8
+ * come from a map read where a shading model's would be, from the ORM array's layer past the layers,
9
+ * or from the vertex colour; an added mask placed as the layers are raises one layer's weight, and
10
+ * one layer may be weighed by how much the surface faces up instead of by its channel.
11
+ *
12
+ * **Two ways to combine them.** Laid over, each layer covers everything before it, so a layer's
13
+ * share is its weight times one less each later weight, and the base keeps what none took. Summed,
14
+ * the base is mixed toward each layer times its weight by the weights' sum held to 1, so each
15
+ * layer's share is its weight times that and the base keeps the rest. The shares are worked out once
16
+ * a pixel, in `layeredBegin`; colour, roughness and occlusion are blended by them, and the normal
17
+ * map's tangent-space texels too, before the frame turns them into the world — around a normal read
18
+ * at the mesh's own coordinates, where the material lays one under the layers.
11
19
  *
12
20
  * **Every layer present is read, whatever its share.** A read whose level is implicit is legal only
13
21
  * in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
14
22
  * uniform, and never skips on a share, which is the pixel's own.
15
23
  *
16
24
  * **A lit switch, `LAYERED`**, off until a material first asks, declared last so every switch before
17
- * it keeps its id. Compiled out, its two vectors are not declared and its calls are constants.
25
+ * it keeps its id. Compiled out, its four vectors are not declared and its calls are constants.
18
26
  */
19
27
  export function layeredGlsl(on) {
20
28
  if (!on) {
@@ -22,9 +30,12 @@ export function layeredGlsl(on) {
22
30
  const bool LAYERED = false; // wgsl:override
23
31
  bool layered() { return false; }
24
32
  void layeredBegin() {}
33
+ vec3 layeredColor(vec3 color) { return color; }
25
34
  vec4 layeredAlbedo() { return vec4(1.0); }
26
35
  vec3 layeredOrm() { return vec3(1.0); }
27
36
  vec3 layeredTexel() { return vec3(0.0, 0.0, 1.0); }
37
+ bool layeredMeshNormal() { return false; }
38
+ vec3 layeredMeshTexel() { return vec3(0.0, 0.0, 1.0); }
28
39
  bool layeredGlows() { return false; }
29
40
  vec3 layeredEmissive() { return vec3(0.0); }
30
41
  `;
@@ -32,39 +43,96 @@ vec3 layeredEmissive() { return vec3(0.0); }
32
43
  return /* glsl */ `
33
44
  /* Whether this program blends a material's layers. Off but where one has asked: layered.ts. */
34
45
  const bool LAYERED = true; // wgsl:override
35
- /* The five repeats, base first (x y z w, then x), the count (y) and the glowing layer, or -1 (z). */
36
- uniform vec4 uLayers[2]; // wgsl:material
46
+ /*
47
+ * Four vectors, as surfaceLayers.ts packs them: the five repeats, base first (x y z w, then x); the
48
+ * count (y), the glowing layer or -1 (z) and where the mask is, 0 a map, 1 the ORM array, 2 the
49
+ * vertex colour (w); the blend, 0 over and 1 summed (x), whether a mesh normal is laid under the
50
+ * layers (y), the added mask's layer or -1 (z) and its repeat (w); its intensity (x), the facing
51
+ * layer or -1 (y), its bias (z) and its sharpness (w).
52
+ */
53
+ uniform vec4 uLayers[4]; // wgsl:material
37
54
 
38
- /* The mask's channels that lay a layer, zero past the count: read once, in layeredBegin. */
39
- vec4 lMask;
55
+ /* Each layer's share of this point, the base's and layers 1 to 4's: worked out once, in layeredBegin. */
56
+ float lShareBase;
57
+ vec4 lShare;
40
58
 
41
59
  bool layered() {
42
60
  return uLayers[1].y > 0.5;
43
61
  }
44
62
 
45
- /* The mask, at the mesh's coordinates, where a model's map is. Under a branch on uniforms. */
46
- void layeredBegin() {
47
- vec4 m = texture(uModelMap, vec3(vUv.xy, 0.0));
48
- float n = uLayers[1].y;
49
- lMask = vec4(n > 1.5 ? m.r : 0.0, n > 2.5 ? m.g : 0.0, n > 3.5 ? m.b : 0.0, n > 4.5 ? m.a : 0.0);
63
+ float layerRepeat(int i) {
64
+ return i < 4 ? uLayers[0][i] : uLayers[1].x;
50
65
  }
51
66
 
52
- /* Layer i's share of this point: its channel, less every later layer's. */
53
- float layerShare(int i) {
54
- float keep = 1.0;
55
- for (int j = 3; j >= 0; j--) {
56
- if (j + 1 == i) return lMask[j] * keep;
57
- keep *= 1.0 - lMask[j];
67
+ /* Where the layers are laid: the world's horizontal plane under a projection, the mesh's otherwise. */
68
+ vec2 layerPlace() {
69
+ if (WORLD_UVS && projected()) return planarAt();
70
+ return vUv.xy;
71
+ }
72
+
73
+ vec3 layerAt(int i) {
74
+ return vec3(layerPlace() * layerRepeat(i), float(i));
75
+ }
76
+
77
+ /* The weights as the material keeps them: the mask's channels, at the mesh's own coordinates. */
78
+ vec4 layerWeights() {
79
+ float source = uLayers[1].w;
80
+ if (source > 1.5) return vec4(vColor, 0.0);
81
+ if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy, uLayers[1].y));
82
+ return texture(uModelMap, vec3(vUv.xy, 0.0));
83
+ }
84
+
85
+ /* Which of layers 1 to 4 a packed layer number names, as a vector of one 1: none for -1. */
86
+ vec4 layerPick(float layer) {
87
+ return vec4(equal(vec4(layer), vec4(1.0, 2.0, 3.0, 4.0)));
88
+ }
89
+
90
+ /*
91
+ * The weights, changed where the material asks and zero past the count, and every share from them.
92
+ * Under a branch on uniforms, as its reads are.
93
+ */
94
+ void layeredBegin() {
95
+ vec4 m = layerWeights();
96
+ if (uLayers[2].z > 0.5) {
97
+ /* 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);
99
+ float added = texture(uOrmMap, vec3(layerPlace() * uLayers[2].w, at)).r * uLayers[3].x;
100
+ m = mix(m, clamp(m + added, 0.0, 1.0), layerPick(uLayers[2].z));
101
+ }
102
+ if (uLayers[3].y > 0.5) {
103
+ float up = normalize(vNormal).y * 0.5 + 0.5;
104
+ float facing = clamp(uLayers[3].z + uLayers[3].w * up, 0.0, 1.0);
105
+ m = mix(m, vec4(facing), layerPick(uLayers[3].y));
106
+ }
107
+ float n = uLayers[1].y;
108
+ m *= vec4(n > 1.5 ? 1.0 : 0.0, n > 2.5 ? 1.0 : 0.0, n > 3.5 ? 1.0 : 0.0, n > 4.5 ? 1.0 : 0.0);
109
+ if (uLayers[2].x > 0.5) {
110
+ float taken = min(m.x + m.y + m.z + m.w, 1.0);
111
+ lShare = m * taken;
112
+ lShareBase = 1.0 - taken;
113
+ return;
58
114
  }
59
- return keep;
115
+ /* Each over everything before it: a layer keeps its weight of what every later one leaves. */
116
+ float keep = 1.0;
117
+ lShare.w = m.w * keep;
118
+ keep *= 1.0 - m.w;
119
+ lShare.z = m.z * keep;
120
+ keep *= 1.0 - m.z;
121
+ lShare.y = m.y * keep;
122
+ keep *= 1.0 - m.y;
123
+ lShare.x = m.x * keep;
124
+ keep *= 1.0 - m.x;
125
+ lShareBase = keep;
60
126
  }
61
127
 
62
- float layerRepeat(int i) {
63
- return i < 4 ? uLayers[0][i] : uLayers[1].x;
128
+ float layerShare(int i) {
129
+ if (i == 0) return lShareBase;
130
+ return lShare[i - 1];
64
131
  }
65
132
 
66
- vec3 layerAt(int i) {
67
- return vec3(vUv.xy * layerRepeat(i), float(i));
133
+ /* The vertex colour's part in the albedo: none where it is the mask instead. */
134
+ vec3 layeredColor(vec3 color) {
135
+ return uLayers[1].w > 1.5 ? vec3(1.0) : color;
68
136
  }
69
137
 
70
138
  /* Colour by the shares, and the base layer's coverage, which a cutout reads. */
@@ -88,19 +156,34 @@ vec3 layeredOrm() {
88
156
  return sum;
89
157
  }
90
158
 
91
- /* The tangent-space texels blended, each with its z rebuilt where a two-channel map stored none. */
159
+ /* A tangent-space texel off the normal array, its z rebuilt where a two-channel map stored none. */
160
+ vec3 layerNormalTexel(vec3 at) {
161
+ vec3 t = texture(uNormalMap, at).xyz * 2.0 - 1.0;
162
+ t.z = t.z > 0.0 ? t.z : sqrt(max(0.0, 1.0 - dot(t.xy, t.xy)));
163
+ return t;
164
+ }
165
+
166
+ /* The tangent-space texels blended by the shares. */
92
167
  vec3 layeredTexel() {
93
168
  vec3 sum = vec3(0.0);
94
169
  for (int i = 0; i < 5; i++) {
95
170
  if (float(i) >= uLayers[1].y) break;
96
- vec3 t = texture(uNormalMap, layerAt(i)).xyz * 2.0 - 1.0;
97
- t.z = t.z > 0.0 ? t.z : sqrt(max(0.0, 1.0 - dot(t.xy, t.xy)));
98
- sum += t * layerShare(i);
171
+ sum += layerNormalTexel(layerAt(i)) * layerShare(i);
99
172
  }
100
173
  float len = length(sum);
101
174
  return len > 1e-5 ? sum / len : vec3(0.0, 0.0, 1.0);
102
175
  }
103
176
 
177
+ /* Whether a normal read at the mesh's own coordinates lies under the layers. */
178
+ bool layeredMeshNormal() {
179
+ return uLayers[2].y > 0.5;
180
+ }
181
+
182
+ /* That normal's texel: the normal array's layer past the layers, at the mesh's coordinates. */
183
+ vec3 layeredMeshTexel() {
184
+ return layerNormalTexel(vec3(vUv.xy, uLayers[1].y));
185
+ }
186
+
104
187
  /* Whether the emissive map belongs to one layer rather than to the whole surface. */
105
188
  bool layeredGlows() {
106
189
  return uLayers[1].z > -0.5;