@driftengine/core 4.9.0 → 4.11.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 +133 -11
- package/README.md +43 -38
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -4
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/backend/api.d.ts +10 -3
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +189 -4
- package/dist/render/backend/webgl2/renderer.js +614 -66
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +24 -4
- package/dist/render/backend/webgpu/buffers.js +116 -59
- package/dist/render/backend/webgpu/clothKernels.d.ts +8 -0
- package/dist/render/backend/webgpu/clothKernels.js +76 -0
- package/dist/render/backend/webgpu/clothOps.d.ts +39 -0
- package/dist/render/backend/webgpu/clothOps.js +78 -0
- package/dist/render/backend/webgpu/clothSetLayout.d.ts +25 -0
- package/dist/render/backend/webgpu/clothSetLayout.js +84 -0
- package/dist/render/backend/webgpu/clothSetPack.d.ts +33 -0
- package/dist/render/backend/webgpu/clothSetPack.js +144 -0
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/drawCommand.d.ts +20 -4
- package/dist/render/backend/webgpu/drawCommand.js +11 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +85 -42
- package/dist/render/backend/webgpu/flatPass.js +137 -20
- package/dist/render/backend/webgpu/gpuClothSet.d.ts +80 -0
- package/dist/render/backend/webgpu/gpuClothSet.js +462 -0
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/latePass.js +1 -0
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/motionPass.js +15 -6
- package/dist/render/backend/webgpu/pipelineCache.d.ts +28 -1
- package/dist/render/backend/webgpu/pipelineCache.js +46 -1
- package/dist/render/backend/webgpu/postPass.d.ts +1 -1
- package/dist/render/backend/webgpu/renderer.d.ts +200 -35
- package/dist/render/backend/webgpu/renderer.js +993 -168
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +9 -2
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +121 -47
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +242 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/backend/webgpu/vertexFormats.d.ts +22 -0
- package/dist/render/backend/webgpu/vertexFormats.js +97 -0
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/globalMediumPass.d.ts +2 -0
- package/dist/render/globalMediumPass.js +1 -0
- package/dist/render/indexWidth.d.ts +17 -0
- package/dist/render/indexWidth.js +23 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightMatrix.d.ts +11 -0
- package/dist/render/lightMatrix.js +14 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +14 -0
- package/dist/render/mesh.js +44 -14
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/renderQuality.d.ts +30 -0
- package/dist/render/renderQuality.js +5 -0
- package/dist/render/rendererHarness.d.ts +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/screenSpaceReflection.d.ts +2 -1
- package/dist/render/shader.d.ts +15 -0
- package/dist/render/shader.js +41 -0
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/flat/directionalShadow.js +84 -10
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +3 -0
- package/dist/render/shaders/flat/index.d.ts +21 -0
- package/dist/render/shaders/flat/index.js +42 -7
- package/dist/render/shaders/flat/layered.d.ts +19 -0
- package/dist/render/shaders/flat/layered.js +115 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +58 -21
- package/dist/render/shaders/flat/mapReads.d.ts +10 -0
- package/dist/render/shaders/flat/mapReads.js +38 -0
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/movingSun.d.ts +21 -0
- package/dist/render/shaders/flat/movingSun.js +46 -0
- package/dist/render/shaders/flat/normalMap.d.ts +6 -2
- package/dist/render/shaders/flat/normalMap.js +14 -3
- package/dist/render/shaders/flat/overlay.d.ts +3 -2
- package/dist/render/shaders/flat/overlay.js +42 -20
- package/dist/render/shaders/flat/pointShadow.js +2 -2
- package/dist/render/shaders/flat/preamble.js +59 -27
- package/dist/render/shaders/flat/worldUv.d.ts +22 -0
- package/dist/render/shaders/flat/worldUv.js +113 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3616 -3042
- package/dist/render/shaders/generated/flat.wgsl.js +3688 -3113
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +8 -3
- package/dist/render/shaders/generated/globalMedium.wgsl.js +8 -3
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +15 -10
- package/dist/render/shaders/generated/lightVolume.wgsl.js +16 -11
- package/dist/render/shaders/globalMedium.js +9 -1
- package/dist/render/shaders/lightVolume.js +9 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/tangentFrame.d.ts +1 -1
- package/dist/render/shaders/tangentFrame.js +16 -3
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/skinnedClothRun.d.ts +28 -0
- package/dist/render/skinnedClothRun.js +103 -35
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceLayers.d.ts +39 -0
- package/dist/render/surfaceLayers.js +26 -0
- package/dist/render/surfaceOverlay.d.ts +16 -3
- package/dist/render/surfaceOverlay.js +11 -6
- package/dist/render/surfaceProjection.d.ts +34 -0
- package/dist/render/surfaceProjection.js +30 -0
- package/dist/render/surfaceTexture.d.ts +68 -7
- package/dist/render/surfaceTexture.js +56 -17
- package/dist/render/vertexPacking.d.ts +48 -0
- package/dist/render/vertexPacking.js +68 -0
- package/package.json +6 -6
- package/src/index.ts +12 -4
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/backend/api.ts +13 -3
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +723 -79
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +195 -70
- package/src/render/backend/webgpu/clothKernels.ts +86 -0
- package/src/render/backend/webgpu/clothOps.ts +86 -0
- package/src/render/backend/webgpu/clothSetLayout.ts +102 -0
- package/src/render/backend/webgpu/clothSetPack.ts +197 -0
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/drawCommand.ts +25 -4
- package/src/render/backend/webgpu/flatPass.ts +212 -41
- package/src/render/backend/webgpu/gpuClothSet.ts +564 -0
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/latePass.ts +1 -0
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/motionPass.ts +18 -7
- package/src/render/backend/webgpu/pipelineCache.ts +53 -7
- package/src/render/backend/webgpu/renderer.ts +1201 -202
- package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +121 -47
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +364 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/backend/webgpu/vertexFormats.ts +113 -0
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/glCompressed.ts +83 -0
- package/src/render/globalMediumPass.ts +7 -0
- package/src/render/indexWidth.ts +27 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightMatrix.ts +15 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +72 -14
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/renderQuality.ts +38 -0
- package/src/render/rendererHarness.ts +15 -0
- package/src/render/screenSpaceReflection.ts +2 -1
- package/src/render/shader.ts +59 -0
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/flat/directionalShadow.ts +84 -10
- package/src/render/shaders/flat/glassTint.ts +7 -1
- package/src/render/shaders/flat/index.ts +63 -7
- package/src/render/shaders/flat/layered.ts +115 -0
- package/src/render/shaders/flat/main.ts +58 -21
- package/src/render/shaders/flat/mapReads.ts +38 -0
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/movingSun.ts +46 -0
- package/src/render/shaders/flat/normalMap.ts +14 -3
- package/src/render/shaders/flat/overlay.ts +42 -20
- package/src/render/shaders/flat/pointShadow.ts +2 -2
- package/src/render/shaders/flat/preamble.ts +59 -27
- package/src/render/shaders/flat/worldUv.ts +113 -0
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/flat.wgsl.ts +3688 -3113
- package/src/render/shaders/generated/globalMedium.wgsl.ts +8 -3
- package/src/render/shaders/generated/lightVolume.wgsl.ts +16 -11
- package/src/render/shaders/globalMedium.ts +9 -1
- package/src/render/shaders/lightVolume.ts +9 -1
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/tangentFrame.ts +16 -3
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/skinnedClothRun.ts +138 -38
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceLayers.ts +57 -0
- package/src/render/surfaceOverlay.ts +24 -7
- package/src/render/surfaceProjection.ts +57 -0
- package/src/render/surfaceTexture.ts +124 -27
- package/src/render/vertexPacking.ts +109 -0
- package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +0 -74
- package/dist/render/backend/webgpu/gpuSkinnedCloth.js +0 -452
- package/src/render/backend/webgpu/gpuSkinnedCloth.ts +0 -502
|
@@ -6,6 +6,17 @@ export const MAIN_GLSL = `void main() {
|
|
|
6
6
|
* turns a float into an array index. A plain texture is an array of one, so layer 0.
|
|
7
7
|
*/
|
|
8
8
|
vec3 surfaceAt = vec3(vUv.xy, floor(vUv.z + 0.5));
|
|
9
|
+
/*
|
|
10
|
+
* The coordinates a map's frame and its cutout's level are measured along: the mesh's, or the
|
|
11
|
+
* world's where the material projects its maps (worldUv.ts) — in which case the mesh's tangents
|
|
12
|
+
* no longer run along them either. Triplanar reads its own three planes below; every other
|
|
13
|
+
* reader of surfaceAt takes the horizontal plane.
|
|
14
|
+
*/
|
|
15
|
+
vec2 frameAt = vUv.xy;
|
|
16
|
+
int frameTangents = vHasTangents;
|
|
17
|
+
projectSurface(surfaceAt, frameAt, frameTangents);
|
|
18
|
+
/* A layered material's mask, read once for every layer's share below: layered.ts. */
|
|
19
|
+
if (LAYERED && layered()) layeredBegin();
|
|
9
20
|
if (dot(vec4(vWorldPos, 1.0), uClipPlane) < 0.0) discard;
|
|
10
21
|
/*
|
|
11
22
|
* The layer's surface effects, zeros where the albedo array carries no table — see
|
|
@@ -25,6 +36,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
25
36
|
vec2 fxDx = dFdx(surfaceAt.xy);
|
|
26
37
|
vec2 fxDy = dFdy(surfaceAt.xy);
|
|
27
38
|
if (uWriteMode.y != 0.0 && !ditherKeeps(uWriteMode.y)) discard;
|
|
39
|
+
/* An opacity spent on the screen door instead of the blend: preamble.ts. 0 keeps nothing. */
|
|
40
|
+
if (uWriteMode.z != 0.0 && ditherThreshold() >= vAlpha) discard;
|
|
28
41
|
/* A draw's dissolve cuts the surface away before anything is shaded: overlay.ts. */
|
|
29
42
|
if (SURFACE_OVERLAY) {
|
|
30
43
|
if (overlayCuts(surfaceAt.xy)) discard;
|
|
@@ -62,14 +75,14 @@ export const MAIN_GLSL = `void main() {
|
|
|
62
75
|
*/
|
|
63
76
|
float coverage = 1.0;
|
|
64
77
|
if (uMaterialFlags.x != 0) {
|
|
65
|
-
vec4 texel =
|
|
78
|
+
vec4 texel = albedoTexel(surfaceAt);
|
|
66
79
|
// Discarded before anything else is computed: a thrown-away fragment should not pay
|
|
67
80
|
// for the lighting it will never contribute to. The test credits alpha for the mip level
|
|
68
81
|
// it samples, so a needle averaged thin down the chain is not lost; see cutoutCoverage.ts.
|
|
69
82
|
// Behind a branch on a uniform, so a material with no cutoff pays nothing for it.
|
|
70
83
|
float kept = texel.a;
|
|
71
84
|
if (uCutout.x > 0.0) {
|
|
72
|
-
float tested = cutoutAlpha(texel.a,
|
|
85
|
+
float tested = cutoutAlpha(texel.a, frameAt * vec2(textureSize(uAlbedo, 0).xy));
|
|
73
86
|
if (uCutout.y == 0.0) {
|
|
74
87
|
if (tested < uCutout.x) discard;
|
|
75
88
|
} else {
|
|
@@ -81,7 +94,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
81
94
|
*/
|
|
82
95
|
float share = cutoutShare(tested, uCutout.x);
|
|
83
96
|
if (uCutout.y == 1.0) {
|
|
84
|
-
if (!cutoutKeeps(share, gl_FragCoord.xy,
|
|
97
|
+
if (!cutoutKeeps(share, gl_FragCoord.xy, uHighlightMin.w)) discard;
|
|
85
98
|
kept = 1.0;
|
|
86
99
|
} else {
|
|
87
100
|
kept = share;
|
|
@@ -114,7 +127,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
114
127
|
float ormRoughness = vRoughness;
|
|
115
128
|
float metal = 0.0;
|
|
116
129
|
if (uMaterialFlags.y != 0) {
|
|
117
|
-
vec3 t =
|
|
130
|
+
vec3 t = ormTexel(surfaceAt);
|
|
118
131
|
ormOcclusion = mix(1.0, t.r, uOrmScale.r);
|
|
119
132
|
ormRoughness = clamp(t.g * uOrmScale.g, 0.0, 1.0);
|
|
120
133
|
metal = clamp(t.b * uOrmScale.b, 0.0, 1.0);
|
|
@@ -155,6 +168,14 @@ export const MAIN_GLSL = `void main() {
|
|
|
155
168
|
vec3 glassGlow = vec3(0.0);
|
|
156
169
|
float glassTransmission = uSeeThrough.z;
|
|
157
170
|
float glassFrost = uSeeThrough.w;
|
|
171
|
+
/*
|
|
172
|
+
* **A thin surface lets light from behind through, coloured by itself**: a banner, a leaf, a
|
|
173
|
+
* lampshade, an opaque material's \`diffuseTransmission\`, in the glass tint's spare lane. It
|
|
174
|
+
* gathers the light behind it in glassGlow, as a pane does, and adds it through its own colour.
|
|
175
|
+
* None on glass, which has its own way through.
|
|
176
|
+
*/
|
|
177
|
+
float thin = glassTransmission > 0.0 ? 0.0 : uGlassTint.w;
|
|
178
|
+
bool seesBehind = glassTransmission > 0.0 || thin > 0.0;
|
|
158
179
|
|
|
159
180
|
/*
|
|
160
181
|
* The normal a refracting draw bends by: the shading normal, a normal map's tilt and every relief
|
|
@@ -196,7 +217,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
196
217
|
* below. The rule is about non-uniform branches, and this branch is on a uniform.
|
|
197
218
|
*/
|
|
198
219
|
vec3 unmapped = n;
|
|
199
|
-
if (uNormalStrength > 0.0) n = normalMapped(n, surfaceAt);
|
|
220
|
+
if (uNormalStrength > 0.0) n = normalMapped(n, surfaceAt, frameAt, frameTangents);
|
|
200
221
|
/* A draw's wrinkles, by region, over whatever the map made: overlay.ts. */
|
|
201
222
|
if (SURFACE_OVERLAY) n = overlayWrinkle(n, unmapped, surfaceAt.xy);
|
|
202
223
|
|
|
@@ -367,6 +388,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
367
388
|
*/
|
|
368
389
|
shadingNormal = n;
|
|
369
390
|
if (backFace) n = -n;
|
|
391
|
+
/* A blending rim, on the base colour every light below reads: overlay.ts. */
|
|
392
|
+
if (SURFACE_OVERLAY) albedo = overlayRimBase(albedo, surfaceAt.xy, n);
|
|
370
393
|
/*
|
|
371
394
|
* A model's surface, gathered once, on a branch on the switches alone (models.ts) — and whether
|
|
372
395
|
* there is one, asked once: every site below is a branch on these two, which a pipeline with no
|
|
@@ -449,7 +472,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
449
472
|
float sunFacing = smoothstep(0.0, 0.02, surfaceNdl);
|
|
450
473
|
float direct = ndl * sunShade * sunFacing;
|
|
451
474
|
/* Glass: the sun on the far side of a pane lights it through the glass. See glassGlow. */
|
|
452
|
-
if (
|
|
475
|
+
if (seesBehind) glassGlow += sunColor * max(-surfaceNdl, 0.0) * sunShade;
|
|
453
476
|
|
|
454
477
|
/*
|
|
455
478
|
* Hemispheric: sky above, ground below, mixed by which way the surface looks. An
|
|
@@ -1280,7 +1303,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1280
1303
|
*/
|
|
1281
1304
|
float falloff;
|
|
1282
1305
|
/*
|
|
1283
|
-
* **A light may name its own falloff, and then it is
|
|
1306
|
+
* **A light may name its own falloff, and then it is the usual one for a light without
|
|
1284
1307
|
* inverse-square falloff**: \`(1 - (d/R)^2)^n\` with no distance term, so a fill authored to
|
|
1285
1308
|
* light a whole hall across a hundred metres does, where the inverse square would have it
|
|
1286
1309
|
* gone a few metres out. Zero is the frame's own rule below, which every light was before.
|
|
@@ -1301,8 +1324,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1301
1324
|
* the glass, shaped and shadowed like any lamp, and is added to glassGlow once its shape is
|
|
1302
1325
|
* known below. For everything else a lamp behind the surface is skipped here, as always.
|
|
1303
1326
|
*/
|
|
1304
|
-
float backNdl =
|
|
1305
|
-
glassTransmission > 0.0 ? max(-dot(n, toLight / max(dist, 1e-4)), 0.0) : 0.0;
|
|
1327
|
+
float backNdl = seesBehind ? max(-dot(n, toLight / max(dist, 1e-4)), 0.0) : 0.0;
|
|
1306
1328
|
/* A model that sees light from behind keeps the lamps behind the surface. See models.ts. */
|
|
1307
1329
|
if (ndl <= 0.0 && backNdl <= 0.0 && !modelledBehind) continue;
|
|
1308
1330
|
|
|
@@ -1322,7 +1344,9 @@ export const MAIN_GLSL = `void main() {
|
|
|
1322
1344
|
#if POINT_SHADOWS
|
|
1323
1345
|
float grazing = 1.0 - ndl;
|
|
1324
1346
|
float normalOffset = (0.06 + dist * 0.05) * grazing * grazing + 0.02;
|
|
1325
|
-
|
|
1347
|
+
/* Toward a lamp behind a thin surface, which is in the map itself: away from it, the surface
|
|
1348
|
+
would stand in its own shadow. A pane is in no map, so glass keeps the usual side. */
|
|
1349
|
+
vec3 receiverPoint = vWorldPos + (thin > 0.0 && ndl <= 0.0 ? -n : n) * normalOffset;
|
|
1326
1350
|
|
|
1327
1351
|
/*
|
|
1328
1352
|
* uPointShadowWeight is how present the cubemap is, and it is the difference
|
|
@@ -1698,7 +1722,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1698
1722
|
float signedForm = areaSignedForm(n, seenCentre, right, up, seenHalf);
|
|
1699
1723
|
float form = mix(max(0.0, signedForm), abs(signedForm), uAreaLightTwoSided[a]);
|
|
1700
1724
|
/* The form factor is linear in the normal, so the one seen from behind is its negation. */
|
|
1701
|
-
float backForm =
|
|
1725
|
+
float backForm = seesBehind
|
|
1702
1726
|
? mix(max(0.0, -signedForm), abs(signedForm), uAreaLightTwoSided[a])
|
|
1703
1727
|
: 0.0;
|
|
1704
1728
|
if (form <= 0.0 && backForm <= 0.0) continue;
|
|
@@ -1872,7 +1896,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1872
1896
|
* \`driftLight.ts\`.
|
|
1873
1897
|
*/
|
|
1874
1898
|
if (driftShare > 0.0) {
|
|
1875
|
-
if (
|
|
1899
|
+
if (seesBehind) {
|
|
1876
1900
|
glassGlow += driftLightIrradiance(vWorldPos, -n) * (driftShare * uDriftLight.w);
|
|
1877
1901
|
}
|
|
1878
1902
|
/* The standard expression in its own order — albedo times the field, then the share — so a
|
|
@@ -1932,6 +1956,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
1932
1956
|
* underneath: a ceiling emitting a dull warm haze over a pale panel cannot be expressed
|
|
1933
1957
|
* by scaling the panel, and scaling it gets the brightness right and the hue wrong.
|
|
1934
1958
|
*/
|
|
1959
|
+
/* What a thin surface lets through from behind, through its own colour; a metal lets none. */
|
|
1960
|
+
if (thin > 0.0) lit += albedo * glassGlow * (thin * (1.0 - metal));
|
|
1935
1961
|
diffuseAlone = lit;
|
|
1936
1962
|
vec3 emissiveTint = vEmissiveColor.r < 0.0 ? albedo : vEmissiveColor;
|
|
1937
1963
|
/*
|
|
@@ -1952,7 +1978,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1952
1978
|
*/
|
|
1953
1979
|
vec3 emissiveMapped = vec3(1.0);
|
|
1954
1980
|
if (uMaterialFlags.z != 0) {
|
|
1955
|
-
emissiveMapped =
|
|
1981
|
+
emissiveMapped = emissiveTexel(surfaceAt) * uEmissiveScale;
|
|
1956
1982
|
}
|
|
1957
1983
|
/* Pulse, flicker and fade from the layer's effects; exactly 1 where it names none. */
|
|
1958
1984
|
float fxGlow = fx4.z + fx5.x + fx5.w > 0.0 ? fxEmission(surfaceAt.z) : 1.0;
|
|
@@ -1996,7 +2022,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1996
2022
|
// finishing a run reads the same at noon and at midnight. Costs one compare
|
|
1997
2023
|
// per fragment and no extra draw call — the box is a uniform, not geometry.
|
|
1998
2024
|
if (uHighlightMax.w > 0.0) {
|
|
1999
|
-
vec3 inside = step(uHighlightMin, vWorldPos) * step(vWorldPos, uHighlightMax.xyz);
|
|
2025
|
+
vec3 inside = step(uHighlightMin.xyz, vWorldPos) * step(vWorldPos, uHighlightMax.xyz);
|
|
2000
2026
|
lit += albedo * uHighlightMax.w * inside.x * inside.y * inside.z;
|
|
2001
2027
|
}
|
|
2002
2028
|
}
|
|
@@ -2096,11 +2122,21 @@ export const MAIN_GLSL = `void main() {
|
|
|
2096
2122
|
* map here, on a branch on uniforms alone, which keeps its derivatives legal.
|
|
2097
2123
|
*/
|
|
2098
2124
|
vec3 refractN = shadingNormal;
|
|
2099
|
-
if (uLightingEnabled == 0 && uNormalStrength > 0.0) refractN = normalMapped(refractN, surfaceAt);
|
|
2125
|
+
if (uLightingEnabled == 0 && uNormalStrength > 0.0) refractN = normalMapped(refractN, surfaceAt, frameAt, frameTangents);
|
|
2100
2126
|
vec3 refractV = normalize(uCameraPos - vWorldPos);
|
|
2101
2127
|
ivec2 snapSize = textureSize(uRefractScene, 0);
|
|
2102
2128
|
vec2 screenUv = gl_FragCoord.xy / vec2(snapSize);
|
|
2103
|
-
|
|
2129
|
+
/*
|
|
2130
|
+
* **The normal's sideways part as the eye sees it**: the shading normal in view space, its x
|
|
2131
|
+
* and y across the screen, y turned to the way this frame's rows run (w of the tint). It was the
|
|
2132
|
+
* normal's world x and y until 4.10.0, which on a quad facing the camera is the quad's own lean
|
|
2133
|
+
* against the world's axes: one offset over the whole quad, a lens, with a normal map's tilt a
|
|
2134
|
+
* small change on top. In view space a quad facing the eye bends by nothing but its map, which
|
|
2135
|
+
* is a shimmer, and a pane bends by how it leans toward the eye wherever the eye stands.
|
|
2136
|
+
*/
|
|
2137
|
+
vec3 seenN = mat3(uView) * refractN;
|
|
2138
|
+
vec2 bend = vec2(seenN.x, seenN.y * uRefractTint.w);
|
|
2139
|
+
vec2 bent = clamp(screenUv + bend * uSeeThrough.x, vec2(0.0), vec2(1.0));
|
|
2104
2140
|
/*
|
|
2105
2141
|
* **An explicit level, and frost is what picks it** — the 2026-08-07 rule, and the reason a
|
|
2106
2142
|
* frosted pane blurs rather than fades: the copy carries a mip chain on a frame that draws glass,
|
|
@@ -2114,7 +2150,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
2114
2150
|
/* Unsigned: a pane passes the same light seen from either side, and so does its Fresnel. */
|
|
2115
2151
|
float cosView = max(abs(dot(refractN, refractV)), 0.05);
|
|
2116
2152
|
float pathLength = uSeeThrough.y * vThickness / cosView;
|
|
2117
|
-
vec3 seen = behind * pow(uRefractTint, vec3(pathLength));
|
|
2153
|
+
vec3 seen = behind * pow(uRefractTint.rgb, vec3(pathLength));
|
|
2118
2154
|
if (glassTransmission > 0.0) {
|
|
2119
2155
|
/*
|
|
2120
2156
|
* **Glass keeps its own surface and shows what is behind over it**, by how much it lets
|
|
@@ -2123,8 +2159,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
2123
2159
|
* The glow of the lights behind it is added last, by how frosted it is.
|
|
2124
2160
|
*/
|
|
2125
2161
|
float fresnel = 0.04 + 0.96 * pow(1.0 - cosView, 5.0);
|
|
2126
|
-
shaded = mix(shaded, seen * uGlassTint, glassTransmission * (1.0 - fresnel)) +
|
|
2127
|
-
applyOutputTransform(glassGlow * uGlassTint * (glassFrost * glassTransmission) * (1.0 - fog));
|
|
2162
|
+
shaded = mix(shaded, seen * uGlassTint.rgb, glassTransmission * (1.0 - fresnel)) +
|
|
2163
|
+
applyOutputTransform(glassGlow * uGlassTint.rgb * (glassFrost * glassTransmission) * (1.0 - fog));
|
|
2128
2164
|
} else {
|
|
2129
2165
|
shaded = seen;
|
|
2130
2166
|
}
|
|
@@ -2136,9 +2172,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
2136
2172
|
* **It did not need MeshData.colors widened to four floats**, which is how the consumer who
|
|
2137
2173
|
* asked for it had costed the change -- widening colors moves every mesh producer, the
|
|
2138
2174
|
* container layout and every baked asset. Alpha is a factor on the draw's opacity, not a
|
|
2139
|
-
* component of its albedo, so it rides a lane instead and nothing existing moves.
|
|
2175
|
+
* component of its albedo, so it rides a lane instead and nothing existing moves. Where the draw
|
|
2176
|
+
* spends it on the screen door instead (\`uWriteMode.z\`), it was spent at the top and is 1 here.
|
|
2140
2177
|
*/
|
|
2141
|
-
float alpha = uOpacity * coverage * vAlpha;
|
|
2178
|
+
float alpha = uOpacity * coverage * (uWriteMode.z != 0.0 ? 1.0 : vAlpha);
|
|
2142
2179
|
|
|
2143
2180
|
/*
|
|
2144
2181
|
* **Order-independent transparency, when this draw is accumulating into it.**
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where each of a material's maps is read: a layered material's blend (`layered.ts`), the three
|
|
3
|
+
* planes of a triplanar projection (`worldUv.ts`), or the map itself at the surface's coordinates.
|
|
4
|
+
*
|
|
5
|
+
* **Functions rather than branches in `main`, for the bundle's sake.** The generated WGSL stores an
|
|
6
|
+
* item once however many of the sixteen permutations share it, and `main` differs in every one, so
|
|
7
|
+
* a line there is paid sixteen times and a line here once. Called from the same uniform branches the
|
|
8
|
+
* reads stood in, so their implicit levels are as legal as they were: AGENTS.md 2026-08-07.
|
|
9
|
+
*/
|
|
10
|
+
export declare const MAP_READS_GLSL = "\n/* The surface's coordinates moved onto the world's horizontal plane where a material projects them,\n with the frame's coordinates and the mesh's tangents, which no longer run along them, set aside. */\nvoid projectSurface(inout vec3 at, inout vec2 frameAt, inout int frameTangents) {\n if (WORLD_UVS && projected()) {\n at.xy = planarAt();\n frameAt = at.xy;\n frameTangents = 0;\n }\n}\n\nvec4 albedoTexel(vec3 at) {\n if (LAYERED && layered()) return layeredAlbedo();\n if (WORLD_UVS && triplanar()) return triplanarAlbedo(at.z);\n return texture(uAlbedo, at);\n}\n\nvec3 ormTexel(vec3 at) {\n if (LAYERED && layered()) return layeredOrm();\n if (WORLD_UVS && triplanar()) return triplanarOrm(at.z);\n return texture(uOrmMap, at).rgb;\n}\n\nvec3 emissiveTexel(vec3 at) {\n if (LAYERED && layered() && layeredGlows()) return layeredEmissive();\n if (WORLD_UVS && triplanar()) return triplanarEmissive(at.z);\n return texture(uEmissiveMap, at).rgb;\n}\n";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where each of a material's maps is read: a layered material's blend (`layered.ts`), the three
|
|
3
|
+
* planes of a triplanar projection (`worldUv.ts`), or the map itself at the surface's coordinates.
|
|
4
|
+
*
|
|
5
|
+
* **Functions rather than branches in `main`, for the bundle's sake.** The generated WGSL stores an
|
|
6
|
+
* item once however many of the sixteen permutations share it, and `main` differs in every one, so
|
|
7
|
+
* a line there is paid sixteen times and a line here once. Called from the same uniform branches the
|
|
8
|
+
* reads stood in, so their implicit levels are as legal as they were: AGENTS.md 2026-08-07.
|
|
9
|
+
*/
|
|
10
|
+
export const MAP_READS_GLSL = /* glsl */ `
|
|
11
|
+
/* The surface's coordinates moved onto the world's horizontal plane where a material projects them,
|
|
12
|
+
with the frame's coordinates and the mesh's tangents, which no longer run along them, set aside. */
|
|
13
|
+
void projectSurface(inout vec3 at, inout vec2 frameAt, inout int frameTangents) {
|
|
14
|
+
if (WORLD_UVS && projected()) {
|
|
15
|
+
at.xy = planarAt();
|
|
16
|
+
frameAt = at.xy;
|
|
17
|
+
frameTangents = 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
vec4 albedoTexel(vec3 at) {
|
|
22
|
+
if (LAYERED && layered()) return layeredAlbedo();
|
|
23
|
+
if (WORLD_UVS && triplanar()) return triplanarAlbedo(at.z);
|
|
24
|
+
return texture(uAlbedo, at);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
vec3 ormTexel(vec3 at) {
|
|
28
|
+
if (LAYERED && layered()) return layeredOrm();
|
|
29
|
+
if (WORLD_UVS && triplanar()) return triplanarOrm(at.z);
|
|
30
|
+
return texture(uOrmMap, at).rgb;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
vec3 emissiveTexel(vec3 at) {
|
|
34
|
+
if (LAYERED && layered() && layeredGlows()) return layeredEmissive();
|
|
35
|
+
if (WORLD_UVS && triplanar()) return triplanarEmissive(at.z);
|
|
36
|
+
return texture(uEmissiveMap, at).rgb;
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
@@ -57,7 +57,7 @@ const bool PHYSICAL_SPECULAR = PHYSICAL_SPECULAR_ON; // wgsl:override
|
|
|
57
57
|
* A model's numbers, two vectors a material — the lit stage's uniform budget has no more room
|
|
58
58
|
* (surfaceModel.ts) — and whether a model map is bound, in the last component.
|
|
59
59
|
*/
|
|
60
|
-
uniform vec4 uModelParams[2];
|
|
60
|
+
uniform vec4 uModelParams[2]; // wgsl:material
|
|
61
61
|
/* The model's own channels, in the albedo's layout: what each means is each model's to say. */
|
|
62
62
|
uniform highp sampler2DArray uModelMap;
|
|
63
63
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sun's moving layer read through a matrix of its own: the one the frame's dynamic shadow pass
|
|
3
|
+
* was drawn with, where that is not the static layer's.
|
|
4
|
+
*
|
|
5
|
+
* **Why a matrix of its own.** The static layer wants a square over the whole of what stands still,
|
|
6
|
+
* so distant roofs keep their shadows; what moves wants a tight one, so a character's shadow is
|
|
7
|
+
* sharp. One matrix for both is one of the two given up. A caller fits each as it likes and draws
|
|
8
|
+
* each pass with its own (`beginShadowPass(matrix, 'dynamic')`); the renderer keeps the dynamic
|
|
9
|
+
* pass's and the lit stage reads that layer through it, the receiver's position projected from the
|
|
10
|
+
* world here rather than carried in a second varying.
|
|
11
|
+
*
|
|
12
|
+
* **A lit switch, `MOVING_SUN`**, off until a frame's dynamic pass is drawn with a matrix the static
|
|
13
|
+
* layer does not share, then on for good. Declared beside the other lit switches, ahead of the
|
|
14
|
+
* shadow lookup that calls it; compiled out, the moving layer is read at the static layer's place,
|
|
15
|
+
* exactly as it always was, and its matrix and depth span are not declared at all.
|
|
16
|
+
*
|
|
17
|
+
* **What it gives up**: a receiver outside the static layer's square takes no sun shadow at all,
|
|
18
|
+
* moving casters included, since everything is faded by that square first; so the tight square
|
|
19
|
+
* belongs inside the wide one.
|
|
20
|
+
*/
|
|
21
|
+
export declare function movingSunGlsl(on: boolean): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sun's moving layer read through a matrix of its own: the one the frame's dynamic shadow pass
|
|
3
|
+
* was drawn with, where that is not the static layer's.
|
|
4
|
+
*
|
|
5
|
+
* **Why a matrix of its own.** The static layer wants a square over the whole of what stands still,
|
|
6
|
+
* so distant roofs keep their shadows; what moves wants a tight one, so a character's shadow is
|
|
7
|
+
* sharp. One matrix for both is one of the two given up. A caller fits each as it likes and draws
|
|
8
|
+
* each pass with its own (`beginShadowPass(matrix, 'dynamic')`); the renderer keeps the dynamic
|
|
9
|
+
* pass's and the lit stage reads that layer through it, the receiver's position projected from the
|
|
10
|
+
* world here rather than carried in a second varying.
|
|
11
|
+
*
|
|
12
|
+
* **A lit switch, `MOVING_SUN`**, off until a frame's dynamic pass is drawn with a matrix the static
|
|
13
|
+
* layer does not share, then on for good. Declared beside the other lit switches, ahead of the
|
|
14
|
+
* shadow lookup that calls it; compiled out, the moving layer is read at the static layer's place,
|
|
15
|
+
* exactly as it always was, and its matrix and depth span are not declared at all.
|
|
16
|
+
*
|
|
17
|
+
* **What it gives up**: a receiver outside the static layer's square takes no sun shadow at all,
|
|
18
|
+
* moving casters included, since everything is faded by that square first; so the tight square
|
|
19
|
+
* belongs inside the wide one.
|
|
20
|
+
*/
|
|
21
|
+
export function movingSunGlsl(on) {
|
|
22
|
+
if (!on) {
|
|
23
|
+
return /* glsl */ `
|
|
24
|
+
const bool MOVING_SUN = false; // wgsl:override
|
|
25
|
+
vec3 movingSunAt() { return vec3(0.0); }
|
|
26
|
+
float movingSunSpan() { return 1.0; }
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
return /* glsl */ `
|
|
30
|
+
/* Whether the moving layer has a matrix of its own. Off until a frame draws it with one: movingSun.ts. */
|
|
31
|
+
const bool MOVING_SUN = true; // wgsl:override
|
|
32
|
+
/* The dynamic shadow pass's world-to-light matrix, and the depth it spans in metres. */
|
|
33
|
+
uniform mat4 uMovingLightViewProj;
|
|
34
|
+
uniform float uMovingShadowDepthSpan;
|
|
35
|
+
|
|
36
|
+
/* The receiver in the moving layer's map: x and y across it, z its depth, all 0 to 1. */
|
|
37
|
+
vec3 movingSunAt() {
|
|
38
|
+
vec4 l = uMovingLightViewProj * vec4(vWorldPos, 1.0);
|
|
39
|
+
return l.xyz / l.w * 0.5 + 0.5;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
float movingSunSpan() {
|
|
43
|
+
return uMovingShadowDepthSpan;
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
* lit block for every light and by an unlit refracting draw for the direction it bends, so a lit
|
|
4
4
|
* pane and an unlit distortion bend by one tilt rather than two transcriptions of it.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* The frame is built from `frameAt`, the coordinates the map was laid by — the mesh's, or the
|
|
7
|
+
* world's where a material projects them (`worldUv.ts`), with the mesh's tangents then set aside
|
|
8
|
+
* by `hasTangents`, since they run along coordinates the map no longer follows.
|
|
9
|
+
*
|
|
10
|
+
* Depth zero, after the tangent frame and the world's projection it calls; see `flatFrag`. **Only ever called under a branch
|
|
7
11
|
* on a uniform** — `uNormalStrength` and whatever gates its caller — which is what makes the
|
|
8
12
|
* derivatives inside `tangentFrame` and the implicit level of the read legal: AGENTS.md 2026-08-07.
|
|
9
13
|
*/
|
|
10
|
-
export declare const NORMAL_MAP_GLSL = "\nvec3 normalMapped(vec3 n, vec3 at) {\n vec3 mapped = texture(uNormalMap, at).xyz * 2.0 - 1.0;\n /*\n * z rebuilt where none is stored. A tangent-space normal points out of its surface, so a\n * stored z at or below zero is never a real one: it is a two-channel map, BC5, whose blue a\n * device samples as zero and which arrives here as -1. Every map baked from BC5 to PNG before\n * 4.8.4 carried the same zero. A select rather than a flag: no uniform to bind, no material\n * that has to say what format it holds, and continuous at the boundary, since a unit texel\n * lying flat has its z near zero either way. A texel with z above zero is left as it was.\n */\n mapped.z = mapped.z > 0.0 ? mapped.z : sqrt(max(0.0, 1.0 - dot(mapped.xy, mapped.xy)));\n mat3 tbn = tangentFrame(n, vWorldPos,
|
|
14
|
+
export declare const NORMAL_MAP_GLSL = "\nvec3 normalMapped(vec3 n, vec3 at, vec2 frameAt, int hasTangents) {\n /* On three planes where the material projects them so: worldUv.ts. */\n if (WORLD_UVS && triplanar()) return triplanarNormal(n, at.z);\n /* A layered material's texels, blended by its mask before the frame turns them: layered.ts. */\n if (LAYERED && layered()) {\n mat3 layeredFrame = tangentFrame(n, vWorldPos, frameAt, vTangent, hasTangents);\n return normalize(mix(n, normalize(layeredFrame * layeredTexel()), uNormalStrength));\n }\n vec3 mapped = texture(uNormalMap, at).xyz * 2.0 - 1.0;\n /*\n * z rebuilt where none is stored. A tangent-space normal points out of its surface, so a\n * stored z at or below zero is never a real one: it is a two-channel map, BC5, whose blue a\n * device samples as zero and which arrives here as -1. Every map baked from BC5 to PNG before\n * 4.8.4 carried the same zero. A select rather than a flag: no uniform to bind, no material\n * that has to say what format it holds, and continuous at the boundary, since a unit texel\n * lying flat has its z near zero either way. A texel with z above zero is left as it was.\n */\n mapped.z = mapped.z > 0.0 ? mapped.z : sqrt(max(0.0, 1.0 - dot(mapped.xy, mapped.xy)));\n mat3 tbn = tangentFrame(n, vWorldPos, frameAt, vTangent, hasTangents);\n return normalize(mix(n, normalize(tbn * mapped), uNormalStrength));\n}\n";
|
|
@@ -3,12 +3,23 @@
|
|
|
3
3
|
* lit block for every light and by an unlit refracting draw for the direction it bends, so a lit
|
|
4
4
|
* pane and an unlit distortion bend by one tilt rather than two transcriptions of it.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* The frame is built from `frameAt`, the coordinates the map was laid by — the mesh's, or the
|
|
7
|
+
* world's where a material projects them (`worldUv.ts`), with the mesh's tangents then set aside
|
|
8
|
+
* by `hasTangents`, since they run along coordinates the map no longer follows.
|
|
9
|
+
*
|
|
10
|
+
* Depth zero, after the tangent frame and the world's projection it calls; see `flatFrag`. **Only ever called under a branch
|
|
7
11
|
* on a uniform** — `uNormalStrength` and whatever gates its caller — which is what makes the
|
|
8
12
|
* derivatives inside `tangentFrame` and the implicit level of the read legal: AGENTS.md 2026-08-07.
|
|
9
13
|
*/
|
|
10
14
|
export const NORMAL_MAP_GLSL = /* glsl */ `
|
|
11
|
-
vec3 normalMapped(vec3 n, vec3 at) {
|
|
15
|
+
vec3 normalMapped(vec3 n, vec3 at, vec2 frameAt, int hasTangents) {
|
|
16
|
+
/* On three planes where the material projects them so: worldUv.ts. */
|
|
17
|
+
if (WORLD_UVS && triplanar()) return triplanarNormal(n, at.z);
|
|
18
|
+
/* A layered material's texels, blended by its mask before the frame turns them: layered.ts. */
|
|
19
|
+
if (LAYERED && layered()) {
|
|
20
|
+
mat3 layeredFrame = tangentFrame(n, vWorldPos, frameAt, vTangent, hasTangents);
|
|
21
|
+
return normalize(mix(n, normalize(layeredFrame * layeredTexel()), uNormalStrength));
|
|
22
|
+
}
|
|
12
23
|
vec3 mapped = texture(uNormalMap, at).xyz * 2.0 - 1.0;
|
|
13
24
|
/*
|
|
14
25
|
* z rebuilt where none is stored. A tangent-space normal points out of its surface, so a
|
|
@@ -19,7 +30,7 @@ vec3 normalMapped(vec3 n, vec3 at) {
|
|
|
19
30
|
* lying flat has its z near zero either way. A texel with z above zero is left as it was.
|
|
20
31
|
*/
|
|
21
32
|
mapped.z = mapped.z > 0.0 ? mapped.z : sqrt(max(0.0, 1.0 - dot(mapped.xy, mapped.xy)));
|
|
22
|
-
mat3 tbn = tangentFrame(n, vWorldPos,
|
|
33
|
+
mat3 tbn = tangentFrame(n, vWorldPos, frameAt, vTangent, hasTangents);
|
|
23
34
|
return normalize(mix(n, normalize(tbn * mapped), uNormalStrength));
|
|
24
35
|
}
|
|
25
36
|
`;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A draw's surface overlay in the lit stage: the rim, the dissolve and the wrinkles
|
|
3
|
-
* `surfaceOverlay.ts` packs into `uOverlay`. Called from `main` at
|
|
4
|
-
* before anything is shaded, the wrinkles after the normal map,
|
|
3
|
+
* `surfaceOverlay.ts` packs into `uOverlay`. Called from `main` at four places — the dissolve's cut
|
|
4
|
+
* before anything is shaded, the wrinkles after the normal map, a blending rim on the base colour
|
|
5
|
+
* once the normal is final and before any light reads the colour, and the glow beside emission.
|
|
5
6
|
*
|
|
6
7
|
* **A lit switch, `SURFACE_OVERLAY`**, off until a draw first sets an overlay and then on for good,
|
|
7
8
|
* as `litSwitchesGlsl`'s are; declared after the models so every switch before it keeps its id.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A draw's surface overlay in the lit stage: the rim, the dissolve and the wrinkles
|
|
3
|
-
* `surfaceOverlay.ts` packs into `uOverlay`. Called from `main` at
|
|
4
|
-
* before anything is shaded, the wrinkles after the normal map,
|
|
3
|
+
* `surfaceOverlay.ts` packs into `uOverlay`. Called from `main` at four places — the dissolve's cut
|
|
4
|
+
* before anything is shaded, the wrinkles after the normal map, a blending rim on the base colour
|
|
5
|
+
* once the normal is final and before any light reads the colour, and the glow beside emission.
|
|
5
6
|
*
|
|
6
7
|
* **A lit switch, `SURFACE_OVERLAY`**, off until a draw first sets an overlay and then on for good,
|
|
7
8
|
* as `litSwitchesGlsl`'s are; declared after the models so every switch before it keeps its id.
|
|
@@ -19,6 +20,7 @@ export function overlayGlsl(on) {
|
|
|
19
20
|
const bool SURFACE_OVERLAY = false; // wgsl:override
|
|
20
21
|
bool overlayCuts(vec2 uv) { return false; }
|
|
21
22
|
vec3 overlayWrinkle(vec3 mapped, vec3 unmapped, vec2 uv) { return mapped; }
|
|
23
|
+
vec3 overlayRimBase(vec3 base, vec2 uv, vec3 n) { return base; }
|
|
22
24
|
vec3 overlayGlow(vec2 uv, vec3 n) { return vec3(0.0); }
|
|
23
25
|
`;
|
|
24
26
|
}
|
|
@@ -26,7 +28,7 @@ vec3 overlayGlow(vec2 uv, vec3 n) { return vec3(0.0); }
|
|
|
26
28
|
/* Whether this program carries a draw's overlay. Off but where one has been set: overlay.ts. */
|
|
27
29
|
const bool SURFACE_OVERLAY = true; // wgsl:override
|
|
28
30
|
/* The overlay's fifteen vectors; packSurfaceOverlay in surfaceOverlay.ts says what each holds. */
|
|
29
|
-
uniform vec4 uOverlay[15];
|
|
31
|
+
uniform vec4 uOverlay[15]; // wgsl:material
|
|
30
32
|
|
|
31
33
|
/* Whether the atlas is what the refraction slot holds: not where this draw refracts or is glass. */
|
|
32
34
|
bool overlayImagesBound() {
|
|
@@ -84,8 +86,42 @@ vec2 overlayScreen() {
|
|
|
84
86
|
return vec2(eye.x / depth + uClusterFrustum.w, eye.y / depth + 1.0) * 0.5;
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
/*
|
|
90
|
+
* The rim's weight here, 0 to 1 before the pulse and the mask: the edge leaning toward normals that
|
|
91
|
+
* face up, raised to the contrast, times the noise laid in screen space. Its strength is the
|
|
92
|
+
* caller's: an added rim takes it times its light, a blending one times its colour.
|
|
93
|
+
*/
|
|
94
|
+
float overlayRimWeight(vec2 uv, vec3 n) {
|
|
95
|
+
vec3 toEye = normalize(uCameraPos - vWorldPos);
|
|
96
|
+
float edge = pow(1.0 - clamp(dot(n, toEye), 0.0, 1.0), max(uOverlay[1].x, 1e-4));
|
|
97
|
+
float up = pow(clamp(n.y * 0.5 + 0.5, 0.0, 1.0), max(uOverlay[1].y, 1e-4));
|
|
98
|
+
float rim = pow(edge * up, max(uOverlay[1].z, 1e-4));
|
|
99
|
+
float time = uSurfaceScene.x;
|
|
100
|
+
if (uOverlay[2].x > 0.0 && overlayImagesBound()) {
|
|
101
|
+
vec2 at = overlayScreen() * uOverlay[3].z + uOverlay[3].xy * time;
|
|
102
|
+
rim *= overlayImage(uOverlay[2], at).r;
|
|
103
|
+
}
|
|
104
|
+
rim = min(rim, 1.0);
|
|
105
|
+
rim *= mix(uOverlay[4].x, uOverlay[4].y, 0.5 + 0.5 * sin(uOverlay[3].w * time));
|
|
106
|
+
if (uOverlay[5].x > 0.0 && overlayImagesBound()) {
|
|
107
|
+
rim *= 1.0 - uOverlay[1].w * overlayImage(uOverlay[5], uv).r;
|
|
108
|
+
}
|
|
109
|
+
return rim;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* A blending rim: the base colour pulled toward the rim's by the weight times the alpha, held at
|
|
114
|
+
* one, before any light reads it, so the edge is lit as the surface is. The colour arrives already
|
|
115
|
+
* held at one a channel. Nothing where the rim adds instead, or where there is none.
|
|
116
|
+
*/
|
|
117
|
+
vec3 overlayRimBase(vec3 base, vec2 uv, vec3 n) {
|
|
118
|
+
if (uOverlay[0].w <= 0.0 || uOverlay[4].z < 0.5) return base;
|
|
119
|
+
float weight = clamp(uOverlay[0].w * overlayRimWeight(uv, n), 0.0, 1.0);
|
|
120
|
+
return mix(base, uOverlay[0].rgb, weight);
|
|
121
|
+
}
|
|
122
|
+
|
|
87
123
|
/* What the overlay adds to the light the surface gives off: the dissolve's band, the colour laid
|
|
88
|
-
over through its noise, and
|
|
124
|
+
over through its noise, and an adding rim. Zero where the draw sets none of them. */
|
|
89
125
|
vec3 overlayGlow(vec2 uv, vec3 n) {
|
|
90
126
|
vec3 glow = vec3(0.0);
|
|
91
127
|
float noise = overlayDissolveNoise(uv);
|
|
@@ -94,22 +130,8 @@ vec3 overlayGlow(vec2 uv, vec3 n) {
|
|
|
94
130
|
glow += uOverlay[8].rgb * uOverlay[8].w * band + uOverlay[9].rgb * uOverlay[9].w * noise;
|
|
95
131
|
}
|
|
96
132
|
float strength = uOverlay[0].w;
|
|
97
|
-
if (strength > 0.0) {
|
|
98
|
-
|
|
99
|
-
float edge = pow(1.0 - clamp(dot(n, toEye), 0.0, 1.0), max(uOverlay[1].x, 1e-4));
|
|
100
|
-
float up = pow(clamp(n.y * 0.5 + 0.5, 0.0, 1.0), max(uOverlay[1].y, 1e-4));
|
|
101
|
-
float rim = pow(edge * up, max(uOverlay[1].z, 1e-4));
|
|
102
|
-
float time = uSurfaceScene.x;
|
|
103
|
-
if (uOverlay[2].x > 0.0 && overlayImagesBound()) {
|
|
104
|
-
vec2 at = overlayScreen() * uOverlay[3].z + uOverlay[3].xy * time;
|
|
105
|
-
rim *= overlayImage(uOverlay[2], at).r;
|
|
106
|
-
}
|
|
107
|
-
rim = min(rim, 1.0);
|
|
108
|
-
rim *= mix(uOverlay[4].x, uOverlay[4].y, 0.5 + 0.5 * sin(uOverlay[3].w * time));
|
|
109
|
-
if (uOverlay[5].x > 0.0 && overlayImagesBound()) {
|
|
110
|
-
rim *= 1.0 - uOverlay[1].w * overlayImage(uOverlay[5], uv).r;
|
|
111
|
-
}
|
|
112
|
-
glow += uOverlay[0].rgb * strength * rim;
|
|
133
|
+
if (strength > 0.0 && uOverlay[4].z < 0.5) {
|
|
134
|
+
glow += uOverlay[0].rgb * strength * overlayRimWeight(uv, n);
|
|
113
135
|
}
|
|
114
136
|
return glow;
|
|
115
137
|
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* picture and is its own change.
|
|
14
14
|
*/
|
|
15
15
|
import { MAX_SHADOW_FILTER_TAPS } from '../../renderQuality.js';
|
|
16
|
-
import {
|
|
16
|
+
import { LIT_OUTPUT_TRANSFORM_GLSL } from '../outputTransform.js';
|
|
17
17
|
import { LAMP_GLASS_GLSL } from './lampGlass.js';
|
|
18
18
|
export const POINTSHADOW_GLSL = `/**
|
|
19
19
|
* How much of one tap's occlusion survives its own penumbra.
|
|
@@ -343,7 +343,7 @@ ${LAMP_GLASS_GLSL}
|
|
|
343
343
|
|
|
344
344
|
layout(location = 0) out vec4 outColor;
|
|
345
345
|
|
|
346
|
-
${
|
|
346
|
+
${LIT_OUTPUT_TRANSFORM_GLSL}
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
349
|
* A fixed Poisson disk avoids the grid-shaped edge left by square 3x3 PCF.
|