Using SimpleGame rootNode with GameStates

Hi fellow monkeys!



I've been starting to incorporate GameStates into one of my projects, and have noticed that the SimpleGame rootNode does not work well when used in addition to the GameStates.



To test this, I've created a SimpleGame that places a box at the origin and a GameState that creates a quad with its corner at the origin.



When the GameState is enabled, the quad is visible, as is the box, but the z order is not consistent. Sometimes the box is properly rendered in front of the quad, other times it is entirely behind the quad.



Both the SimpleGame rootNode and the GameState rootNode have ZBufferStates, and I believe I have updated the RenderStates properly before rendering.



Am I just missing something, or if I want elements to be visible in all GameStates (the origin box in this example), do I have to put it in its own GameState that is always enabled, or is there some way to have the SimpleGame rootNode render properly?



I am not opposed to using a separate GameState, it's just it'd be easier if I didn't have to. The common scene elements are mostly for debugging (origin box, axis indicators, etc.), and are somewhat temporary.



I've attached my test SimpleGame for debugging purposes.

Thanks!




/**
 * @author talyn
 */
public class GameStateTest extends SimpleGame {
   private TestGameState testGameState;

   @Override
   protected void simpleInitGame() {

      // init the default camera and input handler
      input = new FPSHandler( GameUtils.createCamera( 0.1f, 1000f, true, 45.0f ) );
      ((FPSHandler)input).getMouseLookHandler().setLockAxis( Vector3f.UNIT_Y );
      display.getRenderer().setCamera( ((FPSHandler)input).getCamera() );

      // create a box
      Box origin = new Box( "origin", Vector3f.ZERO, 1000, 1000, 1000 );
      origin.setModelBound( new BoundingBox() );
      origin.setSolidColor( ColorRGBA.orange );
      rootNode.attachChild( origin );
      origin.updateModelBound();
      origin.updateWorldBound();

      // turn off the lighting
      lightState.setEnabled( false );

      // update the root node
      rootNode.setRenderQueueMode( Renderer.QUEUE_OPAQUE );
      rootNode.updateGeometricState( 0, true );
      rootNode.updateRenderState();

      // init the game states
      GameStateManager.create();
      testGameState = new TestGameState();
      GameStateManager.getInstance().attachChild( testGameState );
      testGameState.setActive( true );
   }

   @Override
   protected void simpleUpdate() {
      GameStateManager.getInstance().update( timer.getTimePerFrame() );
   }

   @Override
   protected void simpleRender() {
      GameStateManager.getInstance().render( timer.getTimePerFrame() );
   }

   /**
    * @author talyn
    */
   private class TestGameState extends CameraGameState {
      private QuadMesh quadMesh;
      private FPSHandler input;

      public TestGameState() {
         super( "testGameState" );

         input = new FPSHandler( cam, 200, 0.4f );
         input.setRunFactor( 5 );

         quadMesh = new QuadMesh( "testQuadMesh", 3000, 3000, 4, 4 );
         quadMesh.setSolidColor( ColorRGBA.yellow );
         rootNode.attachChild( quadMesh );

         rootNode.setRenderQueueMode( Renderer.QUEUE_OPAQUE );
         rootNode.updateGeometricState( 0, true );
         rootNode.updateRenderState();
      }

      @Override
      protected void onActivate() {
         super.onActivate();
         rootNode.updateGeometricState( 0, true );
         rootNode.updateRenderState();
      }

      @Override
      protected void initCamera() {
         Vector3f camloc = new Vector3f( 1981.1938f, 1493.8588f, 4288.733f );
         Vector3f camdir = new Vector3f( -0.32673532f, -0.36782086f, -0.8706043f );
         cam = GameUtils.createCamera( 0.1f, 10000, true, 45.0f );
         cam.setLocation( camloc );
         cam.lookAt( camloc.add(camdir), Vector3f.UNIT_Y );
      }

      @Override
      protected void stateUpdate( float tpf ) {
         input.update( tpf );
      }
   }

   public static void main( String[] args ) {
      new GameStateTest().start();
   }
}



Edit: Here are some images from the latest StandardGameTest (see below):

Start (Full size: http://i43.tinypic.com/whgwhx.png)

Closer (Full size: http://i39.tinypic.com/2ytuyo9.png)

Even closer (Full size: http://i39.tinypic.com/ff46ma.png)

Closest (Full size: http://i39.tinypic.com/1zf0ut.png)

GameStates are meant to be used with StandardGame rather than SimpleGame :wink:



Take a look at jmetest.game.TestStandardGame for a usage exampleā€¦

The way you use the Gamestates is absolutely ok. Just because Gamestate is "invented"

with StandardGame does not mean that StandardGame is mandatory. In the end it is

just a very good way to divide a game into different parts with its own render and update-method.



Actually I didn't see anything about using ZBuffer in your code. Everything should work as you described it, if the ZBufferState is attached. Maybe you can post the part where you set this!?

Thanks for the replies, I've switched my testcase over to a StandardGame, only to have the same thing happen.



I've noticed that as the camera approaches the origin box, the box becomes more regular - to the point where at about 50 units from where the box and the quad intersect, the join looks regular (a straight line).



Moving the code for the creation of the box into the same GameState doesn't seem to make any difference, and going back to my original project, the same is true there.



Ttrocha, the original code I posted used some utility methods for creating rootNodes and cameras, the root node I was using had the default ZBufferState instantiated in SimpleGame and BasicGameState. I've removed those methods below, and am using default ZBufferStates (from BasicGameState):



   ZBufferState buf = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
        buf.setEnabled(true);
        buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
        rootNode.setRenderState(buf);



Any ideas?  :?

Here is my StandardGameTest:


/**
 * @author talyn
 */
public class StandardGameTest {
   private StandardGame game;

   public StandardGameTest() {
       System.setProperty( "jme.stats", "set" );      // Enable statistics gathering
      game = new StandardGame( "A Simple Test" );      // Instantiate StandardGame
   }

   public void start() throws InterruptedException {
      // Show settings screen
      boolean result = GameSettingsPanel.prompt(game.getSettings());

      if ( result ) {      // Start StandardGame, it will block until it has initialized successfully, then return
         game.start();

         GameTaskQueueManager.getManager().update( new Callable<Void>() {
            public Void call() throws Exception {

               TestGameState testGameState = new TestGameState();
               OriginBoxGameState originGameState = new OriginBoxGameState();
               GameStateManager.getInstance().attachChild( originGameState );
               GameStateManager.getInstance().attachChild( testGameState );
               originGameState.setActive( true );
               testGameState.setActive( true );

               return null;
            }
         });
      }
   }

   /**
    * @author talyn
    */
   private class OriginBoxGameState extends DebugGameState {

      public OriginBoxGameState() {
         // create a box
         Box origin = new Box( "origin", Vector3f.ZERO, 1000, 1000, 1000 );
         origin.setSolidColor( ColorRGBA.orange );
         origin.setModelBound( new BoundingBox() );
         origin.updateModelBound();
         origin.updateWorldBound();
         rootNode.attachChild( origin );

         // disable the lighting
         lightState.setEnabled( false );

         KeyBindingManager.getKeyBindingManager().set( "camprint", KeyInput.KEY_U );

//         rootNode.setRenderQueueMode( Renderer.QUEUE_OPAQUE );
         rootNode.updateGeometricState( 0, true );
         rootNode.updateRenderState();
      }

      /* (non-Javadoc)
       * @see com.jmex.game.state.DebugGameState#update(float)
       */
      @Override
      public void update( float tpf ) {
         super.update( tpf );
         if ( KeyBindingManager.getKeyBindingManager().isValidCommand( "camprint", false ) ) {
            Vector3f loc = DisplaySystem.getDisplaySystem().getRenderer().getCamera().getLocation();
            Vector3f dir = DisplaySystem.getDisplaySystem().getRenderer().getCamera().getDirection();
            System.out.println( "Vector3f camloc = new Vector3f( "+loc.x+"f, "+loc.y+"f, "+loc.z+"f );" );
            System.out.println( "Vector3f camdir = new Vector3f( "+dir.x+"f, "+dir.y+"f, "+dir.z+"f );" );
         }
      }
   }

   /**
    * @author talyn
    */
   private class TestGameState extends CameraGameState {
      private FirstPersonHandler input;

      public TestGameState() {
         super( "testGameState" );

//         // create a box
//         Box origin = new Box( "origin", Vector3f.ZERO, 1000, 1000, 1000 );
//         origin.setSolidColor( ColorRGBA.orange );
//         origin.setModelBound( new BoundingBox() );
//         origin.updateModelBound();
//         origin.updateWorldBound();
//         rootNode.attachChild( origin );

         input = new FirstPersonHandler( cam, 1000, 0.4f );
         input.getMouseLookHandler().setLockAxis( Vector3f.UNIT_Y );

         float size = 3000;
         Quad quad = new Quad( "testQuad", size, size );
         quad.getLocalRotation().fromAngleAxis( FastMath.HALF_PI, Vector3f.UNIT_X );
         quad.setLocalTranslation( size/2f, 0, size/2f );
         quad.setSolidColor( ColorRGBA.yellow );
         rootNode.attachChild( quad );

//         rootNode.setRenderQueueMode( Renderer.QUEUE_OPAQUE );
         rootNode.updateGeometricState( 0, true );
         rootNode.updateRenderState();
      }

      @Override
      protected void initCamera() {
         Vector3f camloc = new Vector3f( 1640.4131f, 1310.4327f, 4960.967f );
         Vector3f camdir = new Vector3f( -0.13918862f, -0.44239116f, -0.8859552f );

         int w = DisplaySystem.getDisplaySystem().getRenderer().getWidth();
         int h = DisplaySystem.getDisplaySystem().getRenderer().getHeight();
         cam = DisplaySystem.getDisplaySystem().getRenderer().createCamera( w, h );
         float aspect = ((float)w) / ((float)h);

         cam.setFrustumPerspective( 45.0f, aspect, 0.1f, 10000 );
         cam.setParallelProjection( false );
         cam.setLocation( camloc );
         cam.lookAt( camloc.add(camdir), Vector3f.UNIT_Y );
         cam.update();
      }

      @Override
      protected void stateUpdate( float tpf ) {
         input.update( tpf );
         cam.update();
      }
   }

   /**
    * @param args
    */
   public static void main( String[] args ) throws Exception {
      StandardGameTest sgt = new StandardGameTest();
      sgt.start();
   }
}



Edit: I just added some images from the above code to the first post