back face culling

Hi

When reading about OpenGL we see that it supports face culling; eg:


@Override
public void init(GLAutoDrawable gLDrawable)
{
    GL  gl  = gLDrawable.getGL();
    //...
    // enable face culling
    gl.glEnable(GL.GL_CULL_FACE);
    gl.glCullFace(GL.GL_BACK);
    gl.glFrontFace(GL.GL_CW);
}

This is easy to understand for a 2D triangle with vertices [v0,v1,v2] ordered either [v0,v1,v2] for an anticlockwise vertex ordering or ordered [v0,v2,v1] for a clockwise ordering.

However, the texts always fail to discuss in detail how to handle the 3D case. For example, how are we to handle the following list of triangle vertices if the ordering is not specified:


class CubeTriangles
{
    public static int vertexCount = 12 * 3;
    
    public static final float vertexData[] =
    {
            0.25f,  0.25f, -1.25f, 1.0f,
            0.25f, -0.25f, -1.25f, 1.0f,
           -0.25f,  0.25f, -1.25f, 1.0f,

            0.25f, -0.25f, -1.25f, 1.0f,
           -0.25f, -0.25f, -1.25f, 1.0f,
           -0.25f,  0.25f, -1.25f, 1.0f,

            0.25f,  0.25f, -2.75f, 1.0f,
           -0.25f,  0.25f, -2.75f, 1.0f,
            0.25f, -0.25f, -2.75f, 1.0f,

            0.25f, -0.25f, -2.75f, 1.0f,
           -0.25f,  0.25f, -2.75f, 1.0f,
           -0.25f, -0.25f, -2.75f, 1.0f,

           -0.25f,  0.25f, -1.25f, 1.0f,
           -0.25f, -0.25f, -1.25f, 1.0f,
           -0.25f, -0.25f, -2.75f, 1.0f,
           //...

If the vertices are to be correctly ordered when filling a vertex buffer then how is the clockwise/anticlockwise ordering resolved? Let’s say a triangle has vertices [v0,v1,v2] and the cross-product of v0v1 x v0v2 gives a normal n about which the vertices are ordered anti-clockwise. Viewed from the opposite side [-n] then the vertices are ordered clockwise. Thus, I can’t see how the ordering is resolved unless a fixed reference vector is specified. This may be possible for triangles making up a sphere but what about twisted and convoluted surfaces?

If anyone knows the established and robust way of handling 3D face ordering/culling I’d appreciate hearing from you.

Thanks

Graham

Backface culling is basicly resolved after projection,so it’s escencialy done in 2D. In 3D, you would do it checking normals against the camera’s view vector, for example in a geometry shader.

What that means is that what a back face is and what a front face is happens to be completely arbitrary, so you need a convention set by yourself to determine that. The whole “Clockwise and counter clockwise” thing only has a meaning in 2D.

An inverted complex figure makes just as much sense as one that isn’t.

As Ed Daenar said.

For backface culling to work, the polygon vertex order must be known. This information is stored implicitly in your vertex array/index array.

Ed Daenar said: "In 3D, you would do it checking normals against the camera’s view ".

I have a couple of questions:

  1. It’s common in a 3D view to use the mouse to rotate a model. Are you saying that the normals have to be recomputed each time a model is rotated? For a large model this can be expensive.

  2. It’s the same issue when specifying vertex normals for lighting. The OpenGL FAQs says to just compute the crossproduct - fine but which way to point? A view can have several different lights and unlike a single camera point we do not have a single reference point for resolving the correct sense of a surface vertex for lighting.

  3. Some surfaces/solids it can be detrermined what is the inside and what is outside; eg a sphere. But for many surfaces the notion of in/out is meaningless.

  1. GL doesn’t compute any normals. If you want lighting to work properly, yes you would have to compute normal vectors. You don’t need to recompute normals (on CPU side) if you rotate it.

Of course, in your shader, you do have to transform the normals to eye space to compute lighting as usual.

  1. It sounds like you need to do 2 sided lighting. That mean you do a dot product in your shader.
    result = dot(mynormal, LightVector);

and of result is negative, you flip the normal.
mynormal = -mynormal;

and then do your lighting calculation as usual.

  1. See above for 2 sided lighting.