First, let's talk about what "texture mapping" means. The phrase is intended to be taken literally. A texture mapping is the "mapping" from a surface into a texture image. Your surface is defined by vertices, and each vertex has a position.
When it comes to triangle rasterization, the texture mapping is typically created on a per-vertex basis. That is, each vertex has a texture coordinate, which says "for this position in space, get your texture data from this location in the texture." Between a triangle's vertices, the texture coordinates are interpolated, creating a smooth mapping across the planer surface.
But this is merely one particular kind of mapping. There's nothing stopping you from mapping things in another way.
Second, let's talk about what "projection" means. When you render a 3D scene to the screen, you are performing some kind of projection operation. A "projection" is merely the transformation of a position from one dimensionality to another. In our case, from 3D space into a 2D space, namely the screen.
3D rendering involves projection. We have 3D points, and we want to do stuff on a 2D image (namely, the screen). So we have to perform projection: we take the 3D scene and project it onto the 2D image. This operation happens on the vertex positions.
Now, before we do the meat of the projection operation, we generally want to transform the positions into a space relative to the camera. This is done with a 4x4 matrix transform, going from model space to camera space. To do the projection, we apply another 4x4 matrix transform, leading us into 4-dimensional clip-space. Of course, since 4x4 matrices can be composed, we can do this with a single matrix multiply of a composed model-to-clip-space matrix.
At that point, we're done with the vertex shader, because OpenGL or D3D will do the rest of the projection work converting from a 4D clip-space position into a 2D screen-space position. See, this is all hard-coded, and I'm not about to get into the deep details of this process here. But there is one detail I do want to cover.
Perspective projection is not a linear transformation, and a 4x4 matrix can only encode linear transformations. So how do we do projection with a matrix? Because the next step after the VS is dividing the position by the 4th component, the W component. Division by a coordinate is not a linear transform, and it is this division that makes perspective projection non-linear. So we set the W component to the value that needs to be divided in order to do perspective projection.
That division, called the perspective divide, is important. OpenGL/D3D does this step for us automatically when rendering.
So, what is "projection texture mapping"? Well, let's lay out the goal of this process:
We want to compute texture coordinates for our objects so that it appears that a texture is projected over the objects in the scene.
That's the goal. Since we're computing texture coordinates, we are performing "texture mapping". And since we're casting a 2D image over a 3D scene, that sounds like "projection", since we're changing dimensionality.
The trick here is to realize that this projection is no different from the kind of projection you use to render. When you render, you're projecting a portion of a 3D scene into a 2D screen image. When you do projection texture mapping, you're projecting a portion of a 3D scene into a 2D texture image. The only difference is what the destination is. In the former case, you're projecting to do rasterization. In the latter, you're using the post-projection positions as texture coordinates.
But the math is the same.
Indeed, OpenGL even has special Proj
texture accessing functions which take that W
component, so that you don't have to do the perspective division yourself.
All of the math for doing projection texture mapping is exactly the same as you would use for rendering. Instead of projecting the scene onto a screen-sized area, you're projecting it onto the [0, 1] normalized texture coordinate area. Oh yes, you will use different camera and projection matrices than the one you use for rendering. But the actual math itself, the formulas you use, are all identical.