Z Buffer Problems

Hi!



I'm building a little factory simulation game, where the player plops machines onto a factory floor where they can interact. It's also my first JME project, so I'm learning the ropes. I appreciate your patience with a newbie question.



My problem is that the ZBufferState I put on my root node isn't working for me. Here is what I've done so far:



Initialize my "empty factory" scene onto the root node. A quad to act as the factory floor, a texture state for the quad, and an AxisRods primitive at the origin so I don't get confused. I'm leaving the texture stuff out of the snippet, it shouldn't affect zbuffer stuff. Then I set up a ZBufferState with LessThanEqualTo, make it writable and enabled, then add it to my root node.



Am I correct in assuming that if my root node has a ZBufferState on it, all of its children it will be treated the same way zbuffer-wise?



mOriginMarker = new Node("Origin");
mOriginMarker.attachChild(new AxisRods("Axes", true, 0.5f));

Quad floor = new Quad("Factory Floor", 16f, 16f);
floor.translatePoints(8f, 8f, 0f);
floor.setModelBound(new BoundingBox());
floor.updateModelBound();
// texture is loaded at this point, fed into a texturestate, and it seems to work
floor.setRenderState(textureState);

// Z Buffer
zBuffer = mDisplay.getRenderer().createZBufferState();
zBuffer.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
zBuffer.setWritable(true);
zBuffer.setEnabled(true);
      
mRootNode.setRenderState(zBuffer);
mRootNode.attachChild(mOriginMarker);
mRootNode.attachChild(floor);
mRootNode.updateGeometricState(0.0f, true);
mRootNode.updateRenderState();



So when I render that, it looks as I expect (figure A), but I added the nodes in the right order, so that's no surprise.

Later, when you hit a button, a new node is added to the Root Node (a sibling to the floor). This node contains 4 quads that are supposed to be a quick and dirty blueprint-looking of where a new machine will be placed. It's a blue squashed box (2 by 2 by 0.01) as a base with 3 cyan squashed boxes on top of it (each 1x1x0.2). It should look like a square with 3 quadrants covered up. It is very ugly, I'll fix that later ;).

This is what showed me that my ZBuffer isn't on. When I attach the 3 tiles to the blueprint node, THEN add the base, it renders the base above them. When I add the base first, it renders well.



A = Before
B = What I have
C = What I want to do without worrying about the order I attach my spatials

Did I set up my ZBufferState incorrectly? Do I have to add it to every node that I want depth-checking on (even if it is already on the parent)? Do I need to do something other than update the geometry when I add the new blueprint node to my scene?

Thanks for your help,
Fletch

Hi Fletch,



have you ever tried to use the SceneMonitor extension ?

http://code.google.com/p/scenemonitor/



It's a great tool to test / fix attributes of the objects of your scene graph (included the renderStates like ZBufferState).

Here's an example skeleton class that shows how to use it:



package com.lotec.lessons.loader.ogre;


import com.acarter.scenemonitor.SceneMonitor;
import com.jme.app.SimpleGame;


public class SceneMonitorExample extends SimpleGame
{
  public static void main(String[] args)
  {
    SceneMonitorExample app = new SceneMonitorExample();
    app.setConfigShowMode(ConfigShowMode.AlwaysShow);
    app.start();
  }


  @Override
  protected void simpleInitGame()
  {
    // your init code here;

    SceneMonitor.getMonitor().registerNode(this.rootNode, "Root Node");
    SceneMonitor.getMonitor().showViewer(true);
  }


  @Override
  protected void simpleRender()
  {
    super.simpleRender();
   
    // your render code here;
   
    SceneMonitor.getMonitor().renderViewer(display.getRenderer());
  }


  @Override
  protected void simpleUpdate()
  {
    super.simpleUpdate();
   
    // your update code here;
   
    SceneMonitor.getMonitor().updateViewer(tpf);
  }


  @Override
  protected void cleanup()
  {
    super.cleanup();
   
    // your cleanUp code here;
   
    SceneMonitor.getMonitor().cleanup();
  }
}




See also the attached picture for a real use case ...

That looks awesome! I imagine that would be really helpful. I'll be checking that out presently. I imagine it will become more useful as I get deeper into this stuff.



And I appreciate the skeleton code, too.



Thanks!

Fletch

I set up SceneMonitor (very easy to integrate, took like 2 minutes) and I learned a couple of things.



First of all I see that I got a ZBufferState with the LessThanOrEqualTo function, setWritable(true) and setEnabled(true) for free! There was already one in my BasicGameState's rootNode, it had been set up in the constructor before I even got there. I didn't even have to create one on my own.



The next weird thing is that when I click on the "BluePrint" node in SceneMonitor to look closer, it suddenly fixes the ZBuffer issue on the display! That made me think that maybe my issue was calling updateRenderState().



So, I dropped in an "updateRenderState()" after I added the blueprint.



if ( theUIEventToBuildThingWasHit() )
   mPositioningBlueprint = new BlueprintSprite(mFactoryManager.getNewMachineType());
        rootNode.attachChild(mPositioningBlueprint.getNode());      
   // New!
        rootNode.updateRenderState();
}



And now it works as I expect it to. My understanding of updateRenderState() was that it should only be called when RenderStates are changed. But it seems like when you add children to the scenegraph you also have to call it in order for the RenderStates to percolate all the way through. I'll look at the code and search the forums to get a better understanding of that.

Thanks for your help,
Rob

Hi Rob,


Fletch said:

My understanding of updateRenderState() was that it should only be called when RenderStates are changed. But it seems like when you add children to the scenegraph you also have to call it in order for the RenderStates to percolate all the way through. I'll look at the code and search the forums to get a better understanding of that.


That's correct, but you should also update the render state(s) of the new object, after attaching it to the root node (if you don't call rootNode.updateRenderState() at the end of your method).
To do this, you could use myObject.updateRenderState() - it should be faster that calling rootNode.updateRenderState() again.

See also this topic, that talks about a similar problem:
http://www.jmonkeyengine.com/jmeforum/index.php?topic=11184.msg84385#msg84385
Fletch said:

I set up SceneMonitor (very easy to integrate, took like 2 minutes) and I learned a couple of things.

Good to hear!