17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 02:49:19 +02:00

fix(shaders): parallax mapping reads its depth from a mip about four texels per pixel coarser, filtered bicubically where the hit is refined, so the relief no longer breaks into stalactites and the edges of stones no longer step along the texel grid of the compressed depth; it takes 16 to 64 layers by the angle of view and six steps of refinement, casts the shadows of the relief from the sun over the sun light and darkens the hollows deeper than the mean depth of the texture while lightening the tops, so the mean brightness of a surface stays the same

This commit is contained in:
maj00r
2026-10-14 15:02:14 +02:00
parent 3d6a465570
commit 20cf81b362
2 changed files with 67 additions and 10 deletions

View File

@@ -36,6 +36,11 @@ float length2(vec3 v)
return dot(v, v);
}
#ifdef PARALLAX
float parallax_occlusion = 0.0;
float parallax_shadow = 0.0;
#endif
float calc_shadow()
{
#if SHADOWMAP_ENABLED
@@ -289,6 +294,9 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
// Sun, headlights and emission are added afterwards so they are NOT
// attenuated by AMBIENT_SCALE - this only dims the indirect term.
fragcolor *= AMBIENT_SCALE;
#ifdef PARALLAX
fragcolor *= 1.0 - parallax_occlusion;
#endif
vec3 emissioncolor = vec3(emission);
@@ -331,6 +339,9 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
float shadow1 = 0.0;
if (shadowtone < 1.0)
shadow1 = (1.0 - shadowtone) * clamp(calc_shadow(), 0.0, 1.0);
#ifdef PARALLAX
shadow1 = max(shadow1, parallax_shadow);
#endif
// Sun HDR scale -> SUN_DIFFUSE_SCALE (default 2.5). Controls how
// bright sun-lit (unshaded) faces get. Lower this if surfaces in

View File

@@ -1,28 +1,71 @@
float ParallaxDepth(vec2 f_coord, float lod)
{
vec2 size = vec2(textureSize(normalmap, int(lod)));
vec2 st = f_coord * size - 0.5;
vec2 cell = floor(st);
vec2 f = st - cell;
vec2 w0 = (1.0 - f) * (1.0 - f) * (1.0 - f) / 6.0;
vec2 w1 = (4.0 - 6.0 * f * f + 3.0 * f * f * f) / 6.0;
vec2 w3 = f * f * f / 6.0;
vec2 w2 = 1.0 - w0 - w1 - w3;
vec2 g0 = w0 + w1;
vec2 g1 = w2 + w3;
vec2 h0 = (cell - 0.5 + w1 / g0) / size;
vec2 h1 = (cell + 1.5 + w3 / g1) / size;
return g0.y * (g0.x * textureLod(normalmap, h0, lod).b + g1.x * textureLod(normalmap, vec2(h1.x, h0.y), lod).b)
+ g1.y * (g0.x * textureLod(normalmap, vec2(h0.x, h1.y), lod).b + g1.x * textureLod(normalmap, h1, lod).b);
}
float ParallaxShadow(vec2 f_coord, float depth, float lod, float scale)
{
if (lights_count == 0U || depth <= 0.0) {
return 0.0;
}
vec3 lightDir = normalize(transpose(f_tbn) * normalize(-lights[0].dir));
if (lightDir.z <= 0.0) {
return 0.0;
}
const int steps = 12;
float layerDepth = depth / float(steps);
vec2 deltaTexCoords = lightDir.xy / max(lightDir.z, 0.25) * scale * layerDepth;
float shadow = 0.0;
for (int i = 1; i <= steps; ++i)
{
float rayDepth = depth - layerDepth * float(i);
float surface = ParallaxDepth(f_coord + deltaTexCoords * float(i), lod);
shadow = max(shadow, (rayDepth - surface) * 12.0 * (1.0 - float(i) / float(steps + 1)));
}
return clamp(shadow, 0.0, 1.0);
}
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir, float scale, float offset)
{
vec2 dx = dFdx(f_coord);
vec2 dy = dFdy(f_coord);
vec2 size = vec2(textureSize(normalmap, 0));
float footprint = max(length(dFdx(f_coord) * size), length(dFdy(f_coord) * size));
float lod = clamp(log2(max(footprint, 1e-4)) + 2.0, 0.0, log2(max(size.x, size.y)));
float fade = (1.0 - smoothstep(60.0, 100.0, length(f_pos.xyz))) * smoothstep(0.0, 0.1, viewDir.z);
if (fade <= 0.0) {
return f_coord;
}
float meanDepth = textureLod(normalmap, f_coord, log2(max(size.x, size.y))).b;
#if EXTRAEFFECTS_ENABLED
const float minLayers = 8.0;
const float maxLayers = 32.0;
const float minLayers = 16.0;
const float maxLayers = 64.0;
float numLayers = mix(maxLayers, minLayers, clamp(viewDir.z, 0.0, 1.0));
float layerDepth = 1.0 / numLayers;
vec2 deltaTexCoords = viewDir.xy * scale * fade / numLayers;
vec2 currentTexCoords = f_coord;
float currentLayerDepth = 0.0;
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dx, dy).b;
for (int i = 0; i < 40 && currentLayerDepth < currentDepthMapValue; ++i)
float currentDepthMapValue = textureLod(normalmap, currentTexCoords, lod).b;
for (int i = 0; i < 100 && currentLayerDepth < currentDepthMapValue; ++i)
{
currentTexCoords -= deltaTexCoords;
currentLayerDepth += layerDepth;
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dx, dy).b;
currentDepthMapValue = textureLod(normalmap, currentTexCoords, lod).b;
}
for (int i = 0; i < 5; ++i)
currentDepthMapValue = ParallaxDepth(currentTexCoords, lod);
for (int i = 0; i < 6; ++i)
{
deltaTexCoords *= 0.5;
layerDepth *= 0.5;
@@ -34,11 +77,14 @@ vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir, float scale, float offset)
currentTexCoords += deltaTexCoords;
currentLayerDepth -= layerDepth;
}
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dx, dy).b;
currentDepthMapValue = ParallaxDepth(currentTexCoords, lod);
}
parallax_occlusion = clamp(0.8 * (currentLayerDepth - meanDepth), -0.3, 0.6) * fade;
parallax_shadow = ParallaxShadow(currentTexCoords, currentLayerDepth, lod, scale * fade) * fade;
return currentTexCoords;
#else
float height = textureGrad(normalmap, f_coord, dx, dy).b;
float height = ParallaxDepth(f_coord, lod);
parallax_occlusion = clamp(0.8 * (height - meanDepth), -0.3, 0.6) * fade;
vec2 p = viewDir.xy / max(viewDir.z, 0.2) * (height * (scale - offset) * 0.2 * fade);
return f_coord - p;
#endif