Ocean shader - how?

slapinslapin Posts: 61Member

Hi, all!

After a few cups and a bottle I started thinking I can't now live without ocean shader. And not another sine-ased wavery things, but something nice. What I want is shader style of GTA SA or Saints Row 2 style shaders.

I started by creating normal maps using Ocean modifier. Maybe I will be able to create albedo texture too this way (or not - some Voronoi shader example probably could give better results and could be baket in 2D viewport for later reuse, or some image downloaded from Internet will do) but now what?

I want the following features implemented:
1. Ocean wawes. Basically done, I use random circular waves using 4 points from uniform, huge sine-based waves and a few smaller ones, normal map intermixed several times with different frequencis, looks almost good. I'd like to see a few more possible tricks though. Would be good if that followed some wind vector which could influence direction.
2. When something/someone floats in water, I want appropriate wavy effect. Basicaly it should create wavy surface of ripple and it should follow what is floating. Especially when people and boats/ships float/sail nearby. Or something is dropped into water.
3. When boats sail fast there should be some huge foamy tail behind them following their course.
4. When raining there should be smaller ripples everywhere.
5. When camera digs below water surface it should see underwater picture (i.e. distorted like in most games with underwater stuff, like I mentioned above (GTA, SR).

I want to use steady approach and increase complexity little by little, where could I read about other people's implementations, articles, stories?
Thanks!

Answers

  • slapinslapin Posts: 61Member

    Forgot to mention I use bleeding edge git master (3.1)

  • MagicLordMagicLord Posts: 578Unconfirmed
    edited July 2018

    @slapin said:
    Hi, all!

    After a few cups and a bottle I started thinking I can't now live without ocean shader. And not another sine-ased wavery things, but something nice. What I want is shader style of GTA SA or Saints Row 2 style shaders.

    I started by creating normal maps using Ocean modifier. Maybe I will be able to create albedo texture too this way (or not - some Voronoi shader example probably could give better results and could be baket in 2D viewport for later reuse, or some image downloaded from Internet will do) but now what?

    I want the following features implemented:
    1. Ocean wawes. Basically done, I use random circular waves using 4 points from uniform, huge sine-based waves and a few smaller ones, normal map intermixed several times with different frequencis, looks almost good. I'd like to see a few more possible tricks though. Would be good if that followed some wind vector which could influence direction.
    2. When something/someone floats in water, I want appropriate wavy effect. Basicaly it should create wavy surface of ripple and it should follow what is floating. Especially when people and boats/ships float/sail nearby. Or something is dropped into water.
    3. When boats sail fast there should be some huge foamy tail behind them following their course.
    4. When raining there should be smaller ripples everywhere.
    5. When camera digs below water surface it should see underwater picture (i.e. distorted like in most games with underwater stuff, like I mentioned above (GTA, SR).

    I want to use steady approach and increase complexity little by little, where could I read about other people's implementations, articles, stories?
    Thanks!

    Those effects can be made using meshes with vertex and pixel shaders , detecting when objects collide with water or a nearby other objects, and using camera post process. There is lot of way to achieve those effects, try searching there is lot of discussions how to make those.

  • slapinslapin Posts: 61Member

    Do you know how these are called so I could search for these?
    And how can I do collision detection in shader?

  • MagicLordMagicLord Posts: 578Unconfirmed

    @slapin said:
    Do you know how these are called so I could search for these?
    And how can I do collision detection in shader?

    There is no collision in shaders.
    You must use physics and collision for each object, detect when some object is in collision with water and make it bounce and make it follow the waves height.

    You can search those
    1) Ocean shaders , ocean physics and objects collisions.
    2) Water ripple effects and shaders
    3) boats foam trail effects
    4) rain shader effect on water (shader and multi texture bmending)
    5) Underwater effects and shaders examples

    You must be at ease with shaders coding and physics simulation coding for water.
    I hope it helps.

  • MegalomaniakMegalomaniak Posts: 1,087Admin

    In theory depth buffer can be checked for object proximity. And in practice the default godot 3 SpatialMaterial already has that functionality integrated.

    http://docs.godotengine.org/en/3.0/tutorials/3d/spatial_material.html#proximity-and-distance-fade
    http://docs.godotengine.org/en/3.0/tutorials/shading/shader_materials.html#converting-to-shadermaterial

  • slapinslapin Posts: 61Member
    Answer ✓

    This is what I implemented so far, I need to add splashes and boat foam trail, any basic ideas?
    Shader code:

    shader_type spatial;
    // portions stolen from Krzysztof Jankowski's the islands of shaders repo.
    // (It is brilliant!)
    // Also some lines are from various places on the Internet.
    
    uniform vec2 timescale = vec2(2.0, 3.0);
    uniform float refraction = 0.05;
    uniform float large_waveheight = 0.15;
    uniform float small_waveheight = 0.05;
    // This one I generated this way. I created 2D Vewport with canvas in it
    // Made 2D shader and used Krzysztof Jankowski's random function to fill the screen
    // and use the viewport texture for this uniform.
    uniform sampler2D random_noise: hint_black;
    varying vec3 coords;
    
    // 2d noise function
    // For some reason random function produced
    // too many artifacts, so I had to replace it by texture.
    float noise(vec2 p)
    {
            vec4 tx = textureLod(random_noise, p, 0.5);
            return tx.x;
    }
    
    // Fractional Brownian motion
    float fbm( vec2 p )
    {
      mat2 m2 = mat2(vec2(1.6, -1.2), vec2(1.2, 1.6));
      float f = 0.5000 * noise(p); p = m2*p;
      f += 0.2500 * noise( p ); p = m2*p;
      f += 0.1666 * noise( p ); p = m2*p;
      f += 0.0834 * noise( p );
      return f;
    }
    float water(vec2 p, float time)
    {
            vec2 pos = p;
            mat2 m2 = mat2(vec2(1.6, -1.2), vec2(1.2, 1.6));
            float h = 0.0;
            vec2 shift1 = 0.001 * vec2(time * 160.0 * 2.0, time * 120.0 * 2.0) * 1.0;
            vec2 shift2 = 0.001 * vec2(time * 190.0 * 2.0, -time * 130.0 * 2.0) * 1.0;
            float wave = 0.0;
            wave += sin(pos.x*0.021  * 10.0 + shift2.x)*4.5;
            wave += sin(pos.x*0.0172 * 10.0 + pos.y * 0.010 * 10.0+ shift2.x*1.121)*4.0;
            wave -= sin(pos.x*0.00104 * 10.0 + pos.y*0.005 * 10.0 + shift2.x*0.121)*4.0;
            wave += (1.0 - abs(cos(4.5 * (pos.x*0.0172 * 10.0 + pos.y * 0.010 * 10.0+ shift2.x*1.121)))) * 0.7;
            wave += (1.0 - abs(cos(5.5 * (pos.x*0.0172 * 10.0 + pos.y * 0.010 * 10.0+ shift2.x*1.121)))) * 0.5;
            wave += (1.0 - abs(cos(8.5 * (pos.x*0.0172 * 10.0 + pos.y * 0.010 * 10.0+ shift2.x*1.121)))) * 0.2;
    
            // wave += sin(pos.x*0.02221 * 10.0 +pos.y*0.01233 * 10.0 +shift2.x*3.437)*5.0;
            // wave += sin(pos.x*0.03112 * 10.0 +pos.y*0.01122 * 10.0 +shift2.x*4.269)*2.5;
            wave *= large_waveheight;
            wave -= fbm(pos*0.004 - shift2 * 0.5) * small_waveheight * 24.0;
    
            float amp = 16.0 * small_waveheight;
            shift1 *= .3;
            for (int i=0; i<7; i++)
            {
                    wave -= abs(sin((noise(pos*0.01+shift1)-.5)*3.14))*amp;
                    amp *= .51;
                    shift1 *= 1.841;
                    pos = m2 * 0.9331 * pos;
            }
    
            h += wave;
            return h;
    }
    void vertex()
    {
            vec4 vtx = vec4(VERTEX, 1.0);
            vec4 worldv = WORLD_MATRIX * vtx;
            VERTEX.y = water(vec2(worldv.x, worldv.z), TIME);
            float hdiff = water(worldv.xz + vec2(0.0, 0.2), 0.0) - water(worldv.xz + vec2(0.0, -0.2), 0.0);
            float hdiff2 = water(worldv.xz + vec2(0.2, 0.0), 0.0) - water(worldv.xz + vec2(-0.2, 0.0), 0.0);
            TANGENT = normalize(vec3(0.0, hdiff, 0.4));
            BINORMAL = normalize(vec3(0.4, hdiff2, 0.0));
            NORMAL = cross(TANGENT, BINORMAL);
            coords = VERTEX.xyz;
    }
    
    void fragment()
    {
            ALBEDO = vec3(0, 0, 1);
            ROUGHNESS = 0.2;
            METALLIC = 0.5;
            vec2 uv_offsets = vec2(0.0, 0.0);
            uv_offsets.x += 0.12 * sin(TIME * 0.02 + UV.x);
            uv_offsets.x += 0.05 * sin(TIME * 3.0 + UV.x);
            uv_offsets.y += 0.12 * cos(TIME * 0.02 + UV.y);
            uv_offsets.y += 0.05 * cos(TIME * 3.0 + UV.y);
    
            vec3 ref_normal = normalize(mix(NORMAL, TANGENT * uv_offsets.x + BINORMAL * uv_offsets.y + NORMAL * NORMALMAP.z, NORMALMAP_DEPTH));
            vec2 ref_ofs = SCREEN_UV + ref_normal.xy * refraction;
            ALPHA = 0.4;
            EMISSION += textureLod(SCREEN_TEXTURE, ref_ofs, ROUGHNESS * 8.0).rgb * (1.0 - ALPHA);
            ALBEDO *= ALPHA;
            ALPHA = 1.0;
    }
    
    
    
  • slapinslapin Posts: 61Member
    Answer ✓

    This shader is aware of actual object place, so I can use ocean chunks and they will match.
    I need this for "endless" ocean for "endless" world I make :)

    So the question is how to add splashes to it first. Then I will need everything else...

  • SIsilicon28SIsilicon28 Posts: 35Member
    Answer ✓

    I have an ocean demo in the asset store. Maybe you could check it out and pick up a thing or two.

Sign In or Register to comment.