From 3d6a465570c51586219f5e2a186f8717183508bb Mon Sep 17 00:00:00 2001 From: maj00r Date: Wed, 14 Oct 2026 14:23:52 +0200 Subject: [PATCH] fix(shaders): parallax mapping of the opengl33 materials is shared by the four parallax shaders in parallax.glsl and samples its depth with the gradients of the surface instead of letting a loop of varying length pick the mip level, picks the number of layers by the angle of view alone and refines the hit with a binary search instead of one linear step, so stones near the camera no longer show combs of layer slices; it fades out between 60 and 100 m instead of stopping at a hard line and fades out at grazing angles, and the simple offset without extra effects no longer divides by an unbounded cosine of the view --- shaders/mat_detail_parallax.frag | 49 +-------------------- shaders/mat_detail_parallax_specgloss.frag | 50 +--------------------- shaders/mat_parallax.frag | 49 +-------------------- shaders/mat_parallax_specgloss.frag | 49 +-------------------- shaders/parallax.glsl | 45 +++++++++++++++++++ 5 files changed, 53 insertions(+), 189 deletions(-) create mode 100644 shaders/parallax.glsl diff --git a/shaders/mat_detail_parallax.frag b/shaders/mat_detail_parallax.frag index 75919b13..8547a11d 100644 --- a/shaders/mat_detail_parallax.frag +++ b/shaders/mat_detail_parallax.frag @@ -38,13 +38,13 @@ uniform sampler2D detailnormalmap; #include #include -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir); +#include void main() { //parallax mapping vec3 viewDir = normalize(-TangentFragPos); //tangent view pos - tangent frag pos - vec2 f_coord_p = ParallaxMapping(f_coord, viewDir); + vec2 f_coord_p = ParallaxMapping(f_coord, viewDir, param[2].z, param[2].w); vec4 normal_map = texture(normalmap, f_coord_p); vec4 detailnormal_map = texture(detailnormalmap, f_coord_p * param[2].x); vec4 tex_color = texture(diffuse, f_coord_p); @@ -87,48 +87,3 @@ void main() } #endif } - -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir) -{ - float pos_len = length(f_pos.xyz); - - if (pos_len > 100.0) { - return f_coord; - } - -#if EXTRAEFFECTS_ENABLED - const float minLayers = 8.0; - const float maxLayers = 32.0; - float LayersWeight = pos_len / 20.0; - vec2 currentTexCoords = f_coord; - float currentDepthMapValue = texture(normalmap, currentTexCoords).b; - LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight); - float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers - float layerDepth = 1.0 / numLayers; // calculate the size of each layer - float currentLayerDepth = 0.0; // depth of current layer - vec2 P = viewDir.xy * param[2].z; // the amount to shift the texture coordinates per layer (from vector P) - vec2 deltaTexCoords = P / numLayers; - - - while(currentLayerDepth < currentDepthMapValue) - { - currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P - currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates - currentLayerDepth += layerDepth; // get depth of next layer - } - - vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations) - - float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation - float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth; - - float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates - vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight); - - return finalTexCoords; -#else - float height = texture(normalmap, f_coord).b; - vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2); - return f_coord - p; -#endif -} diff --git a/shaders/mat_detail_parallax_specgloss.frag b/shaders/mat_detail_parallax_specgloss.frag index fcc33ac3..94d27fc8 100644 --- a/shaders/mat_detail_parallax_specgloss.frag +++ b/shaders/mat_detail_parallax_specgloss.frag @@ -42,13 +42,13 @@ uniform sampler2D detailnormalmap; #include #include -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir); +#include void main() { //parallax mapping vec3 viewDir = normalize(vec3(0.0f, 0.0f, 0.0f) - TangentFragPos); //tangent view pos - tangent frag pos - vec2 f_coord_p = ParallaxMapping(f_coord, viewDir); + vec2 f_coord_p = ParallaxMapping(f_coord, viewDir, param[2].z, param[2].w); vec4 normal_map = texture(normalmap, f_coord_p); vec4 detailnormal_map = texture(detailnormalmap, f_coord_p * param[2].x); @@ -93,49 +93,3 @@ void main() } #endif } - -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir) -{ - - float pos_len = length(f_pos.xyz); - - if (pos_len > 100.0) { - return f_coord; - } - -#if EXTRAEFFECTS_ENABLED - const float minLayers = 8.0; - const float maxLayers = 32.0; - float LayersWeight = pos_len / 20.0; - vec2 currentTexCoords = f_coord; - float currentDepthMapValue = texture(normalmap, currentTexCoords).b; - LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight); - float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers - float layerDepth = 1.0 / numLayers; // calculate the size of each layer - float currentLayerDepth = 0.0; // depth of current layer - vec2 P = viewDir.xy * param[2].z; // the amount to shift the texture coordinates per layer (from vector P) - vec2 deltaTexCoords = P / numLayers; - - - while(currentLayerDepth < currentDepthMapValue) - { - currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P - currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates - currentLayerDepth += layerDepth; // get depth of next layer - } - - vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations) - - float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation - float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth; - - float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates - vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight); - - return finalTexCoords; -#else - float height = texture(normalmap, f_coord).b; - vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2); - return f_coord - p; -#endif -} diff --git a/shaders/mat_parallax.frag b/shaders/mat_parallax.frag index 7adac054..7cccf012 100644 --- a/shaders/mat_parallax.frag +++ b/shaders/mat_parallax.frag @@ -32,13 +32,13 @@ uniform sampler2D normalmap; #include #include -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir); +#include void main() { //parallax mapping vec3 viewDir = normalize(vec3(0.0f, 0.0f, 0.0f) - TangentFragPos); //tangent view pos - tangent frag pos - vec2 f_coord_p = ParallaxMapping(f_coord, viewDir); + vec2 f_coord_p = ParallaxMapping(f_coord, viewDir, param[2].y, param[2].z); vec4 tex_color = texture(diffuse, f_coord_p); @@ -74,48 +74,3 @@ void main() } #endif } - -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir) -{ - float pos_len = length(f_pos.xyz); - - if (pos_len > 100.0) { - return f_coord; - } - -#if EXTRAEFFECTS_ENABLED - const float minLayers = 8.0; - const float maxLayers = 32.0; - float LayersWeight = pos_len / 20.0; - vec2 currentTexCoords = f_coord; - float currentDepthMapValue = texture(normalmap, currentTexCoords).b; - LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight); - float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers - float layerDepth = 1.0 / numLayers; // calculate the size of each layer - float currentLayerDepth = 0.0; // depth of current layer - vec2 P = viewDir.xy * param[2].y; // the amount to shift the texture coordinates per layer (from vector P) - vec2 deltaTexCoords = P / numLayers; - - - while(currentLayerDepth < currentDepthMapValue) - { - currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P - currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates - currentLayerDepth += layerDepth; // get depth of next layer - } - - vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations) - - float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation - float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth; - - float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates - vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight); - - return finalTexCoords; -#else - float height = texture(normalmap, f_coord).b; - vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2); - return f_coord - p; -#endif -} diff --git a/shaders/mat_parallax_specgloss.frag b/shaders/mat_parallax_specgloss.frag index 8b590fae..40075084 100644 --- a/shaders/mat_parallax_specgloss.frag +++ b/shaders/mat_parallax_specgloss.frag @@ -36,13 +36,13 @@ uniform sampler2D specgloss; #include #include -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir); +#include void main() { //parallax mapping vec3 viewDir = normalize(vec3(0.0f, 0.0f, 0.0f) - TangentFragPos); //tangent view pos - tangent frag pos - vec2 f_coord_p = ParallaxMapping(f_coord, viewDir); + vec2 f_coord_p = ParallaxMapping(f_coord, viewDir, param[2].y, param[2].z); vec4 tex_color = texture(diffuse, f_coord_p); @@ -80,48 +80,3 @@ void main() } #endif } - -vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir) -{ - float pos_len = length(f_pos.xyz); - - if (pos_len > 100.0) { - return f_coord; - } - -#if EXTRAEFFECTS_ENABLED - const float minLayers = 8.0; - const float maxLayers = 32.0; - float LayersWeight = pos_len / 20.0; - vec2 currentTexCoords = f_coord; - float currentDepthMapValue = texture(normalmap, currentTexCoords).b; - LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight); - float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers - float layerDepth = 1.0 / numLayers; // calculate the size of each layer - float currentLayerDepth = 0.0; // depth of current layer - vec2 P = viewDir.xy * param[2].y; // the amount to shift the texture coordinates per layer (from vector P) - vec2 deltaTexCoords = P / numLayers; - - - while(currentLayerDepth < currentDepthMapValue) - { - currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P - currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates - currentLayerDepth += layerDepth; // get depth of next layer - } - - vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations) - - float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation - float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth; - - float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates - vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight); - - return finalTexCoords; -#else - float height = texture(normalmap, f_coord).b; - vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2); - return f_coord - p; -#endif -} diff --git a/shaders/parallax.glsl b/shaders/parallax.glsl new file mode 100644 index 00000000..b5107e81 --- /dev/null +++ b/shaders/parallax.glsl @@ -0,0 +1,45 @@ +vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir, float scale, float offset) +{ + vec2 dx = dFdx(f_coord); + vec2 dy = dFdy(f_coord); + 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; + } + +#if EXTRAEFFECTS_ENABLED + const float minLayers = 8.0; + const float maxLayers = 32.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) + { + currentTexCoords -= deltaTexCoords; + currentLayerDepth += layerDepth; + currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dx, dy).b; + } + for (int i = 0; i < 5; ++i) + { + deltaTexCoords *= 0.5; + layerDepth *= 0.5; + if (currentLayerDepth < currentDepthMapValue) { + currentTexCoords -= deltaTexCoords; + currentLayerDepth += layerDepth; + } + else { + currentTexCoords += deltaTexCoords; + currentLayerDepth -= layerDepth; + } + currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dx, dy).b; + } + return currentTexCoords; +#else + float height = textureGrad(normalmap, f_coord, dx, dy).b; + vec2 p = viewDir.xy / max(viewDir.z, 0.2) * (height * (scale - offset) * 0.2 * fade); + return f_coord - p; +#endif +}