Shader d’eau

Il transforme un plan 3D plat et fixe en une surface aquatique en mouvement. Pour cela, il utilise le temps du jeu pour faire onduler verticalement les points du modèle 3D, simulant ainsi le relief de vagues de différentes tailles.

Visuellement, le shader applique une couleur de base sombre pour représenter la profondeur de l’eau. Il repère ensuite les sommets des vagues les plus élevés pour y injecter une couleur plus claire, ce qui crée automatiquement de l’écume là où la mer s’agite. Enfin, il configure la surface pour qu’elle soit hautement réfléchissante, permettant aux lumières de l’environnement de créer des reflets réalistes qui bougent en phase avec les vagues.

Shader code
shader_type spatial;
render_mode cull_disabled, depth_draw_always, specular_schlick_ggx;

uniform float _WaveSpeed : hint_range(0.0, 5.0) = 1.5;
uniform float _WaveHeight : hint_range(0.0, 2.0) = 0.4;
uniform float _WaveFrequency : hint_range(0.0, 2.0) = 0.5;


uniform vec3 _WaterColor : source_color = vec3(0.005, 0.15, 0.25);
uniform vec3 _ShallowColor : source_color = vec3(0.05, 0.4, 0.5);
uniform vec3 _FoamColor : source_color = vec3(0, 0.46, 0.65);
uniform float _BeersLaw : hint_range(0.1, 5.0) = 0.3;
uniform float _RefractionStrength : hint_range(0.0, 0.1) = 0.05;
uniform float _Roughness : hint_range(0.0, 1.0) = 0.0;

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;

float get_wave_height(vec2 pos, float time) {
    float wave = sin(pos.x * _WaveFrequency + time * _WaveSpeed) * 0.5;
    wave += cos(pos.y * _WaveFrequency * 1.2 + time * _WaveSpeed * 0.8) * 0.4;
    wave += sin((pos.x + pos.y) * _WaveFrequency * 2.0 + time * _WaveSpeed * 1.5) * 0.1;
    return wave * _WaveHeight;
}

void vertex() {
    vec3 world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
    float height = get_wave_height(world_pos.xz, TIME);
    VERTEX.y += height;
    UV2.x = height; 
}

void fragment() {
    vec3 w_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
    float e = 0.1;
    float h_left  = get_wave_height(w_pos.xz + vec2(-e, 0.0), TIME);
    float h_right = get_wave_height(w_pos.xz + vec2(e, 0.0), TIME);
    float h_down  = get_wave_height(w_pos.xz + vec2(0.0, -e), TIME);
    float h_up    = get_wave_height(w_pos.xz + vec2(0.0, e), TIME);
    
    vec3 normal_wave = normalize(vec3(h_left - h_right, 2.0 * e, h_down - h_up));
    NORMAL = (VIEW_MATRIX * vec4(normal_wave, 0.0)).xyz;
    vec2 refracted_uv = SCREEN_UV + (normal_wave.xz * _RefractionStrength);
    float depth_raw = textureLod(DEPTH_TEXTURE, refracted_uv, 0.0).r;
    vec3 ndc = vec3(refracted_uv * 2.0 - 1.0, depth_raw);
    vec4 view_pos = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
    view_pos.xyz /= view_pos.w;
    
    float depth_buffer = -view_pos.z;
    float water_depth = depth_buffer - VERTEX.z;
	
    if (water_depth < 0.0) {
        refracted_uv = SCREEN_UV;
        depth_raw = textureLod(DEPTH_TEXTURE, refracted_uv, 0.0).r;
        ndc = vec3(refracted_uv * 2.0 - 1.0, depth_raw);
        view_pos = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
        view_pos.xyz /= view_pos.w;
        water_depth = -view_pos.z - VERTEX.z;
    }
    float depth_fade = exp(-water_depth * _BeersLaw);
    depth_fade = clamp(depth_fade, 0.0, 1.0);
    vec3 background_color = textureLod(SCREEN_TEXTURE, refracted_uv, 0.0).rgb;
    vec3 water_base = mix(_WaterColor, _ShallowColor, depth_fade);
    float current_height = UV2.x;
    float foam_mask = smoothstep(_WaveHeight * 0.1, _WaveHeight * 0.9, current_height);

    float shore_foam = smoothstep(0.2, 0.0, water_depth);
    float total_foam = clamp(foam_mask * 0.4 + shore_foam * 0.7, 0.0, 1.0);
    vec3 final_water = mix(water_base, background_color, depth_fade * 0.5);
    ALBEDO = mix(final_water, _FoamColor, total_foam);
    ROUGHNESS = _Roughness;
    SPECULAR = 0.8;
    METALLIC = 0.0;
}
Live Preview
Tags
eau, mer, ocean, réaliste
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.

Related shaders

guest

0 Comments
Oldest
Newest Most Voted