How does zLevel work?

None of my tests at getting zLevel to work have worked. I expect that I’m just doing something silly, but I’ve no idea what. Does anyone have any sample code that uses zLevel which shows how it is supposed to be used?

My simplest test was just something like the following (in the draw() function):

zLevel(0)
background(0,0,0,255)
translate(WIDTH/2,HEIGHT/2)
fill(0,255,0,255)
ellipse(0,0,40)
fill(255,0,0,255)
zLevel(-1)
ellipse(20,20,40)

Then I tried playing around with different values for the second zLevel. With 1 then I get a sensible result. With -1 then the red circle is under the green one, but there’s a square chopped out instead of a circle. With large numbers (c. \pm 10) then the red circle disappears.

What am I doing wrong?

Looks like there’s a problem with the ellipse shaders on iPad. I’ll have to look into this. Sorry, Andrew, looks like you’ve discovered a bug!

All zLevel is doing is setting the z-transform on the current matrix. (You can actually pass a z parameter to transform(x,y,z) for the same effect.)

The bug is to do with the rendering, right. So that doesn’t explain (or does it?) why the ellipse simply stops rendering for large values of the zLevel.

I imagine it could be exceeding the OpenGL near and far planes.

I’ve just checked and the near and far planes of the camera are -10 to 10. So any z value beyond those will be clipped.

Reviving this old topic. I’m having another problem with zlevel and/or translation along the z axis.

I’ve been trying to draw my sprites at different z levels as a quick alternative to sorting and drawing everything in z-order. However, the transparent areas of sprites interact unpredictably when on different z levels. Quite often, areas that are blank on a “front” sprite show through pixels from primitives (lines, rects, etc) behind the sprite, but ignore the “rear” sprite.

Example of the issue. Both the tree and the bull are sprites with depths between -10 and 0, the grass is drown at z level 10.

Is there an alternative way to deal with draw order without having to do frame by frame sorts?

.

Hello @Mark. The simple code below also illustrates what you are observing:


--
-- Z Order Explorer
--

function setup()
    img = {}
    img[1] = readImage("Small World:Tree Cone")
    img[2] = readImage("Small World:Watch Tower")
    img[3] = readImage("Planet Cute:Character Princess Girl")
    -- These parameters are the beta 1.5 version of the Codea API
    -- Version 1.4.6 will need to use the previous syntax
    parameter.number("Z1", 0, 10, 2)
    parameter.number("Z2", 0, 10, 5)
    parameter.number("Z3", 0, 10, 8)
    rectMode(CENTER)
end

function draw()
    background(0)
    translate(WIDTH/2, HEIGHT/2)
    zLevel(0); local z = 0 -- Keep track of z level
    fill(37, 235, 22)
    rect(0, 0, WIDTH * 0.8, HEIGHT * 0.8)
    imgZ = {Z1, Z2, Z3}
    scale(3, 3)
    for i = 1, 3 do
        local dz = imgZ[i] - z
        zLevel(dz); z = z + dz -- Keep track of z level
        sprite(img[i], i * 20 - 40, 0)
    end
end

I am wondering: Is this, however, the expected behaviour given how OpenGL deals with these sorts of things? See this article on transparency sorting.

Yes, this is due to transparency sorting.

.@Mark you would only need to do y-sorting on your trees and characters (after drawing your level). So you draw from highest y-value to lowest.

@Simeon, the trouble is (of course) that all the creatures can be in motion at once. So trees and critters need to be pitched into a common array (quite different from the current code where the bull, targets, special creatures, and trees are all different tables) and then sorted on each draw cycle.

It’s quite possible, obviously, and not even that difficult, but it means quite a bit of refactoring the current code.

Could you maintain an additional table containing the trees and critters? From my understanding they are static and do not get created mid-level. So it would just be a once-off (per level load) to merge the two game logic lists into one rendering table. The rendering table (e.g., allObjects) gets sorted on Y each frame.

That is:

table.sort( allObjects, function( o1, o2 ) return o1.y > o2.y end )

for _,obj in pairs(allObjects) do 
    obj:draw()
end

Sorting may be long. You can just have a table of z with 1’s an 2’s and cycle twice through the list, once tagetting the 1’s and then targetting the 2’s.

.@Jmv38 probably not in this case — it looks to be around 10 - 20 objects, so a very small amount to sort.

The reason you want to sort on Y position is because as a character moves down the field it can go from “behind” the tree to “in front of” the tree. I think your suggestion would handle two layers only.

Yes, you are correct. My suggestion was just in case of many many object + if 2 levels was enough…

I might not be understanding this - but after reading this I’m left thinking that zLevel has no use unless you are working with opaque rectangular images… am I correct?

What other situation might it be useful?

Z level is also useful when you want to draw a semi-transparent object above an other object. But can’t just set the z level to have it works as expected, you also have to take care of when it is drawn to the screen. Which means you could achieve the same with all z level =0 and manage the drawing order. Which means… what you’ve said. Maybe you are right.

In my case, I created an “Actor” class that is the base class for everything from trees and rocks to giant owls and… air hockey puck riding cows. By having everything in a table of actors, I can sort them on z order (in my case, the same as y order). So far, with only a couple of dozen actors in the pile, performance seems to be fine.

That Actor class seems pretty cool. I would do the same but in my situation each game object has multiple parts drawn at different levels. Example: some game piece emits a force field that should draw over the current piece and other pieces. Others have one that should be drawn below all pieces.

I’ve had to build three methods (drawBefore / draw / drawAfter) and then call drawBefore on all of them, then draw on all, then drawAfter on all.

It starts getting confusing when you want one game piece to be on top of everything or something. I was hoping zLevel was the answer to my dreams but alas no.

Maybe a zLevel that works the way I’m expecting is possible by somehow batching the draw commands instead if trying to execute immediately?

.@Neztec when i need z level to work i put everything in a mesh with addRect and use the z coordinate for the z level. However transparent objects have to be added after non transparent ones, and in z order. And the difficulty is you have to create one texture image with all your drawings.

Ooo, that’s interesting. Sounds a bit hard to structure your application like that but that’s a solution I didn’t think of. Thanks.