With a triangle the (normalized) cross-product is guaranteed to give you a normal perpendicular to the surface. The trouble with quads is that you can have a quad that is non-planar (i.e. the four points don't lie on a plane). In this case however I'm not sure if the quad is guaranteed to be rendered correctly (although most OpenGL implementations tend to render a quad as two triangles, so you just get a quad that is folded in half).

But if your quads are planar (which they probably should be . . .) then you can take the cross-product of any two non-parallel edge vectors, normalize it, and that will give you a normal for the surface. (For example, the vector upper-left-corner => upper-right-corner crossed with upper-left-corner => bottom-left-corner would give you a normal, but upper-left-corner => upper-right-corner crossed with bottom-left-corner => bottom-right-corner could give you a zero vector if the top and bottom edges are parallel.)

(Of course if you cross the vectors in the wrong order you'll get a normal pointing in the wrong direction. You can try to figure it out with complicated right-hand rules and whatnot, but I'd suggest just trying A x B and then if that doesn't work, B x A. )

All of this applies to flat shading, of course, where you're expected to supply normals to surfaces/faces. If you want to use smooth (Gouraud) shading then you need to get normals to vertices instead of faces, and that requires knowledge of more than just one polygon at once.

Sometimes it's easier to find vertex normals, however. Suppose you're trying to render a sphere with lots of quads. The normal for each quad is a bit tricky to find, but the normal for each vertex is easy: it's just the vector from the centre of the sphere to the vertex, normalized.

I should mention that mathematically normals are supposed to have length 1, which is what is means to "normalize" a vector. You have to ensure that the vectors you pass to OpenGL as normals have length 1, unless you're feeling lazy in which case you can just call

Code:

glEnable(GL_RESCALE_NORMAL);

But really, normalizing a vector is quite simple so you might as well do it yourself.

Code:

void Vector::normalize() {
double the_length = length();
set_x(get_x() / the_length);
set_y(get_y() / the_length);
set_z(get_z() / the_length);
}

Well, that post was more rambling than it had to be. Hope you have fun with OpenGL, and do ask more questions if you have any.