ProjectedGrid and legacy water effects from jME 2

I have downloaded the original code for the projectedgrid water from

again and put it in a project in JME. Unfortunately, this shows the same result. So, it seems it has nothing to do with parameters. My first guess would be that the code is not compatible with the lates JME build anymore?

Not sure though where to start looking… Shaders are not exactly my expertise (read: I never played around with them at all).

Maybe we imported something wrong when converting it from the original code?

I can chime in, as we are using this code as well. We’re also having the size problems as in @TastyLemons video with reflections of geometry on the water surface. Unfortunately the shader code is so damn convoluted I can’t make much sense of it.

I’m looking at this currently at work, I can post what I find here. I’m definitely thinking of replacing the frag and vert shaders used for drawing foam and reflections, because the code is just too … ancient Egyptian algebra to get around, and I want to expose certain shader parameters to the application so as to be able to manipulate them runtime, such as foam on/off, wireframe on/off, reflection on/off, reflection intensity, etc.

I have found the solution to the reflection/refraction issue. You need to specify that the reflection/refraction cameras should not use parallel projection. Parallel projection seems to be the default setting for the Camera class now.

In the ProjectedWaterProcessorWithRefraction class, createPreViews() method:

[java]
protected void createPreViews() {
reflectionCam = new Camera(renderWidth, renderHeight);
reflectionCam.setParallelProjection(false);
refractionCam = new Camera(renderWidth, renderHeight);
refractionCam.setParallelProjection(false);
[/java]

2 Likes

Tried it out. Worked!. Nice find.

Hopefully @matthias can be reached to apply these fixes to his own repo, but if not then someone should just fork it. Actually, no reason not to fork it right away now and submit a pull request.

Seems he’s alive and well :smiley: Fix was applied:

I have made an update to the code mainly to improve the below sea level view. The idea is to use the refraction camera below sea level instead of the reflection camera (caused weird effects when there were objects above sea level).

It also fixes a small issue with the refraction when objects are partially submerged in water for the surface view (could see some black colored refractions close to the object when waves move the water above the xz-plane).

I’ll just post the necessary changes here since i have not taught myself how to update github etc.

[java]
public class TestProjectedGridWithProjectedWater extends SimpleApplication {

// new object declarations
private WaterHeightGenerator waterHeightGenerator;
private Material gridMaterial;

// Modification to simpleInitApp()
@Override
public void simpleInitApp() {
	...
	waterHeightGenerator = new WaterHeightGenerator();
    grid = new MyProjectedGrid(timer, cam, 100, 70, 0.02f, waterHeightGenerator);
    projectedGridGeometry = new Geometry("Projected Grid", grid);  // create cube geometry from the shape
    projectedGridGeometry.setCullHint(CullHint.Never);
    gridMaterial = setWaterProcessor();
    projectedGridGeometry.setMaterial(gridMaterial);
    projectedGridGeometry.setLocalTranslation(0, 0, 0);
    rootNode.attachChild(projectedGridGeometry);

@Override
public void simpleUpdate(float tpf) {
	//Determine if camera is above or below sea level
    if (cam.getLocation().y > waterHeightGenerator.getHeight(cam.getLocation().x, cam.getLocation().z, timer.getTimeInSeconds())) {
        gridMaterial.setBoolean("abovewater", true);
    } else {
        gridMaterial.setBoolean("abovewater", false);
    }[/java] 

[java]
public class ProjectedWaterProcessorWithRefraction implements SceneProcessor {

public class RefractionProcessor implements SceneProcessor {

public void preFrame(float tpf) {
// Commented line to be able to look up from the water using refractionCam.
// Line also caused some weird artifacts in surface view on objects partially submerged in water.
//refractionCam.setClipPlane(refractionClipPlane, Plane.Side.Negative);//,-1
}[/java]

projectedwatershader_refraction.frag:
[java]
void main()
{

projCoordDepth += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
projCoordDepth = clamp(projCoordDepth, 0.001, 0.999);

//Calculation of refractionColor moved here to be able to use it both above and below water
vec4 refractionColor = texture2D(m_refraction, projCoordDepth);
float depth = texture2D(m_depthMap, projCoordDepth).r;
depth = pow(depth,15.0);
float invDepth = 1.0-depth;

vec4 reflectionColor = texture2D(m_reflection, projCoord);
if ( m_abovewater == false ) {
	//Use refractionColor instead of reflectionColor below water
	vec4 endColor = mix(refractionColor,m_waterColor,fresnelTerm);
	gl_FragColor = mix(endColor,m_waterColor,fogDist);
}
else {
	vec4 waterColorNew = mix(m_waterColor,m_waterColorEnd,fresnelTerm);
	vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);


	float foamVal = (vVertex.y-vVertex.w) / (m_amplitude * 2.0);
	foamVal = clamp(foamVal,0.0,1.0);
	vec4 foamTex = texture2D(m_foamMap, foamCoords + vnormal * 0.6 + normalVector.xy * 0.05 );
	float normLength = length(vnormal*5.0);
	foamVal *= 1.0-normLength;
	foamVal *= foamTex.a;
	endColor = mix(endColor,foamTex,clamp(foamVal,0.0,0.95));

    //Code moved before the if statement
    //vec4 refractionColor = texture2D(m_refraction, projCoordDepth);
    //float depth = texture2D(m_depthMap, projCoordDepth).r;
    //depth = pow(depth,15.0);
    //float invDepth = 1.0-depth;

	endColor = refractionColor*vec4(invDepth*fresnel) + endColor*vec4(depth*fresnel);
	if( m_useFadeToFogColor == false) {
		gl_FragColor = endColor + reflectionColor * vec4(fresnelTerm);
	} else {
		gl_FragColor = (endColor + reflectionColor * vec4(fresnelTerm)) * (1.0-fogDist) + gl_Fog.color * fogDist;
	}
}[/java]
1 Like

It turns out that the change in the above post causes another issue. Because geometries above the xz plane are no longer clipped in the refraction view, the geometries will be drawn on the water surface even if they are above water. The refraction drawings will be painted on the water behind the geometries themselves, but can become visible around the edges of the geometry depending on the wave state.

1 Like

If you specify that the nearest pixel should be read from the refraction textures, the white “frame” that sometimes is seen around objects below water will disappear.

[java]
protected void createTextures() {
reflectionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
reflectionTexture.setWrap(Texture.WrapMode.Repeat);
refractionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
refractionTexture.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
refractionTexture.setMagFilter(Texture.MagFilter.Nearest);
depthTexture = new Texture2D(renderWidth, renderHeight, Format.Depth);
depthTexture.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
depthTexture.setMagFilter(Texture.MagFilter.Nearest);
}
[/java]
The quality of the refraction is decided by the renderWidth and renderHeight in ProjectedWaterProcessorWithRefraction.

1 Like