Good enough parallax POM – Light tones go down – Version 2

The cheap algorithm makes it run at the minimum or zero speed when closer to the horizon, and at the maximum speed when looking down.
Light tones are ideal for patching mechanisms on walls.
If you use the option that lowers light tones, you’d first have to do the “linear invert”.
Limiting from the “Levels” in GIMP gives me more room to maneuver in the shader.
The height map has several fetch. Using a single shader for the BC4 heightmap and at a lower resolution means it uses less bandwidth.
Delete the light lines and hard shadows if they are not used, and enable the normal map by default.

Test Godot 4.5.

Shader code
shader_type spatial;//Walt_GD
render_mode cull_back, diffuse_burley;

// --- Separate textures ---
uniform sampler2D texture_RGB : source_color, repeat_enable; //2k texture compressed in Comprenator AMD: KTX2 BC7 Quality 0.49 or Gimp DDS BC1
uniform sampler2D texture_Normal : hint_normal, repeat_enable;//2k texture compressed in Comprenator AMD: KTX2 BC5  Quality 0.49 or Gimp DDS BC5
uniform sampler2D texture_height_r  : hint_default_black, repeat_enable; // 512 texture compressed in Comprenator AMD: KTX2 BC4  Quality 0.49 or Gimp DDS BC4.  Black would be the surface, light tones go down.

uniform float parallax_height_scale : hint_range(0.0, 1.5,0.005) = 0.05;
uniform int min_steps = 4;
uniform int max_steps = 8;
uniform int binary_search_steps = 3; // Optional refinement, PC/Console: 4–8, Mobile/Low VRAM: 2
uniform float normal_depth : hint_range(0.0, 1.0, 0.05) = 0.25;
uniform float tiles : hint_range(1.0, 22.0,0.25) = 16.0;
uniform float light_pom : hint_range(0.0, 0.55, 0.05) = 0.5; // more is less
uniform float shadow_pom : hint_range(0.0, 1.5, 0.05) = 1.0;
void vertex() {
}

vec2 parallax_mapping(vec3 view_dir_tangent, vec2 tex_coords) {
    float steps_f = mix(float(min_steps), float(max_steps), abs(view_dir_tangent.z));
    int steps = max(1, int(round(steps_f)));
    float layer_depth = 1.0 / float(steps);
    vec2 step_uv = view_dir_tangent.xy * parallax_height_scale * layer_depth;

    vec2 current_uv = tex_coords;
    vec2 prev_uv = tex_coords;
    float current_depth = 0.0;
    float prev_depth = 0.0;
    bool crossed = false;

    // Marching --- Explicit Branching ---
    for (int i = 0; i <= steps; i++) {
        float h = texture(texture_height_r, current_uv).r; // channel R only
        if (current_depth > h) {
            crossed = true;
            break;
        }
        prev_uv = current_uv;
        prev_depth = current_depth;
        current_uv +=  step_uv; // Light or dark tones
        current_depth += layer_depth;
    }

    if (!crossed) return current_uv;

    // Binary Search opcional
    vec2 a_uv = prev_uv; float a_depth = prev_depth;
    vec2 b_uv = current_uv; float b_depth = current_depth;

    for (int k = 0; k < binary_search_steps; k++) {
        vec2 mid_uv = 0.5 * (a_uv + b_uv);
        float mid_depth = 0.5 * (a_depth + b_depth);
        float h_mid = texture(texture_height_r, mid_uv).r;

        if (mid_depth > h_mid) {
            b_uv = mid_uv; b_depth = mid_depth;
        } else {
            a_uv = mid_uv; a_depth = mid_depth;
        }
    }

    return 0.5 * (a_uv + b_uv);
}

void fragment() {
    // TBN with T-flip and tangent step with transpose
    mat3 tbn_matrix = mat3(-TANGENT, BINORMAL, NORMAL);
    vec3 view_dir_tangent = normalize(transpose(tbn_matrix) * VIEW);

    // UV POM
    vec2 corrected_uvs = parallax_mapping(view_dir_tangent, UV * tiles);

    // ALBEDO
	mediump vec3 rgb_pack = texture(texture_RGB, corrected_uvs).rgb;
	ALBEDO = rgb_pack;
	// NORMAL_MAP
	mediump vec2 xy_pack = texture(texture_Normal, corrected_uvs).xy;
  	//NORMAL_MAP = vec3(xy_pack.xy, 1.0);// Enable if not in use: Hard Light and Shadows
	mediump vec2 LSpom = (step (vec2(light_pom),xy_pack.xy) - shadow_pom);// Optional Hard Light and Shadows
	NORMAL_MAP = vec3 ( min(NORMAL_MAP.xy + LSpom,0.0),1.0); // Optional Hard Light and Shadows
	NORMAL_MAP_DEPTH = normal_depth;
	
	ROUGHNESS = 1.0;
	SPECULAR  = 0.5;
}
Tags
cheap, machinery, parallax, POM, rocks, sci-fi, terrain
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from WaltGD

Cheap parallax planes array

Cheap caustics

Good enough parallax POM – Light tones lift – Version 1

Related shaders

Good enough parallax POM – Light tones lift – Version 1

UCBC’s Stylized Light with Light Masking

Cheap terrain with fake normal map or POM

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments