tags:

views:

2780

answers:

6

By default it seems that objects are drawn front to back. I am drawing a 2-D UI object and would like to create it back to front. For example I could create a white square first then create a slightly smaller black square on top of it thus creating a black pane with a white border. This post had some discussion on it and described this order as the "Painter's Algorithm" but ultimately the example they gave simply rendered the objects in reverse order to get the desired effect. I figure back to front (first objects go in back, subsequent objects get draw on top) rendering can be achieved via some transformation (gOrtho?) ?

I will also mention that I am not interested in a solution using a wrapper library such as GLUT.

I have also found that the default behavior on the Mac using the Cocoa NSOpenGLView appears to draw back to front, where as in windows I cannot get this behavior. The setup code in windows I am using is this:

glViewport (0, 0, wd, ht);
glMatrixMode(GL_PROJECTION);           
glLoadIdentity();                      
glOrtho (0.0f, wd, ht, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);             
glLoadIdentity();
A: 

Drawing order is hard. There is no easy solution. The painter's alogorithm (sort objects by their distance in relation to your camera's view) is the most straightforward, but as you have discovered, it doesn't solve all cases.

I would suggest a combination of the painter's algroithm and layers. You build layers for specific elements on your program. So you got a background layer, objects layers, special effect layers, and GUI layer.

Use the painter's algorithm on each layer's items. In some special layers (like your GUI layer), don't sort with the painter's algorithm, but by your call order. You call that white square first so it gets drawn first.

MrValdez
Nice thoughts but all that requires extra work. As I mentioned, on the Mac, if I'm not mistaken, it seems to do what I want it to do. The default setup for the NSOpenGLView allows for back to front ordering without any special handling
AlanKley
+1  A: 

Draw items that you want to be in back slightly behind the items that you want to be in the front. That is, actually change the z value (assuming z is perpendicular to the screen plane). You don't have to change it a lot to get the items to draw in front of eachother. And if you only change the z value slightly, you shouldn't notice much of an offset from their desired position. You could even go really fancy, and calculate the correct x,y position based on the changed z position, so that the item appears where it is supposed to be.

Kibbee
Good idea. I guess there is no "automatic" way to do this, however.
AlanKley
+2  A: 

For your specific question, no there is no standardized way to specify depth ordering in OpenGL. Some implementations may do front to back depth ordering by default because it's usually faster, but that is not guaranteed (as you discovered).

But I don't really see how it will help you in your scenario. If you draw a black square in front of a white square the black square should be drawn in front of the white square regardless of what order they're drawn in, as long as you have depth buffering enabled. If they're actually coplanar, then neither one is really in front of the other and any depth sorting algorithm would be unpredictable.

The tutorial that you posted a link to only talked about it because depth sorting IS relevant when you're using transparency. But it doesn't sound to me like that's what you're after.

But if you really have to do it that way, then you have to do it yourself. First send your white square to the rendering pipeline, force the render, and then send your black square. If you do it that way, and disable depth buffering, then the squares can be coplanar and you will still be guaranteed that the black square is drawn over the white square.

Gerald
Thanks Gerald. In my 2-D mindset, I'm not working with the Z-plane at all and would expect all objects to fall on the same Z coord where order is very important in determining what will show. I have implemented an in-memory object list which can easily be iterated backwards based on a flag.
AlanKley
I believe I found a way to setup the GL world to enable back to front drawing. See my provided answer below. I am unaccepting this answer.
AlanKley
Your solution isn't what you asked for in your question. Of course disabling the depth buffer will draw them in the order you supply them, it's not a flag that makes them draw back to front unless you draw them back to front yourself.
Gerald
Though I guess since you say you're living in a 2D world where everything is on the same z-plane, your concept of back to front is different than mine.
Gerald
+3  A: 

The following call will turn off depth testing causing objects to be drawn in the order created. This will in effect cause objects to draw back to front.

glDepthFunc(GL_NEVER);      // Ignore depth values (Z) to cause drawing bottom to top

Be sure you do not call this:

glEnable (GL_DEPTH_TEST);   // Enables Depth Testing
AlanKley
A: 

As AlanKley pointed out, the way to do this is to disable the depth buffer. The painter's algorithm is really a 2D scan-conversion technique used to render polygons in the correct order when you don't have something like a z-buffer. But you wouldn't apply it to 3D polygons. You'd typically transform and project them (handling intersections with other polygons) and then sort the resulting list of 2D projected polygons by their projected z-coordinate, then draw them in reverse z-order.

I've always thought of the painter's algorithm as an alternate technique for hidden surface removal when you can't (or don't want to) use a z-buffer.

davidavr
Granted, My example is very specific and doesn't address the 3D world. I'm trying to implement a MessageBox error reporting pane and it will always display flat
AlanKley
+1  A: 

Your stuff will be drawn in the exact order you call the glBegin/glEnd functions in. You can get depth-buffering using the z-buffer, and if your 2d objects have different z values, you can get the effect you want that way. The only way you are seeing the behavior you describe on the Mac is if the program is drawing stuff in back-to-front order manually or using the z-buffer to accomplish this. OpenGL otherwise does not have any functionality automatically as you describe.

Jim Buck
The 2 square ex. I described WAS being drawn between glBegin/glEnd. I drew the white square first and the black square second and all I saw was a white square. My goal in asking the question is to simulate a 2-D world without using z coordinates. On the mac I see a black square with white border.
AlanKley
You must have had z-buffering on and were drawing two squares that had the same z-value. I guess depending on the graphics hardware between the two systems and rounding errors, the second square could "poke through" the other one. Just turn off z-buffering and draw the squares in the desired order.
Jim Buck