ultifinitus
ultifinitus

Reputation: 1893

In what order should I send my vertices to OpenGL for culling

I'm learning a spot of 3D OpenGL, and it's going rather well, I've got a nice camera moving about and some simple cube objects, at the moment. Currently using vertex arrays, but I'm swapping to VBOs pretty quick here. I'm just trying to enable culling, however I'm not sure what order in which I ought to specify my vertices, right now this is what I'm doing:

void cube::update_verts(){
    GLushort cur=0;

    ///back face
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z;

    ///right face
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z+sz;

    ///top face
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z+sz;

    ///front face
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z+sz;

    ///bottom face
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z+sz;

    ///left face
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z+sz;
}

///Drawing Code:

glVertexPointer(3,GL_FLOAT,0,object.verts);
glColorPointer(3,GL_UNSIGNED_BYTE,0,object.colors);
glDrawArrays(GL_QUADS,0,6*4);

However it's definitely quite wrong, because when I glEnable(GL_CULL_FACE); my cubes don't show the correct faces (as seen below).

Normal

Regular View From Top

Problem child

View From Side

With both of these images culling is enabled.

In what order should I specify the vertices?


(EDIT) Updated Working Function:

void cube::update_verts(){
    GLushort cur=0;

    ///top face
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z;


    ///bottom face
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z+sz;

    ///left face
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z;

    ///right face
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z+sz;

    ///front face
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z+sz;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z+sz;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z+sz;


    ///back face
    verts[cur++]=x; verts[cur++]=y; verts[cur++]=z;
    verts[cur++]=x; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y+sy; verts[cur++]=z;
    verts[cur++]=x+sx; verts[cur++]=y; verts[cur++]=z;

}

Upvotes: 34

Views: 29599

Answers (3)

Craig
Craig

Reputation: 21

Here's a nested cube. Inner cube and outer cube using @genpfault's numbering of the cube faces. The data is in a *.ply (3D point cloud) format, with RGB color data as well.

ply
format ascii 1.0  
element vertex 16  
property float32 x  
property float32 y  
property float32 z  
property uchar red  
property uchar green  
property uchar blue  
element face 24  
property list uint8 int32 vertex_indices  
end_header  
-4.00 -4.00 4.00 255 0 0  
4.00 -4.00 4.00 255 0 0  
4.00 4.00 4.00 255 0 0  
-4.00 4.00 4.00 255 0 0  
-4.00 -4.00 -4.00 255 0 0  
4.00 -4.00 -4.00 255 0 0  
-4.00 4.00 -4.00 255 0 0  
4.00 4.00 -4.00 255 0 0  
-6.00 -6.00 6.00 255 255 255  
6.00 -6.00 6.00 255 255 255  
-6.00 6.00 6.00 255 255 255  
6.00 6.00 6.00 255 255 255  
-6.00 -6.00 -6.00 255 255 255  
6.00 -6.00 -6.00 255 255 255  
-6.00 6.00 -6.00 255 255 255  
6.00 6.00 -6.00 255 255 255  
3 0 1 2  
3 1 3 2  
3 1 5 3  
3 5 7 3  
3 5 4 7  
3 4 6 7  
3 4 0 6  
3 0 2 6  
3 4 5 0  
3 5 1 0  
3 2 3 6  
3 3 7 6  
3 8 9 10  
3 9 11 10  
3 9 13 11  
3 13 15 11  
3 13 12 15  
3 12 14 15  
3 12 8 14  
3 8 10 14  
3 12 13 8  
3 13 9 8  
3 10 11 14   
3 11 15 14 

Upvotes: -1

genpfault
genpfault

Reputation: 52090

By default? In counter-clockwise order.

Consider a triangle facing the camera:

A
|\
| \
|  \
B---C

A->B->C would be front facing (counter-clockwise order), A->C->B would be rear-facing (clockwise order).

You can change which way OpenGL considers "front facing" via glFrontFace():

The projection of a polygon to window coordinates is said to have clockwise winding if an imaginary object following the path from its first vertex, its second vertex, and so on, to its last vertex, and finally back to its first vertex, moves in a clockwise direction about the interior of the polygon. The polygon's winding is said to be counterclockwise if the imaginary object following the same path moves in a counterclockwise direction about the interior of the polygon. glFrontFace specifies whether polygons with clockwise winding in window coordinates, or counterclockwise winding in window coordinates, are taken to be front-facing. Passing GL_CCW to mode selects counterclockwise polygons as front-facing; GL_CW selects clockwise polygons as front-facing.

By default, counterclockwise polygons are taken to be front-facing.

For ordering your vertices, consider an ideal cube:

  6---7
 /|  /|
2---3 |
| 4-|-5
|/  |/ 
0---1

For each face mentally rotate it to face the camera (your mind's eye):

Sides:
2---3  3---7  7---6  6---2
|   |  |   |  |   |  |   |
|   |  |   |  |   |  |   |
0---1  1---5  5---4  4---0

Bottom/Top:
0---1  6---7
|   |  |   |
|   |  |   |
4---5  2---3

Then you can just visually read off the quads or triangle pairs in the right counter-clockwise order:

2---3                3         2---3 
|   |  becomes      /|   and   |  / 
|   |             /  |         |/ 
0---1            0---1         0 

Triangles 0-1-3 and 0-3-2
Quad 0-1-3-2

It doesn't matter which vertex you start the triangle/quad with, for example with the first triangle 0-1-3, 1-3-0, and 3-0-1 are all equally valid, front-facing triangles.

Upvotes: 130

TopSecretPorkChop
TopSecretPorkChop

Reputation: 89

I learned another rule of thumb (literally) for determining the vertex order known as the "right hand rule".
Imagine your open hand (right) inside the cube with your thumb pointing towards the center of the cube. If you then curl your hand into a fist, your fingers will pass the vertices in the correct order. Since you are using your right hand for this it is called the "right hand rule".

Conversely, if you start with your left hand and point your thumb away from the center of the cube, your fingers will again sweep the vertices in the correct order. This is known as the "left hand rule" (surprise).

Both methods work to give you counter-clockwise ordering. For clockwise ordering, just use the opposite hand.

Upvotes: 8

Related Questions