@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.
- package/CHANGELOG.json +36 -0
- package/README.md +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/render/backend/webgl2/renderer.d.ts +16 -1
- package/dist/render/backend/webgl2/renderer.js +41 -2
- package/dist/render/backend/webgpu/renderer.d.ts +2 -0
- package/dist/render/backend/webgpu/renderer.js +9 -0
- package/dist/render/shaders/flat/areaLight.d.ts +1 -1
- package/dist/render/shaders/flat/areaLight.js +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +1 -0
- package/dist/render/shaders/flat/index.d.ts +5 -0
- package/dist/render/shaders/flat/index.js +1 -1
- package/dist/render/shaders/flat/layerLooks.d.ts +16 -0
- package/dist/render/shaders/flat/layerLooks.js +116 -0
- package/dist/render/shaders/flat/layered.d.ts +6 -4
- package/dist/render/shaders/flat/layered.js +62 -13
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +7 -2
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/preamble.js +6 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +144 -16
- package/dist/render/shaders/generated/flat.wgsl.js +183 -55
- package/dist/render/surfaceLayerLooks.d.ts +80 -0
- package/dist/render/surfaceLayerLooks.js +83 -0
- package/dist/render/surfaceLayers.d.ts +47 -6
- package/dist/render/surfaceLayers.js +5 -1
- package/package.json +6 -6
- package/scripts/browser.d.mts +5 -0
- package/scripts/browser.mjs +68 -14
- package/scripts/look.d.mts +81 -0
- package/scripts/look.mjs +380 -0
- package/src/index.ts +2 -0
- package/src/render/backend/webgl2/renderer.ts +40 -2
- package/src/render/backend/webgpu/renderer.ts +8 -0
- package/src/render/shaders/flat/areaLight.ts +1 -1
- package/src/render/shaders/flat/glassTint.ts +3 -1
- package/src/render/shaders/flat/index.ts +6 -1
- package/src/render/shaders/flat/layerLooks.ts +116 -0
- package/src/render/shaders/flat/layered.ts +63 -13
- package/src/render/shaders/flat/main.ts +7 -2
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/preamble.ts +6 -0
- package/src/render/shaders/generated/flat.wgsl.ts +183 -55
- package/src/render/surfaceLayerLooks.ts +155 -0
- package/src/render/surfaceLayers.ts +52 -7
|
@@ -0,0 +1,116 @@
|
|
|
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: boolean): string {
|
|
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 layerSpecular(int i, float own) { return own; }
|
|
26
|
+
float layerRepeatDown(int i, float across) { return across; }
|
|
27
|
+
float layerOcclusionStrength() { return 0.0; }
|
|
28
|
+
bool layerOcclusionAmbient() { return false; }
|
|
29
|
+
vec2 layerOcclusionRange() { return vec2(0.0, 1.0); }
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
return /* glsl */ `
|
|
33
|
+
/* Whether layers are picked from shared arrays and given looks of their own: layerLooks.ts. */
|
|
34
|
+
const bool LAYER_LOOKS = true; // wgsl:override
|
|
35
|
+
/*
|
|
36
|
+
* Fifteen vectors, as surfaceLayerLooks.ts packs them: the array layer each of the five reads, base
|
|
37
|
+
* first (floats 0 to 4); where the maps beyond the layers start (5), the mesh occlusion's strength
|
|
38
|
+
* (6) and whether it darkens the ambient light rather than the colour (7); then two vectors a
|
|
39
|
+
* layer, base first: its tint (x y z) and normal strength (w), then its roughness range (x to y)
|
|
40
|
+
* and metalness range (z to w); then each layer's specular, -1 for the surface's own (48 to 52), its
|
|
41
|
+
* repeat down (53 to 57), and the occlusion's range (58 to 59).
|
|
42
|
+
*/
|
|
43
|
+
uniform vec4 uLayerLooks[15]; // wgsl:material
|
|
44
|
+
|
|
45
|
+
/* Float k of the fifteen vectors. */
|
|
46
|
+
float layerLook(int k) {
|
|
47
|
+
return uLayerLooks[k / 4][k % 4];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* The layer of the albedo, normal and ORM arrays a material's layer i reads. */
|
|
51
|
+
float layerArray(int i) {
|
|
52
|
+
if (LAYER_LOOKS) return layerLook(i);
|
|
53
|
+
return float(i);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Where the maps beyond the layers start in each array. */
|
|
57
|
+
float layerExtras() {
|
|
58
|
+
if (LAYER_LOOKS) return uLayerLooks[1].y;
|
|
59
|
+
return uLayers[1].y;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
vec3 layerTint(int i) {
|
|
63
|
+
if (LAYER_LOOKS) return uLayerLooks[2 + i * 2].xyz;
|
|
64
|
+
return vec3(1.0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* The ORM's roughness and metalness, each spread over the layer's own range. */
|
|
68
|
+
vec2 layerRanges(int i, vec2 roughMetal) {
|
|
69
|
+
if (LAYER_LOOKS) {
|
|
70
|
+
vec4 range = uLayerLooks[3 + i * 2];
|
|
71
|
+
return vec2(mix(range.x, range.y, roughMetal.x), mix(range.z, range.w, roughMetal.y));
|
|
72
|
+
}
|
|
73
|
+
return roughMetal;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* A tangent-space texel bent further or less by the layer's strength: its x and y scaled, its z
|
|
78
|
+
* kept, so 0 lies flat and a strength above 1 steepens every slope the map holds. z is held above
|
|
79
|
+
* zero so a texel lying exactly flat on its surface cannot normalise to nothing at strength 0.
|
|
80
|
+
*/
|
|
81
|
+
vec3 layerStrengthen(int i, vec3 texel) {
|
|
82
|
+
if (LAYER_LOOKS) return normalize(vec3(texel.xy * uLayerLooks[2 + i * 2].w, max(texel.z, 1e-4)));
|
|
83
|
+
return texel;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* The layer's specular, or the surface's own where it names none. */
|
|
87
|
+
float layerSpecular(int i, float own) {
|
|
88
|
+
if (LAYER_LOOKS) {
|
|
89
|
+
float named = layerLook(48 + i);
|
|
90
|
+
return named < 0.0 ? own : named;
|
|
91
|
+
}
|
|
92
|
+
return own;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* The layer's repeat down, which is its repeat across unless it gave two. */
|
|
96
|
+
float layerRepeatDown(int i, float across) {
|
|
97
|
+
if (LAYER_LOOKS) return layerLook(53 + i);
|
|
98
|
+
return across;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
float layerOcclusionStrength() {
|
|
102
|
+
if (LAYER_LOOKS) return uLayerLooks[1].z;
|
|
103
|
+
return 0.0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
bool layerOcclusionAmbient() {
|
|
107
|
+
if (LAYER_LOOKS) return uLayerLooks[1].w > 0.5;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
vec2 layerOcclusionRange() {
|
|
112
|
+
if (LAYER_LOOKS) return uLayerLooks[14].zw;
|
|
113
|
+
return vec2(0.0, 1.0);
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { layerLooksGlsl } from './layerLooks.ts';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* A material blended from layers by a mask: `SurfaceMaterial.layers`, packed into `uLayers` by
|
|
3
5
|
* `surfaceLayers.ts`.
|
|
4
6
|
*
|
|
5
|
-
* **Layer `i` is layer `i` of the material's arrays
|
|
7
|
+
* **Layer `i` is layer `i` of the material's arrays** — or the layer `layerLooks.ts` picks, with the
|
|
8
|
+
* tint, ranges and normal strength it gives each — each read at its own repeat of where the
|
|
6
9
|
* layers are laid: the mesh's coordinates, or the world's horizontal plane where the material has a
|
|
7
10
|
* projection (`worldUv.ts`). The mask's channels weigh layers 1 to 4 — red, green, blue, alpha — and
|
|
8
11
|
* come from a map read where a shading model's would be, from the ORM array's layer past the layers,
|
|
@@ -21,10 +24,11 @@
|
|
|
21
24
|
* in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
|
|
22
25
|
* uniform, and never skips on a share, which is the pixel's own.
|
|
23
26
|
*
|
|
24
|
-
* **A lit switch, `LAYERED`**, off until a material first asks, declared
|
|
25
|
-
* it keeps its id. Compiled out, its four vectors are not declared and its calls are
|
|
27
|
+
* **A lit switch, `LAYERED`**, off until a material first asks, declared after every switch before
|
|
28
|
+
* it so each keeps its id. Compiled out, its four vectors are not declared and its calls are
|
|
29
|
+
* constants. `looks` compiles `LAYER_LOOKS` in beside it, and means nothing without it.
|
|
26
30
|
*/
|
|
27
|
-
export function layeredGlsl(on: boolean): string {
|
|
31
|
+
export function layeredGlsl(on: boolean, looks = false): string {
|
|
28
32
|
if (!on) {
|
|
29
33
|
return /* glsl */ `
|
|
30
34
|
const bool LAYERED = false; // wgsl:override
|
|
@@ -38,6 +42,8 @@ bool layeredMeshNormal() { return false; }
|
|
|
38
42
|
vec3 layeredMeshTexel() { return vec3(0.0, 0.0, 1.0); }
|
|
39
43
|
bool layeredGlows() { return false; }
|
|
40
44
|
vec3 layeredEmissive() { return vec3(0.0); }
|
|
45
|
+
float layeredAmbient() { return 1.0; }
|
|
46
|
+
float layeredSpecular(float own) { return own; }
|
|
41
47
|
`;
|
|
42
48
|
}
|
|
43
49
|
return /* glsl */ `
|
|
@@ -51,10 +57,12 @@ const bool LAYERED = true; // wgsl:override
|
|
|
51
57
|
* layer or -1 (y), its bias (z) and its sharpness (w).
|
|
52
58
|
*/
|
|
53
59
|
uniform vec4 uLayers[4]; // wgsl:material
|
|
54
|
-
|
|
60
|
+
${layerLooksGlsl(looks)}
|
|
55
61
|
/* Each layer's share of this point, the base's and layers 1 to 4's: worked out once, in layeredBegin. */
|
|
56
62
|
float lShareBase;
|
|
57
63
|
vec4 lShare;
|
|
64
|
+
/* What an occlusion read at the mesh's coordinates leaves of this point, 1 where none: layeredBegin. */
|
|
65
|
+
float lMeshOcclusion;
|
|
58
66
|
|
|
59
67
|
bool layered() {
|
|
60
68
|
return uLayers[1].y > 0.5;
|
|
@@ -71,14 +79,15 @@ vec2 layerPlace() {
|
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
vec3 layerAt(int i) {
|
|
74
|
-
|
|
82
|
+
float across = layerRepeat(i);
|
|
83
|
+
return vec3(layerPlace() * vec2(across, layerRepeatDown(i, across)), layerArray(i));
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
/* The weights as the material keeps them: the mask's channels, at the mesh's own coordinates. */
|
|
78
87
|
vec4 layerWeights() {
|
|
79
88
|
float source = uLayers[1].w;
|
|
80
89
|
if (source > 1.5) return vec4(vColor, 0.0);
|
|
81
|
-
if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy,
|
|
90
|
+
if (source > 0.5) return texture(uOrmMap, vec3(vUv.xy, layerExtras()));
|
|
82
91
|
return texture(uModelMap, vec3(vUv.xy, 0.0));
|
|
83
92
|
}
|
|
84
93
|
|
|
@@ -92,10 +101,22 @@ vec4 layerPick(float layer) {
|
|
|
92
101
|
* Under a branch on uniforms, as its reads are.
|
|
93
102
|
*/
|
|
94
103
|
void layeredBegin() {
|
|
104
|
+
/*
|
|
105
|
+
* The occlusion at the mesh's coordinates, once: the ORM array's layer past the layers and past
|
|
106
|
+
* any mask and added mask it carries, spread over its range and taken at its strength.
|
|
107
|
+
*/
|
|
108
|
+
lMeshOcclusion = 1.0;
|
|
109
|
+
float strength = layerOcclusionStrength();
|
|
110
|
+
if (strength > 0.0) {
|
|
111
|
+
float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0) + (uLayers[2].z > 0.5 ? 1.0 : 0.0);
|
|
112
|
+
vec2 range = layerOcclusionRange();
|
|
113
|
+
float occlusion = mix(range.x, range.y, texture(uOrmMap, vec3(vUv.xy, at)).r);
|
|
114
|
+
lMeshOcclusion = mix(1.0, occlusion, strength);
|
|
115
|
+
}
|
|
95
116
|
vec4 m = layerWeights();
|
|
96
117
|
if (uLayers[2].z > 0.5) {
|
|
97
118
|
/* The ORM array's layer past the layers, and past the mask where the array carries that too. */
|
|
98
|
-
float at =
|
|
119
|
+
float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0);
|
|
99
120
|
float added = texture(uOrmMap, vec3(layerPlace() * uLayers[2].w, at)).r * uLayers[3].x;
|
|
100
121
|
m = mix(m, clamp(m + added, 0.0, 1.0), layerPick(uLayers[2].z));
|
|
101
122
|
}
|
|
@@ -135,23 +156,52 @@ vec3 layeredColor(vec3 color) {
|
|
|
135
156
|
return uLayers[1].w > 1.5 ? vec3(1.0) : color;
|
|
136
157
|
}
|
|
137
158
|
|
|
138
|
-
/*
|
|
159
|
+
/*
|
|
160
|
+
* Colour by the shares, each layer's tinted, and the base layer's coverage, which a cutout reads;
|
|
161
|
+
* then darkened by the occlusion at the mesh's coordinates, where it is the colour that takes it.
|
|
162
|
+
*/
|
|
139
163
|
vec4 layeredAlbedo() {
|
|
140
164
|
vec4 sum = vec4(0.0);
|
|
141
165
|
for (int i = 0; i < 5; i++) {
|
|
142
166
|
if (float(i) >= uLayers[1].y) break;
|
|
143
167
|
vec4 t = texture(uAlbedo, layerAt(i));
|
|
144
|
-
sum.rgb += t.rgb * layerShare(i);
|
|
168
|
+
sum.rgb += t.rgb * layerTint(i) * layerShare(i);
|
|
145
169
|
if (i == 0) sum.a = t.a;
|
|
146
170
|
}
|
|
171
|
+
if (!layerOcclusionAmbient()) sum.rgb *= lMeshOcclusion;
|
|
147
172
|
return sum;
|
|
148
173
|
}
|
|
149
174
|
|
|
175
|
+
/* What the ambient light keeps: the occlusion at the mesh's coordinates, where it takes it. */
|
|
176
|
+
float layeredAmbient() {
|
|
177
|
+
return layerOcclusionAmbient() ? lMeshOcclusion : 1.0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* The specular by the shares, each layer's own or the surface's where it names none. The surface's
|
|
182
|
+
* own, untouched, where no material has asked for looks: shares summing to one in floating point
|
|
183
|
+
* are not quite one, and a layered material that names nothing must draw exactly as before.
|
|
184
|
+
*/
|
|
185
|
+
float layeredSpecular(float own) {
|
|
186
|
+
if (LAYER_LOOKS) {
|
|
187
|
+
float sum = 0.0;
|
|
188
|
+
for (int i = 0; i < 5; i++) {
|
|
189
|
+
if (float(i) >= uLayers[1].y) break;
|
|
190
|
+
sum += layerSpecular(i, own) * layerShare(i);
|
|
191
|
+
}
|
|
192
|
+
return sum;
|
|
193
|
+
}
|
|
194
|
+
return own;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Occlusion, roughness and metalness by the shares, each layer's spread over its own ranges. */
|
|
150
198
|
vec3 layeredOrm() {
|
|
151
199
|
vec3 sum = vec3(0.0);
|
|
152
200
|
for (int i = 0; i < 5; i++) {
|
|
153
201
|
if (float(i) >= uLayers[1].y) break;
|
|
154
|
-
|
|
202
|
+
vec3 t = texture(uOrmMap, layerAt(i)).rgb;
|
|
203
|
+
t.yz = layerRanges(i, t.yz);
|
|
204
|
+
sum += t * layerShare(i);
|
|
155
205
|
}
|
|
156
206
|
return sum;
|
|
157
207
|
}
|
|
@@ -168,7 +218,7 @@ vec3 layeredTexel() {
|
|
|
168
218
|
vec3 sum = vec3(0.0);
|
|
169
219
|
for (int i = 0; i < 5; i++) {
|
|
170
220
|
if (float(i) >= uLayers[1].y) break;
|
|
171
|
-
sum += layerNormalTexel(layerAt(i)) * layerShare(i);
|
|
221
|
+
sum += layerStrengthen(i, layerNormalTexel(layerAt(i))) * layerShare(i);
|
|
172
222
|
}
|
|
173
223
|
float len = length(sum);
|
|
174
224
|
return len > 1e-5 ? sum / len : vec3(0.0, 0.0, 1.0);
|
|
@@ -181,7 +231,7 @@ bool layeredMeshNormal() {
|
|
|
181
231
|
|
|
182
232
|
/* That normal's texel: the normal array's layer past the layers, at the mesh's coordinates. */
|
|
183
233
|
vec3 layeredMeshTexel() {
|
|
184
|
-
return layerNormalTexel(vec3(vUv.xy,
|
|
234
|
+
return layerNormalTexel(vec3(vUv.xy, layerExtras()));
|
|
185
235
|
}
|
|
186
236
|
|
|
187
237
|
/* Whether the emissive map belongs to one layer rather than to the whole surface. */
|
|
@@ -18,6 +18,9 @@ export const MAIN_GLSL = `void main() {
|
|
|
18
18
|
projectSurface(surfaceAt, frameAt, frameTangents);
|
|
19
19
|
/* A layered material's mask, read once for every layer's share below: layered.ts. */
|
|
20
20
|
if (LAYERED && layered()) layeredBegin();
|
|
21
|
+
/* And the specular every highlight below reads: its layers' own, where a material gives them. */
|
|
22
|
+
surfaceSpecular = vSpecular;
|
|
23
|
+
if (LAYERED && layered()) surfaceSpecular = layeredSpecular(vSpecular);
|
|
21
24
|
if (dot(vec4(vWorldPos, 1.0), uClipPlane) < 0.0) discard;
|
|
22
25
|
/*
|
|
23
26
|
* The layer's surface effects, zeros where the albedo array carries no table — see
|
|
@@ -511,6 +514,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
511
514
|
#endif
|
|
512
515
|
/* A draw's own ambient, where one is set, in place of the frame's: \`setAmbientSH\`. */
|
|
513
516
|
if (uAmbientSH[6].w > 0.5) ambient = ambientHarmonics(n);
|
|
517
|
+
/* Less of it where a layered material's mesh occlusion darkens the ambient light: layered.ts. */
|
|
518
|
+
if (LAYERED && layered()) ambient *= layeredAmbient();
|
|
514
519
|
/*
|
|
515
520
|
* A metal keeps its ambient and loses its direct diffuse.
|
|
516
521
|
*
|
|
@@ -564,7 +569,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
564
569
|
* mix(x, y, 0) is exactly x, so at metal 0 this is vec3(vSpecular) and the line below is the
|
|
565
570
|
* one it replaces with the scalar broadened to three components.
|
|
566
571
|
*/
|
|
567
|
-
vec3 specColor = mix(vec3(
|
|
572
|
+
vec3 specColor = mix(vec3(surfaceSpecular), albedo, metal);
|
|
568
573
|
/*
|
|
569
574
|
* **A metal's highlight goes white at a grazing angle, and that is most of what reads as
|
|
570
575
|
* polished.**
|
|
@@ -1657,7 +1662,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1657
1662
|
* any lamp in the scene. The condition is the old one exactly when metal is 0, so nothing
|
|
1658
1663
|
* that binds no map takes a different branch than it took before.
|
|
1659
1664
|
*/
|
|
1660
|
-
if (
|
|
1665
|
+
if (surfaceSpecular > 0.0 || metal > 0.0) {
|
|
1661
1666
|
vec3 toEyeLamp = normalize(uCameraPos - vWorldPos);
|
|
1662
1667
|
vec3 lampHalfway = normalize(toLight / max(dist, 1e-4) + toEyeLamp);
|
|
1663
1668
|
/* The same grazing whitening the sun's highlight takes, and zero at metal 0 for the look. */
|
|
@@ -221,7 +221,7 @@ void modelSurface(vec3 n, vec3 albedo, float roughness, float metal, vec3 at) {
|
|
|
221
221
|
if (MODEL_SKIN) {
|
|
222
222
|
if (SKIN_DIFFUSE) mAlbedo = vec3(1.0);
|
|
223
223
|
}
|
|
224
|
-
mSpecColor = mix(vec3(
|
|
224
|
+
mSpecColor = mix(vec3(surfaceSpecular), albedo, metal);
|
|
225
225
|
mRoughness = roughness;
|
|
226
226
|
mMetal = metal;
|
|
227
227
|
mMap = vec4(0.5, 0.5, 1.0, 1.0);
|
|
@@ -52,6 +52,12 @@ in vec3 vColor;
|
|
|
52
52
|
in vec3 vWorldPos;
|
|
53
53
|
in float vEmissive;
|
|
54
54
|
in float vSpecular;
|
|
55
|
+
/*
|
|
56
|
+
* The specular this fragment shades with: its vertices' own, or a layered material's layers'
|
|
57
|
+
* blend of theirs, set once at the top of main. Every read of the specular reads this rather than
|
|
58
|
+
* the varying, so a layer's specular reaches the highlight, the reflection and the area lights alike.
|
|
59
|
+
*/
|
|
60
|
+
float surfaceSpecular;
|
|
55
61
|
in vec4 vLightPos;
|
|
56
62
|
in vec3 vUv;
|
|
57
63
|
in vec3 vEmissiveColor;
|