render order (yet again!)

I think Ive made at least two topics about render order after starting using Panda3d, and I always felt I don’t really “get” it. … nder_Order

Now I understand the purpose of the “cull bins”. The nodes in different bins are rendered in different order. But thats about all I get.

So Ive seen people put custom sort values for other bins as well.
If I want 3 object to render in custom order, but render behind everything else, I assign them to “background” bin and set custom sort values. Is doing this wrong?
Do the values for the “fixed” bin must be only between 40 to 50? (where “unsorted” starts)?

The “background” bin is also of type BT_fixed, so you may set custom sort values on the objects you assign to the background bin, and this will have the desired effect.

There is no relation between the numbers 40 and 50, which control the sorting of the bins themselves, and the per-object sort values that you assign to individual objects within a bin. They’re different sorts. You can use any integer at all for your objects.


I think that bit info should be added to the manual.

I couldnt find this in the manual too.

Like this table in the manual? Or did you have something else in mind?

   Bin Name        Sort  Type
   --------------  ----  ----------------
   "background"     10   BT_fixed
   "opaque"         20   BT_state_sorted
   "transparent"    30   BT_back_to_front
   "fixed"          40   BT_fixed
   "unsorted"       50   BT_unsorted

As always, please feel free to improve the manual to clarify things like this that may be unclear.


Stil though, just setting the sort doesn’t work:

from pandac.PandaModules import *
import direct.directbase.DirectStart

dlight = DirectionalLight('dlight')
dlnp = render.attachNewNode(dlight)

alight = AmbientLight('alight')
alnp = render.attachNewNode(alight)

model = loader.loadModel('box')
model.setBin('fixed', 20)

model2 = loader.loadModel('box')
model2.setBin('fixed', 10)


The manual also implicitly tells that it wont work and suggests other methods like creating a separate display region.
Now I remember why I could never get this.

But youre saying it should work and there is an option to set the sort value, so I’m confused.

In what way doesn’t it work? That code would make model2 always draw before model, which would be correct as long as all parts of model2 are always behind all parts of model. So what’s the problem you’re seeing? And in what way does the manual say that won’t work?


Simply: they are rendered by their logical zbuffer order, from back to front:

Oh, well, sure. That’s because you don’t have transparency enabled and there aren’t any transparent parts anyway. In this case the Z-buffer is used to resolve depth sorting issues, and the Z-buffer doesn’t rely on draw order.

Using setBin() changes the draw order, but it doesn’t change the visual effect unless you are using some rendering approach that depends on draw order, such as blending transparency.

If you also call:

model.setTransparency(TransparencyAttrib.MAlpha, 1)
model2.setTransparency(TransparencyAttrib.MAlpha, 1)

then you’ll see the difference.


Note that those are two different things you’re talking about.
If you don’t want to use the z-buffer for depth sorting, then you should use:


Might also want to disable depth write while you’re at it.

But because faces would no longer be properly sorted (a triangle that’s behind another may show through, etc) that is probably not what you want.

Why isn’t Panda doing that by itself?
Thats what has confused me all along.

The Z-Buffer is used to resolve ordering issues on a pixel-by-pixel basis. It works perfectly as long as transparency isn’t involved. When you want to use transparency, the Z-Buffer doesn’t work any more, and you have to order things explicitly from back to front.

Panda does do all of this for you automatically, at least as far as it is possible to do it automatically.

What do you expect it do be doing differently?


If I set the custom sort order, why do I have to manually tell panda to ignore zbuffer now and render them by my order?

Because by setting the sort order, you’re only telling Panda which model to send to the GPU first.

Depth testing is performed on the GPU. Basically, depth testing compares the depth values of the face with the one already in the depth buffer, before it writes the pixels to the framebuffer. If it notices that there is already a face closer to the camera, then it won’t write those pixels.

This is completely different from the order in which models are sent to the GPU.

So what does that mean? GPU is the one to choose? what should I do? Will disabling depth testing be enough?

I highly recommend reading up on how Z-buffering works, this will probably help you gain a much better understanding.

You probably don’t want to simply disable depth testing, because this means that concave meshes may be rendered incorrectly. If your models are convex (like the cube) it will be just fine, though.

(By ‘convex’ I mean that from every angle there are never two overlapping triangles facing you. By ‘concave’ I mean the opposite-- triangles on the other side of the model that are also facing you may show through.)

(Just on a sidenote, if you’re not using depth testing for those models, it probably won’t make sense to have them write to the depth buffer at all, so you can call setDepthWrite(True) as an optimisation.)

I think the fundamental confusion here is that you’re thinking that draw order controls which object is drawn on top of other objects. This is only true in the absence of a Z-buffer. (And thank goodness for Z-buffers, because strictly ordering the entire scene to draw in order from back to front is pretty much impossible, so without a Z-buffer your typically complex scene couldn’t be rendered properly.)

I don’t know what your ultimate goal here is, but if you’re trying to get your skyboxes to render correctly, then you may not care about concave surfaces and disabling Z-buffer is the right thing to do.

In most cases, you want to keep the Z-buffer enabled, as rdb points out, because using the Z-buffer is usually the best way to deal with overlapping objects where you want the depth to determine which object is on top. That’s the whole point of the Z-buffer, to eliminate the need to manually sort these objects with respect to depth.


Well yeah, thats exactly what I concluded from the manual page.
OK, absense of a z-buffer for that object only, right?
But disabling z buffer will only work properly for convex meshes, right?

this didn’t work either

All right, my bad, you also have to make the object a little transparent to see the difference.

model.setTransparency(TransparencyAttrib.MAlpha, 1)
model2.setTransparency(TransparencyAttrib.MAlpha, 1)

Or, you can simply disable the Z-buffer test on these objects and see the effect you expect to see:


Yes, disabling Z-buffer on a concave object is generally bad, because then the object might be self-occluding, which means it will be random which part of the object appears to be on top.


So I suppose we can conclude that there is no real way to set a render order, that is the order in which they are drawn, of concave meshes. Adding a little bit of transparency sounds like a hacky approach.
I think for many cases a separate display region would be best.

Mind if I add the part of disabling depth test/write to the manual page?

The render order is the order in which they are drawn, but you are referring to the visual effect of appearing on top, which really is something completely different.

If you have a concave object A that you want to appear on top of another concave object B, even though B is actually closer to the camera, one way to do this is to draw A in a separate DisplayRegion which is sorted after the one that draws B. But you do have to clear the depth buffer in this second DisplayRegion, otherwise you will still have the same problem.

I’m in favor of improving the manual in general, but it seems that your confusion about draw order and depth test is a very specific confusion that may or may not be common. Text added to the manual on this subject should be written to clarify this confusion–and explain that draw order is not necessarily related to appearing on top–without getting too distracted by the details of disabling the depth buffer should you actually want that effect.