Hi, I'm new here and wondered if anyone had any info about rendering underwater (preferably with caustics)
so far I have this in the update loop to add bloom and depth of field and I added a dark gradient to the skybox
if(waterEffectRenderPass.getWaterPlane().pseudoDistance(cam.getLocation()) > 0)
{
UWdofPass.setEnabled(false);
UWbloomPass.setEnabled(false);
}
else
{
UWdofPass.setEnabled(true);
UWbloomPass.setEnabled(true);
}
I have this in the init function
UWdofPass = new DepthOfFieldRenderPass(cam, 1);
UWdofPass.setBlurSize(UWdofPass.getBlurSize() + 0.01f);
if (!UWdofPass.isSupported()) {
Text t = Text.createDefaultTextLabel("Text",
"GLSL Not supported on this computer.");
t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
t.setLightCombineMode(LightCombineMode.CombineClosest);
t.setLocalTranslation(new Vector3f(0, 20, 0));
statNode.attachChild(t);
} else {
UWdofPass.add(rootNode);
pManager.add(UWdofPass);
}
UWbloomPass = new BloomRenderPass(cam, 4);
if(!UWbloomPass.isSupported()) {
Text t = Text.createDefaultTextLabel("Text", "GLSL Not supported on this computer.");
t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
t.setLightCombineMode(LightCombineMode.Off);
t.setLocalTranslation(new Vector3f(0,20,0));
statNode.attachChild(t);
} else {
UWbloomPass.add(rootNode);
UWbloomPass.setUseCurrentScene(true);
pManager.add(UWbloomPass);
}
and I have obviously scoped the private vars UWbloomPass and UWdofPass appropriately, lol It looks really naff but it's something similar to what the unity boys and gals are doing and looks good in the island demo, I'm assuming caustics will require a shader and or light source such as the sun and am looking to add this in the future just I like to do one thing at a time, please help me so I can continue to try and contrib to jME
Screenies
http://picasaweb.google.com/lh/photo/CKcDgGhcOispHAgoMnDyiQ?feat=directlink
http://picasaweb.google.com/lh/photo/vvpFeOkuDil_N9adsJEaIA?feat=directlink
EDIT: NOT EVEN A COMMENT???
remove the bloom effect and use this beauty
colorchange.java
package jmetest.effects.water;
import com.jme.image.Texture;
import com.jme.image.Texture2D;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.TextureRenderer;
import com.jme.renderer.pass.Pass;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
public class colorchange extends Pass{
/**
*
*/
private static final long serialVersionUID = 1L;
private Camera cam;
private GLSLShaderObjectsState Shader;
private Quad fullScreenQuad;
DisplaySystem display;
private TextureRenderer tRenderer;
/** The final resulting texture to be splatted across the screen */
private Texture2D resultTexture;
/** The copy of the screen */
private Texture2D screenTexture;
public colorchange( Camera cam ) {
this.cam = cam;
display = DisplaySystem.getDisplaySystem();
tRenderer = display.createTextureRenderer(
display.getWidth(), display.getHeight(),
TextureRenderer.Target.Texture2D);
tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
tRenderer.setCamera(cam);
screenTexture = new Texture2D();
screenTexture.setWrap(Texture.WrapMode.Clamp);
tRenderer.setupTexture(screenTexture);
resultTexture = new Texture2D();
resultTexture.setWrap(Texture.WrapMode.Clamp);
resultTexture
.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
tRenderer.setupTexture(resultTexture);
fullScreenQuad = new Quad("FullScreenQuad", display.getWidth() / 4,
display.getHeight() / 4);
fullScreenQuad.getLocalRotation().set(0, 0, 0, 1);
fullScreenQuad.getLocalTranslation().set(display.getWidth() / 2,
display.getHeight() / 2, 0);
fullScreenQuad.getLocalScale().set(1, 1, 1);
fullScreenQuad.setRenderQueueMode(Renderer.QUEUE_ORTHO);
fullScreenQuad.setCullHint(Spatial.CullHint.Never);
fullScreenQuad
.setTextureCombineMode(Spatial.TextureCombineMode.Replace);
fullScreenQuad.setLightCombineMode(Spatial.LightCombineMode.Off);
TextureState ts = display.getRenderer().createTextureState();
ts.setEnabled(true);
fullScreenQuad.setRenderState(ts);
BlendState as = display.getRenderer().createBlendState();
// no blending, result texture has to overwrite screen - not blend!
as.setTestEnabled(true);
as.setTestFunction(BlendState.TestFunction.GreaterThan);
as.setEnabled(true);
fullScreenQuad.setRenderState(as);
fullScreenQuad.updateRenderState();
fullScreenQuad.updateGeometricState(0.0f, true);
Shader = display.getRenderer().createGLSLShaderObjectsState();
Shader.load(
"varying vec2 vTexCoord;"+
"void main(void)"+
"{"+
" vec2 Pos = sign(gl_Vertex.xy);"+
" gl_Position = vec4(Pos.xy, 0, 1);"+
" vTexCoord.x = 0.5 * (1.0 + Pos.x);"+
" vTexCoord.y = 0.5 * (1.0 + Pos.y);"+
"}"
,
"uniform sampler2D scene;"+
"varying vec2 vTexCoord;"+
"void main()"+
"{"+
" vec4 sum = texture2D(scene, vTexCoord);"+
" if((sum.b < sum.r) && (sum.b < sum.g)){"+
" if(sum.r >= 0.05){ sum.r -= 0.05; }"+
" if(sum.g >= 0.05){ sum.g -= 0.03; }"+
" if(sum.b <= 0.8){ sum.b += 0.15; }"+
" }"+
" sum.a = 1.0;"+
"gl_FragColor = sum;"+
"}"
);
Shader.setEnabled(true);
}
@Override
protected void doRender(Renderer r) {
BlendState as = (BlendState) fullScreenQuad.states[RenderState.StateType.Blend.ordinal()];
TextureState ts = (TextureState) fullScreenQuad.states[RenderState.StateType.Texture.ordinal()];
as.setEnabled(false);
// rendering the screen
tRenderer.copyToTexture(screenTexture, DisplaySystem
.getDisplaySystem().getWidth(), DisplaySystem
.getDisplaySystem().getHeight());
fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = Shader;
r.draw(fullScreenQuad);
}
}
link colorchange to your project and then in the game init before adding blur try this
UWcc = new colorchange(cam);
UWcc.add(rootNode);
pManager.add(UWcc);
declare
private colorchange UWcc;
and then where bloom change UWbloomPass to UWcc
UWcc.setEnabled(true)
should work minus caustics now ;)
That looks really good! How about adding some blue fog, maybe bubbles? I think you got the water effect perfect then.
For caustics, you can generate an animated texture and tile it over the ground, use this tool:
http://www.dualheights.se/caustics/
it does make the scene more blue but I decided to remove caustics because my fps suffered, I'm quite happy with the non-realistic approach to underwater and if I need caustics I can simply alpha blend the texture of the waves and project that texture 
that looks very nice, when i have time, i'll add this to the TestIsland example
As far as i see, you first create a full screen texture, and then in the fragment shader, check and adjust the color of the fragment depending on the color of the texture.
Would it not be more efficient to only check and adjust the color of the fragment without creating a texture first ?
i just thought, you could adjust the color without creating fullscreen textures, but i might be wrong, i really dont know much about shaders. 