Cubemap Reflective Water Surface

Hey guys,

A reflective water shader that I modified and used for my own project:

 

The original idea was to create a shader that by inputing an HDRI could simulate some sort of natural water with reflection and lighting physics that looks like real water but in 2d.

In the end I found that it works better with cubemap than HDRI, that was originally supported in godot.

After some optimization. now it could run 120fps on my old m1 macbook laptop(not owning a windows laptop these days is really a headache sometimes, but talking about the quality of windows11 today…).

 

iChannel0 would be your screen texture you can put anything under the shader, then it will look like under the water surface.

iChannel1 need to be an rgb noise(if you dont have it you can use the third pic in the screenshots, or you can generate one yourself)

iChannel2 is where you put your cubemap(If you don’t have any on hand, you can download one from here: 

https://www.humus.name/index.php?page=Textures&start=0

this guy has a lot cool stuff on his website :)

 

BTW:

This shader only runs well in Forward+!!(DEMO project below since it’s rendered on web it’s in compatible mode so the reflection was a bit broken)

 

Here’s my project:

Tranquil Koi: https://store.steampowered.com/app/3184080/Tranquil_Koi/

Original shader:

https://www.shadertoy.com/view/ldB3Wd

Shader code
shader_type canvas_item;


uniform sampler2D iChannel0:hint_screen_texture, repeat_disable, filter_nearest; // input channel 0
uniform sampler2D iChannel1; // input channel 1
uniform samplerCube iChannel2; // input channel 2

uniform vec4 tint_color:source_color;

float bias(float x, float b) {
    return x / ((1.0 / b - 2.0) * (1.0 - x) + 1.0);
}

float gain(float x, float g) {
    float t = (1.0 / g - 2.0) * (1.0 - (2.0 * x));
    return x < 0.5 ? (x / (t + 1.0)) : (t - x) / (t - 1.0);
}

vec3 degamma(vec3 c) {
    return pow(c, vec3(2.2));
}

vec3 gamma(vec3 c) {
    return pow(c, vec3(1.0 / 1.5));
}

#define DIVS 4

void fragment() {

	vec2 uv = SCREEN_UV;
	//vec2 uv = UV;
    uv.y =  1.-uv.y;
    uv.x *= (1. / SCREEN_PIXEL_SIZE).x / (1. / SCREEN_PIXEL_SIZE).y;
	//vec2 uv_lowres = floor(uv * vec2(1.0 / 2.0)) * 2.0;
    float h = 0.0;

    float time = TIME;


    for (int iy = 0; iy < DIVS; iy++) {
        for (int ix = 0; ix < DIVS * 2; ix++) {
            vec4 t = texture(iChannel1, vec2(float(ix), float(iy)) * (4.0 / 256.0),100);

            vec2 p = vec2(float(ix), float(iy)) * (1.0 / float(DIVS - 1));
            p += (0.75 / float(DIVS - 1)) * (t.xy * 2.0 - 1.0);

            vec2 v = uv - p;
            float d = dot(v, v);
            d = pow(d, 0.7);
            float life = 10.0;

            float n = time * 2.0 * (t.w + 0.05) - t.z * 10.0;
            n *= 0.01 + t.w;
            n = mod(n, life*0.5 + t.z * 3.0 + 2.0);

            float x = d * 99.0;
            float T = x < (2.0 * PI * n) ? 1.0 : 0.0;
            float e = max(1.0 - (n / life), 0.0);
            float F = e * x / (2.0 * PI * n);

            float s = sin(x - (2.0 * PI * n) - PI * 0.5);
            s = s * 0.5 + 0.5;
            s = bias(s, 0.5);

            s = (F * s) / (x + 1.1) * T;

            h += s * 100.0 * (0.5 + t.w);
        }
    }

    vec3 n = vec3(dFdx(h), 15.0, dFdy(h));
    n = normalize(n);

    //vec3 e = normalize(vec3(-uv.y * 2.0 - 1.0, 1.0, uv.x * 2.0 - 1.0));
	vec3 e = normalize(vec3(-uv.y*1.0+1.0,1.0,uv.x*1.0-1.0));
	//vec3 e = normalize(vec3(1000.0, 1000.0, 1000.0));
    vec3 rv = reflect(-e, n);
    vec3 reflect_color = degamma(texture(iChannel2, rv).xyz);

    vec3 fn = refract(vec3(0, 1, 0), n, 2.5);
    //uv += fn.xz * 0.1;

    float lod = length(fn.xz) * 10.0;

    vec3 c = vec3(0.0);

    //c += degamma(textureLod(iChannel0, uv + vec2(0.66, 0.0), lod).xyz);
	c += degamma(textureLod(iChannel0, (SCREEN_UV + fn.xz * 0.05), lod).xyz);

    c *= 1.0 - h * 0.0125;
    c += reflect_color * .2;

    vec3 L = normalize(vec3(1.0, 1.0, 1.0));
    float dl = max(dot(n, L), 0.0) * 0.7 + 0.3;
    c *= dl;

    c = gamma(c);
	//vec4 f_c = vec4(c,1.0);
	//f_c = mix(f_c,tint_color,0.2);
	//f_c *= tint_color;
	//COLOR = f_c;
    COLOR = vec4(c, 1.0);
}
Tags
2d, cubemap, dripples, reflection, water, wave, wipples
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

2D Reflective Water

2D water surface with wave and noise

PSX Style Water Surface – Pixelation, Waves, Scrolling Textures

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments