Water rendering using Sine waves and GLSL shaders

I’ve rarely used GLSL shaders before and am trying to make some real-ish looking water in JMonkeyEngine using sine waves and GLSL shaders. I used f(x,t)=asin(xw+t*p) where x is the coordinate, w is frequency a is amplitude, t is time and p is phase shift, I then took 3 of these and took the sum to get a final height value for each vertex coordinate. My fragment Shader is very simple and just makes everything blue for now (I plan on adding some stuff later when it renders properly). I was too lazy (and didn’t have the knowledge of GLSL) to write this on my own so I asked chatGPT to write it.
This is the Vertex shader it spat out.



// Input vertex position from vertex array
attribute vec3 inPosition;

// Uniform variables for wave parameters
uniform float g_Time;    // Time variable for animation
uniform float amplitude1;
uniform float frequency1;
uniform float phase1;

uniform float amplitude2;
uniform float frequency2;
uniform float phase2;

uniform float amplitude3;
uniform float frequency3;
uniform float phase3;

// Output position for the fragment shader
varying vec3 fragPos;

void main()
{
    // Calculate the wave offsets for x and y axes
    float wave1 = amplitude1 * sin(inPosition.x * frequency1 + g_Time * phase1);
    float wave2 = amplitude2 * sin(inPosition.y * frequency2 + g_Time * phase2);
    float wave3 = amplitude3 * sin(inPosition.x * frequency3 + inPosition.y * frequency3 + g_Time * phase3);

    // Sum the wave offsets
    float wave = wave1 + wave2 + wave3;

    // Apply the wave offset to the z-coordinate of the vertex position
    vec3 pos = inPosition;
    pos.y += wave; // Assuming y is the up-axis in a 3D space

    // Set the final vertex position
    gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0);

    // Pass the position to the fragment shader
    fragPos = pos;
}

I implemented it like this in my code

 public void setUpWater(){
        waterGeom = new Geometry("waterGeo", new Box(10,1,10));
        waterGeom.setLocalTranslation(0,-10,0);
        waterMaterial = new Material(assetManager, "MatDefs/water.j3md");

        waterMaterial.setFloat("amplitude1", 0.5f);
        waterMaterial.setFloat("frequency1", 2.0f);
        waterMaterial.setFloat("phase1", 1.0f);

        waterMaterial.setFloat("amplitude2", 0.3f);
        waterMaterial.setFloat("frequency2", 1.5f);
        waterMaterial.setFloat("phase2", 0.8f);

        waterMaterial.setFloat("amplitude3", 0.2f);
        waterMaterial.setFloat("frequency3", 1.0f);
        waterMaterial.setFloat("phase3", 1.2f);

        waterMaterial.setColor("Color", ColorRGBA.Blue);

        waterGeom.setMaterial(waterMaterial);
        rootNode.attachChild(waterGeom);
    }
// some more of my code
    public void simpleUpdate(float tpf) {
        float time = getTimer().getTimeInSeconds();
        waterMaterial.setFloat("g_Time", time);
    //rest of my update function
   }

water.j3md

MaterialDef Water {
    MaterialParameters {
        Float g_Time
        Float amplitude1
        Float frequency1
        Float phase1

        Float amplitude2
        Float frequency2
        Float phase2

        Float amplitude3
        Float frequency3
        Float phase3
    }

    Technique {
        VertexShader GLSL100: Shaders/water.vert
        FragmentShader GLSL100: Shaders/water.frag

        WorldParameters {
            WorldViewProjectionMatrix
        }
    }
}

is there anything I am doing wrong or that says why this doesn’t render? I do call setUpWater() in my simpleInitApp() function
all help is appreciated!

Does it render if you use a standard unshaded material?

Uniforms that are from material parameters need to have an “m_” prefix. Also, it is best practice, although probably not required, to have material parameter names capitalized.

To be honest, it will probably be easier to find an existing simple shader and tweak it towards your goal rather than use the ‘nice looking nonsense’ that chatGPT generates.

Fork Unshaded.j3md, strip out the stuff you don’t need until you have something working that draws a colored mesh on the screen… then iterate from there using the other JME shaders as examples.

…the end result will be much more satisfying, anyway.

1 Like

I’ll try that, i could learn GLSL anyways, it would be usefull later