Im having trouble getting my head around NDC. Assuming we are using OpenGL 3, and doing the perspective projection ourselves, do we have to worry about normalized device coordinates?

In perspective projection, a 3D point in a truncated pyramid frustum (eye coordinates) is mapped to a cube (NDC); the x-coordinate from [l, r] to [-1, 1], the y-coordinate from [b, t] to [-1, 1] and the z-coordinate from [n, f] to [-1, 1].

I am doing the perspective transform via a tutorial like this:

Referring to the diagram:[ol][] Your 4x4 PROJECTION transform takes you from 4D eye coordinates to 4D clip coordinates.[] Then the perspective divide takes you from 4D clip coordinates to 3D NDC coordinates.[*] Then the viewport transformation takes those 3D NDC coordinates into 3D window coordinates.[/ol]

Ok, so the divide by w has to be performed by the perspective projection. The viewport transformation ‘expects’ the input to be in NDC otherwise it wont work.

In that case, does the following perspective transformation produces Normalized Device Coordinates?:

Suggest you look back at this diagram and memorize it.

(And your matrix[0] term looks wrong. And you can simplify the perspective implementation a good bit. Check out Mesa3D’s gluPerspective implementation.)

Im a bit lost here, perhaps because of the difference between FFP and non-FFP way of doing things.

In FFP, I would set a viewport using glViewport and then the camera using gluPerspective, and not have to worry about the perspective divide. So, which function in the FFP does the divide? I didnt have to call a function to do so my guess is that its happening in the perspective matrix created by gluPerspective.

In my code, isn’t the line

matrix[11] = -1;

suppossed to do exactly that? Divide by -z to get clip coords?

See, the whole thing is: the gpu does the division. You only need to feed it clipspace coords to gl_Position. If you’re providing gl_Position.w=1.0 , then the division doesn’t change XYZ, so you’re effectively giving NDC.

This “-1” in the matrix is just flipping the Z axis. The convention of GL is that Z- points forward in modelview space, but in viewspace the convention is that Z+ points forward. Yeah, a nasty tidbit imho, and I’m not sure why it’s like this. In your own code, be it FFP or non-FFP you are free to make all spaces point forward to Z+ ; (via glMultMatrix) that’s the first thing I tackled (I’ve seen many others here do this, too). Anyway, it’s nothing critical.

When you move from FFP to non-FFP, you simply copy and use the existing code for things like gluPerspective, it’s just that you manually create, multiply and upload matrices (that ultimately only calculate the ModelViewProjection matrix, which produces Clipspace coords).

glViewport(0,0,1280,720);
vec3 someVtx=vec3(5,6,7);
mat4 mPerspective = mat4::perspective(45.0f,...);
mat4 mView = mat4::lookat(...);
mat4 mModel = ...;
mat4 MVP = mPerspective*mView * mModel;
//--------[ GPU side !!! ]-------------------[
vec4 CLIPSPACE = MVP * vec4(someVtx,1.0f); // vertex shader!!
// this CLIPSPACE var is known as gl_Position
//------[ stuff out of your control ]-------[
vec3 NDC = vec3(CLIPSPACE.xyz/CLIPSPACE.w);
// well, you can tweak some of the numbers here,
// i.e with glViewport()
float screenX = (NDC.x *0.5+0.5)*1280;
float screenY = (NDC.y *0.5+0.5)*720;
//------------------------------------------/
//-------------------------------------------/