I still haven’t finished reading everything, but I’ve got enough comments that I don’t want to wait to post them all at once.
Chapter 3. OpenGL’s Moving Triangle page, Moving the Vertices section:
“The cosf and sinf functions compute the cosine and sine respectively. It isn’t important to know exactly how these functions work, but they effectively compute a circle of radius 2. By multiplying by 0.5f, it shrinks the circle down to a radius of 1.”
You need to replace the word radius with diameter.
Chapter 4. Objects at Rest, Perspective Correction page, Mathematical Perspective section:
“A perspective projection essentially shifts vertices towards the eye, based on the location of that particular vertex. Vertices farther in Z from the front of the projection are shifted less than those closer to the eye.”
I believe you mean to say that vertices farther in Z (…) are shifted more than those closer to the eye. Or maybe I am not interpreting in the same way what you mean by the front of the projection. I’m assuming you just mean that vertices farther from the projection plane are shifted more than vertices nearer the projection plane; there’s no need to distinguish which side of the projection plane is being referenced.
Figure 4.6 shows the eye at the origin, but has the following caption:
“The projection of the point P onto the projection plane, located at the origin. R is the projection and E is the eye point.”
The projection plane isn’t located at the origin in the figure, however.
Beneath that, there is the text:
“What we have are two similar right triangles; the triangle formed by E, R and the origin; …”
But E (the eye) is at the origin, so there are only two distinct points.
Equation 4.1 is given as:
R = P * (Ez / Pz)
But if P is on the projection plane, then Pz is zero and equation 4.1 is indeterminate. I believe you need equation 4.1 to be something more like:
R = P * (Ez / (Ez + Pz))
Same chapter and page, The Perspective Divide section:
“You might notice that the scaling can be expressed as a division operation (dividing by the reciprocal). And you may recall that the difference between clip space and normalized device coordinate space is a division by the W coordinate. So instead of doing the divide in the shader, we can simply set the W coordinate of each vertex correctly and let the hardware handle it.”
I’ve got a few problems with this. First sentence: division is multiplying by the reciprocal, not dividing by the reciprocal. Third sentence, re: setting the W coordinate of each vertex correctly. I don’t know what you mean by “correctly” or by “letting the hardware handle it.” With shaders, isn’t it the programmer’s responsibility to make the hardware handle it?
It’s here that I have some issues basically surrounding the use and explanation of the W coordinate. At this time I need to think more about this because it’s intertwined with lots of things, so I’ll try to come back to it later. In the meantime, I’ll just point out that you have defined W coordinates in all your geometry passed to OpenGL, but that you never use those W coordinates in example 4.2 (ManualPerspective Vertex Shader); it appears that in Example 4.4 (MatrixPerspective Vertex Shader) you assume and require all W coordinates have a value of one (i.e., that the input geometry be in Euclidean coordinates), though there is nothing to verify or force the programmer to comply.
As background information, the way homogeneous coordinates are converted to Euclidean coordinates is by dividing all coordinates of any point by its W coordinate. As long as W is not zero, then W will be one after the conversion. Presumably, to allow homogeneous coordinate geometry is the reason that OpenGL allows the programmer to pass W coordinates to the OpenGL pipeline. Otherwise, a value of one could have been assigned to W within the OpenGL pipeline. (The world we live in consists of Euclidean geometry, so at some point geometry in the OpenGL pipeline must be represented as Euclidean geometry if we hope to represent reality.)
Basically, the perspective where I am coming from is to set the stage for eventually getting to an OpenGL 4.0 pipeline with all five shader stages in use. Using them to render rational geometry, such as rational Bezier curves and surfaces, and by extension NURBS curves and surfaces, requires that homogeneous coordinate geometry (i.e., W not all the same) be used. I know you’re nowhere near that at this stage in the tutorials (and might choose never to go that far), but beginning with OpenGL 4.0 and the use of tesselation shaders, homogeneous coordinate geometry will be important and descriptions of W and the transformations here ought not lead to contradictions or confusion later.