Water spoils FengGUI

hello,



im not sure, whether this subject has been discussed so far on these forums. If that is so, im sorry and i would be thankfull for any link to any suitable topic.



im trying to use some FengGUI together with JME. It works quite fine, but i have just discovered a new problem.



When im trying to add the watereffects to my game, it suddenly looks a bit… well… strange… you can have a look at the pictures.



it might be possible its just a very simple or basic mistake i did, but as i dont have much experience in neither jme nor fenggui i dont know what to do.



thanks for any help,

Fellkneul





My Code:



UserInterface.java


package gui;


import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.ImageIcon;

import jmetest.effects.water.TestProjectedWater;

import org.fenggui.binding.render.lwjgl.LWJGLBinding;

import com.jme.app.BaseGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.input.MouseInputListener;
import com.jme.math.FastMath;
import com.jme.math.Plane;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jme.scene.Spatial;
import com.jme.scene.Spatial.TextureCombineMode;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.WireframeState;
import com.jme.scene.state.ZBufferState;
import com.jmex.effects.water.ProjectedGrid;
import com.jmex.effects.water.WaterHeightGenerator;
import com.jmex.effects.water.WaterRenderPass;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;


public class UserInterface extends BaseGame
{
   //


   //                     VARIABLES & CONSTANTS
   //
   
   //CONSTANTS
   //   Camera
   private static final float camSpeed = 40f;
   private static final float camMaxWinkel = 40;
   private static final float camMinWinkel = 5;
   private static final float camMaxZoom = -1500f;
   private static final float camMinZoom = -500f;
   
   //   Sichtweite
   private static final float farPlane = 10000f;
   
   
   
   //OBJECTS
   //   Logger
   private Logger logger;
   
   //   System
   private Camera cam;
   private CameraNode camNode;
   private Node camPivot;
   
   private Node rootNode;
   
   private BasicPassManager pManager;
   private Timer timer;
   
   private UserInterfaceMenu menu;
   
   
   
   //   WorldData
   private Skybox skybox;
   
   private TerrainBlock terrainBlock;
   
   private ProjectedGrid projectedGrid;
   private WaterRenderPass waterRenderPass;
   
   
   
   //PROPERTIES
   //   Window
   private int width;
   private int height;
   private int depth;
   private int freq;
   private boolean fullscreen;
   
   //   Camera
   private float camZoomIn = 0;
   
   
   
   //
   //                              METHODS
   //
   
   //---Initialisiere System
   @Override
   protected void initSystem()
   {
      //initialisiere Logger
      logger = Logger.getLogger("UserInterface");
      
      
      
      // Informationen abspeichern - In unserm Fall: einfach setzten
      width = 1024;
      height = 786;
      depth = 32;
      freq = -1;
      fullscreen = false;
      
      
      
      // Cameraobjekt initialisieren
      try
      {
         display = DisplaySystem.getDisplaySystem(settings.getRenderer());
         display.createWindow(width, height, depth, freq, fullscreen);
         display.setTitle("Game");
         cam = display.getRenderer().createCamera(width, height);
      }
      catch(JmeException e)
      {
         logger.log(Level.SEVERE, "--->>>Konnte Display-System nicht initialisieren!", e);
         System.exit(1);
      }
      
      cam.setFrustumPerspective(45.0f, (float) width / (float) height, 1, farPlane);
      cam.update();
      display.getRenderer().setCamera(cam);
      
      camNode = new CameraNode("CamNode", cam);
      
      // Hintergrundfarbe
      display.getRenderer().setBackgroundColor(ColorRGBA.black.clone());
      
      
   
      // Setze Timer und PassManager
      timer = Timer.getTimer();
      pManager = new BasicPassManager();
      
      
      
      // Input & Keybindings
      MouseInput.get().setCursorVisible(true);
      
      MouseInput.get().addListener(new MouseInputListener()
      {
         
         @Override
         public void onButton(int button, boolean pressed, int x, int y)
         {
            
         }
         
         @Override
         public void onMove(int xDelta, int yDelta, int newX, int newY)
         {
            
         }
         
         @Override
         public void onWheel(int wheelDelta, int x, int y)
         {
            camZoomIn += wheelDelta;
         }
      });
      
      KeyBindingManager.getKeyBindingManager().set("exit", KeyInput.KEY_ESCAPE);
      KeyBindingManager.getKeyBindingManager().set("up", KeyInput.KEY_UP);
      KeyBindingManager.getKeyBindingManager().set("dn", KeyInput.KEY_DOWN);
      KeyBindingManager.getKeyBindingManager().set("lt", KeyInput.KEY_LEFT);
      KeyBindingManager.getKeyBindingManager().set("rt", KeyInput.KEY_RIGHT);
      KeyBindingManager.getKeyBindingManager().set("strg", KeyInput.KEY_RCONTROL);
      
      
      
      //UserInterface - Menu
      menu = new UserInterfaceMenu(new org.fenggui.Display(new LWJGLBinding()));
   }
   
   //---Initialisiere Spiel
   @Override
   protected void initGame()
   {
      //RootNode erstellen
      CullState rootNodeCullState = display.getRenderer().createCullState();
      rootNodeCullState.setCullFace(CullState.Face.Back);
      
      ZBufferState bufferState = display.getRenderer().createZBufferState();
      bufferState.setEnabled(true);
      bufferState.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
      
      rootNode = new Node("RootNode");
      rootNode.setCullHint(Spatial.CullHint.Never);
      rootNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);
      rootNode.setRenderState(rootNodeCullState);
      rootNode.setRenderState(bufferState);
      
      
      
      //CameraNode einstellen
      camPivot = new Node();
      camPivot.setLocalTranslation(new Vector3f(200f, 130f, 200f));
      camPivot.attachChild(camNode);
      camPivot.getLocalRotation().fromAngles(20 * FastMath.DEG_TO_RAD, 45 * FastMath.DEG_TO_RAD, 0);
      camNode.setLocalTranslation(new Vector3f(0f, 0f, -1000f));
      rootNode.attachChild(camPivot);
      
      cam.setLocation(new Vector3f(50, 100, 50));
      
      
      
      //Create Enviroment
      //   Skybox
      skybox = new Skybox("GameSkybox", 10, 10, 10);
      
      String dir = "jmetest/data/skybox1/";
      Texture skyNorth = TextureManager.loadTexture(TestProjectedWater.class.getClassLoader().getResource(dir + "1.jpg"), Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
      Texture skySouth = TextureManager.loadTexture(TestProjectedWater.class.getClassLoader().getResource(dir + "3.jpg"), Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
      Texture skyEast = TextureManager.loadTexture(TestProjectedWater.class.getClassLoader().getResource(dir + "2.jpg"), Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
      Texture skyWest = TextureManager.loadTexture(TestProjectedWater.class.getClassLoader().getResource(dir + "4.jpg"), Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
      Texture skyUp = TextureManager.loadTexture(TestProjectedWater.class.getClassLoader().getResource(dir + "6.jpg"), Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
      Texture skyDown = TextureManager.loadTexture(TestProjectedWater.class.getClassLoader().getResource(dir + "5.jpg"), Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear);
      
      skybox.setTexture(Skybox.Face.North, skyNorth);
      skybox.setTexture(Skybox.Face.South, skySouth);
      skybox.setTexture(Skybox.Face.East, skyEast);
      skybox.setTexture(Skybox.Face.West, skyWest);
      skybox.setTexture(Skybox.Face.Up, skyUp);
      skybox.setTexture(Skybox.Face.Down, skyDown);
      skybox.preloadTextures();
      
      CullState skyboxCullState = display.getRenderer().createCullState();
      skyboxCullState.setCullFace(CullState.Face.None);
      skyboxCullState.setEnabled(true);
      skybox.setRenderState(skyboxCullState);
      
      ZBufferState skyboxBufferState = display.getRenderer().createZBufferState();
      skyboxBufferState.setEnabled(false);
      skybox.setRenderState(skyboxBufferState);
      
      FogState skyboxFogState = display.getRenderer().createFogState();
      skyboxFogState.setEnabled(false);
      skybox.setRenderState(skyboxFogState);
      
      skybox.setLightCombineMode(Spatial.LightCombineMode.Off);
      skybox.setCullHint(Spatial.CullHint.Never);
      skybox.setTextureCombineMode(TextureCombineMode.Replace);
      skybox.updateRenderState();
      
      skybox.lockBounds();
      skybox.lockMeshes();
      
      rootNode.attachChild(skybox);
      
      
      
      //   Terrain
      URL grayScale = null;
      try
      {
         grayScale = new URL("file:C:\Users\Philipp\Documents\Programme\Eigene Programme\Java\3D Tests\src\onlinegame\HeightMap.jpg");
      }
      catch(MalformedURLException e)
      {
         e.printStackTrace();
      }
      
      ImageBasedHeightMap heightMap = new ImageBasedHeightMap(new ImageIcon(grayScale).getImage());
      
      Vector3f terrainScale = new Vector3f(64, 2, 64); // Skalieren
      terrainBlock = new TerrainBlock("Terrain", heightMap.getSize(), terrainScale, heightMap.getHeightMap(), new Vector3f(0, -10, 0)); // TerrainBlock
      
      //erstellen
      terrainBlock.setModelBound(new BoundingBox()); // Boundingbox
      terrainBlock.updateModelBound();
      
      //Texturen laden
      URL sandImage = null;
      URL grassImage = null;
      try
      {
         sandImage = new URL("file:C:\Users\Philipp\Documents\Programme\Eigene Programme\Java\3D Tests\src\onlinegame\sand.jpg");
         grassImage = new URL("file:C:\Users\Philipp\Documents\Programme\Eigene Programme\Java\3D Tests\src\onlinegame\grass.jpg");
      }
      catch(MalformedURLException e)
      {
         e.printStackTrace();
      }
      
      // Generieren der Textur
      ProceduralTextureGenerator pt = new ProceduralTextureGenerator(heightMap);
      pt.addTexture(new ImageIcon(sandImage), 0, 0, 50);
      pt.addTexture(new ImageIcon(grassImage), 0, 50, 300);
      pt.createTexture(2048);
      
      // Textur an das Terrain anpassen
      TextureState ts = display.getRenderer().createTextureState();
      ts.setEnabled(true);
      Texture t1 = TextureManager.loadTexture(pt.getImageIcon().getImage(), Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, true);
      ts.setTexture(t1, 0);
      terrainBlock.setRenderState(ts);
      terrainBlock.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
      rootNode.attachChild(terrainBlock);
      
      
      
      //   Water
      //Wasser
      Node reflectedNode = new Node("waterReflectNode");
      reflectedNode.attachChild(skybox);
      reflectedNode.attachChild(terrainBlock);
      rootNode.attachChild(reflectedNode);
      
      projectedGrid = new ProjectedGrid("ProjectedGrid", cam, 100, 70, 0.01f, new WaterHeightGenerator());
      
      waterRenderPass = new WaterRenderPass(cam, 1, true, true);
      waterRenderPass.setClipBias(.5f);
      waterRenderPass.setWaterMaxAmplitude(5.0f);
      waterRenderPass.setWaterPlane(new Plane(new Vector3f(0.0f, 1.0f, 0.0f), 0.0f));
      waterRenderPass.setWaterEffectOnSpatial(projectedGrid);
      waterRenderPass.setReflectedScene(reflectedNode);
      waterRenderPass.setSkybox(skybox);
      
      rootNode.attachChild(projectedGrid);
      
      
      
      //Update RootNode
      rootNode.updateGeometricState(0.0f, true);
      rootNode.updateRenderState();
      
      //Add Passes to the pManager
      pManager.add(waterRenderPass);
      RenderPass RootNodeRenderPass = new RenderPass();
      RootNodeRenderPass.add(rootNode);
      pManager.add(RootNodeRenderPass);
   }
   
   
   
   
   
   
   
   //---Renderer
   @Override
   protected void render(float interpolation)
   {
      display.getRenderer().clearBuffers();
      
      pManager.renderPasses(display.getRenderer());
      
      menu.getDisplay().display();
   }
   
   
   
   //---Updater
   @Override
   protected void update(float interpolation)
   {
      //tpf
      timer.update();
      float tpf = timer.getTimePerFrame();
      
      
      
      //Keybindings
      //Keybindings by Fellkneul
      boolean up = KeyBindingManager.getKeyBindingManager().isValidCommand("up");
      boolean dn = KeyBindingManager.getKeyBindingManager().isValidCommand("dn");
      boolean lt = KeyBindingManager.getKeyBindingManager().isValidCommand("lt");
      boolean rt = KeyBindingManager.getKeyBindingManager().isValidCommand("rt");
      
      float currentSpeed = camSpeed * interpolation;

      if(KeyBindingManager.getKeyBindingManager().isValidCommand("exit"))
      {
         finished = true;
      }
      if(up)
      {
         Vector3f abc = camPivot.getLocalRotation().getRotationColumn(2);
         float winkel = abc.angleBetween(new Vector3f(0f, 1f, 0f));
         abc.multLocal(1 / FastMath.sin(winkel));
         abc.setY(0);
         abc.multLocal(-currentSpeed);
         camPivot.getLocalTranslation().addLocal(abc);
      }
      if(dn)
      {
         Vector3f abc = camPivot.getLocalRotation().getRotationColumn(2);
         abc.multLocal(1 / FastMath.sin(abc.angleBetween(new Vector3f(0f, 1f, 0f))));
         abc.setY(0);
         abc.multLocal(currentSpeed);
         camPivot.getLocalTranslation().addLocal(abc);
      }
      if(lt)
      {
         Vector3f abc = camPivot.getLocalRotation().getRotationColumn(0);
         abc.multLocal(1 / FastMath.sin(abc.angleBetween(new Vector3f(0f, 1f, 0f))));
         abc.setY(0);
         abc.multLocal(-currentSpeed);
         camPivot.getLocalTranslation().addLocal(abc);
      }
      if(rt)
      {
         Vector3f abc = camPivot.getLocalRotation().getRotationColumn(0);
         abc.multLocal(1 / FastMath.sin(abc.angleBetween(new Vector3f(0f, 1f, 0f))));
         abc.setY(0);
         abc.multLocal(currentSpeed);
         camPivot.getLocalTranslation().addLocal(abc);
      }
      if(KeyBindingManager.getKeyBindingManager().isValidCommand("strg"))
      {
         float pX = -((float) MouseInput.get().getXDelta() / (float) width);
         float pY = -((float) MouseInput.get().getYDelta() / (float) height);
         

         if(pX != 0) // Dreht um Y-Achse
         {
            Vector3f strich = camPivot.getLocalRotation().getRotationColumn(1);
            float winkel = strich.angleBetween(new Vector3f(0f, 1f, 0f));
            Vector3f theAxis = new Vector3f(0f, FastMath.cos(winkel), -FastMath.sin(winkel));
            camPivot.setLocalRotation(camPivot.getLocalRotation().mult(new Quaternion().fromAngleAxis(FastMath.HALF_PI * pX, theAxis)));
         }
         if(pY != 0) // Dreht um X-Achse
         {
            Vector3f theAxis = new Vector3f(1f, 0f, 0f);
            camPivot.setLocalRotation(camPivot.getLocalRotation().mult(new Quaternion().fromAngleAxis(FastMath.HALF_PI * pY, theAxis)));
            
            float winkel = camPivot.getLocalRotation().toAngles(null)[0] * FastMath.RAD_TO_DEG;
            if(winkel > camMaxWinkel)
            {
               float[] angles = camPivot.getLocalRotation().toAngles(null);
               angles[0] = camMaxWinkel * FastMath.DEG_TO_RAD;
               camPivot.getLocalRotation().fromAngles(angles);
            }
            else if(winkel < camMinWinkel)
            {
               float[] angles = camPivot.getLocalRotation().toAngles(null);
               angles[0] = camMinWinkel * FastMath.DEG_TO_RAD;
               camPivot.getLocalRotation().fromAngles(angles);
            }
         }
      }
      if(camZoomIn != 0)
      {
         if((camZoomIn > 0) && (camNode.getLocalTranslation().z < camMinZoom))
         {
            camNode.getLocalTranslation().z += camZoomIn;
            camZoomIn = 0;
         }
         else if((camZoomIn < 0) && (camNode.getLocalTranslation().z > camMaxZoom))
         {
            camNode.getLocalTranslation().z += camZoomIn;
            camZoomIn = 0;
         }
         else
         {
            camZoomIn = 0;
         }
      }
      
      //float preY = tb.getHeight(camPivot.getLocalTranslation().x, camPivot.getLocalTranslation().z);
      float preY = 0;
      
      if(Float.isNaN(preY))
      {
         camPivot.getLocalTranslation().y = 10;
      }
      else
      {
         camPivot.getLocalTranslation().y = preY;
      }
      
      
      camNode.updateWorldData(0);
      skybox.setLocalTranslation(cam.getLocation());
      
      
      rootNode.updateGeometricState(tpf, true);
      
      pManager.updatePasses(tpf);
   }
   
   
   
   
   
   
   //---Reinitialiser
   @Override
   protected void reinit()
   {
      
   }
   
   //---Aufr

it seems you render FengGUI in basegame's render method, try to render FengGUI in its own renderpass.

Its not easy to get FengGU und jme to work nicely together.

Search for FengGUI in the wiki, there are a few useful hints there.

I was having similar problems with FengGUI and GameStates regarding the use of XML themes.  I was able to fix my problem by creating the LWJGLBinding for FengGUI inside of the OpenGL thread:





GameTaskQueueManager.getManager().render(new Callable<Object>() {
    public Object call() throws Exception {

      // SET UP FengGUI HERE

      return null;
    }
  }).get();

first of all thanks for your help:



@core-dump: i will try out whether this helps later. it seems like sbook has experienced similar problems as i did, so i would like to try out his suggestions first.



@sbook: i'm sorry… but… i've got no idea what to do with this. Do i just add this piece of code in my initSystem method at the point where i used to setup the FengGUI? Because when i do so, the game would just stop working. The Future.get() function keeps waiting and nothing happens.

sbook refers to a problem, which can happen if you use multiple threads (when using standardgame or spawning your own threads).



Since you use BaseGame, this should not be an issue.

You will get a deadlock, because GameTaskQueueManager.getManager().render().get() never returns :wink:

right… now i understand… so what sbook said does not actually help me as im not using standardgame. what if i used standardgame?? would there be any improvement maybe??


Core-Dump said:

it seems you render FengGUI in basegame's render method, try to render FengGUI in its own renderpass.
Its not easy to get FengGU und jme to work nicely together.
Search for FengGUI in the wiki, there are a few useful hints there.


well.. that means i take a pManager and have it rendered it in my BaseGame.render() function? and i create some kind of renderPass for my fenggui and pass it to the pManager?

EDIT: pManager = BasicPassManager, sorry for that...

I'd stick with BaseGame, using StandardGame makes things more difficult.

There are only a few things to do, to render FenggUI in its own pass:



Extend RenderPass:


public class UserInterfaceMenu extends Pass {



Implement doRender() and apply default Renderstates before drawing FengGUI.
(it could be that jme was using another texture id than FenggUI is using)

   @Override
   protected void doRender(Renderer r) {
      for (RenderState rs : Renderer.defaultStateList) {
         rs.apply();
      }
      display.display();
   }



In your BaseGames render() method, do not draw the FengGUI display anmore. Instead add it as a RenderPass



   @Override
   protected void initGame()
   {
....
....
      pManager.add(menu);
   }
   //---Renderer


   @Override
   protected void render(float interpolation)
   {
      display.getRenderer().clearBuffers();
      pManager.renderPasses(display.getRenderer());
//      menu.getDisplay().display();
   }
   


works fine, thanks a lot!!