OpenGL is widely used in computer graphics (and many other fields) applications for visualization. In this project, an icosahedron whose facets are painted with different colors is created using OpenGL, and an animation is generated exhibit the 3-D structure of the icosahedron.

An icosahedron has 12 vertices, 20 facets, and 30 edges, which can be displayed by OpenGL if the 3-D coordinates of of the 12 vertices are given.

OpenGL uses two coordinate systems—(*x*_{o}, *y*_{o}, *z*_{o})^{T} and (*x*^{′}_{o}, *y*^{′}_{o}, *z*^{′}_{o})^{T}—to locate 3-D points (as shown in Fig. a↓). The relationship between the two coordinate systems is [*x*^{′}_{o}, *y*^{′}_{o}, *z*^{′}_{o}, *w*^{′}_{o}]^{T} = *M*_{model}[*x*_{o}, *y*_{o}, *z*_{o}, *w*_{o}]^{T},in which [*x*_{o}, *y*_{o}, *z*_{o}, *w*_{o}]^{T} and [*x*^{′}_{o}, *y*^{′}_{o}, *z*^{′}_{o}, *w*^{′}_{o}]^{T} are the homogeneous coordinates of [*x*_{o}, *y*_{o}, *z*_{o}]^{T} and [*x*^{′}_{o}, *y*^{′}_{o}, *z*^{′}_{o}]^{T}, respectively. *M*_{model}, a four-by-four matrix, facilitates the creation of objects at various poses. Imagine that one wants to use OpenGL to create the model of a gull diving into the surface of a lake. Instead of directly generating a gull diving into water at a certain angle, one can generate a flying gull at the origin of virtual reality (possibly through the import of the points obtained from a laser scanner) and then use *M*_{model} to move it to an appropriate position and orientation.

The coordinate system of the observer in OpenGL is usually called the eye coordinate system—[*x*_{e}, *y*_{e}, *z*_{e}]^{T} (as shown in Fig. a↑). The transformation from [*x*^{′}_{o}, *y*^{′}_{o}, *z*^{′}_{o}, *w*^{′}_{o}]^{T} to [*x*_{e}, *y*_{e}, *z*_{e}, *w*_{e}]^{T} is [*x*_{e}, *y*_{e}, *z*_{e}, *w*_{e}]^{T} = *M*_{view}[*x*^{′}_{o}, *y*^{′}_{o}, *z*^{′}_{o}, *w*^{′}_{o}]^{T}. Therefore,

In OpenGL, not all points in space will be rendered for users to visualize; only the points whose locations inside the view frustum (shown in Fig. a↑) are visible, and other points are culled. The view frustum is controlled by six parameters : *l*, *r*, *t*, *b*, *f*, and *n*. The first four parameters can be positive or negative numbers, but *f* and *n* are restricted to positive numbers given the coordinate configurations shown in Fig. a↑, in which the positive direction of *z*_{e} points away from the bottom of the frustum.

Coordinate readings in the eye space ([*x*_{e}, *y*_{e}, *z*_{e}, *w*_{e}]^{T}) are converted to the clip coordinates (denoted by [*x*_{c}, *y*_{c}, *z*_{c}, *w*_{c}]^{T}) through the multiplication with the projection matrix, *M*_{proj}. That is, [*x*_{c}, *y*_{c}, *z*_{c}, *w*_{c}]^{T} = *M*_{proj}[*x*_{e}, *y*_{e}, *z*_{e}, *w*_{e}]^{T}. Next, the clip coordinates are converted to the normalized device coordinates (NDC, shown in Fig. b↑) through normalization, so [*x*_{n}, *y*_{n}, *z*_{n}]^{T} = [*x*_{c} ⁄ *w*_{c}, *y*_{c} ⁄ *w*_{c}, *z*_{c} ⁄ *w*_{c}]^{T}. *x*_{n}, *y*_{n}, and *z*_{n} all range between [ − 1, 1] because *l*, *b*, and − *n* in the eye space are mapped to − 1 and *r*, *t*, and − *f* are mapped to 1. Multiplied with the half width and height of the viewport, respectively, *x*_{n} and *y*_{n} specify the projected location of point **P** on the viewport, as shown in Fig. (c↑). Note that although theoretically, *w*_{c} can be any nonzero value, OpenGL choose to set *w*_{c} = − *z*_{e}, which may be used to preserve the depth information of a point even after projection.