@driftengine/core 4.8.7 → 4.10.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 +123 -11
- package/README.md +43 -38
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -3
- 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/atmosphere.d.ts +13 -0
- package/dist/render/atmosphere.js +9 -1
- package/dist/render/backend/api.d.ts +19 -4
- package/dist/render/backend/createRenderer.d.ts +6 -0
- package/dist/render/backend/createRenderer.js +4 -1
- 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 +180 -4
- package/dist/render/backend/webgl2/renderer.js +550 -40
- 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 +19 -4
- package/dist/render/backend/webgpu/buffers.js +18 -11
- 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/device.d.ts +7 -1
- package/dist/render/backend/webgpu/device.js +31 -3
- package/dist/render/backend/webgpu/drawCommand.d.ts +18 -4
- package/dist/render/backend/webgpu/drawCommand.js +10 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +100 -42
- package/dist/render/backend/webgpu/flatPass.js +191 -43
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +6 -0
- package/dist/render/backend/webgpu/pipelineCache.js +7 -0
- package/dist/render/backend/webgpu/postPass.d.ts +51 -9
- package/dist/render/backend/webgpu/postPass.js +16 -2
- package/dist/render/backend/webgpu/reflectionSurfacePass.d.ts +30 -0
- package/dist/render/backend/webgpu/reflectionSurfacePass.js +100 -0
- package/dist/render/backend/webgpu/renderer.d.ts +283 -37
- package/dist/render/backend/webgpu/renderer.js +1363 -202
- 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 +241 -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/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/displayRange.d.ts +31 -0
- package/dist/render/displayRange.js +47 -0
- package/dist/render/filmicCurve.d.ts +74 -0
- package/dist/render/filmicCurve.js +203 -0
- package/dist/render/fog.d.ts +4 -1
- package/dist/render/fog.js +12 -2
- package/dist/render/frame/resources.d.ts +2 -2
- package/dist/render/frame/resources.js +6 -0
- package/dist/render/frameReflections.d.ts +40 -0
- package/dist/render/frameReflections.js +48 -0
- package/dist/render/glCompressed.js +83 -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/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +5 -0
- package/dist/render/mesh.js +6 -0
- package/dist/render/pass.d.ts +49 -0
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/reflectionSurfaceTargets.d.ts +28 -0
- package/dist/render/reflectionSurfaceTargets.js +99 -0
- package/dist/render/renderQuality.d.ts +39 -8
- package/dist/render/renderQuality.js +4 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +24 -1
- package/dist/render/screenSpaceReflection.d.ts +7 -1
- package/dist/render/screenSpaceReflection.js +5 -0
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/filmLook.js +2 -1
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +2 -0
- package/dist/render/shaders/flat/index.d.ts +16 -0
- package/dist/render/shaders/flat/index.js +33 -5
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +43 -5
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/overlay.d.ts +16 -0
- package/dist/render/shaders/flat/overlay.js +117 -0
- package/dist/render/shaders/flat/pointShadow.js +3 -3
- package/dist/render/shaders/flat/preamble.js +38 -24
- package/dist/render/shaders/flat/reflectionSurface.d.ts +21 -0
- package/dist/render/shaders/flat/reflectionSurface.js +61 -0
- package/dist/render/shaders/fog.d.ts +1 -1
- package/dist/render/shaders/fog.js +9 -2
- package/dist/render/shaders/fringe.d.ts +29 -0
- package/dist/render/shaders/fringe.js +55 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.js +1 -1
- 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/film.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/film.wgsl.js +1 -1
- package/dist/render/shaders/generated/fire.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/fire.wgsl.js +1 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3254 -2920
- package/dist/render/shaders/generated/flat.wgsl.js +3292 -2957
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/particle.wgsl.js +4 -4
- package/dist/render/shaders/generated/rush.wgsl.d.ts +56 -26
- package/dist/render/shaders/generated/rush.wgsl.js +56 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/scatter.wgsl.js +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +1 -1
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +22 -2
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +22 -2
- package/dist/render/shaders/generated/water.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/water.wgsl.js +1 -1
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +2 -2
- package/dist/render/shaders/gpudriven/fog.wgsl.js +11 -3
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/rush.js +54 -11
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/ssrResolve.d.ts +17 -0
- package/dist/render/shaders/ssrResolve.js +51 -0
- package/dist/render/shaders/ssrTrace.js +26 -0
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/ssrPass.d.ts +16 -0
- package/dist/render/ssrPass.js +106 -1
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceOverlay.d.ts +132 -0
- package/dist/render/surfaceOverlay.js +85 -0
- package/dist/render/surfaceTexture.d.ts +57 -7
- package/dist/render/surfaceTexture.js +125 -17
- package/dist/render/temporalAa.d.ts +14 -0
- package/dist/render/temporalAa.js +20 -0
- package/dist/render/vertexDefaults.d.ts +17 -0
- package/dist/render/vertexDefaults.js +24 -0
- package/package.json +6 -6
- package/src/index.ts +24 -2
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/atmosphere.ts +22 -1
- package/src/render/backend/api.ts +22 -3
- package/src/render/backend/createRenderer.ts +18 -1
- 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 +672 -37
- 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 +42 -16
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/device.ts +42 -3
- package/src/render/backend/webgpu/drawCommand.ts +22 -4
- package/src/render/backend/webgpu/flatPass.ts +250 -40
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/pipelineCache.ts +7 -0
- package/src/render/backend/webgpu/postPass.ts +18 -0
- package/src/render/backend/webgpu/reflectionSurfacePass.ts +114 -0
- package/src/render/backend/webgpu/renderer.ts +1655 -230
- 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 +363 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/displayRange.ts +61 -0
- package/src/render/filmicCurve.ts +229 -0
- package/src/render/fog.ts +19 -3
- package/src/render/frame/resources.ts +6 -0
- package/src/render/frameReflections.ts +72 -0
- package/src/render/glCompressed.ts +83 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +6 -0
- package/src/render/pass.ts +53 -1
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/reflectionSurfaceTargets.ts +105 -0
- package/src/render/renderQuality.ts +44 -8
- package/src/render/sceneTarget.ts +30 -2
- package/src/render/screenSpaceReflection.ts +7 -1
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/filmLook.ts +2 -1
- package/src/render/shaders/flat/glassTint.ts +5 -1
- package/src/render/shaders/flat/index.ts +49 -5
- package/src/render/shaders/flat/main.ts +43 -5
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/overlay.ts +117 -0
- package/src/render/shaders/flat/pointShadow.ts +3 -3
- package/src/render/shaders/flat/preamble.ts +38 -24
- package/src/render/shaders/flat/reflectionSurface.ts +61 -0
- package/src/render/shaders/fog.ts +9 -2
- package/src/render/shaders/fringe.ts +59 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +1 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/caustics.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/film.wgsl.ts +1 -1
- package/src/render/shaders/generated/fire.wgsl.ts +1 -1
- package/src/render/shaders/generated/flat.wgsl.ts +3292 -2957
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +4 -4
- package/src/render/shaders/generated/rush.wgsl.ts +56 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +1 -1
- package/src/render/shaders/generated/smoke.wgsl.ts +1 -1
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +22 -2
- package/src/render/shaders/generated/water.wgsl.ts +1 -1
- package/src/render/shaders/gpudriven/fog.wgsl.ts +11 -3
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/rush.ts +54 -11
- package/src/render/shaders/ssrResolve.ts +52 -0
- package/src/render/shaders/ssrTrace.ts +26 -0
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/ssrPass.ts +138 -1
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceOverlay.ts +195 -0
- package/src/render/surfaceTexture.ts +161 -27
- package/src/render/temporalAa.ts +20 -0
- package/src/render/vertexDefaults.ts +28 -0
|
@@ -25,6 +25,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
25
25
|
vec2 fxDx = dFdx(surfaceAt.xy);
|
|
26
26
|
vec2 fxDy = dFdy(surfaceAt.xy);
|
|
27
27
|
if (uWriteMode.y != 0.0 && !ditherKeeps(uWriteMode.y)) discard;
|
|
28
|
+
/* A draw's dissolve cuts the surface away before anything is shaded: overlay.ts. */
|
|
29
|
+
if (SURFACE_OVERLAY) {
|
|
30
|
+
if (overlayCuts(surfaceAt.xy)) discard;
|
|
31
|
+
}
|
|
28
32
|
|
|
29
33
|
/*
|
|
30
34
|
* Surface colour and its coverage, resolved before anything else — including before it is
|
|
@@ -77,7 +81,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
77
81
|
*/
|
|
78
82
|
float share = cutoutShare(tested, uCutout.x);
|
|
79
83
|
if (uCutout.y == 1.0) {
|
|
80
|
-
if (!cutoutKeeps(share, gl_FragCoord.xy,
|
|
84
|
+
if (!cutoutKeeps(share, gl_FragCoord.xy, uHighlightMin.w)) discard;
|
|
81
85
|
kept = 1.0;
|
|
82
86
|
} else {
|
|
83
87
|
kept = share;
|
|
@@ -139,6 +143,11 @@ export const MAIN_GLSL = `void main() {
|
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
vec3 lit = albedo;
|
|
146
|
+
/* How much of the environment the frame shows here, and how a found reflection would land:
|
|
147
|
+
reflectionSurface.ts. None where nothing is reflected. */
|
|
148
|
+
vec3 reflectedProbe = vec3(0.0);
|
|
149
|
+
vec3 reflectedTint = vec3(0.0);
|
|
150
|
+
float reflectedRoughness = 1.0;
|
|
142
151
|
/* Skin's diffuse, held before emission for the screen-space blur's own pass: models.ts. */
|
|
143
152
|
vec3 diffuseAlone = vec3(0.0);
|
|
144
153
|
/* The light arriving at a glass pane from behind it, gathered in each light loop below and added
|
|
@@ -186,7 +195,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
186
195
|
* right: a mipped colour image, sampled under uniform control flow, exactly as uAlbedo is
|
|
187
196
|
* below. The rule is about non-uniform branches, and this branch is on a uniform.
|
|
188
197
|
*/
|
|
198
|
+
vec3 unmapped = n;
|
|
189
199
|
if (uNormalStrength > 0.0) n = normalMapped(n, surfaceAt);
|
|
200
|
+
/* A draw's wrinkles, by region, over whatever the map made: overlay.ts. */
|
|
201
|
+
if (SURFACE_OVERLAY) n = overlayWrinkle(n, unmapped, surfaceAt.xy);
|
|
190
202
|
|
|
191
203
|
/*
|
|
192
204
|
* Microscopic relief: the surface's own texture, as a turn of the normal rather than a change
|
|
@@ -915,6 +927,15 @@ export const MAIN_GLSL = `void main() {
|
|
|
915
927
|
environment * mix(vec3(1.0), albedo, metal),
|
|
916
928
|
weight
|
|
917
929
|
);
|
|
930
|
+
reflectedTint = mix(vec3(1.0), albedo, metal) * weight;
|
|
931
|
+
reflectedProbe = environment * reflectedTint;
|
|
932
|
+
reflectedRoughness = surfaceRoughness;
|
|
933
|
+
}
|
|
934
|
+
/* The reflection pass's surface half leaves here, before the lamps: reflectionSurface.ts. */
|
|
935
|
+
if (REFLECTION_SURFACE) {
|
|
936
|
+
reflectionSurfaceOut(reflectedProbe, reflectedTint, reflectedRoughness, ormOcclusion,
|
|
937
|
+
reflectionAir());
|
|
938
|
+
return;
|
|
918
939
|
}
|
|
919
940
|
/*
|
|
920
941
|
* The sun's highlight, on top of whatever the surface reflects rather than underneath it —
|
|
@@ -1259,7 +1280,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1259
1280
|
*/
|
|
1260
1281
|
float falloff;
|
|
1261
1282
|
/*
|
|
1262
|
-
* **A light may name its own falloff, and then it is
|
|
1283
|
+
* **A light may name its own falloff, and then it is the usual one for a light without
|
|
1263
1284
|
* inverse-square falloff**: \`(1 - (d/R)^2)^n\` with no distance term, so a fill authored to
|
|
1264
1285
|
* light a whole hall across a hundred metres does, where the inverse square would have it
|
|
1265
1286
|
* gone a few metres out. Zero is the frame's own rule below, which every light was before.
|
|
@@ -1939,6 +1960,9 @@ export const MAIN_GLSL = `void main() {
|
|
|
1939
1960
|
* mix(1.0, min(lightShade, sunShade), EMISSIVE_SHADOW_SHARE) * fxGlow;
|
|
1940
1961
|
/* And a lit window's glow, which the scene's lit share already times: not gated on night. */
|
|
1941
1962
|
lit += windowGlow * uEmission.x;
|
|
1963
|
+
/* And a draw's overlay: its rim, its dissolve's band and the colour laid over. Not gated on the
|
|
1964
|
+
night, as emission is: a glow the surface wears rather than light it gives off. overlay.ts. */
|
|
1965
|
+
if (SURFACE_OVERLAY) lit += overlayGlow(surfaceAt.xy, n);
|
|
1942
1966
|
|
|
1943
1967
|
#if NIGHT_EMISSIVE
|
|
1944
1968
|
/*
|
|
@@ -1972,7 +1996,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1972
1996
|
// finishing a run reads the same at noon and at midnight. Costs one compare
|
|
1973
1997
|
// per fragment and no extra draw call — the box is a uniform, not geometry.
|
|
1974
1998
|
if (uHighlightMax.w > 0.0) {
|
|
1975
|
-
vec3 inside = step(uHighlightMin, vWorldPos) * step(vWorldPos, uHighlightMax.xyz);
|
|
1999
|
+
vec3 inside = step(uHighlightMin.xyz, vWorldPos) * step(vWorldPos, uHighlightMax.xyz);
|
|
1976
2000
|
lit += albedo * uHighlightMax.w * inside.x * inside.y * inside.z;
|
|
1977
2001
|
}
|
|
1978
2002
|
}
|
|
@@ -2076,7 +2100,17 @@ export const MAIN_GLSL = `void main() {
|
|
|
2076
2100
|
vec3 refractV = normalize(uCameraPos - vWorldPos);
|
|
2077
2101
|
ivec2 snapSize = textureSize(uRefractScene, 0);
|
|
2078
2102
|
vec2 screenUv = gl_FragCoord.xy / vec2(snapSize);
|
|
2079
|
-
|
|
2103
|
+
/*
|
|
2104
|
+
* **The normal's sideways part as the eye sees it**: the shading normal in view space, its x
|
|
2105
|
+
* and y across the screen, y turned to the way this frame's rows run (w of the tint). It was the
|
|
2106
|
+
* normal's world x and y until 4.10.0, which on a quad facing the camera is the quad's own lean
|
|
2107
|
+
* against the world's axes: one offset over the whole quad, a lens, with a normal map's tilt a
|
|
2108
|
+
* small change on top. In view space a quad facing the eye bends by nothing but its map, which
|
|
2109
|
+
* is a shimmer, and a pane bends by how it leans toward the eye wherever the eye stands.
|
|
2110
|
+
*/
|
|
2111
|
+
vec3 seenN = mat3(uView) * refractN;
|
|
2112
|
+
vec2 bend = vec2(seenN.x, seenN.y * uRefractTint.w);
|
|
2113
|
+
vec2 bent = clamp(screenUv + bend * uSeeThrough.x, vec2(0.0), vec2(1.0));
|
|
2080
2114
|
/*
|
|
2081
2115
|
* **An explicit level, and frost is what picks it** — the 2026-08-07 rule, and the reason a
|
|
2082
2116
|
* frosted pane blurs rather than fades: the copy carries a mip chain on a frame that draws glass,
|
|
@@ -2090,7 +2124,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
2090
2124
|
/* Unsigned: a pane passes the same light seen from either side, and so does its Fresnel. */
|
|
2091
2125
|
float cosView = max(abs(dot(refractN, refractV)), 0.05);
|
|
2092
2126
|
float pathLength = uSeeThrough.y * vThickness / cosView;
|
|
2093
|
-
vec3 seen = behind * pow(uRefractTint, vec3(pathLength));
|
|
2127
|
+
vec3 seen = behind * pow(uRefractTint.rgb, vec3(pathLength));
|
|
2094
2128
|
if (glassTransmission > 0.0) {
|
|
2095
2129
|
/*
|
|
2096
2130
|
* **Glass keeps its own surface and shows what is behind over it**, by how much it lets
|
|
@@ -2137,6 +2171,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
2137
2171
|
return;
|
|
2138
2172
|
}
|
|
2139
2173
|
|
|
2174
|
+
/* WebGL2's frame writes the reflection maps itself, with the fog already reckoned above. */
|
|
2175
|
+
if (REFLECTION_MAPS) {
|
|
2176
|
+
reflectionSurfaceOut(reflectedProbe, reflectedTint, reflectedRoughness, ormOcclusion, fog);
|
|
2177
|
+
}
|
|
2140
2178
|
outColor = vec4(shaded, alpha);
|
|
2141
2179
|
}
|
|
2142
2180
|
`;
|
|
@@ -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,16 @@
|
|
|
1
|
+
/**
|
|
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 three places — the dissolve's cut
|
|
4
|
+
* before anything is shaded, the wrinkles after the normal map, and the glow beside emission.
|
|
5
|
+
*
|
|
6
|
+
* **A lit switch, `SURFACE_OVERLAY`**, off until a draw first sets an overlay and then on for good,
|
|
7
|
+
* as `litSwitchesGlsl`'s are; declared after the models so every switch before it keeps its id.
|
|
8
|
+
* Compiled out, the three calls are stubs and the fifteen vectors are not declared at all, which is
|
|
9
|
+
* what lets WebGL2 build a lit program without them on a device that has no room.
|
|
10
|
+
*
|
|
11
|
+
* **Images come from the atlas bound where the frame's refraction copy goes**, which an opaque draw
|
|
12
|
+
* never reads; a draw that refracts or is glass reads that copy there, so its overlay reads no image
|
|
13
|
+
* (`overlayImagesBound`). Each image is read by `textureLod` at level 0: several are reached under a
|
|
14
|
+
* branch on a per-pixel value, and the atlas carries no chain anyway.
|
|
15
|
+
*/
|
|
16
|
+
export declare function overlayGlsl(on: boolean): string;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
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 three places — the dissolve's cut
|
|
4
|
+
* before anything is shaded, the wrinkles after the normal map, and the glow beside emission.
|
|
5
|
+
*
|
|
6
|
+
* **A lit switch, `SURFACE_OVERLAY`**, off until a draw first sets an overlay and then on for good,
|
|
7
|
+
* as `litSwitchesGlsl`'s are; declared after the models so every switch before it keeps its id.
|
|
8
|
+
* Compiled out, the three calls are stubs and the fifteen vectors are not declared at all, which is
|
|
9
|
+
* what lets WebGL2 build a lit program without them on a device that has no room.
|
|
10
|
+
*
|
|
11
|
+
* **Images come from the atlas bound where the frame's refraction copy goes**, which an opaque draw
|
|
12
|
+
* never reads; a draw that refracts or is glass reads that copy there, so its overlay reads no image
|
|
13
|
+
* (`overlayImagesBound`). Each image is read by `textureLod` at level 0: several are reached under a
|
|
14
|
+
* branch on a per-pixel value, and the atlas carries no chain anyway.
|
|
15
|
+
*/
|
|
16
|
+
export function overlayGlsl(on) {
|
|
17
|
+
if (!on) {
|
|
18
|
+
return /* glsl */ `
|
|
19
|
+
const bool SURFACE_OVERLAY = false; // wgsl:override
|
|
20
|
+
bool overlayCuts(vec2 uv) { return false; }
|
|
21
|
+
vec3 overlayWrinkle(vec3 mapped, vec3 unmapped, vec2 uv) { return mapped; }
|
|
22
|
+
vec3 overlayGlow(vec2 uv, vec3 n) { return vec3(0.0); }
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
return /* glsl */ `
|
|
26
|
+
/* Whether this program carries a draw's overlay. Off but where one has been set: overlay.ts. */
|
|
27
|
+
const bool SURFACE_OVERLAY = true; // wgsl:override
|
|
28
|
+
/* The overlay's fifteen vectors; packSurfaceOverlay in surfaceOverlay.ts says what each holds. */
|
|
29
|
+
uniform vec4 uOverlay[15]; // wgsl:material
|
|
30
|
+
|
|
31
|
+
/* Whether the atlas is what the refraction slot holds: not where this draw refracts or is glass. */
|
|
32
|
+
bool overlayImagesBound() {
|
|
33
|
+
return uSeeThrough.x <= 0.0 && uSeeThrough.z <= 0.0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* One image of the atlas at uv, repeated within its region; zero where the region has no size. */
|
|
37
|
+
vec4 overlayImage(vec4 region, vec2 uv) {
|
|
38
|
+
if (region.x <= 0.0) return vec4(0.0);
|
|
39
|
+
return textureLod(uRefractScene, region.zw + fract(uv) * region.xy, 0.0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* The dissolve's noise at uv, and whether the draw dissolves at all: -1 where it does not. */
|
|
43
|
+
float overlayDissolveNoise(vec2 uv) {
|
|
44
|
+
if (uOverlay[6].x <= 0.0 || uOverlay[7].z <= 0.0) return -1.0;
|
|
45
|
+
if (!overlayImagesBound()) return -1.0;
|
|
46
|
+
return overlayImage(uOverlay[6], uv * uOverlay[7].xy).r;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Whether the dissolve cuts this fragment away: where its noise is under the threshold, or all of
|
|
50
|
+
it at a threshold of 1. */
|
|
51
|
+
bool overlayCuts(vec2 uv) {
|
|
52
|
+
float noise = overlayDissolveNoise(uv);
|
|
53
|
+
if (noise < 0.0) return false;
|
|
54
|
+
return noise < uOverlay[7].z || uOverlay[7].z >= 1.0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* The wrinkle normal blended into the mapped one by the two masks' channels times the six weights,
|
|
59
|
+
* in the frame the normal map is read in. **Under uniform control flow up to the frame**, which
|
|
60
|
+
* takes derivatives: every branch before it is on the overlay's numbers alone, and the weight a
|
|
61
|
+
* pixel takes is a mix rather than a branch.
|
|
62
|
+
*/
|
|
63
|
+
vec3 overlayWrinkle(vec3 mapped, vec3 unmapped, vec2 uv) {
|
|
64
|
+
if (uOverlay[10].x <= 0.0 || !overlayImagesBound()) return mapped;
|
|
65
|
+
mat3 tbn = tangentFrame(unmapped, vWorldPos, vUv.xy, vTangent, vHasTangents);
|
|
66
|
+
vec3 a = overlayImage(uOverlay[11], uv).rgb;
|
|
67
|
+
vec3 b = overlayImage(uOverlay[12], uv).rgb;
|
|
68
|
+
float weight = clamp(
|
|
69
|
+
dot(a, uOverlay[13].xyz) + dot(b, vec3(uOverlay[13].w, uOverlay[14].xy)), 0.0, 1.0);
|
|
70
|
+
vec3 wrinkle = overlayImage(uOverlay[10], uv).xyz * 2.0 - 1.0;
|
|
71
|
+
/* z rebuilt where none is stored, as normalMapped does: see normalMap.ts. */
|
|
72
|
+
wrinkle.z = wrinkle.z > 0.0 ? wrinkle.z : sqrt(max(0.0, 1.0 - dot(wrinkle.xy, wrinkle.xy)));
|
|
73
|
+
return normalize(mix(mapped, normalize(tbn * wrinkle), weight));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* The rim's place on the screen, 0 to 1 up its height and its width in the same units: from view
|
|
78
|
+
* space and the projection's tangent, not from gl_FragCoord, whose y runs up on one backend and
|
|
79
|
+
* down on the other (the 2026-08-17 rule), and whose scale is a render target's, not the screen's.
|
|
80
|
+
*/
|
|
81
|
+
vec2 overlayScreen() {
|
|
82
|
+
vec4 eye = uView * vec4(vWorldPos, 1.0);
|
|
83
|
+
float depth = max(-eye.z, 1e-4) * uClusterFrustum.z;
|
|
84
|
+
return vec2(eye.x / depth + uClusterFrustum.w, eye.y / depth + 1.0) * 0.5;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* What the overlay adds to the light the surface gives off: the dissolve's band, the colour laid
|
|
88
|
+
over through its noise, and the rim. Zero where the draw sets none of them. */
|
|
89
|
+
vec3 overlayGlow(vec2 uv, vec3 n) {
|
|
90
|
+
vec3 glow = vec3(0.0);
|
|
91
|
+
float noise = overlayDissolveNoise(uv);
|
|
92
|
+
if (noise >= 0.0) {
|
|
93
|
+
float band = 1.0 - clamp((noise - uOverlay[7].z) / uOverlay[7].w, 0.0, 1.0);
|
|
94
|
+
glow += uOverlay[8].rgb * uOverlay[8].w * band + uOverlay[9].rgb * uOverlay[9].w * noise;
|
|
95
|
+
}
|
|
96
|
+
float strength = uOverlay[0].w;
|
|
97
|
+
if (strength > 0.0) {
|
|
98
|
+
vec3 toEye = normalize(uCameraPos - vWorldPos);
|
|
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;
|
|
113
|
+
}
|
|
114
|
+
return glow;
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
@@ -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.
|
|
@@ -341,9 +341,9 @@ float areaShadow(
|
|
|
341
341
|
${LAMP_GLASS_GLSL}
|
|
342
342
|
#endif
|
|
343
343
|
|
|
344
|
-
out vec4 outColor;
|
|
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.
|
|
@@ -108,9 +108,15 @@ uniform sampler2D uRefractScene;
|
|
|
108
108
|
* gives up, and four separate floats cost half the shadowed lights such a device can have. The tints
|
|
109
109
|
* stay colours of their own. Zero transmission is not glass — see glass.ts.
|
|
110
110
|
*/
|
|
111
|
-
uniform vec4 uSeeThrough;
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
uniform vec4 uSeeThrough; // wgsl:material
|
|
112
|
+
/*
|
|
113
|
+
* What a metre of the medium leaves of each channel (rgb), and in w which way this frame's rows run
|
|
114
|
+
* up the screen: +1 where the first row is the bottom (WebGL2), -1 where it is the top (WebGPU). The
|
|
115
|
+
* bend is taken in view space, whose y is up whatever the framebuffer says, so it is turned here to
|
|
116
|
+
* the rows a screen coordinate counts. A vec4 where a vec3 already spent the row.
|
|
117
|
+
*/
|
|
118
|
+
uniform vec4 uRefractTint; // wgsl:material
|
|
119
|
+
uniform vec3 uGlassTint; // wgsl:material
|
|
114
120
|
flat in int vHasTangents;
|
|
115
121
|
|
|
116
122
|
/**
|
|
@@ -141,7 +147,7 @@ uniform mediump sampler2DArray uAlbedo;
|
|
|
141
147
|
* card. Its draw culls nothing, and a back face is lit as a front, with the shading normal turned
|
|
142
148
|
* toward the viewer.
|
|
143
149
|
*/
|
|
144
|
-
uniform ivec4 uMaterialFlags;
|
|
150
|
+
uniform ivec4 uMaterialFlags; // wgsl:material
|
|
145
151
|
/**
|
|
146
152
|
* Alpha below which a textured fragment is thrown away entirely, 0 to disable.
|
|
147
153
|
*
|
|
@@ -155,13 +161,17 @@ uniform ivec4 uMaterialFlags;
|
|
|
155
161
|
* else changes.
|
|
156
162
|
*
|
|
157
163
|
* **Four numbers in one row**: x is the cutoff, y how this frame resolves the edge (0 the hard test,
|
|
158
|
-
* 1 a dither the temporal resolve averages, 2 alpha-to-coverage; see \`cutoutDither.ts\`), z
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
164
|
+
* 1 a dither the temporal resolve averages, 2 alpha-to-coverage; see \`cutoutDither.ts\`), z unused,
|
|
165
|
+
* w the material's lighting channels — a mask a light shades it only where its own shares a bit
|
|
166
|
+
* with (\`SurfaceMaterial.lightChannels\`, 1 unless a material names others). One vector rather than
|
|
167
|
+
* a float and three more, because every loose scalar is a row of WebGL2's 224 that the light budget
|
|
168
|
+
* gives up.
|
|
169
|
+
*
|
|
170
|
+
* **z was the frame the dither's pattern is offset by until 4.10.0**, and that made every material
|
|
171
|
+
* new every frame: a material is kept on WebGPU by its numbers, and one of them changed with the
|
|
172
|
+
* clock. The frame is the pass's, in \`uHighlightMin.w\`.
|
|
163
173
|
*/
|
|
164
|
-
uniform vec4 uCutout;
|
|
174
|
+
uniform vec4 uCutout; // wgsl:material
|
|
165
175
|
/**
|
|
166
176
|
* A draw's own ambient, as nine spherical-harmonic coefficients of incoming radiance, red green blue
|
|
167
177
|
* in turn, twenty-seven floats, and in the last of the twenty-eight a 1 where they are on — 0 is the
|
|
@@ -169,7 +179,7 @@ uniform vec4 uCutout;
|
|
|
169
179
|
* and the basis, and its tests hold this to it. Seven rows of the material block, which is per draw
|
|
170
180
|
* as far as anything here is: \`setAmbientSH\` moves it between two draws as \`setMaterial\` does.
|
|
171
181
|
*/
|
|
172
|
-
uniform vec4 uAmbientSH[7];
|
|
182
|
+
uniform vec4 uAmbientSH[7]; // wgsl:material
|
|
173
183
|
|
|
174
184
|
/** The ambient a surface facing \`n\` receives from \`uAmbientSH\`: \`ambientFromSH\`'s arithmetic. */
|
|
175
185
|
vec3 ambientHarmonics(vec3 n) {
|
|
@@ -216,7 +226,7 @@ uniform highp sampler2DArray uNormalMap;
|
|
|
216
226
|
* shadow samplers, where a profile with shadows off should declare none of them; it is the wrong
|
|
217
227
|
* tool for one image on a shader that already declares one.
|
|
218
228
|
*/
|
|
219
|
-
uniform float uNormalStrength;
|
|
229
|
+
uniform float uNormalStrength; // wgsl:material
|
|
220
230
|
|
|
221
231
|
/**
|
|
222
232
|
* Occlusion, roughness and metallic in one image. glTF's packing, because that is what an import
|
|
@@ -237,7 +247,7 @@ uniform highp sampler2DArray uOrmMap;
|
|
|
237
247
|
* occlusionTexture.strength is: 1 + strength * (texel - 1). A multiply at 0 means fully occluded,
|
|
238
248
|
* which is the opposite of what a caller asking for no occlusion means.
|
|
239
249
|
*/
|
|
240
|
-
uniform vec3 uOrmScale;
|
|
250
|
+
uniform vec3 uOrmScale; // wgsl:material
|
|
241
251
|
/**
|
|
242
252
|
* 1 when \`uEnvironment\` holds the GGX-prefiltered cube, 0 when it holds the capture's box chain.
|
|
243
253
|
*
|
|
@@ -253,7 +263,7 @@ uniform vec3 uOrmScale;
|
|
|
253
263
|
* (\`uniformVectorBudget.ts\`). y is how much of the environment the material mirrors, z how
|
|
254
264
|
* bright what it mirrors is.
|
|
255
265
|
*/
|
|
256
|
-
uniform vec3 uEnvironmentDials;
|
|
266
|
+
uniform vec3 uEnvironmentDials; // wgsl:material
|
|
257
267
|
|
|
258
268
|
/**
|
|
259
269
|
* Where a surface glows, and in what colour.
|
|
@@ -275,7 +285,7 @@ uniform highp sampler2DArray uEmissiveMap;
|
|
|
275
285
|
* The counterpart of \`uOrmScale\`: a factor that multiplies a texture is not a value, and this is
|
|
276
286
|
* where the multiplier lives once an image supplies the shape.
|
|
277
287
|
*/
|
|
278
|
-
uniform vec3 uEmissiveScale;
|
|
288
|
+
uniform vec3 uEmissiveScale; // wgsl:material
|
|
279
289
|
|
|
280
290
|
#if DIRECTIONAL_SHADOWS
|
|
281
291
|
/*
|
|
@@ -362,7 +372,7 @@ uniform vec4 uSurfaceScene;
|
|
|
362
372
|
* draw moves it), y the night factor emission is gated on. One row where two floats were two
|
|
363
373
|
* (\`uniformVectorBudget.ts\`).
|
|
364
374
|
*/
|
|
365
|
-
uniform vec2 uEmission;
|
|
375
|
+
uniform vec2 uEmission; // wgsl:material
|
|
366
376
|
#if NIGHT_EMISSIVE
|
|
367
377
|
/**
|
|
368
378
|
* Emission that only shows where the dominant light does not reach. 0 is off and is the default.
|
|
@@ -387,7 +397,7 @@ uniform float uNightEmissive;
|
|
|
387
397
|
* of that to change one channel is how a renderer ends up with two shaders that
|
|
388
398
|
* disagree about the sun. The caller owns the blend state; this owns the number.
|
|
389
399
|
*/
|
|
390
|
-
uniform float uOpacity;
|
|
400
|
+
uniform float uOpacity; // wgsl:material
|
|
391
401
|
|
|
392
402
|
/**
|
|
393
403
|
* Two per-draw switches on how a fragment is *written* rather than what colour it is, sharing one
|
|
@@ -419,7 +429,7 @@ uniform float uOpacity;
|
|
|
419
429
|
* crossfade reads as grain for as long as it lasts, which is why it should be short; and a blended
|
|
420
430
|
* draw that asks for it is dithered too, since the test is a discard.
|
|
421
431
|
*/
|
|
422
|
-
uniform vec2 uWriteMode;
|
|
432
|
+
uniform vec2 uWriteMode; // wgsl:material
|
|
423
433
|
|
|
424
434
|
/** Whether this fragment is one \`uWriteMode.y\` keeps. Integer arithmetic, per the device rule. */
|
|
425
435
|
bool ditherKeeps(float amount) {
|
|
@@ -452,7 +462,7 @@ bool ditherKeeps(float amount) {
|
|
|
452
462
|
* one uniform skips the untaken side rather than computing both and discarding one, which is
|
|
453
463
|
* only true because nothing here reads it through a *varying*-dependent branch.
|
|
454
464
|
*/
|
|
455
|
-
uniform int uLightingEnabled;
|
|
465
|
+
uniform int uLightingEnabled; // wgsl:material
|
|
456
466
|
/**
|
|
457
467
|
* How this draw meets the medium: the atmospheric haze and the underwater tint both, folded
|
|
458
468
|
* together because both are the *camera's* medium rather than a property of the surface — see
|
|
@@ -474,7 +484,7 @@ uniform int uLightingEnabled;
|
|
|
474
484
|
* is what "exactly as its colour says" has to mean for it; the cost is that such a draw will
|
|
475
485
|
* not tint if the camera goes under water, unlike everything else in the frame.
|
|
476
486
|
*/
|
|
477
|
-
uniform int uFogEnabled;
|
|
487
|
+
uniform int uFogEnabled; // wgsl:material
|
|
478
488
|
|
|
479
489
|
/**
|
|
480
490
|
* A pass-level scale over the grain the geometry declared, 0 to 1.
|
|
@@ -484,7 +494,7 @@ uniform int uFogEnabled;
|
|
|
484
494
|
* imported model that declares nothing is drawn with the pass's own answer, and a scene
|
|
485
495
|
* can dial a whole draw down without rebuilding its geometry.
|
|
486
496
|
*/
|
|
487
|
-
uniform float uGrain;
|
|
497
|
+
uniform float uGrain; // wgsl:material
|
|
488
498
|
/*
|
|
489
499
|
* The material's own relief: how strong, and how many bumps to a metre.
|
|
490
500
|
*
|
|
@@ -493,7 +503,7 @@ uniform float uGrain;
|
|
|
493
503
|
* between them, and the geometry carrying them is identical in all three cases. See
|
|
494
504
|
* Renderer.setSurfaceRelief. x is the strength and y the bumps to a metre, in one row.
|
|
495
505
|
*/
|
|
496
|
-
uniform vec2 uRelief;
|
|
506
|
+
uniform vec2 uRelief; // wgsl:material
|
|
497
507
|
/**
|
|
498
508
|
* How hard the bound surface texture's own luminance turns the shading normal, 0 for not at all.
|
|
499
509
|
*
|
|
@@ -516,7 +526,7 @@ uniform vec2 uRelief;
|
|
|
516
526
|
* 0..1 like its neighbours for the same reason: this is an amplitude against a luminance
|
|
517
527
|
* gradient, not a fraction of anything.
|
|
518
528
|
*/
|
|
519
|
-
uniform float uTextureRelief;
|
|
529
|
+
uniform float uTextureRelief; // wgsl:material
|
|
520
530
|
|
|
521
531
|
/**
|
|
522
532
|
* How much of the environment this material mirrors, 0 to 1.
|
|
@@ -651,8 +661,12 @@ uniform vec3 uProbeGridSets;
|
|
|
651
661
|
/**
|
|
652
662
|
* A world-space box that lights up regardless of time of day: its corners, and in the far corner's
|
|
653
663
|
* w the gain — one row where a loose float was another (\`uniformVectorBudget.ts\`).
|
|
664
|
+
*
|
|
665
|
+
* **And in the near corner's w the frame the cutout dither's pattern is offset by**, for the same
|
|
666
|
+
* reason: a row the lit stage already pays for, holding a number the pass sets and no material does.
|
|
667
|
+
* See \`uCutout\`.
|
|
654
668
|
*/
|
|
655
|
-
uniform
|
|
669
|
+
uniform vec4 uHighlightMin;
|
|
656
670
|
uniform vec4 uHighlightMax;
|
|
657
671
|
|
|
658
672
|
/*
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the lit stage leaves for a reflection traced in the frame: how much of the environment each
|
|
3
|
+
* pixel shows, and how a reflection found in the frame would land there instead. Read by the
|
|
4
|
+
* reflection pass (`screenSpaceReflection.ts`), which swaps the one for the other where its ray
|
|
5
|
+
* finds something.
|
|
6
|
+
*
|
|
7
|
+
* **The swap is exact because the lit stage's own blend is a mix**: `lit = mix(lit, environment ·
|
|
8
|
+
* tint, weight)` leaves `environment · tint · weight` of the probe in the frame, and a reflection
|
|
9
|
+
* found in the frame belongs there with the same tint and the same weight. So the frame gains
|
|
10
|
+
* `(found · tint − environment · tint) · weight` and nothing else moves: the diffuse the blend
|
|
11
|
+
* already took its share from keeps it. Both are carried the rest of the way the shaded colour
|
|
12
|
+
* goes — the occlusion, the water and the medium in front of the surface — so the swap lands in the
|
|
13
|
+
* frame's own units.
|
|
14
|
+
*
|
|
15
|
+
* **Two outputs beside the colour, written by every lit draw and kept only where a target is
|
|
16
|
+
* bound.** WebGL2 binds them during opaque lit draws alone; WebGPU's frame pass binds none, and a
|
|
17
|
+
* second pass replays the frame's opaque draws into them with `REFLECTION_SURFACE` on, which leaves
|
|
18
|
+
* before the lamps (`main`). What it gives up is a vector of arithmetic on every lit pixel whether
|
|
19
|
+
* or not anything reads it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function reflectionSurfaceGlsl(maps: boolean): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the lit stage leaves for a reflection traced in the frame: how much of the environment each
|
|
3
|
+
* pixel shows, and how a reflection found in the frame would land there instead. Read by the
|
|
4
|
+
* reflection pass (`screenSpaceReflection.ts`), which swaps the one for the other where its ray
|
|
5
|
+
* finds something.
|
|
6
|
+
*
|
|
7
|
+
* **The swap is exact because the lit stage's own blend is a mix**: `lit = mix(lit, environment ·
|
|
8
|
+
* tint, weight)` leaves `environment · tint · weight` of the probe in the frame, and a reflection
|
|
9
|
+
* found in the frame belongs there with the same tint and the same weight. So the frame gains
|
|
10
|
+
* `(found · tint − environment · tint) · weight` and nothing else moves: the diffuse the blend
|
|
11
|
+
* already took its share from keeps it. Both are carried the rest of the way the shaded colour
|
|
12
|
+
* goes — the occlusion, the water and the medium in front of the surface — so the swap lands in the
|
|
13
|
+
* frame's own units.
|
|
14
|
+
*
|
|
15
|
+
* **Two outputs beside the colour, written by every lit draw and kept only where a target is
|
|
16
|
+
* bound.** WebGL2 binds them during opaque lit draws alone; WebGPU's frame pass binds none, and a
|
|
17
|
+
* second pass replays the frame's opaque draws into them with `REFLECTION_SURFACE` on, which leaves
|
|
18
|
+
* before the lamps (`main`). What it gives up is a vector of arithmetic on every lit pixel whether
|
|
19
|
+
* or not anything reads it.
|
|
20
|
+
*/
|
|
21
|
+
export function reflectionSurfaceGlsl(maps) {
|
|
22
|
+
return /* glsl */ `
|
|
23
|
+
/*
|
|
24
|
+
* Whether this pipeline is the reflection pass's surface half: the frame's opaque draws again,
|
|
25
|
+
* against the depth they wrote, leaving the two outputs below and no light. Off in every other
|
|
26
|
+
* pipeline, and set from the key as skin's halves are. See reflectionSurface.ts.
|
|
27
|
+
*/
|
|
28
|
+
const bool REFLECTION_SURFACE = false; // wgsl:override
|
|
29
|
+
/*
|
|
30
|
+
* Whether the frame's own draws write the two outputs as well: WebGL2's arrangement, on where the
|
|
31
|
+
* frame's materials' reflections are, and off in every WebGPU pipeline, which replays the draws
|
|
32
|
+
* instead. A lit switch, so a program that does not write them carries nothing live across the
|
|
33
|
+
* lamps for them.
|
|
34
|
+
*/
|
|
35
|
+
const bool REFLECTION_MAPS = ${maps ? 'true' : 'false'}; // wgsl:override
|
|
36
|
+
/* The environment as the frame shows it, and the surface's roughness in w. */
|
|
37
|
+
layout(location = 1) out vec4 outReflectedProbe;
|
|
38
|
+
/* What a reflection found in the frame is multiplied by to land where the environment did. */
|
|
39
|
+
layout(location = 2) out vec4 outReflectedTint;
|
|
40
|
+
|
|
41
|
+
/* How much of the surface the medium in front of it leaves: the fog block below's own measure. */
|
|
42
|
+
float reflectionAir() {
|
|
43
|
+
return uFogEnabled != 0 ? mediumFog(distance(vWorldPos, uCameraPos), vWorldPos.y) : 0.0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* The two outputs, carried through what the shaded colour meets after the blend: its occlusion,
|
|
48
|
+
* the water, and the air, as \`main\` applies them. \`air\` is the fog the caller has already
|
|
49
|
+
* reckoned, so the frame's own draws pay for it once.
|
|
50
|
+
*/
|
|
51
|
+
void reflectionSurfaceOut(vec3 probe, vec3 tint, float roughness, float occlusion, float air) {
|
|
52
|
+
vec3 keep = vec3(occlusion * (1.0 - air));
|
|
53
|
+
if (uFogEnabled != 0) {
|
|
54
|
+
vec3 waterTransmission = vec3(0.42) + uUnderwaterColor * 2.0;
|
|
55
|
+
keep *= mix(vec3(1.0), waterTransmission, uUnderwaterFactor * 0.55);
|
|
56
|
+
}
|
|
57
|
+
outReflectedProbe = vec4(probe * keep, roughness);
|
|
58
|
+
outReflectedTint = vec4(tint * keep, 1.0);
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
@@ -34,4 +34,4 @@
|
|
|
34
34
|
* never needed the camera position in their fragment stage, and a block that declares
|
|
35
35
|
* everything it uses can be pasted anywhere.
|
|
36
36
|
*/
|
|
37
|
-
export declare const FOG_GLSL = "\nuniform vec3 uFogColor;\n/** Extinction per metre **at the camera's own height**, not at the base. */\nuniform float uFogDensity;\n/** Reciprocal scale height of the haze, per metre. 0 is a uniform medium. */\nuniform float uFogHeightFalloff;\n/** The camera's height, so a fragment's own height is one subtraction away. */\nuniform float uFogEyeY;\nuniform vec3 uUnderwaterColor;\nuniform float uUnderwaterFogDensity;\nuniform float uUnderwaterFactor;\n/** 0 integrates a medium (Beer-Lambert); 1 ramps linearly between near and far. */\nuniform int uFogMode;\n/** Linear mode only: where haze begins, and where it is total. */\nuniform float uFogNear;\nuniform float uFogFar;\n\n/** What distance converges toward: the day's haze, or the water column. */\nvec3 mediumColor() {\n return mix(uFogColor, uUnderwaterColor, uUnderwaterFactor);\n}\n\n/**\n * How much of a surface standing at height pointY, dist metres away, is lost to\n * the medium in between. 0 is perfectly clear, 1 is the medium's own colour.\n */\nfloat mediumFog(float dist, float pointY) {\n /*\n * A depth ramp rather than a medium, for worlds authored against one.\n *\n * Beer-Lambert is the honest model and stays the default: it integrates something\n * physically there, so extinction begins at the eye and never stops. A linear near/far\n * fog is not that \u2014 it is a *look*, with a hard start distance before which the air is\n * perfectly clear, and it is what the fixed-function pipeline offered and what several\n * renderers still expose. Approximating one with the other is not a matter of tuning:\n * matched at half occlusion, the exponential curve still lays haze over everything\n * inside near, where the ramp lays none, and near-field colour desaturates toward the\n * fog colour with nothing to show for it.\n *\n * Height falloff has no meaning here and is ignored: a ramp is defined on distance\n * alone.\n */\n if (uFogMode == 1) {\n float span = max(uFogFar - uFogNear, 1e-4);\n float ramp = clamp((dist - uFogNear) / span, 0.0, 1.0);\n if (uUnderwaterFactor <= 0.0) return ramp;\n float wetLinear = uUnderwaterFogDensity * dist;\n return mix(ramp, 1.0 - exp2(-wetLinear * wetLinear * 1.442695), uUnderwaterFactor);\n }\n\n float t = (pointY - uFogEyeY) * uFogHeightFalloff;\n // (1 - e^-t)/t, which tends to 1 as the ray levels out. Guarded rather than\n // branched: at t = 0 the quotient is 0/0, and 1e-4 of a scale height is 8 mm.\n float denom = abs(
|
|
37
|
+
export declare const FOG_GLSL = "\nuniform vec3 uFogColor;\n/** Extinction per metre **at the camera's own height**, not at the base. */\nuniform float uFogDensity;\n/** Reciprocal scale height of the haze, per metre. 0 is a uniform medium. */\nuniform float uFogHeightFalloff;\n/** The camera's height, so a fragment's own height is one subtraction away. */\nuniform float uFogEyeY;\nuniform vec3 uUnderwaterColor;\nuniform float uUnderwaterFogDensity;\nuniform float uUnderwaterFactor;\n/** 0 integrates a medium (Beer-Lambert); 1 ramps linearly between near and far. */\nuniform int uFogMode;\n/** Linear mode only: where haze begins, and where it is total. */\nuniform float uFogNear;\nuniform float uFogFar;\n\n/** What distance converges toward: the day's haze, or the water column. */\nvec3 mediumColor() {\n return mix(uFogColor, uUnderwaterColor, uUnderwaterFactor);\n}\n\n/**\n * How much of a surface standing at height pointY, dist metres away, is lost to\n * the medium in between. 0 is perfectly clear, 1 is the medium's own colour.\n */\nfloat mediumFog(float dist, float pointY) {\n /*\n * A depth ramp rather than a medium, for worlds authored against one.\n *\n * Beer-Lambert is the honest model and stays the default: it integrates something\n * physically there, so extinction begins at the eye and never stops. A linear near/far\n * fog is not that \u2014 it is a *look*, with a hard start distance before which the air is\n * perfectly clear, and it is what the fixed-function pipeline offered and what several\n * renderers still expose. Approximating one with the other is not a matter of tuning:\n * matched at half occlusion, the exponential curve still lays haze over everything\n * inside near, where the ramp lays none, and near-field colour desaturates toward the\n * fog colour with nothing to show for it.\n *\n * Height falloff has no meaning here and is ignored: a ramp is defined on distance\n * alone.\n */\n if (uFogMode == 1) {\n float span = max(uFogFar - uFogNear, 1e-4);\n float ramp = clamp((dist - uFogNear) / span, 0.0, 1.0);\n if (uUnderwaterFactor <= 0.0) return ramp;\n float wetLinear = uUnderwaterFogDensity * dist;\n return mix(ramp, 1.0 - exp2(-wetLinear * wetLinear * 1.442695), uUnderwaterFactor);\n }\n\n // Where the medium begins along the ray: uFogNear, the linear mode's slot, which this mode\n // never read before Atmosphere.fogStart. The ray is integrated from there on, at the density\n // of that point; at a start of 0 every term is the one it always was. See render/fog.ts.\n float start = min(uFogNear, dist);\n float before = dist > 0.0 ? start / dist : 0.0;\n float t = (pointY - uFogEyeY) * uFogHeightFalloff;\n float rest = t * (1.0 - before);\n // (1 - e^-t)/t, which tends to 1 as the ray levels out. Guarded rather than\n // branched: at t = 0 the quotient is 0/0, and 1e-4 of a scale height is 8 mm.\n float denom = abs(rest) < 1e-4 ? 1e-4 : rest;\n float air =\n 1.0 - exp(-uFogDensity * exp(-t * before) * (dist - start) * (1.0 - exp(-denom)) / denom);\n if (uUnderwaterFactor <= 0.0) return air;\n // Water is its own medium and keeps its own curve, so crossing the surface\n // changes nothing about how the water column reads.\n float wet = uUnderwaterFogDensity * dist;\n return mix(air, 1.0 - exp2(-wet * wet * 1.442695), uUnderwaterFactor);\n}\n";
|
|
@@ -84,11 +84,18 @@ float mediumFog(float dist, float pointY) {
|
|
|
84
84
|
return mix(ramp, 1.0 - exp2(-wetLinear * wetLinear * 1.442695), uUnderwaterFactor);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// Where the medium begins along the ray: uFogNear, the linear mode's slot, which this mode
|
|
88
|
+
// never read before Atmosphere.fogStart. The ray is integrated from there on, at the density
|
|
89
|
+
// of that point; at a start of 0 every term is the one it always was. See render/fog.ts.
|
|
90
|
+
float start = min(uFogNear, dist);
|
|
91
|
+
float before = dist > 0.0 ? start / dist : 0.0;
|
|
87
92
|
float t = (pointY - uFogEyeY) * uFogHeightFalloff;
|
|
93
|
+
float rest = t * (1.0 - before);
|
|
88
94
|
// (1 - e^-t)/t, which tends to 1 as the ray levels out. Guarded rather than
|
|
89
95
|
// branched: at t = 0 the quotient is 0/0, and 1e-4 of a scale height is 8 mm.
|
|
90
|
-
float denom = abs(
|
|
91
|
-
float air =
|
|
96
|
+
float denom = abs(rest) < 1e-4 ? 1e-4 : rest;
|
|
97
|
+
float air =
|
|
98
|
+
1.0 - exp(-uFogDensity * exp(-t * before) * (dist - start) * (1.0 - exp(-denom)) / denom);
|
|
92
99
|
if (uUnderwaterFactor <= 0.0) return air;
|
|
93
100
|
// Water is its own medium and keeps its own curve, so crossing the surface
|
|
94
101
|
// changes nothing about how the water column reads.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chromatic aberration: a lens bending each colour by its own amount, so red and green land a
|
|
3
|
+
* little nearer the centre than blue toward the frame's edges.
|
|
4
|
+
*
|
|
5
|
+
* **Linear in wavelength, from an offset outward.** A simple lens's dispersion is close to linear
|
|
6
|
+
* in wavelength over the visible range, so red (611 nm) and green (549 nm) are pulled toward the
|
|
7
|
+
* centre by their distance from blue (464 nm), which is drawn where it is. Nothing moves inside
|
|
8
|
+
* `start` — a share of the half-frame, 0 at the centre — and the pull grows linearly past it,
|
|
9
|
+
* scaled so that the frame's edge takes the whole of `intensity`, which is a percentage.
|
|
10
|
+
*
|
|
11
|
+
* **What it gives up**: it re-reads the scene at the composite's first sample, so the camera's
|
|
12
|
+
* motion blur and the depth of field, which re-read the scene themselves, carry less of the fringe
|
|
13
|
+
* where they are strong. A pass of its own after both would carry it whole, at a full-frame read
|
|
14
|
+
* and write a frame. **What would make that wrong** is a game that blurs heavily and fringes
|
|
15
|
+
* heavily at once, where the colour edges would be seen to soften with the blur.
|
|
16
|
+
*/
|
|
17
|
+
/** How many floats `resolveFringe` fills: the red pull, the green pull, and where they begin. */
|
|
18
|
+
export declare const FRINGE_FLOATS = 3;
|
|
19
|
+
/**
|
|
20
|
+
* The fringe's three numbers, into `out`: how far red and green are pulled toward the centre at
|
|
21
|
+
* the frame's edge, as a share of the half-frame, and the start offset. `intensity` 0 or below is
|
|
22
|
+
* none; a start of 1 or more is none too, since nothing then lies past it. Not finite is none.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveFringe(intensity: number, start: number, out: Float32Array): void;
|
|
25
|
+
/**
|
|
26
|
+
* `withFringe(scene)`: the scene's colour with red and green read again where the lens put them.
|
|
27
|
+
* Reads `uScene` and `vUv`, which the including stage declares, and `uFringe`, which this declares.
|
|
28
|
+
*/
|
|
29
|
+
export declare const FRINGE_GLSL = "\n/** Red's and green's pull at the frame's edge, and where it begins: see shaders/fringe.ts. */\nuniform vec3 uFringe;\n\nvec3 withFringe(vec3 scene) {\n if (uFringe.x <= 0.0) return scene;\n vec2 lens = vUv * 2.0 - 1.0;\n vec2 past = sign(lens) * clamp(abs(lens) - uFringe.z, 0.0, 1.0);\n vec2 red = (lens - past * uFringe.x) * 0.5 + 0.5;\n vec2 green = (lens - past * uFringe.y) * 0.5 + 0.5;\n return vec3(textureLod(uScene, red, 0.0).r, textureLod(uScene, green, 0.0).g, scene.b);\n}\n";
|