ZOrder between Quad and Text in Ortho

Hi.

I feel I missed something small and important this time also :frowning: :blush:

Poor me :frowning:



Akhem…

I have a Node with attached Quad (background) and 13 Texts (lines) that together with some glue code makes nice view part of MCV Console. Errr, the problem is that I cannot make text render above quad. I’ve read this http://www.jmonkeyengine.com/jmeforum/index.php?topic=3739.0, and trialled my understanding by many different combinations of ZOrder between Quad and Text and different ZBuffer functions, but I cannot make it work. In every tried combination, Quad renders above text lines (grrrrrrrrr)… my keyboard paid the tool of my anger  :evil:



When I disable quad (just by not attaching it to its parent Node) everything works like a cake, but when I enable it, it covers the Text.



Help… <gulp>… please…



Oh… the code, in case you bother to read…

Piece from Console spatial…


   private void textLines() {
        int fontHeight = 18;
        for (int i = 0; i < lines.length; i++) {
            lines[i] = Text.createDefaultTextLabel("console-line" + i, "");
            lines[i].setRenderQueueMode(Renderer.QUEUE_ORTHO);
            lines[i].setLocalTranslation(-(WIDTH / 2), fontHeight * i, 0);
            lines[i].setTextColor(ColorRGBA.yellow);
            lines[i].updateRenderState();
            lines[i].setZOrder(1);
            attachChild(lines[i]);
        }
    }

    private void background() {
        Quad background = new Quad("console-background", WIDTH, HEIGHT);
        background.setRenderQueueMode(Renderer.QUEUE_ORTHO);
        background.setDefaultColor(ColorRGBA.darkGray);
        background.setLightCombineMode(LightState.OFF);
        background.setZOrder(2);
        background.updateRenderState();
        attachChild(background);
    }



Piece from game where ZBuffer is set..


    private void zBuffer() {
        ZBufferState s = display.getRenderer().createZBufferState();
        s.setEnabled(true);
        s.setFunction(ZBufferState.CF_LEQUAL); // Tried CF_EQUAL, CF_LESS, CF_NOTEQUAL, CF_GREATER... no one gives a damn :'-(
        root.setRenderState(s);
    }

I don't see you calling updateRenderState anywhere yet, except before you attach the lines/quad (since it's not attachted yet that will not make it inherit it's (future) parent's zbuffer state or anything). Do you call it somewhere after you've set up your whole scene "tree"?

I had an issue with z-order and ortho also and I was able to get the text on top with

buf.setFunction(ZBufferState.CF_NOTEQUAL);



and text z-order set to 1. any of the other options (CF_LEQUAL, etc…) put the text behind the quad.

@llama, no, I don’t call it afterwards. I didn’t know its important to call it after attaching… I though I need to call updateRenderStates only on the node where render states are changed. Didn’t know that ZBuffer order goes to that…



Just tried it out, it doesn’t work… tried with CF_LEQUAL and CF_NOT_EQUAL with ZBuffer values set to both extremes… not sure if I understood: am I supposed to call updateRenderState on the ConsoleSpatial node after lines and background are attached (which I tried), or on the root when I attach ConsoleSpatial?



Also tried what mud2005 suggested and it doesn’t work. When setting ZBuffer function to CF_NOTEQUAL, the sphere that’s set to the center of space gets somewhat unhealthy ‘slice’ of grey. Here’s the screenshot.



Dunno if its important to mention, I’m using jme nightbuild on linux…

Also, I have an inventory system that uses quads positioned one above other, and ZBuffering works there without flaw… is there maybe some core difference in using Text instances against Quads?



Updated code from console spatial:


    public ConsoleSpatial(int windowHeight) {
        super("console");
        setRenderQueueMode(Renderer.QUEUE_ORTHO);
        setLocalTranslation(new Vector3f(WIDTH / 2, windowHeight - (HEIGHT / 2), 0));
        background();
        textLines();
        updateRenderState();
    }

    private void textLines() {
        int fontHeight = 18;
        for (int i = 0; i < lines.length; i++) {
            lines[i] = Text.createDefaultTextLabel("console-line" + i, "");
            lines[i].setRenderQueueMode(Renderer.QUEUE_ORTHO);
            lines[i].setLocalTranslation(-(WIDTH / 2), fontHeight * i, 0);
            lines[i].setTextColor(ColorRGBA.yellow);
            lines[i].setZOrder(2);
            attachChild(lines[i]);
      //      lines[i].updateRenderState();
        }
    }

    private void background() {
        Quad background = new Quad("console-background", WIDTH, HEIGHT);
        background.setRenderQueueMode(Renderer.QUEUE_ORTHO);
        background.setDefaultColor(ColorRGBA.darkGray);
        background.setLightCombineMode(LightState.OFF);
        background.setZOrder(1);
        attachChild(background);
//        background.updateRenderState();
    }

Sorry for doubleposting:



I've made it work (at least partially). The problem was in that I haven't set ZBufferState for the node, instead of I relied for it to inherit root's ZBufferState. Sorry for any inconveniences. Now I see the text above the quad, but as the chars are written, they delete the parts of the quad and show the scene beneath.  Must be something with alpha state, nevertheless, I'll take a look of it myself…

Just make sure every element in the scene has a proper Z-Buffer state, for example that it's always drawn (CF_ALWAYS, I believe) is fine, then if an object in in the ORTHO queue the Z-order decides when which element is drawn, and so every element will draw on top of the last one this way.



The renderstates of an individual element are set when you invoke updateRenderState() on it, or if you updateRenderState() on one of it's parent Nodes (and of course the child has to be already attachted for that). If you're not sure your element has the right Zbuffer state, just use the debugger to pause your application, and check for yourself.



If you can make a test where there's 2 overlapping elements (such as 2 quads, or a text and a quad) where the overlap can not be switched by exchanging their distinct z-order values, I'd say we have a bug.



edit for the new reply while I was posting this:

Even if a pixel is invisible (due to alpha), it still writes to the Z-Buffer. So when you next draw a quad, and you use a z-test to see if it can draw there if nothing has been drawn before, it will fail. It's easier to do it the other way around: make sure elements are ALWAYS drawn, so the last element to be drawn will be the one on top. This way your alpha blending happens on top or areas already drawn. If you have a lot of overlap this might be a bit slower… but it'll save you some headaches.


Can you please point me somewhere where I can read all about functions used in ZBuffering, AlphaState and Texturing?  I don't quite understand how it all works and what are the effects of changing function… I mean, I can see the difference, but I don't really know what am I doing when changing something. When I say functions I mean functions as int flags as CF_xxx or SB_xxx and similar stuff set in render states.



edit:

P.S. when setting ZBuffer to CF_ALWAYS for node that has background and text lines as children, text is again behind the background (tried setting both zorders one higher than the other). CF_NOTEQUAL seems to does what I want. If I only made that alpha works OK…



edit2:

found enough explanations on wikipedia, sorry for buggin'…

I wish :slight_smile: I don't understand half of how alpha / texture-blending works myself.



The javadoc for the CF_ zbuffer states is ok though, as long as you understand how a zbuffer works. For that I think you can find some good information with a bit of googling or even wikipedia.

Beat me if I understand anything now… I'm confused as hell…



The worst part is that I've made it work without even touching alpha blending. And I don't know why it works, but it does :smiley:

What I've made is setting two distinct zbuffers for background and text lines. The background zbuffer is set to CF_ALWAYS pass the test, and line's zbuffer passes on CF_EQUALS.

It even clips my text not to go out of console window… I be damned :smiley:



Here's the code if anyone gets to same troubles. Please comment if something is wrong or anti-patterned.


    public ConsoleSpatial(int windowHeight) {
        super("console");
        setRenderQueueMode(Renderer.QUEUE_ORTHO);
        setLocalTranslation(new Vector3f(WIDTH / 2, windowHeight - (HEIGHT / 2), 0));
        background();
        textLines();
        updateRenderState();
    }

    private void textLines() {
        int fontHeight = 18;

        ZBufferState state = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
        state.setEnabled(true);
        state.setFunction(ZBufferState.CF_EQUAL);

        for (int i = 0; i < lines.length; i++) {
            lines[i] = Text.createDefaultTextLabel("console-line" + i, "");
            lines[i].setLocalTranslation(-(WIDTH / 2), fontHeight * i, 0);
            lines[i].setTextColor(ColorRGBA.yellow);
            lines[i].setRenderState(state);
            attachChild(lines[i]);
        }
    }

    private void background() {
        Quad background = new Quad("console-background", WIDTH, HEIGHT);
        background.setDefaultColor(ColorRGBA.darkGray);
        background.setLightCombineMode(LightState.OFF);

        ZBufferState state = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
        state.setEnabled(true);
        state.setFunction(ZBufferState.CF_ALWAYS);
        background.setRenderState(state);

        attachChild(background);
    }

Text sets it's own alpha blending, so it's already being used here :slight_smile:



It "works" now, because you tell it to always draw the background and the lines (ALWAYS), and the text only if something already has been drawn at that z-depth (EQUAL). (actually that is a pretty funny hack to do clipping).



If text were to be drawn first however, it would not show up. The only reason it works now is cause they have the same Z order, and right now it happens to be that jME draws the first item added to a Node before the second item if their zorder is the same. (switch around background(); and textLines(); and it'll probably stop working). Maybe in the future it will stop working anyway if we do some different type of sorting or adding childeren to nodes.



So I'd encourage you to just add some setZorder() methods to all the scene elements, and see for yourself which will make it keep working and which won't.


Now I see the text above the quad, but as the chars are written, they delete the parts of the quad and show the scene beneath.


to solve this I loaded a font with alpha background instead of black and filter option

Texture.FM_NEAREST

instead of

Texture.FM_LINEAR

here is example

URL fontLoc;
      fontLoc = JMEEnterTextField.class.getClassLoader().getResource(
            "Data/Images/Font/mygamefont.png");
      
      TextureState fontTS = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
      Texture t = TextureManager.loadTexture(fontLoc, Texture.MM_LINEAR,
            Texture.FM_NEAREST, Image.GUESS_FORMAT_NO_S3TC, 1f, true);
      fontTS.setTexture(t);
      fontTS.setEnabled(true);
         
      playerNameText = Text.createDefaultTextLabel("text", playerNames);
           playerNameText.setRenderState(fontTS);
      playerNameText.updateRenderState();



EDIT: after testing this was a bad fix I ended up not using a z buffer at all and somehow got it to work, not even sure I made so many changes to my code at once. wish I could be more help

Truly, its not working when attaching order is switched… and the minute I though I managed to do it… grrrr :frowning: … I'm sorry for trying your patience out there…



@mud2005

This piece of knowledge purified my thoughts, that damn font hasn't alpha channel… so it overwrites background quad. And I'm banging my head over the wall why my inventory (which works pretty same way) works OK, and this does not. I'll try again… thanks…

deus_ex_machina said:

Truly, its not working when attaching order is switched... and the minute I though I managed to do it... grrrr :( ... I'm sorry for trying your patience out there...



Yes, but you're very close. If you set the proper z-orders, you should be able to switch these around and it will still work.. because the zorder will decide the order in which things are drawn.. you understand?

I hope I do, but it doesn’t work. I made font which doesn’t have black background but has alpha instead, set CF_NOTEQUAL and it draws OK on the background… the problems is, when it passes over the background and the sphere which just lies on the behind background as a test, text brightens… see screenshot



Inventory doesn’t work so pretty as I’ve though… I switched order of attaching items and background quads, and imagine, items won’t draw… same story…

I’m going nuts a bit…



If you’re telling me to set ZBuffer to CF_ALWAYS to both text and background, then set zOrders on both, it doesn’t work no matter what are the zOrder equations, one higher than the other does not make difference: in any case quad overlaps the text. I though that hack I’ve done before should work if quad is rendered before the text (by setting zorder) but it doesn’t work. I’m getting REALLY embarrassed here!



Edit:

One funny thing to mention about the hack before… I’ve just tried to change the text z-buffer to be CF_ALWAYS (so it doesn’t clip on the edge of the background)… the second I set the z-orders, it stops working. It puts the text behind the quad… I haven’t touch the attaching order, just made the setZOrder calls on both text lines and the quad… if those methods are called, background gets proudly pushed in the foreground… setZOrder calls commented, works as expected to work…



Edit 2:

…and, the second later, funnier thought came to my mind and problem fixed!

Only one zbuffer is set, to the parent Node…

zOrder to text is set to MINUS 1!!! And it draws the text over the background!

Attaching order is unimportant, no need for alpha text (as you see I use static factory method), if you want clipping, just add zbuffer to textlines which is set to CF_EQUAL…



Did I miss to read somewhere that zOrders are supposed to be set from 0 (reading source, it is initialized to 0) to -MAX or …?



Here’s the final code… finally my personal drama ends… please, please please put somewhere in javadoc that zorders are supposed to go to minus if you want something to be drawn first…



Carpe diem, I’m going to sleep happy :smiley:



  public ConsoleSpatial(int windowHeight) {
        super("console");
        setRenderQueueMode(Renderer.QUEUE_ORTHO);
        setLocalTranslation(new Vector3f(WIDTH / 2, windowHeight - (HEIGHT / 2), 0));
        textLines();
        background();
        zbuffer();
        updateRenderState();
    }

    private void zbuffer() {
        ZBufferState state = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
        state.setEnabled(true);
        state.setFunction(ZBufferState.CF_ALWAYS);
        setRenderState(state);
    }

    private void textLines() {
        int fontHeight = 18;
        int start = -(HEIGHT / 2);

        for (int i = 0; i < lines.length; i++) {
            lines[i] = Text.createDefaultTextLabel("console-line" + i, "");
            lines[i].setLocalTranslation(-(WIDTH / 2), start + (i * fontHeight), 0);
            lines[i].setTextColor(ColorRGBA.yellow);
            lines[i].setZOrder(-1);    // THIS LINE IS VERY IMPORTANT!
            attachChild(lines[i]);
        }
    }

    private void background() {
        Quad background = new Quad("console-background", WIDTH, HEIGHT);
        background.setDefaultColor(ColorRGBA.darkGray);
        background.setLightCombineMode(LightState.OFF);
//        background.setZOrder(1);
        attachChild(background);
    }



edit 3:
after a little bit of research, it seems that renderer doesn't really care for the value of zOrder, just for the sign. I tried to set background to be 'more minus' than text, then less minus than text, and renderer doesn't seem to bother with it... text is always in front of the quad.
On the other side, while zOrders are positive, renderer doesn't care if one is lesser or greater than the other: background always gets drawn infront the text.
Attaching order is unimportant, I've tried switching it.

Now... I guess that probably I don't know how to use ZOrders correctly, but this seems rather un-intuitive to me. And its not really usable if you have few layers of ortho graphics one over another...
You can try to compile the code above and play with setZOrder a bit for a test.

Well, maybe there's a bug. Text does some funky-special LWJGL stuff. Does it work if you use two quads instead of quad+text?

My inventory uses such solution.

Multiple quads textured with a cube, arranged in grid represent diablo-style inventory. Items are additional quads textured with item image and alpha state set, then positioned 'above' inventory quad-grid.



Yesterday I tried to revert attaching order (it first attached quads that make up the grid and then item quads), and it stopped showing the item. I tried setting zOrders and zbuffer state (CF_ALWAYS), and renderer doesn't care at all for zOrders. If cubes are attached first, items get drawn, if items are attached first, cubes overwrite them.



I can probably clean InventorySpatial of some dependencies and put together a test for quads, if  you want.

Regarding Text and Quad, code in my previous post should be without any special dependencies (only jme) so just copy&paste&compile to see the behaviour.

I don't know if it's a good way to do things, but I gave up on ORTHO for my game, I have a pass that sets the camera to parallel projection with the right parameters to get the same effect as the ORTHO pass, but without the harsh clipping in the Z (+/- 1). That means that I can have objects with large Z coordinates to be in front of/behind each other, and 3D objects (orthographically projected) so I can have stuff like spinning dials etc. I can give some more details if it sounds useful.

Everything sounds useful to me :smiley:

Please, give details…

Even if not now, it is useful to know stuff in case I would need it sometimes in the future, and on the other hand, there could be someone reading this topic with same problems and willing to use your solution…



For me, I'll probably try to dig into JME code and maybe fix this ZOrder stuff…

Actually, I just realised that it doesn’t work with Text, which only seems to work on ORTHO :wink: Ah well, if I work that out I’ll let you know :wink: If you want to see the code in the meantime, it needs some work (e.g. accepting parameters for camera, or swapping cameras instead of just changing parameters), but it’s here: https://aircarrier.dev.java.net/source/browse/aircarrier/src/net/java/dev/aircarrier/pass/