Missing Z buffer in plain StandardGame?

Hey all,



I’m an old-skool C++/GL programmer with some C# and D3D knowledge, and I’m now learning Java/jME. Well, re-learning Java, as I actually worked on two JVM implementations back in the 1.0/1.1 days :wink:

Following the StandardGame tutorial, it creates a box, sets the vertex colors randomly, and adds the box to a DebugGameState.

However, when rendering (on my GeForce 7400), the box renders wrong. It almost looks inverted, but by hazarding a guess, I’d say the Z buffer is not working, and the box is being rendered without backface culling.

Is this a known issue? Is it intended to be this way?

The documentation is all functions/classes and no overview or requirements, I’m afraid, so it hasn’t answered this question when I looked.






Just make a ZBuffer render state for your Node. I think only SimpleGame creates a ZBufferState for you…



(though if that's the case it should probably be mentioned in the http://www.jmonkeyengine.com/wiki/doku.php?id=simplegame_to_standardgame tutorial)

Thanks for the answer! Unfortunately, I'm already creating a ZBufferState, and attempting to make sure the settings request a depth buffer from GL. At least, I think that's what I'm doing. Here is the code:



import com.jme.math.*;
import com.jme.scene.*;
import com.jme.scene.shape.*;
import com.jme.scene.state.*;
import com.jme.system.*;
import com.jmex.game.*;
import com.jmex.game.state.*;
import java.util.prefs.*;

public class TestMain extends StandardGame {

   /**
    * @param args The arguments to the program.
    */
   public TestMain(GameSettings gs) {
      super("TestMain Game", StandardGame.GameType.GRAPHICAL, gs);
   }
   public static void main(String[] args) {
      GameSettings gs = new PreferencesGameSettings(Preferences.userRoot());
      gs.setDepth(32);
      gs.setAlphaBits(8);
      gs.setStencilBits(8);
      gs.setDepthBits(8);
      gs.setFullscreen(false);
      gs.setVerticalSync(false);
      gs.setWidth(800);
      gs.setHeight(600);
      TestMain app = new TestMain(gs); // Create Object
      // Signal to show properties dialog
      app.setDialogBehaviour(StandardGame.ALWAYS_SHOW_PROPS_DIALOG);
      app.start(); // Start the program
      app.setupBaseGameState();
   }
   void setupBaseGameState() {
        DebugGameState gameState = new DebugGameState();   // Create our game state
        ZBufferState zbs = display.getRenderer().createZBufferState();
        zbs.setFunction(ZBufferState.CF_LEQUAL);
        zbs.setEnabled(true);
        Node rootNode = gameState.getRootNode();
        rootNode.setRenderState(zbs);

        GameStateManager.getInstance().attachChild(gameState);   // Attach it to the GameStateManager
        gameState.setActive(true);   // Activate it

        Box box = new Box("TestBox", new Vector3f(), 1.0f, 1.0f, 1.0f);      // Create a Box
        box.setRandomColors();   // Set random colors on it

        rootNode.updateRenderState();
        box.updateRenderState();

        rootNode.attachChild(box);   // Attach the box to rootNode in DebugGameState
    }
}




Btw: when should I call updateRenderState()? If I move the calls to updateRenderState() below the call to rootNode.attachChild(box), then the box doesn't render in color, but instead renders in gray (like an unlit/ambient object with a missing texture).
My understanding of updateRenderState() is that calling it later shouldn't matter.
I'm using the 1.0 downloadable release, btw.

And, reading the code for DebugGameState.java, it actually sets the Z buffer state, too. So I'm stumped.

I took GLIntercept to the program, and here are all mentions of "depth" in the call log.





C:JavaEasyEclipse Expert Java 1.3.0jrebin>grep -i depth gliInterceptLog.txt

wglGetProcAddress("glClearDepth")=0x0000

wglGetProcAddress("glDepthRange")=0x0000

wglGetProcAddress("glDepthMask")=0x0000

wglGetProcAddress("glDepthFunc")=0x0000

wglGetProcAddress("glDepthBoundsEXT")=0xb3cddd0

glDisable(GL_DEPTH_TEST)

glDepthMask(true)

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)



glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)



C:JavaEasyEclipse Expert Java 1.3.0jrebin>







Note that the depth test gets disabled, and never re-enabled. How come?

If I assign "zbs" to the box in addition to the root node, before calling updateRenderState() on either, then the Z test is properly enabled for the box.

I thought that child nodes inherited the states as set by the parent node? At least, there's a sticky thread to that effect.

What's going on?

Your two questions are actually linked (sorry for not spotting it sooner)



  rootNode.updateRenderState();
  box.updateRenderState();

  rootNode.attachChild(box);   



The only way to update a Geometry's renderstate objects (based on inheritance) is by calling update renderstate. That's because calculating all the inhereted renderstates is expensive (espc LightState and such), so the programmer is given control over that.

As you see you update the renderstates of Box before it is a child or rootNode, thus it doesn't inherit any states.

So the render states are not inherited by collection when descending the node tree, but instead inherited by copying or referencing when calling updateRenderStates(). I see. In other scene graphs that inherit render states in the graph, the inheritance typically happens during traversal, and is thus "free."



Personally, I don't like putting render state in the transform/containment hierarchy at all. Just because a tree and a rock are both in a mossy forest, doesn't mean they both share a "moss" texture after all. But, hey, that's a discussion for another forum. Thanks for your help!

They can't be inhererted by descending the node tree at render time, because that's not order objects are drawn in. (unless you use the unoptimized method (renderqueue) of drawing). So it can't be done for "free". Calculating the correct render states by updating the tree when the user requires it (by calling updateRenderState) allows for some very good optimizations (right now for example we do sorting on texture state when drawing the opaque queue, which allows for huge FPS boosts… you couldn't do that if every time you ask an object what it's texture state is it would have to go down the branch to collect it's state).



For textures, light, etc. you can control wether you want them to inherit textures, light, etc or not. Maybe you don't want moss on the tree to have the same texture, you're certainly likely to want the same LightState. There are many more cases like that…

They can't be inhererted by descending the node tree at render time, because that's not order objects are drawn in.


I view traversal (selecting, really), sorting (batching), and rendering (issue) are three separate phases. Depending on what you're doing, you want to sort different ways. For example, if you do pass-per-light, you want the first pass to write to Z, and be drawn from near-to-far, to improve early-Z culling. Anyway, I was just offering observations.

I agree that there may be many objects that share material, lighting, and other environment state -- but tying that sharing to the transform/containment hierarchy is unnecessarily constrictive. Luckily, sharing can also be done by just assigning the same state object to multiple objects, so I could create just a single, flat "hierarchy" of objects, and then do state sharing using another mechanism, so I'm not complaining.

Yes, the "mixing" of these different hierachies is not per se the "best" or "most powerful". It is however IMHO, the easiest to understand.

A little bit off-topic here… You are not supposed to extend StandardGame or might make little amphibians cry  :P.



Instead, create a class that has a StandardGame reference and do your computations exclusively in GameStates or other threads using the GameTaskQueue.

duenez said:

A little bit off-topic here... You are not supposed to extend StandardGame or might make little amphibians cry  :P.

Instead, create a class that has a StandardGame reference and do your computations exclusively in GameStates or other threads using the GameTaskQueue.


Your frog suit is in the mail.

To not divert any further from the OP's original questions, I started a new thread about the correct usage of StandardGame.

http://www.jmonkeyengine.com/jmeforum/index.php?topic=6575