0 votes

Hi, I'm pretty new to shaders and I've been building a water shader from various tutorials on YT and elsewhere.
It's going well except that waves kind of show up through other waves. So if I'm looking at a wave, then I can also see the wave behind it perfectly. Please see the GIF here.

I'm not really sure what would be causing this and I don't know where to look.
Here's a dump of my shader code:

shader_type spatial;
render_mode world_vertex_coords;

const float PI = 3.14159265358979323846;

// help from https://catlikecoding.com/unity/tutorials/flow/waves/
// https://www.youtube.com/watch?v=Jq3he9Lbj7M

// vertex props
uniform float amplitude = 1.0;
uniform float modulator_wavelength;
uniform vec4 wave_one = vec4(1.0, 1.0, 0.2, 60.0);
uniform vec4 wave_two = vec4(0.7, -0.5, 0.1, 31.0);
uniform vec4 wave_three = vec4(0.3, 0.6, 0.4, 18.0);

// frag props
uniform float metallic : hint_range(0.0, 1.0);
uniform float roughness : hint_range(0.0, 1.0);

uniform sampler2D texture_map : hint_albedo;
uniform vec2 texture_scale = vec2(8.0, 8.0);

uniform sampler2D uv_offset_texture : hint_black;
uniform vec2 uv_offset_scale = vec2(0.2, 0.2);
uniform float uv_offset_speed = 0.05;
uniform float uv_offset_amplitude = 0.2;

uniform sampler2D normal_map : hint_normal;
uniform float refraction = 0.05;

uniform sampler2D noise_tex;
uniform float beer_factor = 1;
uniform float noise_cutoff = 0.8;
uniform float shore_noise_cutoff = 0.4;
uniform float foam_level = 0.2;
uniform float shore_foam_distance = 20.0;
uniform sampler2D shore_foam_tex;

float get_k(float wavelength) {
    return 2.0 * PI / wavelength;
}
float get_c(float k) {
    return sqrt(9.8 / k);
}
float get_f(float k, vec2 d, vec3 vert, float time) {
    return k * (dot(d, vert.xz) - time * get_c(k));
}
float get_a(float steepness, float k) {
    return steepness / k * amplitude;
}

vec3 gerstner_wave(float time, vec4 wave, vec3 vert, bool use_mod, inout vec3 tangent, inout vec3 binormal) {
    float steepness = wave.z;
    float wavelength = wave.w;
    vec2 d = normalize(wave.xy);
    float k = get_k(wavelength);
    float f = get_f(k, d, vert, time);
    float a = get_a(steepness, k);
    vert.x += d.x * (a * cos(f));
    vert.y += a * sin(f);
//  vert.y += amplitude * sin(k * (vert.x - time)); // amp mod
    vert.z += d.y * (a * cos(f));

    // freq/amp mod
    if (use_mod) {
        float k_mod = get_k(modulator_wavelength);
        float f_mod = get_f(k_mod, d, vert, time);
        float a_mod = get_a(steepness, k_mod);
        vert.y += a_mod * sin(f_mod);
    }

    tangent += vec3(
        1.0 - d.x * d.x * (steepness * sin(f)),
        d.x * (steepness * cos(f)),
        -d.x * d.y * (steepness * sin(f))
    );
    binormal += vec3(
        -d.x * d.y * (steepness * sin(f)),
        d.y * (steepness * cos(f)),
        1.0 - d.y * d.y * (steepness * sin(f))
    );
    return vert;
}

void vertex() {
    VERTEX = gerstner_wave(TIME, wave_one, VERTEX, true, TANGENT, BINORMAL);
    VERTEX = gerstner_wave(TIME, wave_two, VERTEX, false, TANGENT, BINORMAL);
    VERTEX = gerstner_wave(TIME, wave_three, VERTEX, false, TANGENT, BINORMAL);
    NORMAL = normalize(cross(BINORMAL, TANGENT));
}

void fragment() {
    vec2 base_uv_offset = UV * uv_offset_scale;
    base_uv_offset += TIME * uv_offset_speed;

    vec2 texture_based_offset = texture(uv_offset_texture, base_uv_offset).rg;
    texture_based_offset = texture_based_offset * 2.0 - 1.0;

    vec2 texture_uv = UV * texture_scale;
    texture_uv += uv_offset_amplitude * texture_based_offset;

    ALBEDO = texture(texture_map, texture_uv).rgb;
    METALLIC = metallic;
    ROUGHNESS = roughness;
    SPECULAR = 1.0;
//  NORMALMAP = texture(normal_map, base_uv_offset * 2.0).rgb;



    float depth = texture(DEPTH_TEXTURE, SCREEN_UV).r;
    depth = depth * 2.0 - 1.0;
    depth = PROJECTION_MATRIX[3][2] / (depth + PROJECTION_MATRIX[2][2]);


    // refraction
    vec3 ref_normal = normalize(mix(NORMAL, TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z, NORMALMAP_DEPTH));
    vec2 ref_ofs = SCREEN_UV - ref_normal.xy * refraction;

    // beers law
    float beer_depth = depth + VERTEX.z;
    beer_depth *= 0.1;
    beer_depth = exp(-beer_depth * beer_factor);
    ALPHA = clamp(1.0 - beer_depth, 0.0, 1.0);

    EMISSION = textureLod(SCREEN_TEXTURE, ref_ofs, ROUGHNESS).rgb * (1.0 - ALPHA);
    ALBEDO *= ALPHA;
    ALPHA = 1.0;


    // bits
    // help from https://roystan.net/articles/toon-water.html
    float noise_full = texture(noise_tex, texture_uv).r;
    float noise = noise_full > noise_cutoff ? 1.0 : 0.0;
    ALBEDO += vec3(noise, noise, noise);

    // shore foam
    float shore_amount = max(min(1.0, (shore_foam_distance - depth - VERTEX.z) / shore_foam_distance), 0.0);
    ALBEDO += texture(shore_foam_tex, texture_uv).rgb * shore_amount;

    // foam
    // help from https://github.com/gstark31897/GodotTerrain
    float shore_noise = noise_full > shore_noise_cutoff ? 1.0 : 0.0;
    float foam_amount = max(min(1.0, (foam_level - depth - VERTEX.z) / foam_level), 0.0);
    ALBEDO += vec3(shore_noise, shore_noise, shore_noise) * foam_amount * 10.0;
}

Any leads (or solutions hehe) would be greatly appreciated!

Godot version 3.2.1.stable
in Engine by (21 points)

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.