Clearing the Z-Buffer

Here is what I want to do:



I want to have a hud that is 3D. I obviously don’t want it to move relative to the camera.



First problem: I could set the local translation and local rotation of the top-most “hud” node to the inverse of the camera. This would stop it moving. I would have preferred to set my own camera (model view matrix) though.



Second problem: I can’t clear the z-buffer and change the near/far planes. Setting the planes would be nice, but is not as critical as clearing the z-buffer.



So, my thoughts for overcoming the second problem were to introduce my own custom RenderState, which would call the renderer’s clearZBuffer() function. Seemed easy enough, except that RenderStates are kept in a fixed sized array and accessed by index:


    public RenderState setRenderState(RenderState rs) {
        RenderState oldState = renderStateList[rs.getType()];
        renderStateList[rs.getType()] = rs;
        return oldState;
    }



and without hacking at RenderState, I can't increase RenderState.RS_MAX_STATE.

My second thought on this would be to override the draw method of a custom Node derived class. This seems to be quite a good option, because I can both set my own camera and clear the Zbuffer, then proceed to call all the children and on return, restore the original camera.

Therefore, as it turns out, the original reason I wanted to add to RenderStates is not a problem, however, another reason that is a problem is if I want to change the point size. So I am posting here to ask what the procedure is for adding render states?

As you know, OpenGL is a state machine. At any point of the rendering pipe, states are on or off (texture bindings, smoothing, lighting, etc), therefore, this problem falls out of the perview of RenderState and more into a Controller.



You can add an abitrary number of controllers to a node and they will perform each frame when the node is reached.

Thanks for your reply, but I don’t quite follow. I realise that reading my post I was a bit incoherent, so I’ll also try and clear it up a bit.



A controller is used in the update traversal of the scene graph, right? Which is very useful for things like updating the position and orientation of a node to that of the camera. However, a controller will not let me (as far as I understand):

  • clear the z buffer for this node (important)
  • change the near and far clipping planes (not critical)



    The other (somewhat cryptic) question in my post was how does jME handle the situation where a new state is needed, since not all OpenGL states are covered in the current set of RenderStates. For example, I would like to change the point size?

Ok, I’ve implemented some controllers to follow the camera. Posting code here to help anyone else who wants to do this.



FollowCamController makes nodes move with the camera. This is good for backgrounds like skydomes or star fields.



public class FollowCamController extends Controller {

    public Spatial[] toChange;

    public FollowCamController() {
        toChange = new Spatial[0];
    }
   
    public FollowCamController(Spatial node) {
        toChange = new Spatial[1];
        toChange[0] = node;
    }
   
    public void addSpatial(Spatial node) {
        // only add if a new node
        int i;
        for (i=0; i<toChange.length; ++i)
            if (toChange[i]==node)
                return;
        // increase toChange size
        // I do this because I assume this method is called only a few times
        // during init, so optimise for update() (below)
        Spatial[] temp = new Spatial[toChange.length+1];
        for (i=0; i<toChange.length; ++i)
            temp[i] = toChange[i];
        toChange = temp;
        toChange[i] = node;
    }
   
   
    /* (non-Javadoc)
     * @see com.jme.scene.Controller#update(float)
     */
    public void update(float time) {
        Camera cam = DisplaySystem.getDisplaySystem().getRenderer().getCamera();
        for (int i=0; i<toChange.length; ++i) {
            toChange[i].setLocalTranslation(cam.getLocation());
        }
    }
}



MatchCamController makes nodes stay put relative to the camera. Good for huds and the like.


public class MatchCamController extends Controller {

    public Spatial[] toChange;

    public MatchCamController() {
        toChange = new Spatial[0];
    }
   
    public MatchCamController(Spatial node) {
        toChange = new Spatial[1];
        toChange[0] = node;
    }
   
    public void addSpatial(Spatial node) {
        // only add if a new node
        int i;
        for (i=0; i<toChange.length; ++i)
            if (toChange[i]==node)
                return;
        // increase toChange size
        // I do this because I assume this method is called only a few times
        // during init, so optimise for update() (below)
        Spatial[] temp = new Spatial[toChange.length+1];
        for (i=0; i<toChange.length; ++i)
            temp[i] = toChange[i];
        toChange = temp;
        toChange[i] = node;
    }

    /* (non-Javadoc)
     * @see com.jme.scene.Controller#update(float)
     */
    public void update(float time) {
        Camera cam = DisplaySystem.getDisplaySystem().getRenderer().getCamera();
        Matrix3f m = new Matrix3f();
        m.fromAxes(cam.getUp(),cam.getDirection(),cam.getLeft());
        for (int i=0; i<toChange.length; ++i) {
            toChange[i].setLocalTranslation(cam.getLocation());
            toChange[i].setLocalRotation(m);
        }
    }
}



I still don't know what to do about the z-buffer, though.

Why can’t you add something like a setRenderer(Renderer) method to your controller so that you have direct access to the given renderer to call clearZBuffer() on? Alternatively, you could simply do: DisplaySystem.getDisplaySystem().getRenderer()



On a different note though, why do you want to clear the zbuffer? If you are trying to draw a GUI, you should not have any zbuffer issues if you are using the provided ortho queue and spatial’s z-ordering.