ProjectedWater implementation too dark!

Hi, first of all, these are great libraries, they made my life much easier.

Secondly, I am still a bit n00bish, but right now I am trying to make a Terrain thingy, with water and effects, I just started using this engine yesterday.



I saw the code for the water and I implemented it with my terrain, I had to make a pManager for it to work, and I made sure I put the necessary lines in render etc.



The problem is that my water is too dark, compared to the terrain, and I thought I tied to too the node for lighting. I even disabled lights one time, and the water was still just as dark, so my guess is that the directional lighting isn’t hitting my water!



Here is a shot, and thank you for the help!






Grrrr, well ok, I did get it to show light, but now when i look at certain directions my skybox turns black, and then my water looses lighting!!



Here is my code:


//imports removed for space...

public class Terrain3D extends BaseGame {
    public static void main(String[] args) {
       Terrain3D app = new Terrain3D();
       // We will load our own "fantastic" Flag Rush logo. Yes, I'm an artist.
        app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG, Lesson9.class
                .getClassLoader().getResource(
                        "jmetest/data/images/FlagRush.png"));
        app.start();
    }
   
    protected BasicPassManager pManager;
    private WaterRenderPass waterEffectRenderPass;
   private ProjectedGrid projectedGrid;
   private float farPlane = 2500.0f;

    //Sky box (we update it each frame)
    private Skybox skybox;
    //the terrain we will drive over.
    private TerrainBlock tb;
   
    /** The camera that we see through. */
    protected Camera cam;
      /** The root of our normal scene graph. */
    protected Node scene;
      /** Handles our mouse/keyboard input. */
    protected InputHandler input;
      /** High resolution timer for jME. */
    protected Timer timer;
      /** The root node of our text. */
    protected Node fpsNode;
      /** Displays all the lovely information at the bottom. */
    protected Text fps;
      /** Simply an easy way to get at timer.getTimePerFrame(). */
    protected float tpf;
      /** True if the renderer should display bounds. */
    protected boolean showBounds = false;

      /** A wirestate to turn on and off for the rootNode */
    protected WireframeState wireState;
      /** A lightstate to turn on and off for the rootNode */
    protected LightState lightState;

      /** Location of the font for jME's text at the bottom */
    public static String fontLocation = "com/jme/app/defaultfont.tga";

    /**
     * This is called every frame in BaseGame.start()
     * @param interpolation unused in this implementation
     * @see com.jme.app.AbstractGame#update(float interpolation)
     */
    protected final void update(float interpolation) {
        /** Recalculate the framerate. */
      timer.update();
        /** Update tpf to time per frame according to the Timer. */
      tpf = timer.getTimePerFrame();
        /** Check for key/mouse updates. */
      input.update(tpf);
        /** Send the fps to our fps bar at the bottom. */
      fps.print("FPS: " + (int) timer.getFrameRate() + " - " +
                display.getRenderer().getStatistics());
        /** Call simpleUpdate in any derived classes of SimpleGame. */
      simpleUpdate();
     
      pManager.updatePasses(tpf);

        /** Update controllers/render states/transforms/bounds for rootNode. */
      scene.updateGeometricState(tpf, true);
     
      //we want to keep the skybox around our eyes, so move it with
      //the camera
      skybox.setLocalTranslation(cam.getLocation());
      skybox.updateGeometricState(0, true);
     
        /** If toggle_wire is a valid command (via key T), change wirestates. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("toggle_wire", false)) {
        wireState.setEnabled(!wireState.isEnabled());
        scene.updateRenderState();
      }
        /** If toggle_lights is a valid command (via key L), change lightstate. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("toggle_lights", false)) {
        lightState.setEnabled(!lightState.isEnabled());
        scene.updateRenderState();
      }
        /** If toggle_bounds is a valid command (via key B), change bounds. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("toggle_bounds", false)) {
        showBounds = !showBounds;
      }
        /** If camera_out is a valid command (via key C), show camera location. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("camera_out", false)) {
        System.err.println("Camera at: " +
                           display.getRenderer().getCamera().getLocation());
      }
     
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit", false)) {
          finish();
      }

    }

    /**
     * This is called every frame in BaseGame.start(), after update()
     * @param interpolation unused in this implementation
     * @see com.jme.app.AbstractGame#render(float interpolation)
     */
    protected final void render(float interpolation) {
       /** Have the PassManager render. */
      pManager.renderPasses(display.getRenderer());
        /** Reset display's tracking information for number of triangles/vertexes */
      display.getRenderer().clearStatistics();
        /** Clears the previously rendered information. */
      display.getRenderer().clearBuffers();
        /** Draw the rootNode and all its children. */
      display.getRenderer().draw(scene);
        /** If showing bounds, draw rootNode's bounds, and the bounds of all its children. */
      if (showBounds)
        Debugger.drawBounds(scene, display.getRenderer());
        /** Draw the fps node to show the fancy information at the bottom. */
      display.getRenderer().draw(fpsNode);
        /** Call simpleRender() in any derived classes. */
      simpleRender();
    }

    /**
     * Creates display, sets up camera, and binds keys.  Called in BaseGame.start() directly after
     * the dialog box.
     * @see com.jme.app.AbstractGame#initSystem()
     */
    protected final void initSystem() {
      try {
          /** Get a DisplaySystem acording to the renderer selected in the startup box. */
        display = DisplaySystem.getDisplaySystem(properties.getRenderer());
         /** Create a window with the startup box's information. */
        display.createWindow(
            properties.getWidth(),
            properties.getHeight(),
            properties.getDepth(),
            properties.getFreq(),
            properties.getFullscreen());
           /** Create a camera specific to the DisplaySystem that works with
            * the display's width and height*/
        cam =
            display.getRenderer().createCamera(
            display.getWidth(),
            display.getHeight());

      }
      catch (JmeException e) {
          /** If the displaysystem can't be initialized correctly, exit instantly. */
        e.printStackTrace();
        System.exit(1);
      }

        /** Set a black background.*/
      display.getRenderer().setBackgroundColor(ColorRGBA.black);

      /** Set up how our camera sees. */
      cam.setFrustumPerspective(45.0f,
                                (float) display.getWidth() /
                                (float) display.getHeight(), 1, 1000);
      Vector3f loc = new Vector3f(0.0f, 0.0f, 25.0f);
      Vector3f left = new Vector3f( -1.0f, 0.0f, 0.0f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(0.0f, 0f, -1.0f);
        /** Move our camera to a correct place and orientation. */
      cam.setFrame(loc, left, up, dir);
        /** Signal that we've changed our camera's location/frustum. */
      cam.update();
        /** Assign the camera to this renderer.*/
      display.getRenderer().setCamera(cam);

      /** Create a basic input controller. */
        FirstPersonHandler firstPersonHandler = new FirstPersonHandler( cam, properties.getRenderer() );
        /** Signal to all key inputs they should work 50x faster. */
        firstPersonHandler.getKeyboardLookHandler().setActionSpeed(50f);
        firstPersonHandler.getMouseLookHandler().setActionSpeed(1f);
        input = firstPersonHandler;

        /** Get a high resolution timer for FPS updates. */
      timer = Timer.getTimer();
     
        /** Signal to the renderer that it should keep track of rendering information. */
      display.getRenderer().enableStatistics(true);

        /** Assign key T to action "toggle_wire". */
      KeyBindingManager.getKeyBindingManager().set(
          "toggle_wire",
          KeyInput.KEY_T);
        /** Assign key L to action "toggle_lights". */
      KeyBindingManager.getKeyBindingManager().set(
          "toggle_lights",
          KeyInput.KEY_L);
        /** Assign key B to action "toggle_bounds". */
      KeyBindingManager.getKeyBindingManager().set(
          "toggle_bounds",
          KeyInput.KEY_B);
        /** Assign key C to action "camera_out". */
      KeyBindingManager.getKeyBindingManager().set(
          "camera_out",
          KeyInput.KEY_C);
      KeyBindingManager.getKeyBindingManager().set(
              "exit",
              KeyInput.KEY_ESCAPE);
    }

    /**
     * Creates rootNode, lighting, statistic text, and other basic render states.
     * Called in BaseGame.start() after initSystem().
     * @see com.jme.app.AbstractGame#initGame()
     */
    protected final void initGame() {
      display.setTitle("Cosmic3D Terrain Demo v.1 NX");
     
      pManager = new BasicPassManager();
        /** Create scene rootNode */
      scene = new Node("scene node graph");

      /** Create a wirestate to toggle on and off.  Starts disabled with
       * default width of 1 pixel. */
      wireState = display.getRenderer().createWireframeState();
      wireState.setEnabled(false);
      scene.setRenderState(wireState);
     
      //Time for a little optimization. We don't need to render back face triangles, so lets
      //not. This will give us a performance boost for very little effort.
      CullState cs = display.getRenderer().createCullState();
      cs.setCullMode(CullState.CS_BACK);
      scene.setRenderState(cs);

      /** Create a ZBuffer to display pixels closest to the camera above farther ones.  */
      ZBufferState buf = display.getRenderer().createZBufferState();
      buf.setEnabled(true);
      buf.setFunction(ZBufferState.CF_LEQUAL);

      scene.setRenderState(buf);

      setupFog();
     
      Node reflectedNode = new Node( "reflectNode" );
     
      buildSkyBox();
      buildTerrain();
     
      reflectedNode.attachChild( skybox );
     //reflectedNode.attachChild( createObjects() );
    
     scene.attachChild( reflectedNode );

      waterEffectRenderPass = new WaterRenderPass( cam, 4, true, true );
      waterEffectRenderPass.setClipBias( 0.5f );
      waterEffectRenderPass.setWaterMaxAmplitude( 2.0f );
      //setting to default value just to show
      waterEffectRenderPass.setWaterPlane( new Plane( new Vector3f( 0.0f, 1.0f, 0.0f ), 0.0f ) );
   
      projectedGrid = new ProjectedGrid( "ProjectedGrid", cam, 64, 64, 0.01f, new WaterHeightGenerator() );
      
      waterEffectRenderPass.setWaterEffectOnSpatial( projectedGrid );
      scene.attachChild( projectedGrid );

      waterEffectRenderPass.setReflectedScene( reflectedNode );
      waterEffectRenderPass.setSkybox( skybox );
      pManager.add( waterEffectRenderPass );

      RenderPass rootPass = new RenderPass();
      rootPass.add( scene );
      pManager.add( rootPass );
     
      // -- FPS DISPLAY
      // First setup alpha state
        /** This allows correct blending of text and what is already rendered below it*/
      AlphaState as1 = display.getRenderer().createAlphaState();
      as1.setBlendEnabled(true);
      as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as1.setDstFunction(AlphaState.DB_ONE);
      as1.setTestEnabled(true);
      as1.setTestFunction(AlphaState.TF_GREATER);
      as1.setEnabled(true);

      // Now setup font texture
      TextureState font = display.getRenderer().createTextureState();
        /** The texture is loaded from fontLocation */
      font.setTexture(
          TextureManager.loadTexture(
          SimpleGame.class.getClassLoader().getResource(
          fontLocation),
          Texture.MM_LINEAR,
          Texture.FM_LINEAR));
      font.setEnabled(true);

      // Then our font Text object.
        /** This is what will actually have the text at the bottom. */
      fps = new Text("FPS label", "");
      fps.setCullMode(SceneElement.CULL_NEVER);
      fps.setTextureCombineMode(TextureState.REPLACE);

      // Finally, a stand alone node (not attached to root on purpose)
      fpsNode = new Node("FPS node");
      fpsNode.attachChild(fps);
      fpsNode.setRenderState(font);
      fpsNode.setRenderState(as1);
      fpsNode.setCullMode(SceneElement.CULL_NEVER);

      // ---- LIGHTS     
      buildLighting();
     
        /** Let derived classes initialize. */
      //simpleInitGame();

        /** Update geometric and rendering information for both the rootNode and fpsNode. */
      scene.updateGeometricState(0.0f, true);
      scene.updateRenderState();
      fpsNode.updateGeometricState(0.0f, true);
      fpsNode.updateRenderState();
    }
   
    private void setupFog() {
      FogState fogState = display.getRenderer().createFogState();
      fogState.setDensity( 1.0f );
      fogState.setEnabled( true );
      fogState.setColor( new ColorRGBA( 0.6f, 0.8f, 1.0f, 1.0f ) );
      fogState.setEnd( farPlane );
      fogState.setStart( farPlane / 10.0f );
      fogState.setDensityFunction( FogState.DF_LINEAR );
      fogState.setApplyFunction( FogState.AF_PER_VERTEX );
      scene.setRenderState( fogState );
   }
   
    private void buildSkyBox() {
       skybox = new Skybox( "skybox", 10, 10, 10 );

      String dir = "jmetest/effects/water/data/";
      Texture north = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "1.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture south = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "3.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture east = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "2.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture west = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "4.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture up = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "6.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture down = TextureManager.loadTexture(
            TestProjectedWater.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 buildLighting() {
        /** Set up a basic, default light. */
        DirectionalLight light = new DirectionalLight();
        light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, .5f));
        light.setDirection(new Vector3f(1,-1,0));
        light.setShadowCaster(true);
        light.setEnabled(true);
       
        /** Attach the light to a lightState and the lightState to scene. */
        LightState lightState = display.getRenderer().createLightState();
        lightState.setEnabled(true);
        lightState.setGlobalAmbient(new ColorRGBA(.25f, .25f, .5f, 1f));
        lightState.attach(light);
        scene.setRenderState(lightState);
    }

    private void buildTerrain() {
       
        MidPointHeightMap heightMap = new MidPointHeightMap(256, 1.25f);
        // Scale the data
        Vector3f terrainScale = new Vector3f(4, 1.0f, 4);
        // create a terrainblock
        tb = new TerrainBlock("Terrain", heightMap.getSize(), terrainScale,
                heightMap.getHeightMap(), new Vector3f(0, -100, 0), false);

        tb.setModelBound(new BoundingBox());
        tb.updateModelBound();

        // generate a terrain texture with 2 textures
        ProceduralTextureGenerator pt = new ProceduralTextureGenerator(
                heightMap);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader()
                .getResource("jmetest/data/texture/grassb.png")), -128, 0, 128);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader()
                .getResource("jmetest/data/texture/dirt.jpg")), 0, 128, 255);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader()
                .getResource("jmetest/data/texture/highest.jpg")), 128, 255,
                384);
        pt.createTexture(32);
       
        // assign the texture to the terrain
        TextureState ts = display.getRenderer().createTextureState();
        Texture t1 = TextureManager.loadTexture(pt.getImageIcon().getImage(),
                Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true);
        ts.setTexture(t1, 0);
       
        //load a detail texture and set the combine modes for the two terrain textures.
        Texture t2 = TextureManager.loadTexture(
                TestTerrain.class.getClassLoader().getResource(
                "jmetest/data/texture/Detail.jpg"),
                Texture.MM_LINEAR_LINEAR,
                Texture.FM_LINEAR);

        ts.setTexture(t2, 1);
        t2.setWrap(Texture.WM_WRAP_S_WRAP_T);

        t1.setApply(Texture.AM_COMBINE);
        t1.setCombineFuncRGB(Texture.ACF_MODULATE);
        t1.setCombineSrc0RGB(Texture.ACS_TEXTURE);
        t1.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
        t1.setCombineSrc1RGB(Texture.ACS_PRIMARY_COLOR);
        t1.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
        t1.setCombineScaleRGB(1.0f);

        t2.setApply(Texture.AM_COMBINE);
        t2.setCombineFuncRGB(Texture.ACF_ADD_SIGNED);
        t2.setCombineSrc0RGB(Texture.ACS_TEXTURE);
        t2.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
        t2.setCombineSrc1RGB(Texture.ACS_PREVIOUS);
        t2.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
        t2.setCombineScaleRGB(1.0f);

        tb.setRenderState(ts);
        //set the detail parameters.
        tb.setDetailTexture(1, 16);
        tb.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
        scene.attachChild(tb);
       
       
    }

    protected void simpleInitGame() {
        scene.attachChild(new Box("my box",new Vector3f(0,0,0),new Vector3f(1,1,1)));
    }

    protected void simpleUpdate() {}

    protected void simpleRender() {}

    protected void reinit() {
    }

    protected void cleanup() {
      LoggingSystem.getLogger().log(Level.INFO, "Cleaning up resources.");
      KeyInput.destroyIfInitalized();
      MouseInput.destroyIfInitalized();
      JoystickInput.destroyIfInitalized();
      waterEffectRenderPass.cleanup();
    }
}

Looks like tar…I'd hate to try to swim in there.  :stuck_out_tongue:

Well thank doesnt help  :smiley:

Sorry, haven't touched the water code yet myself so I don't have anything to offer…just wanted to keep the thread alive. :wink:

FIXED!



I forgot to attach a reflection node to the terrain, and it ended up fixing my problems and made water prettier, i also edited the projected water file some more for a nicer blue effect…



my fps isnt so good though :frowning: with a geForce 7600gs



… but my terrain i  guess used too many triangles



you should set your farplane to the variable farPlane instead of 1000. other from that, great you got it working!

thanx that help things out, i also increased my farplane so the water looks less "cut out" near the skybox.



now im going to try to implement bloom from the sample files.

Sigh… i feel like such a noob, i cant get bloom to work! The way i have it, it doesnt do anything, the terrain does not "glow." I think my nodes may not be attaching right, can someone please help!


//imports removed for space
public class Terrain3D extends BaseGame {
    public static void main(String[] args) {
       Terrain3D app = new Terrain3D();
       // We will load our own "fantastic" Flag Rush logo. Yes, I'm an artist.
        app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG, Terrain3D.class
                .getClassLoader().getResource(
                      "images/ctd.png"));
        app.start();
    }
   
    private BloomRenderPass bloomRenderPass;
   
    protected BasicPassManager pManager;
    private WaterRenderPass waterEffectRenderPass;
   private ProjectedGrid projectedGrid;
   private float farPlane = 10000.0f;
   
    //Sky box (we update it each frame)
    private Skybox skybox;
    //the terrain we will drive over.
    private TerrainBlock tb;
   
    protected Camera cam;
    protected Node scene;
    protected InputHandler input;
    protected Timer timer;
    protected Node fpsNode;
    protected Text fps;
    protected float tpf;
    protected boolean showBounds = false;
    protected WireframeState wireState;
    protected LightState lightState;
    public static String fontLocation = "com/jme/app/defaultfont.tga";


    protected final void update(float interpolation) {
        /** Recalculate the framerate. */
      timer.update();
        /** Update tpf to time per frame according to the Timer. */
      tpf = timer.getTimePerFrame();
        /** Check for key/mouse updates. */
      input.update(tpf);
        /** Send the fps to our fps bar at the bottom. */
      fps.print("FPS: " + (int) timer.getFrameRate() + " - " +
                display.getRenderer().getStatistics());
        /** Call simpleUpdate in any derived classes of SimpleGame. */
      simpleUpdate();
     
      pManager.updatePasses(tpf);

        /** Update controllers/render states/transforms/bounds for rootNode. */
      scene.updateGeometricState(tpf, true);
     
      //we want to keep the skybox around our eyes, so move it with
      //the camera
      skybox.setLocalTranslation(cam.getLocation());
      skybox.updateGeometricState(0, true);
     
        /** If toggle_wire is a valid command (via key T), change wirestates. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("toggle_wire", false)) {
        wireState.setEnabled(!wireState.isEnabled());
        scene.updateRenderState();
      }
        /** If toggle_lights is a valid command (via key L), change lightstate. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("toggle_lights", false)) {
        lightState.setEnabled(!lightState.isEnabled());
        scene.updateRenderState();
      }
        /** If toggle_bounds is a valid command (via key B), change bounds. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("toggle_bounds", false)) {
        showBounds = !showBounds;
      }
        /** If camera_out is a valid command (via key C), show camera location. */
      if (KeyBindingManager
          .getKeyBindingManager()
          .isValidCommand("camera_out", false)) {
        System.err.println("Camera at: " +
                           display.getRenderer().getCamera().getLocation());
      }
     
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit", false)) {
          finish();
      }

    }


    protected final void render(float interpolation) {
       /** Have the PassManager render. */
      pManager.renderPasses(display.getRenderer());
        /** Reset display's tracking information for number of triangles/vertexes */
      display.getRenderer().clearStatistics();
        /** Clears the previously rendered information. */
      display.getRenderer().clearBuffers();
        /** Draw the rootNode and all its children. */
      display.getRenderer().draw(scene);
        /** If showing bounds, draw rootNode's bounds, and the bounds of all its children. */
      if (showBounds)
        Debugger.drawBounds(scene, display.getRenderer());
        /** Draw the fps node to show the fancy information at the bottom. */
      display.getRenderer().draw(fpsNode);
        /** Call simpleRender() in any derived classes. */
      simpleRender();
    }


    protected final void initSystem() {
      try {
          /** Get a DisplaySystem acording to the renderer selected in the startup box. */
        display = DisplaySystem.getDisplaySystem(properties.getRenderer());
         /** Create a window with the startup box's information. */
        display.createWindow(
            properties.getWidth(),
            properties.getHeight(),
            properties.getDepth(),
            properties.getFreq(),
            properties.getFullscreen());
           /** Create a camera specific to the DisplaySystem that works with
            * the display's width and height*/
        cam =
            display.getRenderer().createCamera(
            display.getWidth(),
            display.getHeight());

      }
      catch (JmeException e) {
          /** If the displaysystem can't be initialized correctly, exit instantly. */
        e.printStackTrace();
        System.exit(1);
      }

        /** Set a black background.*/
      display.getRenderer().setBackgroundColor(ColorRGBA.black);

      /** Set up how our camera sees. */
      cam.setFrustumPerspective(45.0f,
                                (float) display.getWidth() /
                                (float) display.getHeight(), 1, farPlane);
      Vector3f loc = new Vector3f(0.0f, 0.0f, 25.0f);
      Vector3f left = new Vector3f( -1.0f, 0.0f, 0.0f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(0.0f, 0f, -1.0f);
        /** Move our camera to a correct place and orientation. */
      cam.setFrame(loc, left, up, dir);
        /** Signal that we've changed our camera's location/frustum. */
      cam.update();
        /** Assign the camera to this renderer.*/
      display.getRenderer().setCamera(cam);

      /** Create a basic input controller. */
        FirstPersonHandler firstPersonHandler = new FirstPersonHandler( cam, properties.getRenderer() );
        /** Signal to all key inputs they should work 100x faster. */
        firstPersonHandler.getKeyboardLookHandler().setActionSpeed(100f);
        firstPersonHandler.getMouseLookHandler().setActionSpeed(1f);
        input = firstPersonHandler;

        /** Get a high resolution timer for FPS updates. */
      timer = Timer.getTimer();
     
        /** Signal to the renderer that it should keep track of rendering information. */
      display.getRenderer().enableStatistics(true);

        /** Assign key T to action "toggle_wire". */
      KeyBindingManager.getKeyBindingManager().set(
          "toggle_wire",
          KeyInput.KEY_T);
        /** Assign key L to action "toggle_lights". */
      KeyBindingManager.getKeyBindingManager().set(
          "toggle_lights",
          KeyInput.KEY_L);
        /** Assign key B to action "toggle_bounds". */
      KeyBindingManager.getKeyBindingManager().set(
          "toggle_bounds",
          KeyInput.KEY_B);
        /** Assign key C to action "camera_out". */
      KeyBindingManager.getKeyBindingManager().set(
          "camera_out",
          KeyInput.KEY_C);
      KeyBindingManager.getKeyBindingManager().set(
              "exit",
              KeyInput.KEY_ESCAPE);
    }

    protected final void initGame() {
      display.setTitle("Cosmic3D Terrain Demo v.1 NX");
     
      cam.setLocation( new Vector3f( 100, 200, 500 ) );
      cam.update();
     
      pManager = new BasicPassManager();
        /** Create scene rootNode */
      scene = new Node("scene node graph");

      /** Create a wirestate to toggle on and off.  Starts disabled with
       * default width of 1 pixel. */
      wireState = display.getRenderer().createWireframeState();
      wireState.setEnabled(false);
      scene.setRenderState(wireState);
     
      //Time for a little optimization. We don't need to render back face triangles, so lets
      //not. This will give us a performance boost for very little effort.
      CullState cs = display.getRenderer().createCullState();
      cs.setCullMode(CullState.CS_BACK);
      scene.setRenderState(cs);

      /** Create a ZBuffer to display pixels closest to the camera above farther ones.  */
      ZBufferState buf = display.getRenderer().createZBufferState();
      buf.setEnabled(true);
      buf.setFunction(ZBufferState.CF_LEQUAL);

      scene.setRenderState(buf);

      setupFog();
     
      Node reflectedNode = new Node( "reflectNode" );
     
      buildSkyBox();
      buildTerrain();
     
      reflectedNode.attachChild( skybox  );
     reflectedNode.attachChild( tb );
    
     scene.attachChild( reflectedNode );
    
      waterEffectRenderPass = new WaterRenderPass( cam, 4, true, true );
      waterEffectRenderPass.setClipBias( 0.5f );
      waterEffectRenderPass.setWaterMaxAmplitude( 5.0f );
      //setting to default value just to show
      waterEffectRenderPass.setWaterPlane( new Plane( new Vector3f( 0.0f, 1.0f, 0.0f ), 0.0f ) );
   
      projectedGrid = new ProjectedGrid( "ProjectedGrid", cam, 32, 32, 0.01f, new WaterHeightGenerator() );
      
      waterEffectRenderPass.setWaterEffectOnSpatial( projectedGrid );
      scene.attachChild( projectedGrid );

      waterEffectRenderPass.setReflectedScene( reflectedNode );
      waterEffectRenderPass.setSkybox( skybox );
      pManager.add( waterEffectRenderPass );
      
      RenderPass rootPass = new RenderPass();
      rootPass.add( scene );
      pManager.add( rootPass );
      
      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.add(scene);
              bloomRenderPass.setUseCurrentScene(true);
              //bloomRenderPass.setEnabled(true);
              //bloomRenderPass.setExposurePow(bloomRenderPass.getExposurePow() + 2.0f);
              pManager.add(bloomRenderPass);
          }  
        
      // -- FPS DISPLAY
      // First setup alpha state
        /** This allows correct blending of text and what is already rendered below it*/
      AlphaState as1 = display.getRenderer().createAlphaState();
      as1.setBlendEnabled(true);
      as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as1.setDstFunction(AlphaState.DB_ONE);
      as1.setTestEnabled(true);
      as1.setTestFunction(AlphaState.TF_GREATER);
      as1.setEnabled(true);

      // Now setup font texture
      TextureState font = display.getRenderer().createTextureState();
        /** The texture is loaded from fontLocation */
      font.setTexture(
          TextureManager.loadTexture(
          SimpleGame.class.getClassLoader().getResource(
          fontLocation),
          Texture.MM_LINEAR,
          Texture.FM_LINEAR));
      font.setEnabled(true);

      // Then our font Text object.
        /** This is what will actually have the text at the bottom. */
      fps = new Text("FPS label", "");
      fps.setCullMode(SceneElement.CULL_NEVER);
      fps.setTextureCombineMode(TextureState.REPLACE);

      // Finally, a stand alone node (not attached to root on purpose)
      fpsNode = new Node("FPS node");
      fpsNode.attachChild(fps);
      fpsNode.setRenderState(font);
      fpsNode.setRenderState(as1);
      fpsNode.setCullMode(SceneElement.CULL_NEVER);

      // ---- LIGHTS     
      buildLighting();
     
        /** Let derived classes initialize. */
      //simpleInitGame();

        /** Update geometric and rendering information for both the rootNode and fpsNode. */
      scene.updateGeometricState(0.0f, true);
      scene.updateRenderState();
      fpsNode.updateGeometricState(0.0f, true);
      fpsNode.updateRenderState();
    }
   
    private void setupFog() {
      FogState fogState = display.getRenderer().createFogState();
      fogState.setDensity( 1.0f );
      fogState.setEnabled( true );
      fogState.setColor( new ColorRGBA( 0.6f, 0.8f, 1.0f, 1.0f ) );
      fogState.setEnd( farPlane );
      fogState.setStart( 500.0f );
      fogState.setDensityFunction( FogState.DF_LINEAR );
      fogState.setApplyFunction( FogState.AF_PER_VERTEX );
      scene.setRenderState( fogState );
   }
   
    private void buildSkyBox() {
       skybox = new Skybox( "skybox", 10, 10, 10 );

      String dir = "jmetest/effects/water/data/";
      Texture north = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "1.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture south = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "3.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture east = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "2.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture west = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "4.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture up = TextureManager.loadTexture(
            TestProjectedWater.class.getClassLoader().getResource(
                  dir + "6.jpg" ),
            Texture.MM_LINEAR,
            Texture.FM_LINEAR );
      Texture down = TextureManager.loadTexture(
            TestProjectedWater.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 buildLighting() {
        /** Set up a basic, default light. */
        DirectionalLight light = new DirectionalLight();
        light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, .5f));
        light.setDirection(new Vector3f(1,-1,0));
        light.setShadowCaster(true);
        light.setEnabled(true);
       
        /** Attach the light to a lightState and the lightState to scene. */
        LightState lightState = display.getRenderer().createLightState();
        lightState.setEnabled(true);
        lightState.setGlobalAmbient(new ColorRGBA(.25f, .25f, .5f, 1f));
        lightState.attach(light);
        scene.setRenderState(lightState);
    }
   
    /**
     * build the height map and terrain block.
     */
    private void buildTerrain() {
       
        MidPointHeightMap heightMap = new MidPointHeightMap(128, 1.25f);
        // Scale the data
        Vector3f terrainScale = new Vector3f(8, 1.25f, 8);
        // create a terrainblock
        tb = new TerrainBlock("Terrain", heightMap.getSize(), terrainScale,
                heightMap.getHeightMap(), new Vector3f(0, -100, 0), false);

        tb.setModelBound(new BoundingBox());
        tb.updateModelBound();

        // generate a terrain texture with 2 textures
        ProceduralTextureGenerator pt = new ProceduralTextureGenerator(
                heightMap);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader()
                .getResource("jmetest/data/texture/grassb.png")), -128, 0, 128);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader()
                .getResource("jmetest/data/texture/dirt.jpg")), 0, 128, 255);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader()
                .getResource("jmetest/data/texture/highest.jpg")), 128, 255,
                384);
        pt.createTexture(32);
       
        // assign the texture to the terrain
        TextureState ts = display.getRenderer().createTextureState();
        Texture t1 = TextureManager.loadTexture(pt.getImageIcon().getImage(),
                Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true);
        ts.setTexture(t1, 0);
       
        //load a detail texture and set the combine modes for the two terrain textures.
        Texture t2 = TextureManager.loadTexture(
                TestTerrain.class.getClassLoader().getResource(
                "jmetest/data/texture/Detail.jpg"),
                Texture.MM_LINEAR_LINEAR,
                Texture.FM_LINEAR);

        ts.setTexture(t2, 1);
       
        t2.setWrap(Texture.WM_WRAP_S_WRAP_T);
       
        t1.setApply(Texture.AM_COMBINE);
        t1.setCombineFuncRGB(Texture.ACF_MODULATE);
        t1.setCombineSrc0RGB(Texture.ACS_TEXTURE);
        t1.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
        t1.setCombineSrc1RGB(Texture.ACS_PRIMARY_COLOR);
        t1.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
        t1.setCombineScaleRGB(1.0f);

        t2.setApply(Texture.AM_COMBINE);
        t2.setCombineFuncRGB(Texture.ACF_ADD_SIGNED);
        t2.setCombineSrc0RGB(Texture.ACS_TEXTURE);
        t2.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
        t2.setCombineSrc1RGB(Texture.ACS_PREVIOUS);
        t2.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
        t2.setCombineScaleRGB(1.0f);

        tb.setRenderState(ts);
        //set the detail parameters.
        tb.setDetailTexture(1, 16);
        tb.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
        scene.attachChild(tb);
       
       
    }

    protected void simpleInitGame() {
        scene.attachChild(new Box("my box",new Vector3f(0,0,0),new Vector3f(1,1,1)));
    }

    protected void simpleUpdate() { }

    protected void simpleRender() {}

    protected void reinit() {
    }

    protected void cleanup() {
      LoggingSystem.getLogger().log(Level.INFO, "Cleaning up resources.");
      KeyInput.destroyIfInitalized();
      MouseInput.destroyIfInitalized();
      JoystickInput.destroyIfInitalized();
      waterEffectRenderPass.cleanup();
      if (bloomRenderPass != null)
          bloomRenderPass.cleanup();
    }
}