Low-cost ripples

Hi. I would need to make some kind of ripples (small waves) effect on a water/mud plane.

I wonder what would be the cheapest way to achieve this. This is just eye candy, and I don’t want to burden the CPU or the GPU.
For the moment, my water is just a big unshaded quad, with lightmap to implement fog-of-war.

Any input is appreciated.

P.S. : This is not yet troubleshooting, but I didn’t find a better place to put this. Feel free to move it if necessary ;-).
I cannot remove the “support topic” either…

Do you want a visual deformation of the mesh, or just a color effect on the quad? Either way, a shader is probably the way to go.

There will be plenty of these online, I think @t0neg0d may have posted code for some as well.

Mesh deformation won’t work, unless you use a grid mesh with a fair amount of subdivision.

The cheapest way imo is normal mapping. Have a ripple normal map, set it to repeat and offset it over time to give the impression that it’s animated.
This won’t give you big waves though, just tiny ripples.

The simple water does that btw, maybe you could look in to it.

In fact, since it’s currently unshaded you could do it with a single texture for the ripples and animate it. Bonus points for sampling the texture at two resolutions and overlaying them for a cooler effect. :slight_smile:

You could just fork Unshaded and monkey with the .frag file.

The tick is that I don’t know precisely where the ripple will occur…

A normal map would probably make it; however, how could I animate it, or even offset it ?

Btw, I have absolutely no idea of what a shader is made of…

My 2 cents:

A mesh you can add/remove quads to and apply the technique @nehon described.

It will take a bit of learning as you’ll need to have a basic grasp of either a) batchNode + shaders or b) the Mesh class + shaders.

You can get the deform effect from either the water filter or I have a deform shader around here some place with texture deforms that produce ripple effects that you can set the x/y center point on. Though it would need to be adjusted to apply strength based on distance from the start point.

I’m interested in seeing the final of whatever you do. I think it was… um… TitanQuest that used this technique for placing ripples in water behind the characters as they walk through it. Was really cool looking =)

@yang71 said: The tick is that I don't know precisely where the ripple will occur...

A normal map would probably make it; however, how could I animate it, or even offset it ?

Btw, I have absolutely no idea of what a shader is made of…

A basic version would not be hard. And you get to jump into the deep and wonderful (and frightening) world of shader creation. :wink:

Copy Unshaded.j3md, Unshaded.vert, and Unshaded.frag to your own shader name. Maybe (in your project), assets/MatDefs/Water.j3md, Water.vert, and Water.frag. The originals live here: http://code.google.com/p/jmonkeyengine/source/browse/#svn%2Ftrunk%2Fengine%2Fsrc%2Fcore-data%2FCommon%2FMatDefs%2FMisc

Edit Water.j3md to refer to your vertex and fragment shaders. Also, to the world parameters for the first technique add Time. It will then look like:
[java]
WorldParameters {
WorldViewProjectionMatrix
Time
}
[/java]

To Water.frag, near the top add the float g_Time uniform.

Replace this line:
[java]color *= texture2D(m_ColorMap, texCoord1);[/java]

With something like:
[java]color *= texture2D(m_ColorMap, texCoord1 + vec2(g_Time, 0.0));[/java]

Now if you use your j3md instead of the Unshaded one, your texture should slide right (pretty fast probably). Scale the g_Time value of the vec2 down to achieve a slower rate.

That’s the basics. Once you’re in you can do more complicated things like sampling the texture twice at two resolutions and multiplying them together.
Like, add a second line after the one above:
[java]color *= texture2D(m_ColorMap, 0.1 * (texCoord1 + vec2(g_Time, 0.0));[/java]

Presuming your texture already repeats across your quad that should result in little waves on top of 10x bigger waves. Vary the g_Time scaling for each one and you should get a pretty neat effect. It may even be ok as is if you slow them both down. That is the bottomless pit of shader tweaking. :slight_smile:

…without adding extra quads to your scene.

2 Likes

@t0neg0d : I cannot see where batchnodes are needed there, sorry.

I don’t know anything about shaders (I tried but it seemed so complicated I delayed it). I’ve stored a few links @Nehon did provide for learning…

I’m really interested in your solution to add some ripples based on the center. That’s just what I need ;-).

As for my project, I’m working on a clone of Moonbase Commander. This is still much WIP.
When I land something into water, it simply disappears… Not nice. I thought the ripple effect would enhance it. Maybe some splash, but this looks easy.

It seems I really need to learn shaders now… Postponing indefinitely may be not a good solution.

@Pspeed : Thanks a lot. Here are a few precise leads I can follow. I’ll have a look at this and keep you posted.

Many thanks !

@yang71 said: When I land something into water, it simply disappears... Not nice. I thought the ripple effect would enhance it. Maybe some splash, but this looks easy.

Ah… that’s a slightly different kind of ripple effect to what I was thinking.

Anyway, try out my shader ideas and then you will have your feet wet at least… :wink:

Ok, thanks @Pspeed. I’ve managed to scroll my texture based on time as you adviced me.

It seems so simple… What I cannot understand, yet, is that it seems we manipulate whole textures in a line. Is it possible to manipulate it based on world coordinates? Or maybe based on texture coordinates ?

I guess it’s time for me to read on…

@yang71 said: Ok, thanks @Pspeed. I've managed to scroll my texture based on time as you adviced me.

It seems so simple… What I cannot understand, yet, is that it seems we manipulate whole textures in a line. Is it possible to manipulate it based on world coordinates? Or maybe based on texture coordinates ?

I guess it’s time for me to read on…

In the one line, I’m just adjusting the texture coordinate based on time. The sky is the limit on what you can do from there… depending on how deeply you want to dive.

Many thanks, again !
I succeeded :D. It’s quite easy when understood the basic principles : the shader is called for each pixel ! Thanks also for the wiki : https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shaders

Here is my shader ; feel free to comment.

#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
#define NEED_TEXCOORD1
#endif

uniform vec4 m_Color;
uniform sampler2D m_ColorMap;
uniform sampler2D m_LightMap;
varying vec2 texCoord1;
varying vec2 texCoord2;
varying vec4 vertColor;

uniform float g_Time;
varying vec3 pos;
uniform float m_Cx,m_Cy,m_Cz;
uniform float m_Tref;

void main(){
vec4 color = vec4(1.0);

#ifdef HAS_COLORMAP
    float dx = pos.x-m_Cx;
    float dy = pos.y-m_Cy;
    float dz = pos.z-m_Cz;
    float dist = sqrt(1+dx*dx+dy*dy+dz*dz);
    float ang = (g_Time-10-m_Tref + 10/dist);
    if ((ang  0.5))
      ang = 0;
    float f = sin(3*6.28*ang);
    color *= texture2D(m_ColorMap, texCoord1)*(1-f*f/dist);
#endif

#ifdef HAS_VERTEXCOLOR
    color *= vertColor;
#endif

#ifdef HAS_COLOR
    color *= m_Color;
#endif

#ifdef HAS_LIGHTMAP
    #ifdef SEPARATE_TEXCOORD
        color.rgb *= texture2D(m_LightMap, texCoord2).rgb;
    #else
        color.rgb *= texture2D(m_LightMap, texCoord1).rgb;
    #endif
#endif

gl_FragColor = color;

}

When I want to build water rings, I just set Cx, Cy and Cz to the center of the desired rings; and Tref to the current time (in seconds).
Then it builds 3 rings that attenuate progressively as they go farther.

2 Likes