This is the testing Godot forums! All forum posts unique to this forum will be deleted! Please use the main forums here for any posts you want to keep. All forum rules still apply.

[Godot 3] water shader

MagicLordMagicLord Posts: 578Unconfirmed

Hi there,

My game needs some water.
Is there a shader available for Godot 3 ?

Best Answers

  • MegalomaniakMegalomaniak Posts: 2,580
    edited January 2018 Accepted Answer

    So based on: http://jayconrod.com/posts/34/water-simulation-in-glsl

    shader_type spatial;
    //render_mode world_vertex_coords;
    
    uniform vec4 color : hint_color;
    
    uniform int numWaves;
    uniform float waterHeight;
    uniform float wavelength = 8.0;
    uniform float amplitude = 8.0;
    uniform float speed = 8.0;
    uniform vec2 direction = vec2(8.0, 8.0);
    
    uniform float pi = 3.1415926535897932384626433832795;
    varying vec3 position;
    varying vec3 worldNormal;
    varying vec3 eyeNormal;
    uniform vec3 eyePos;
    
    float wave(int i, float x, float y, float t) {
        float frequency = 2.0 * pi / wavelength;
        float phase = speed * frequency;
        float theta = dot(direction, vec2(x, y));
        return amplitude * sin(theta * frequency + t * phase);
    }
    
    float waveHeight(float x, float y, float t) {
        float height = 0.0;
        for (int i = 0; i < numWaves; i++) {
            height += wave(i, x, y, t);
        }
        return height;
    }
    
    float dWaveDx(int i, float x, float y, float t) {
        float frequency = 2.0 * pi / wavelength;
        float phase = speed * frequency;
        float theta = dot(direction, vec2(x, y));
        float A = amplitude * direction.x * frequency;
        return A * cos(theta * frequency + t * phase);
    }
    
    float dWaveDy(int i, float x, float y, float t) {
        float frequency = 2.0 * pi / wavelength;
        float phase = speed * frequency;
        float theta = dot(direction, vec2(x, y));
        float A = amplitude * direction.y * frequency;
        return A * cos(theta * frequency + t * phase);
    }
    
    vec3 waveNormal(float x, float y, float t) {
        float dx;
        float dy;
        for (int i; i < numWaves; i++) {
            dx += dWaveDx(i, x, y, t);
            dy += dWaveDy(i, x, y, t);
        }
        vec3 n = vec3(-dx, -dy, 1.0);
        return n;
    }
    
    void vertex() {
        vec4 pos = vec4(VERTEX, 1.0).xzyw;
        pos.z = (waterHeight + waveHeight(pos.x, pos.y, TIME));
        position = pos.xzy / pos.w;
        worldNormal = waveNormal(pos.x, pos.y, TIME);
        eyeNormal = (MODELVIEW_MATRIX * vec4(worldNormal, 0.0).xzyw).xyz;
        NORMAL = eyeNormal;
        TANGENT = eyeNormal;
        BINORMAL = eyeNormal;
        VERTEX = (position).xyz;
    }
    
    void fragment() {
        SPECULAR = float(1.0);
        ROUGHNESS = float(0.05);
    //  CLEARCOAT = float(0.99);
    //  CLEARCOAT_GLOSS = float(1.0);
        ALBEDO = color.rgb;
        ALPHA = color.a;
    }
    

    Its just a simple vertex waveform and needs a vertex dense grid mesh. But its a quick hack job so, like, eh. I do intend to make a proper water shader at some point but I need to familiarize myself with the new shader system more first. Have gotten too used to nodal graph shaders.

  • MegalomaniakMegalomaniak Posts: 2,580
    edited January 2018 Accepted Answer

    Looking at your 'water plane' scene it has more going on than needs, seems to be to-do with the dae importer I guess.

    Anyways. I created a meshinstance with a plane mesh node as a comparison/control measure and a new material for both(not each) planes(yours and mine) and saved the material to a file, then gave the material a new shader(again saved to file), pasted the above shader code, reformatted it a bit since the forums code tag messes up the indentation(although that shouldn't affect the functionality) and then I actually tweaked the shader parameters:

    Here is how the water looks in the level with these parameters:

    Now since I've set the flow direction to be along X axis a lot of the polygons could be removed because in this instance only mesh density along X affects the visual result.

    Next step would be to add a Boolean check to enable/disable the vertex waveform. And then add a UV scrolling function which could be used to animate/scroll a tiling bump/normalmap. As I mentioned earlier I do intend to create a more complex water shader. This was just a quick hack for a starting point so you could have a placeholder. ;)

    PS. holy he... ...llo. Those blue floating spheres are very wasteful in terms of polys. Seriously, just one is 27024 vertices.

Answers

  • MegalomaniakMegalomaniak Posts: 2,580Admin

    And what exactly are you looking for? River? Sea? Oceanic? Pond? A Puddle? more detail, please.

  • MagicLordMagicLord Posts: 578Unconfirmed

    @Megalomaniak said:
    And what exactly are you looking for? River? Sea? Oceanic? Pond? A Puddle? more detail, please.

    It's for rivers and lakes using a mesh or a plane with a normal map animation or any other animation trick that would look like water.

  • MegalomaniakMegalomaniak Posts: 2,580Admin

    Mobile game, desktop? minimum HW requrements?

  • MagicLordMagicLord Posts: 578Unconfirmed

    @Megalomaniak said:
    Mobile game, desktop? minimum HW requrements?

    Godot 3 for medium HW GTX 950.

  • MegalomaniakMegalomaniak Posts: 2,580Admin
    edited January 2018 Accepted Answer

    So based on: http://jayconrod.com/posts/34/water-simulation-in-glsl

    shader_type spatial;
    //render_mode world_vertex_coords;
    
    uniform vec4 color : hint_color;
    
    uniform int numWaves;
    uniform float waterHeight;
    uniform float wavelength = 8.0;
    uniform float amplitude = 8.0;
    uniform float speed = 8.0;
    uniform vec2 direction = vec2(8.0, 8.0);
    
    uniform float pi = 3.1415926535897932384626433832795;
    varying vec3 position;
    varying vec3 worldNormal;
    varying vec3 eyeNormal;
    uniform vec3 eyePos;
    
    float wave(int i, float x, float y, float t) {
        float frequency = 2.0 * pi / wavelength;
        float phase = speed * frequency;
        float theta = dot(direction, vec2(x, y));
        return amplitude * sin(theta * frequency + t * phase);
    }
    
    float waveHeight(float x, float y, float t) {
        float height = 0.0;
        for (int i = 0; i < numWaves; i++) {
            height += wave(i, x, y, t);
        }
        return height;
    }
    
    float dWaveDx(int i, float x, float y, float t) {
        float frequency = 2.0 * pi / wavelength;
        float phase = speed * frequency;
        float theta = dot(direction, vec2(x, y));
        float A = amplitude * direction.x * frequency;
        return A * cos(theta * frequency + t * phase);
    }
    
    float dWaveDy(int i, float x, float y, float t) {
        float frequency = 2.0 * pi / wavelength;
        float phase = speed * frequency;
        float theta = dot(direction, vec2(x, y));
        float A = amplitude * direction.y * frequency;
        return A * cos(theta * frequency + t * phase);
    }
    
    vec3 waveNormal(float x, float y, float t) {
        float dx;
        float dy;
        for (int i; i < numWaves; i++) {
            dx += dWaveDx(i, x, y, t);
            dy += dWaveDy(i, x, y, t);
        }
        vec3 n = vec3(-dx, -dy, 1.0);
        return n;
    }
    
    void vertex() {
        vec4 pos = vec4(VERTEX, 1.0).xzyw;
        pos.z = (waterHeight + waveHeight(pos.x, pos.y, TIME));
        position = pos.xzy / pos.w;
        worldNormal = waveNormal(pos.x, pos.y, TIME);
        eyeNormal = (MODELVIEW_MATRIX * vec4(worldNormal, 0.0).xzyw).xyz;
        NORMAL = eyeNormal;
        TANGENT = eyeNormal;
        BINORMAL = eyeNormal;
        VERTEX = (position).xyz;
    }
    
    void fragment() {
        SPECULAR = float(1.0);
        ROUGHNESS = float(0.05);
    //  CLEARCOAT = float(0.99);
    //  CLEARCOAT_GLOSS = float(1.0);
        ALBEDO = color.rgb;
        ALPHA = color.a;
    }
    

    Its just a simple vertex waveform and needs a vertex dense grid mesh. But its a quick hack job so, like, eh. I do intend to make a proper water shader at some point but I need to familiarize myself with the new shader system more first. Have gotten too used to nodal graph shaders.

  • MagicLordMagicLord Posts: 578Unconfirmed
    edited January 2018

    @Megalomaniak said:
    So based on: http://jayconrod.com/posts/34/water-simulation-in-glsl

    shader_type spatial;
    //render_mode world_vertex_coords;
    
    uniform vec4 color : hint_color;
    
    uniform int numWaves;
    uniform float waterHeight;
    uniform float wavelength = 8.0;
    uniform float amplitude = 8.0;
    uniform float speed = 8.0;
    uniform vec2 direction = vec2(8.0, 8.0);
    
    uniform float pi = 3.1415926535897932384626433832795;
    varying vec3 position;
    varying vec3 worldNormal;
    varying vec3 eyeNormal;
    uniform vec3 eyePos;
    
    float wave(int i, float x, float y, float t) {
      float frequency = 2.0 * pi / wavelength;
      float phase = speed * frequency;
      float theta = dot(direction, vec2(x, y));
      return amplitude * sin(theta * frequency + t * phase);
    }
    
    float waveHeight(float x, float y, float t) {
      float height = 0.0;
      for (int i = 0; i < numWaves; i++) {
          height += wave(i, x, y, t);
      }
      return height;
    }
    
    float dWaveDx(int i, float x, float y, float t) {
      float frequency = 2.0 * pi / wavelength;
      float phase = speed * frequency;
      float theta = dot(direction, vec2(x, y));
      float A = amplitude * direction.x * frequency;
      return A * cos(theta * frequency + t * phase);
    }
    
    float dWaveDy(int i, float x, float y, float t) {
      float frequency = 2.0 * pi / wavelength;
      float phase = speed * frequency;
      float theta = dot(direction, vec2(x, y));
      float A = amplitude * direction.y * frequency;
      return A * cos(theta * frequency + t * phase);
    }
    
    vec3 waveNormal(float x, float y, float t) {
      float dx;
      float dy;
      for (int i; i < numWaves; i++) {
          dx += dWaveDx(i, x, y, t);
          dy += dWaveDy(i, x, y, t);
      }
      vec3 n = vec3(-dx, -dy, 1.0);
      return n;
    }
    
    void vertex() {
      vec4 pos = vec4(VERTEX, 1.0).xzyw;
      pos.z = (waterHeight + waveHeight(pos.x, pos.y, TIME));
      position = pos.xzy / pos.w;
      worldNormal = waveNormal(pos.x, pos.y, TIME);
      eyeNormal = (MODELVIEW_MATRIX * vec4(worldNormal, 0.0).xzyw).xyz;
      NORMAL = eyeNormal;
      TANGENT = eyeNormal;
      BINORMAL = eyeNormal;
      VERTEX = (position).xyz;
    }
    
    void fragment() {
      SPECULAR = float(1.0);
      ROUGHNESS = float(0.05);
    //    CLEARCOAT = float(0.99);
    //    CLEARCOAT_GLOSS = float(1.0);
      ALBEDO = color.rgb;
      ALPHA = color.a;
    }
    

    Its just a simple vertex waveform and needs a vertex dense grid mesh. But its a quick hack job so, like, eh. I do intend to make a proper water shader at some point but I need to familiarize myself with the new shader system more first. Have gotten too used to nodal graph shaders.

    This is a start, changing the camera angle the effect stops working.

  • MegalomaniakMegalomaniak Posts: 2,580Admin

    That looks like you need to tweak the uniforms(from the material interface). If you are willing to share the scene/project I can try to tweak them myself and/or debug it.

  • MagicLordMagicLord Posts: 578Unconfirmed

    @Megalomaniak said:
    That looks like you need to tweak the uniforms(from the material interface). If you are willing to share the scene/project I can try to tweak them myself and/or debug it.

    Download demo
    https://upload.cat/781515baa90f24cf]( https://upload.cat/781515baa90f24cf " https://upload.cat/781515baa90f24cf")

    I would be interested in a shader working with planes instead of dense vertex grids. The water effects could be done blending two normal maps through time with linear values or using some atlas normal map animation.

  • MegalomaniakMegalomaniak Posts: 2,580Admin
    edited January 2018 Accepted Answer

    Looking at your 'water plane' scene it has more going on than needs, seems to be to-do with the dae importer I guess.

    Anyways. I created a meshinstance with a plane mesh node as a comparison/control measure and a new material for both(not each) planes(yours and mine) and saved the material to a file, then gave the material a new shader(again saved to file), pasted the above shader code, reformatted it a bit since the forums code tag messes up the indentation(although that shouldn't affect the functionality) and then I actually tweaked the shader parameters:

    Here is how the water looks in the level with these parameters:

    Now since I've set the flow direction to be along X axis a lot of the polygons could be removed because in this instance only mesh density along X affects the visual result.

    Next step would be to add a Boolean check to enable/disable the vertex waveform. And then add a UV scrolling function which could be used to animate/scroll a tiling bump/normalmap. As I mentioned earlier I do intend to create a more complex water shader. This was just a quick hack for a starting point so you could have a placeholder. ;)

    PS. holy he... ...llo. Those blue floating spheres are very wasteful in terms of polys. Seriously, just one is 27024 vertices.

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.