Why is this flickering? (StandardGame w/Passes)

Summary:  I am trying to combine the pass architecture of SimplePassGame with the use of GameStates.  My game extends StandardGame.  It works… but it flickers when the camera moves.





I made a class that returns a spatial. The following code generates a spatial in much the same way that TestIsland.java does.

If you are familiar with TestIsland, this should look familiar. I realize it is a lot of code, but sorry. More to follow after code block.



public Spatial createTerrain() {

        RawHeightMap heightMap = new RawHeightMap(this.getClass().getClassLoader().getResource(
"data/texture/terrain/heights.raw").getFile(), 129,
                RawHeightMap.FORMAT_16BITLE, false);

        Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
        heightMap.setHeightScale(0.001f);
        TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
                terrainScale, heightMap.getHeightMap(), false);
        page.getLocalTranslation().set(0, 10, 0);
        page.setDetailTexture(1, 1);

        // create some interesting texturestates for splatting
        TextureState ts1 = createSplatTextureState(
                "data/texture/terrain/baserock.jpg", null);

        TextureState ts2 = createSplatTextureState(
                "data/texture/terrain/darkrock.jpg",
                "data/texture/terrain/darkrockalpha.png");

        TextureState ts3 = createSplatTextureState(
                "data/texture/terrain/deadgrass.jpg",
                "data/texture/terrain/deadalpha.png");

        TextureState ts4 = createSplatTextureState(
                "data/texture/terrain/nicegrass.jpg",
                "data/texture/terrain/grassalpha.png");

        TextureState ts5 = createSplatTextureState(
                "data/texture/terrain/road.jpg",
                "data/texture/terrain/roadalpha.png");

        TextureState ts6 = createLightmapTextureState("data/texture/terrain/lightmap.jpg");

        // alpha used for blending the passnodestates together

        AlphaState as = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
        as.setBlendEnabled(true);
        as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
        as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
        as.setTestEnabled(true);
        as.setTestFunction(AlphaState.TF_GREATER);
        as.setEnabled(true);

        // alpha used for blending the lightmap
        AlphaState as2 = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
        as2.setBlendEnabled(true);
        as2.setSrcFunction(AlphaState.SB_DST_COLOR);
        as2.setDstFunction(AlphaState.DB_SRC_COLOR);
        as2.setTestEnabled(true);
        as2.setTestFunction(AlphaState.TF_GREATER);
        as2.setEnabled(true);

        // //////////////////// PASS STUFF START
        // try out a passnode to use for splatting
        PassNode splattingPassNode = new PassNode("SplatPassNode");
        splattingPassNode.attachChild(page);

        PassNodeState passNodeState = new PassNodeState();
        passNodeState.setPassState(ts1);
        splattingPassNode.addPass(passNodeState);

        passNodeState = new PassNodeState();
        passNodeState.setPassState(ts2);
        passNodeState.setPassState(as);
        splattingPassNode.addPass(passNodeState);

        passNodeState = new PassNodeState();
        passNodeState.setPassState(ts3);
        passNodeState.setPassState(as);
        splattingPassNode.addPass(passNodeState);

        passNodeState = new PassNodeState();
        passNodeState.setPassState(ts4);
        passNodeState.setPassState(as);
        splattingPassNode.addPass(passNodeState);

        passNodeState = new PassNodeState();
        passNodeState.setPassState(ts5);
        passNodeState.setPassState(as);
        splattingPassNode.addPass(passNodeState);

        passNodeState = new PassNodeState();
        passNodeState.setPassState(ts6);
        passNodeState.setPassState(as2);
        splattingPassNode.addPass(passNodeState);
        ////////////////////// PASS STUFF END

        // lock some things to increase the performance
        splattingPassNode.lockBounds();
        splattingPassNode.lockTransforms();
        splattingPassNode.lockShadows();

        return splattingPassNode;
    }

    private TextureState createSplatTextureState(String texture, String alpha) {
        TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();

        Texture t0 = TextureManager.loadTexture(MyGame.class
                .getClassLoader().getResource(texture),
                Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
        t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
        t0.setApply(Texture.AM_MODULATE);
       
        t0.setScale(new Vector3f(globalSplatScale, globalSplatScale, 1.0f));
        ts.setTexture(t0, 0);

        if (alpha != null) {
            addAlphaSplat(ts, alpha);
        }

        return ts;
    }
   
    private void addAlphaSplat(TextureState ts, String alpha) {
        Texture t1 = TextureManager.loadTexture(MyGame.class
                .getClassLoader().getResource(alpha), Texture.MM_LINEAR_LINEAR,
                Texture.FM_LINEAR);
        t1.setWrap(Texture.WM_WRAP_S_WRAP_T);
        t1.setApply(Texture.AM_COMBINE);
        t1.setCombineFuncRGB(Texture.ACF_REPLACE);
        t1.setCombineSrc0RGB(Texture.ACS_PREVIOUS);
        t1.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
        t1.setCombineFuncAlpha(Texture.ACF_REPLACE);
        ts.setTexture(t1, ts.getNumberOfSetTextures());
    }
   
   

    private TextureState createLightmapTextureState(String texture) {
        TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();

        Texture t0 = TextureManager.loadTexture(MyGame.class
                .getClassLoader().getResource(texture),
                Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
        t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
        ts.setTexture(t0, 0);

        return ts;
    }




Ok, so that makes a PassNode which ISA Spatial.  Next comes my game class. It extends StandardGame instead of SimplePassGame.  I've dug through these and it looks like the main difference is that SimplePassGame has a BasicPassManager that does some stuff. I added a BasicPassManager to StandardGame, and do all of the things that SimplePassGame does to it.



public class MyStandardGame extends StandardGame {
private MyGameState gameState;
private BasicPassManager pManager;


    public MyStandardGame(String gameName) {
super(gameName);
}

    protected void initGame(){
    pManager = new BasicPassManager();
    super.initGame();
    display.setTitle("Test Terrainsplatting");
   
    // Create a DebugGameState
    createGameState();
    setupEnvironment();
   
    //tm returns a Spatial
    TerrainManager tm = new TerrainManager();
    Spatial terrain = tm.createTerrain();
    gameState.getRootNode().attachChild(terrain);
    gameState.getRootNode().updateRenderState();
   
    RenderPass rootPass = new RenderPass();
        rootPass.add(gameState.getRootNode());
        pManager.add(rootPass);
       
       
     
    }
   
    private void createGameState(){
    gameState = new MyGameState(); // create a game state
GameStateManager.getInstance().attachChild(gameState); // attach it to the GameStateManager
gameState.setActive(true);
    }
   
    protected void update(float interpolation){
        super.update(interpolation);

//gameState.getRootNode().updateGeometricState(interpolation, true);
pManager.updatePasses(interpolation);

    }
   
    protected void render(float interpolation){
    /** Have the PassManager render. */
    super.render(interpolation);
        pManager.renderPasses(display.getRenderer());
    }


    private void setupEnvironment() {
        super.getCamera().setFrustumPerspective(50.0f, (float) display.getWidth()
                / (float) display.getHeight(), 1f, 1000f);
        super.getCamera().setLocation( new Vector3f( -270, 180, -270 ) );
        super.getCamera().lookAt( new Vector3f( 0, 0, 0 ), Vector3f.UNIT_Y );
        super.getCamera().update();

        CullState cs = display.getRenderer().createCullState();
        cs.setCullMode(CullState.CS_BACK);

        gameState.getRootNode().setRenderState(cs);
        gameState.getRootNode().setLightCombineMode(LightState.OFF);
    }




}



Here is a shot of how it looks, kinda. This weirdness is flickering to the top over the perfect looking terrain.




So anyhow, that's what I did.  It draws the terrain and it looks great. It isn't always as severe as in the shot, but when the camera is moving, the terrain is constantly flickering, sometimes only in tiny spots.  I guess if anybody knows common causes of flickering I'd be happy to hear them. I barely know what a pass is, so I have no fundamental understanding of what it is this game is doing ... I hope that changes soon :P

Thanks!

Also, here is MyGameState. It doesn't do much, but maybe it's something I'm not doing?
public class MyGameState extends DebugGameState{


public MyGameState(){
super();
}

@Override
public void cleanup() {
// TODO Auto-generated method stub

}

@Override
public void render(float tpf) {
super.render(tpf);
//this.getRootNode().updateGeometricState(tpf, true);
}

@Override
public void update(float tpf) {
super.update(tpf);
rootNode.updateGeometricState(tpf, true);
}
}

I don't quite have access to a computer right now (weird statement coming from an online post, right?  ) but it might help to throw a couple of updateRenderState and the like everywhere to see if it solves the problem.

When you override the render method you want to clear the screen buffer and then delegate rendering behavior completely to the passManager e.g.



   protected void render(float interpolation) {
      display.getRenderer().clearBuffers();
      /** Have the PassManager render. */
      pManager.renderPasses(display.getRenderer());
   }



Although I'm not sure that's the best way to utilize GameState's or the StandardGame class. Instead of having to extend StandardGame you should create specific GameState classes and add them to StandardGame to create your custom behavior.

MyStandardGame.java - This class uses StandardGame and a PassManagerGameState to render what you want.


package passgame;

import com.jme.math.Vector3f;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jmex.game.StandardGame;
import com.jmex.game.state.GameStateManager;

public class MyStandardGame  {
   private PassManagerGameState pManagerState;
   private BasicPassManager pManager;
   private Node rootNode = new Node("root");
   private StandardGame game = null;
   
   public static void main(String[] args) {
      MyStandardGame mainGame = new MyStandardGame("Pass GameState Test");
      
      
   }

   public MyStandardGame(String gameName) {
      game = new StandardGame(gameName);         
      initGame();
   }
   
   public void start() {
      game.start();
   }

   protected void initGame() {
      //Startup the game
      game.start();
      
      pManager = new BasicPassManager();      
      
      setupEnvironment();

      //tm returns a Spatial
      TerrainManager tm = new TerrainManager();
      Spatial terrain = tm.createTerrain();
      rootNode.attachChild(terrain);
      rootNode.updateRenderState();

      RenderPass rootPass = new RenderPass();
      rootPass.add(rootNode);
      pManager.add(rootPass);
      pManagerState = new PassManagerGameState();
      pManagerState.setPassManager(pManager);
      //Attach game state
      GameStateManager.getInstance().attachChild(pManagerState); // attach it to the GameStateManager

      //Activate game state
      pManagerState.setActive(true);
   }



   private void setupEnvironment() {
      game.getCamera().setFrustumPerspective(50.0f,
            (float) game.getDisplay().getWidth() / (float) game.getDisplay().getHeight(), 1f,
            1000f);
      game.getCamera().setLocation(new Vector3f(-270, 180, -270));
      game.getCamera().lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
      game.getCamera().update();

      CullState cs = game.getDisplay().getRenderer().createCullState();
      cs.setCullMode(CullState.CS_BACK);

      rootNode.setRenderState(cs);
      rootNode.setLightCombineMode(LightState.OFF);
   }

}



PassManagerGameState.java - extends DebugGameState (so we can use all the input handling etc. you could instead create a DebugGameState and attach it as an active GameState)


package passgame;

import com.jme.renderer.pass.BasicPassManager;
import com.jme.system.DisplaySystem;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameState;

public class PassManagerGameState extends DebugGameState {

   private BasicPassManager pManager;
   
   public PassManagerGameState() {
      super();
   }

   public void setPassManager(BasicPassManager pManager) {
      this.pManager = pManager;
   }
   @Override
   public void render(float tpf) {
      pManager.renderPasses(DisplaySystem.getDisplaySystem().getRenderer());
      
   }

}

MyStandardGame


NOOOOOO!!!!!  :'(

Haha what I think Darkfrog meant to say was:



StandardGame, GameStates, and Multithreading (A New Way of Thinking) - by Darkfrog


...by providing StandardGame, which was designed to be the core to be able to be utilized in commercial games without the need to subclass it.


So basically like I said before you'll want *some* class (maybe call it something other than MyStandardGame) that would actually instantiate a StandardGame object and set it up with it's necessary GameState's etc.

Oh, I just looked back at MyStandardGame (I didn't actually read the code the first time…I saw MyStandardGame and then I was blinded by tears) and must apologize for my earlier screaming. :slight_smile:



Yes, thanks Doug for so tactfully organizing my thoughts. :slight_smile:

Notice however, that Doug's solution does not extend StandardGame anymore  :wink:

Thanks Doug. Clearing the buffer and delegating to the GameState did the trick.



However, when I ran your code everything is semi-transparent. I had this problem in mine too, but I was able to fix it by adding a call to updateRenderState() on the gamestate's rootnode.    While I don't really know why it's transparent otherwise, doing the same thing in your code doesn't make the transparency go away.  Was it transparent when you ran it?



I had planned on eventually making a class that had a game as an instance instead of putting all the code into the game, but subclassing seems to be the method of choice for most of the examples, so I did it that way.  I guess if a class isn't final, I assume it can be safely subclassed :slight_smile:



This stuff is all pretty new to me, so I'm slowly learning as I play. I guess I'm just going to keep asking stupid questions and learning a little each time I get an answer.



Today I learned about clearBuffers :stuck_out_tongue:

Brownmonk, that's what the forums are here for asking any questions you have. Plus if you ask a stupid question we'll just bury you in nonsensical ramblings (e.g. Darkfrog  :wink: ), and eventually you'll learn!



Not to mention it's easier to answer your questions the more specific you are with your problem, so your code snippets were great!



I'll have to check out the transparency issue when I get home, I didn't notice it but I also didn't really look for it other than noticing the flickering disappeared, which I think was caused by rendering the image twice once through the MyGameState which was called when you did a super.render(), and then again when you called the BasicPassManager to render it.

I got TestIsland to work with StandardGame as a GameState (extends DebugGameState).



I had the same problem with transparent terrain and the water was being drawn on top of the terrain.



I was just about to give up and post my the code for help, but I try one last thing and it worked perfectly.  Just needed to used the rootNode from DebugGameState, instead of creating a new rootNode.



This might not be the best way to implement it.  I hope this helps with your problem.

/*
 * Copyright (c) 2003-2007 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jmetests;

import java.nio.FloatBuffer;
import java.util.concurrent.Callable;
import java.util.logging.Logger;
import java.util.prefs.Preferences;

import com.jme.image.Texture;
import com.jme.input.MouseInput;
import com.jme.math.Plane;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.PassNode;
import com.jme.scene.PassNodeState;
import com.jme.scene.SceneElement;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.system.PreferencesGameSettings;
import com.jme.util.TextureManager;
import com.jmex.editors.swing.settings.GameSettingsPanel;
import com.jmex.effects.water.WaterRenderPass;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameStateManager;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.RawHeightMap;

/**
 * TestIslandGameState shows multipass texturesplatting(6 passes) through usage of the
 * PassNode together with jME's water effect and a skybox. A simpler version of
 * the terrain without splatting is created and used for rendering into the
 * reflection/refraction of the water.
 *
 * @author Heightmap and textures originally from Jadestone(but heavily
 *         downsampled)
 * @author Rikard Herlitz (MrCoder)
 */

public class TestIslandGameState extends DebugGameState {
   private static final Logger logger = Logger.getLogger(TestIslandGameState.class
         .getName());

   private StandardGame game = null;
   private WaterRenderPass waterEffectRenderPass;
   private Quad waterQuad;
   private Spatial splatTerrain;
   private Spatial reflectionTerrain;
   private Skybox skybox;
   private Camera cam = null;
   private Node rootNode = null;
   private DisplaySystem display = null;
   private boolean started = false;
   protected BasicPassManager pManager = null;

   private float farPlane = 10000.0f;
   private float textureScale = 0.07f;
   private float globalSplatScale = 90.0f;

   public TestIslandGameState(StandardGame game) {
      super();
      this.pManager = new BasicPassManager();
      this.game = game;
   }

   public void update(float interpolation) {
      super.update(interpolation);
      if(!started) return;
      skybox.getLocalTranslation().set(cam.getLocation());
      skybox.updateGeometricState(0.0f, true);

      Vector3f transVec = new Vector3f(cam.getLocation().x, waterEffectRenderPass
            .getWaterHeight(), cam.getLocation().z);
      setTextureCoords(0, transVec.x, -transVec.z, textureScale);
      setVertexCoords(transVec.x, transVec.y, transVec.z);
   }

   @Override
   public void render(float tpf) {
      //super.render(tpf);  Don't call super.render();
      pManager.renderPasses(DisplaySystem.getDisplaySystem().getRenderer());
   }

   protected void initGame() {
      display = DisplaySystem.getDisplaySystem();
      pManager = new BasicPassManager();
      cam = game.getCamera();
      rootNode = getRootNode();// Don't create a new rootNode use the parent classes root node.

      MouseInput.get().setCursorVisible(true);
      setupEnvironment();

      createTerrain();
      createReflectionTerrain();

      buildSkyBox();

      rootNode.attachChild(skybox);
      rootNode.attachChild(splatTerrain);

      waterEffectRenderPass = new WaterRenderPass(cam, 6, false, true);
      waterEffectRenderPass.setWaterPlane(new Plane(
            new Vector3f(0.0f, 1.0f, 0.0f), 0.0f));
      waterEffectRenderPass.setClipBias(-1.0f);
      waterEffectRenderPass.setReflectionThrottle(0.0f);
      waterEffectRenderPass.setRefractionThrottle(0.0f);

      waterQuad = new Quad("waterQuad", 1, 1);
      FloatBuffer normBuf = waterQuad.getNormalBuffer(0);
      normBuf.clear();
      normBuf.put(0).put(1).put(0);
      normBuf.put(0).put(1).put(0);
      normBuf.put(0).put(1).put(0);
      normBuf.put(0).put(1).put(0);

      waterEffectRenderPass.setWaterEffectOnSpatial(waterQuad);
      rootNode.attachChild(waterQuad);

      waterEffectRenderPass.setReflectedScene(skybox);
      waterEffectRenderPass.addReflectedScene(reflectionTerrain);
      waterEffectRenderPass.setSkybox(skybox);
      pManager.add(waterEffectRenderPass);

      RenderPass rootPass = new RenderPass();
      rootPass.add(rootNode);
      pManager.add(rootPass);

      // BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4);
      // if (!bloomRenderPass.isSupported()) {
      // Text t = new Text("Text", "GLSL Not supported on this computer.");
      // t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
      // t.setLightCombineMode(LightState.OFF);
      // t.setLocalTranslation(new Vector3f(0, 20, 0));
      // fpsNode.attachChild(t);
      // } else {
      // bloomRenderPass.setExposurePow(2.0f);
      // bloomRenderPass.setBlurIntensityMultiplier(0.5f);
      //           
      // bloomRenderPass.add(rootNode);
      // bloomRenderPass.setUseCurrentScene(true);
      // pManager.add(bloomRenderPass);
      // }

      // RenderPass fpsPass = new RenderPass();
      // fpsPass.add(fpsNode);
      // pManager.add(fpsPass);

      rootNode.setCullMode(SceneElement.CULL_NEVER);
      rootNode.updateRenderState();
      started = true;
   }

   private void createTerrain() {
      RawHeightMap heightMap = new RawHeightMap(TestIslandGameState.class.getClassLoader()
            .getResource("jmetest/data/texture/terrain/heights.raw").getFile(),
            129, RawHeightMap.FORMAT_16BITLE, false);

      Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
      heightMap.setHeightScale(0.001f);
      TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
            terrainScale, heightMap.getHeightMap(), false);
      page.getLocalTranslation().set(0, -9.5f, 0);
      page.setDetailTexture(1, 1);

      // create some interesting texturestates for splatting
      TextureState ts1 = createSplatTextureState(
            "jmetest/data/texture/terrain/baserock.jpg", null);

      TextureState ts2 = createSplatTextureState(
            "jmetest/data/texture/terrain/darkrock.jpg",
            "jmetest/data/texture/terrain/darkrockalpha.png");

      TextureState ts3 = createSplatTextureState(
            "jmetest/data/texture/terrain/deadgrass.jpg",
            "jmetest/data/texture/terrain/deadalpha.png");

      TextureState ts4 = createSplatTextureState(
            "jmetest/data/texture/terrain/nicegrass.jpg",
            "jmetest/data/texture/terrain/grassalpha.png");

      TextureState ts5 = createSplatTextureState(
            "jmetest/data/texture/terrain/road.jpg",
            "jmetest/data/texture/terrain/roadalpha.png");

      TextureState ts6 = createLightmapTextureState("jmetest/data/texture/terrain/lightmap.jpg");

      // alpha used for blending the passnodestates together
      AlphaState as = display.getRenderer().createAlphaState();
      as.setBlendEnabled(true);
      as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
      as.setTestEnabled(true);
      as.setTestFunction(AlphaState.TF_GREATER);
      as.setEnabled(true);

      // alpha used for blending the lightmap
      AlphaState as2 = display.getRenderer().createAlphaState();
      as2.setBlendEnabled(true);
      as2.setSrcFunction(AlphaState.SB_DST_COLOR);
      as2.setDstFunction(AlphaState.DB_SRC_COLOR);
      as2.setTestEnabled(true);
      as2.setTestFunction(AlphaState.TF_GREATER);
      as2.setEnabled(true);

      // //////////////////// PASS STUFF START
      // try out a passnode to use for splatting
      PassNode splattingPassNode = new PassNode("SplatPassNode");
      splattingPassNode.attachChild(page);

      PassNodeState passNodeState = new PassNodeState();
      passNodeState.setPassState(ts1);
      splattingPassNode.addPass(passNodeState);

      passNodeState = new PassNodeState();
      passNodeState.setPassState(ts2);
      passNodeState.setPassState(as);
      splattingPassNode.addPass(passNodeState);

      passNodeState = new PassNodeState();
      passNodeState.setPassState(ts3);
      passNodeState.setPassState(as);
      splattingPassNode.addPass(passNodeState);

      passNodeState = new PassNodeState();
      passNodeState.setPassState(ts4);
      passNodeState.setPassState(as);
      splattingPassNode.addPass(passNodeState);

      passNodeState = new PassNodeState();
      passNodeState.setPassState(ts5);
      passNodeState.setPassState(as);
      splattingPassNode.addPass(passNodeState);

      passNodeState = new PassNodeState();
      passNodeState.setPassState(ts6);
      passNodeState.setPassState(as2);
      splattingPassNode.addPass(passNodeState);
      // //////////////////// PASS STUFF END

      // lock some things to increase the performance
      splattingPassNode.lockBounds();
      splattingPassNode.lockTransforms();
      splattingPassNode.lockShadows();

      splatTerrain = splattingPassNode;
   }

   private void createReflectionTerrain() {
      RawHeightMap heightMap = new RawHeightMap(TestIslandGameState.class.getClassLoader()
            .getResource("jmetest/data/texture/terrain/heights.raw").getFile(),
            129, RawHeightMap.FORMAT_16BITLE, false);

      Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
      heightMap.setHeightScale(0.001f);
      TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
            terrainScale, heightMap.getHeightMap(), false);
      page.getLocalTranslation().set(0, -9.5f, 0);
      page.setDetailTexture(1, 1);

      // create some interesting texturestates for splatting
      TextureState ts1 = display.getRenderer().createTextureState();
      Texture t0 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource("jmetest/data/texture/terrain/terrainlod.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(1.0f, 1.0f, 1.0f));
      ts1.setTexture(t0, 0);

      // //////////////////// PASS STUFF START
      // try out a passnode to use for splatting
      PassNode splattingPassNode = new PassNode("SplatPassNode");
      splattingPassNode.attachChild(page);

      PassNodeState passNodeState = new PassNodeState();
      passNodeState.setPassState(ts1);
      splattingPassNode.addPass(passNodeState);
      // //////////////////// PASS STUFF END

      // lock some things to increase the performance
      splattingPassNode.lockBounds();
      splattingPassNode.lockTransforms();
      splattingPassNode.lockShadows();

      reflectionTerrain = splattingPassNode;

      initSpatial(reflectionTerrain);
   }

   private void setupEnvironment() {
      cam.setFrustumPerspective(45.0f, (float) display.getWidth()
            / (float) display.getHeight(), 1f, farPlane);
      cam.setLocation(new Vector3f(-320, 80, -270));
      cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
      cam.update();

      CullState cs = display.getRenderer().createCullState();
      cs.setCullMode(CullState.CS_BACK);
      rootNode.setRenderState(cs);

      rootNode.setLightCombineMode(LightState.OFF);

      FogState fogState = display.getRenderer().createFogState();
      fogState.setDensity(1.0f);
      fogState.setEnabled(true);
      fogState.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
      fogState.setEnd(farPlane);
      fogState.setStart(farPlane / 10.0f);
      fogState.setDensityFunction(FogState.DF_LINEAR);
      fogState.setApplyFunction(FogState.AF_PER_VERTEX);
      rootNode.setRenderState(fogState);
   }

   private void addAlphaSplat(TextureState ts, String alpha) {
      Texture t1 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(alpha), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
      t1.setWrap(Texture.WM_WRAP_S_WRAP_T);
      t1.setApply(Texture.AM_COMBINE);
      t1.setCombineFuncRGB(Texture.ACF_REPLACE);
      t1.setCombineSrc0RGB(Texture.ACS_PREVIOUS);
      t1.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
      t1.setCombineFuncAlpha(Texture.ACF_REPLACE);
      ts.setTexture(t1, ts.getNumberOfSetTextures());
   }

   private TextureState createSplatTextureState(String texture, String alpha) {
      TextureState ts = display.getRenderer().createTextureState();

      Texture t0 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(texture), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
      t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
      t0.setApply(Texture.AM_MODULATE);
      t0.setScale(new Vector3f(globalSplatScale, globalSplatScale, 1.0f));
      ts.setTexture(t0, 0);

      if (alpha != null) {
         addAlphaSplat(ts, alpha);
      }

      return ts;
   }

   private TextureState createLightmapTextureState(String texture) {
      TextureState ts = display.getRenderer().createTextureState();

      Texture t0 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(texture), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
      t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
      ts.setTexture(t0, 0);

      return ts;
   }

   private void buildSkyBox() {
      skybox = new Skybox("skybox", 10, 10, 10);

      String dir = "jmetest/data/skybox1/";
      Texture north = TextureManager.loadTexture(TestIslandGameState.class
            .getClassLoader().getResource(dir + "1.jpg"), Texture.MM_LINEAR,
            Texture.FM_LINEAR);
      Texture south = TextureManager.loadTexture(TestIslandGameState.class
            .getClassLoader().getResource(dir + "3.jpg"), Texture.MM_LINEAR,
            Texture.FM_LINEAR);
      Texture east = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(dir + "2.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
      Texture west = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(dir + "4.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
      Texture up = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(dir + "6.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
      Texture down = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
            .getResource(dir + "5.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);

      skybox.setTexture(Skybox.NORTH, north);
      skybox.setTexture(Skybox.WEST, west);
      skybox.setTexture(Skybox.SOUTH, south);
      skybox.setTexture(Skybox.EAST, east);
      skybox.setTexture(Skybox.UP, up);
      skybox.setTexture(Skybox.DOWN, down);
      skybox.preloadTextures();

      CullState cullState = display.getRenderer().createCullState();
      cullState.setCullMode(CullState.CS_NONE);
      cullState.setEnabled(true);
      skybox.setRenderState(cullState);

      ZBufferState zState = display.getRenderer().createZBufferState();
      zState.setEnabled(false);
      skybox.setRenderState(zState);

      FogState fs = display.getRenderer().createFogState();
      fs.setEnabled(false);
      skybox.setRenderState(fs);

      skybox.setLightCombineMode(LightState.OFF);
      skybox.setCullMode(SceneElement.CULL_NEVER);
      skybox.setTextureCombineMode(TextureState.REPLACE);
      skybox.updateRenderState();

      skybox.lockBounds();
      skybox.lockMeshes();
   }

   private void setVertexCoords(float x, float y, float z) {
      FloatBuffer vertBuf = waterQuad.getVertexBuffer(0);
      vertBuf.clear();

      vertBuf.put(x - farPlane).put(y).put(z - farPlane);
      vertBuf.put(x - farPlane).put(y).put(z + farPlane);
      vertBuf.put(x + farPlane).put(y).put(z + farPlane);
      vertBuf.put(x + farPlane).put(y).put(z - farPlane);
   }

   private void setTextureCoords(int buffer, float x, float y, float textureScale) {
      x *= textureScale * 0.5f;
      y *= textureScale * 0.5f;
      textureScale = farPlane * textureScale;
      FloatBuffer texBuf;
      texBuf = waterQuad.getTextureBuffer(0, buffer);
      texBuf.clear();
      texBuf.put(x).put(textureScale + y);
      texBuf.put(x).put(y);
      texBuf.put(textureScale + x).put(y);
      texBuf.put(textureScale + x).put(textureScale + y);
   }

   private void initSpatial(Spatial spatial) {
      ZBufferState buf = display.getRenderer().createZBufferState();
      buf.setEnabled(true);
      buf.setFunction(ZBufferState.CF_LEQUAL);
      spatial.setRenderState(buf);

      CullState cs = display.getRenderer().createCullState();
      cs.setCullMode(CullState.CS_BACK);
      spatial.setRenderState(cs);

      spatial.setCullMode(SceneElement.CULL_NEVER);

      spatial.updateGeometricState(0.0f, true);
      spatial.updateRenderState();
   }

   public static void main(String[] args) {
      // Load user preferences
      PreferencesGameSettings settings = new PreferencesGameSettings(Preferences
            .userRoot().node("TestIslandGameState"));
      StandardGame game = new StandardGame("Test Island", StandardGame.GameType.GRAPHICAL,
            settings);
      // Show settings screen
      try {
         if (!GameSettingsPanel.prompt(game.getSettings())) {
            return;
         }
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      game.start();

      final TestIslandGameState testIslandGameState = new TestIslandGameState(game);
      try {
         game.executeInGL(new Callable<Object>() {
            public Object call() {
               testIslandGameState.initGame();

               // setup PassManagerGameState
               GameStateManager.getInstance().attachChild(testIslandGameState);
               testIslandGameState.setActive(true);
               return null;
            }
         });
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}



The code in my previous post is missing a call to updatePasses() on the BasicPassManager.  The water ripples don't move if it isn't called.

Here is the correct update() function:

   public void update(float interpolation) {
      super.update(interpolation);
      if(!started) return;
      pManager.updatePasses(interpolation);
      skybox.getLocalTranslation().set(cam.getLocation());
      skybox.updateGeometricState(0.0f, true);

      Vector3f transVec = new Vector3f(cam.getLocation().x, waterEffectRenderPass
            .getWaterHeight(), cam.getLocation().z);
      setTextureCoords(0, transVec.x, -transVec.z, textureScale);
      setVertexCoords(transVec.x, transVec.y, transVec.z);
   }