Medieval Water(中世纪水)

Fully procedural water shader. Requires no external textures – generates natural ripples, normal bumps, and dynamic foam entirely through real-time noise algorithms. Perfect for Low-Poly or Stylized game projects.

纯程序化水面着色器。无需任何外部贴图,完全基于噪声算法实时计算出自然的波纹、法线凹凸以及动态泡沫,非常适合低多边形(Low-Poly)或风格化(Stylized)游戏项目。

Shader code
shader_type spatial;

render_mode blend_mix,
depth_draw_opaque,
cull_back,
diffuse_burley,
specular_schlick_ggx;

// === 水面基础参数 ===
uniform vec3 water_color : source_color = vec3(0.15, 0.32, 0.22); //水体基础颜色
uniform float water_metallic : hint_range(0.0, 1.0) = 0.0; //金属度
uniform float water_roughness : hint_range(0.0, 1.0) = 0.75; //粗糙度
uniform float water_specular : hint_range(0.0, 1.0) = 0.6; //高光强度

// === 波浪参数 ===
uniform float wave_speed : hint_range(0.0, 5.0) = 0.2; // 波浪流动速度
uniform float wave_scale : hint_range(1.0, 50.0) = 12.0; // 波浪缩放密集度
uniform float wave_normal_strength : hint_range(0.0, 5.0) = 1.5; // 波浪法线(凹凸)强度

// === 泡沫参数 ===
uniform float foam_amount : hint_range(0.0, 1.0) = 0.15; // 泡沫数量
uniform vec3 foam_color : source_color = vec3(0.72, 0.68, 0.52); //泡沫的颜色
uniform float foam_animation_speed : hint_range(0.0, 5.0) = 1.5; // 泡沫变形速度
uniform float foam_detail : hint_range(10.0, 200.0) = 100.0; // 泡沫细节精细度

// === 2D 随机伪随机数生成器 ===
float random(vec2 uv) {
    return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
}

// === 2D 柏林噪声基础函数 ===
float noise(vec2 uv) {
    vec2 i = floor(uv);
    vec2 f = fract(uv);
    
    // 获取四个角的随机值
    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));
    
    // 平滑插值 (Cubic Hermite Curve)
    vec2 u = f * f * (3.0 - 2.0 * f);
    
    return mix(a, b, u.x) +
           (c - a) * u.y * (1.0 - u.x) +
           (d - b) * u.x * u.y;
}

// === 分形布朗运动 (FBM) - 叠加多层噪声产生细节 ===
float fbm(vec2 uv) {
    float value = 0.0;
    float amplitude = 0.5;
    float frequency = 1.0;
    
    // 叠加 4 层噪声 (Octaves)
    for(int i = 0; i < 4; i++) {
        value += amplitude * noise(uv * frequency);
        frequency *= 2.0;
        amplitude *= 0.5;
    }
    
    return value;
}

// === 波浪高度计算 ===
float wave_noise(vec2 uv, float time) {
    float t = time * wave_speed;
    
    // 生成两个不同方向流动的 UV,模拟水流交错
    vec2 uv1 = uv * wave_scale + vec2(t * 0.3, t * 0.2);
    vec2 uv2 = uv * wave_scale * 1.3 + vec2(-t * 0.25, t * 0.35);
    
    float noise1 = fbm(uv1);
    float noise2 = fbm(uv2);
    
    // 混合两层噪声并将结果映射到 -1.0 到 1.0 之间
    return (noise1 + noise2) - 1.0;
}

// === 动态计算水面法线 ===
vec3 calculate_water_normal(vec2 uv, float time) {
    float offset = 0.01; // 采样偏移量,影响法线锐度
    
    // 获取当前点及相邻点的波浪高度
    float h_c = wave_noise(uv, time);
    float h_r = wave_noise(uv + vec2(offset, 0.0), time);
    float h_u = wave_noise(uv + vec2(0.0, offset), time);
    
    // 通过高度差计算法线向量 (Godot 3D空间中 Y 轴向上)
    vec3 normal;
    normal.x = (h_c - h_r) / offset;
    normal.z = (h_c - h_u) / offset;
    normal.y = 1.0;
    
    return normalize(normal);
}

void fragment() {
    // 1. 动态生成法线贴图
    vec3 water_normal = calculate_water_normal(UV, TIME);
    water_normal *= vec3(wave_normal_strength, 1.0, wave_normal_strength);
    NORMAL_MAP = normalize(water_normal);
    
    // 2. 获取当前像素的波浪高度值 (-1 到 1)
    float wave = wave_noise(UV, TIME);
    
    // 3. 基础水体颜色
    vec3 final_color = water_color;
    
    // 4. 程序化波峰泡沫
    // 使用独立的噪声控制泡沫的形态演变
    float foam_noise = fbm(UV * foam_detail + TIME * foam_animation_speed);
    float foam_anim = smoothstep(0.3, 0.7, foam_noise);
    
    // 提取波峰区域 (当 wave 接近最高点时生成遮罩)
    float foam_mask = smoothstep(0.5, 0.8, wave + 1.0) * foam_amount;
    
    // 混合泡沫颜色
    float foam = foam_mask * foam_anim;
    final_color = mix(final_color, foam_color, foam);
    
    // 5. 波浪光照高光微调 (使波峰略微受光变亮)
    float light_wave = wave * 0.15;
    final_color += vec3(0.05, 0.06, 0.04) * light_wave;
    
    // 6. 水体深浅颜色过渡 (波浪低谷略微偏暗偏蓝绿)
    float murk = wave * 0.05;
    final_color = mix(final_color, vec3(0.12, 0.14, 0.10), murk);
    
    // === 最终属性输出 ===
    ALBEDO = final_color;
    METALLIC = water_metallic;
    // 根据波浪起伏微调粗糙度,增加质感变化
    ROUGHNESS = water_roughness + (wave - 0.5) * 0.05; 
    SPECULAR = water_specular;
}
Live Preview
Tags
medieval, water, 中世纪,
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 GuoXiaoYao

Related shaders

guest

0 Comments
Oldest
Newest Most Voted