Rasterization is the stage of the OpenGL (ES) 2.0 pipeline that determines the pixels covered by a primitive (e.g. a triangle) and interpolates the output variables of the vertex shader (i.e. varying variables and depth) for each covered pixel. These interpolated varying variables and the interpolated depth are then given to the fragment shader. (In a wider sense, the term “rasterization” also includes the execution of the fragment shader and the per-fragment operations.)
Usually, it is not necessary for GLSL programmers to know more about the rasterization stage than described in the previous paragraph. However, it is useful to know some details in order to understand features such as perspectively correct interpolation and the role of the fourth component of the vertex position that is computed by the vertex shader. For some advanced algorithms in computer graphics it is also necessary to know some details of the rasterization process.
The main two parts of the rasterization are:
- Determining the pixels that are covered by a primitive (e.g. a triangle)
- Linear interpolation of varying variables and depth for all covered pixels
Determining Covered Pixels
In OpenGL (ES), a pixel of the framebuffer is defined as being covered by a primitive if the center of the pixel is covered by the primitive as illustrated in the diagram to the right.
There are certain rules for cases when the center of a pixel is exactly on the boundary of a primitive. These rules make sure that two adjacent triangles (i.e. triangles that share an edge) never share any pixels (unless they actually overlap) and never miss any pixels along the edge; i.e. each pixel along the edge between two adjacent triangles is covered by either triangle but not by both. This is important to avoid holes and (in case of semitransparent triangles) multiple rasterizations of the same pixel. The rules are, however, specific to implementations of GPUs; thus, they won't be discussed here.
Linear Interpolation of Varying Variables
Once all the covered pixels are determined, varying variables are interpolated for each pixel. For simplicity, we will only discuss the case of a triangle. (A line works like a triangle with two vertices at the same position.)
For each triangle, the vertex shader computes the positions of the three vertices. In the diagram to the right, these positions are labeled as , , and . The vertex shader also computes values of varying variables at each vertex. We denote one of them as , , and . Note that these values refer to the same varying variable computed at different vertices. The position of the center of the pixel for which we want to interpolate the varying variables is labeled by in the diagram.
We want to compute a new interpolated value at the pixel center from the values , , and at the three vertices. There are several methods to do this. One is using barycentric coordinates , , and , which are computed this way:
The triangle areas , , , and are also shown in the diagram. In three dimensions (or two dimensions with an additional third dimension) the area of a triangle between three points , , , can be computed as one half of the length of a cross product:
With the barycentric coordinates , , and , the interpolation of at from the values , , and at the three vertices is easy:
This way, all varying variables can be linearly interpolated for all covered pixels.
Perspectively Correct Interpolation of Varying Variables
The interpolation described in the previous section can result in certain distortions if applied to scenes that use perspective projection. For the perspectively correct interpolation the distance to the view point is placed in the fourth component of the three vertex positions (, , and ) and the following equation is used for the interpolation:
Thus, the fourth component of the position of the vertices is important for perspectively correct interpolation of varying variables. Therefore, it is also important that the perspective division (which sets this fourth component to 1) is not performed in the vertex shader, otherwise the interpolation will be incorrect in the case of perspective projections. (Moreover, clipping fails in some cases.)
It should be noted that actual OpenGL implementations are unlikely to implement exactly the same procedure because there are more efficient techniques. However, all perspectively correct linear interpolation methods result in the same interpolated values.
All details about the rasterization of OpenGL ES are defined in full detail in Chapter 3 of the “OpenGL ES 2.0.x Specification” available at the “Khronos OpenGL ES API Registry”.