The WaterRenderPass slows down my game too much, I think, so here's a little something I threw together with the help of MrCoder and a few other of the jME forum-goers.
This code reflects the changes suggested below (as of July 25th, 2008 at 1:03 PM)
TestTranslucentWater.java:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package testtranslucentwater;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.RawHeightMap;
/**
*
* @author Tyler
*/
public class TestTranslucentWater extends SimpleGame
{
private Quad waterQuad; //The quad (which will behave like a plane) that we will consider our water.
private TextureState waterTex; //The TextureState for applying the textures.
private Texture waterTexture1; //The first water texture
private Texture waterTexture2; //The second water texture
public static void main(String args[])
{
TestTranslucentWater app = new TestTranslucentWater(); //Usual startup methods...
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
@Override
protected void simpleInitGame()
{
createTerrain(); //Set up our terrain and put our camera above-ground.
createLighting(); //Make our lighting better so we can see.
/* BEGIN WATER IMPLEMENTATION */
waterQuad = new Quad("water quad", 10240, 10240); //Sets up our quad. We'll have it be the size of 100 tiles, to make it look infinite.
waterTex = display.getRenderer().createTextureState(); //Initialize our TextureState
flipQuad(waterQuad); //Quads start facing up, we need to flip this.
//These will assign our textures....
waterTexture1 = TextureManager.loadTexture(TestTranslucentWater.class.getClassLoader().getResource("water1.jpg"), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
waterTexture2 = TextureManager.loadTexture(TestTranslucentWater.class.getClassLoader().getResource("water2.jpg"), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
waterTexture1.setWrap(Texture.WM_WRAP_S_WRAP_T);
//Scale our textures to make them look better, along with wrapping so they don't "fall off" the quad.
waterTexture1.setScale(new Vector3f(100f, 100f, 1f));
waterTexture1.setWrap(Texture.WM_WRAP_S_WRAP_T);
waterTexture2.setScale(new Vector3f(100f, 100f, 1f));
waterTexture2.setWrap(Texture.WM_WRAP_S_WRAP_T);
//Assign our Textures to our TextureState
waterTex.setTexture(waterTexture1, 0);
waterTex.setTexture(waterTexture2, 1);
//Make our quad transparent and assign the TextureState
waterQuad.setRenderState(makeAlphaForTransparency());
waterQuad.setRenderState(waterTex);
//We need to make sure the quad is rendered after the land. QUEUE TRANSPARENT!
waterQuad.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
waterQuad.setLightCombineMode(0);
//Set up our position (i.e. the height of the water at 10)
waterQuad.setModelBound(new BoundingBox());
waterQuad.setLocalTranslation(new Vector3f(0,10, 0));
//The usual
waterQuad.updateModelBound();
waterQuad.updateRenderState();
//Avoids NPE's when we do our first update!
waterTexture1.setTranslation(new Vector3f(0,0,0));
waterTexture2.setTranslation(new Vector3f(0,0,0));
rootNode.attachChild(waterQuad);
}
protected void simpleUpdate()
{
updateWater();
}
private void updateWater()
{
//Prepares our Vector3f
Vector3f tex1, tex2;
tex1 = waterTexture1.getTranslation();
tex2 = waterTexture2.getTranslation();
//These are to keep the float from getting too big. They offer the possibility of a jump, but nobody should notice.
if(tex1.getX() > 1000)
waterTexture1.setTranslation(new Vector3f(0,0,0));
if(tex2.getZ() > 1000)
waterTexture2.setTranslation(new Vector3f(0,0,0));
//Moves our water, nice and slowly.
tex1.x += .04 * tpf;
tex2.y += .09 * tpf;
//The usual.
waterQuad.updateRenderState();
waterQuad.updateGeometricState(tpf, true);
}
private AlphaState makeAlphaForTransparency()
{
AlphaState as1 = display.getRenderer().createAlphaState();
as1.setBlendEnabled(true);
as1.setSrcFunction(4);
as1.setTestEnabled(true);
as1.setTestFunction(4);
as1.setDstFunction(2);
return as1;
}
private void flipQuad(Spatial s)
{
Quaternion rotQuad = new Quaternion();
rotQuad = rotQuad.fromAngleNormalAxis(FastMath.PI * .5f, Vector3f.UNIT_X);
s.setLocalRotation(rotQuad);
}
private void createTerrain()
{
Vector3f terrainScale = new Vector3f(8f, .001f, 8f);
RawHeightMap map = new RawHeightMap(TestTranslucentWater.class.getClassLoader().getResource("0.raw"), 129, RawHeightMap.FORMAT_16BITLE, true);
TerrainPage page = new TerrainPage("mypage", 33, map.getSize(), terrainScale, map.getHeightMap(), false);
page.setDetailTexture(1,1);
TextureState ts = display.getRenderer().createTextureState();
Texture t0 = TextureManager.loadTexture(TestTranslucentWater.class.getClassLoader().getResource("grass.jpg"), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
t0.setApply(Texture.AM_MODULATE);
t0.setScale(new Vector3f(100.0f, 100.0f, 1.0f));
ts.setTexture(t0);
page.setRenderState(ts);
rootNode.attachChild(page);
cam.setLocation(new Vector3f(0f, page.getHeightFromWorld(new Vector3f(0, 0, 0)) + 5f, 0));
}
private void createLighting()
{
lightState.detachAll();
DirectionalLight light = new DirectionalLight();
light.setDirection(new Vector3f(.5f, -.75f, 0f));
light.setAmbient(ColorRGBA.white);
light.setDiffuse(ColorRGBA.white);
light.setEnabled(true);
lightState.attach(light);
}
}
That's the source for slow-moving texture-based water (transparent, too!).
Here is a ZIP'd archive of the NetBeans project folder, along with a folder called "rsrc" that contains the textures I used (found them at ShareCG) in the test. If you open the NetBeans project folder, don't bother using the rsrc folder, NetBeans will know where to look. The rsrc folder is for all of you *cringes* Eclipse users.