# 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 {

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