Underwater effects for jME

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 ;)

Screenshots plz?  XD

http://picasaweb.google.co.uk/lh/photo/4IzYaYckPSrpJUoy6yAZaA?feat=directlink

http://picasaweb.google.co.uk/lh/photo/1AhcEWej8JlpbN6GYZZKrg?feat=directlink



screenies are broken for me so here are two links hosted on my friends account

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 :wink:

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. :slight_smile: