So far, we have learned how to write GLSL shaders, and we have introduced abstractions to make working with them easier. What we can draw so far with OpenGL are images that can be computed in the fragment shader (Chapter 13) and colored meshes (Chapter 14 and many previous chapters).
In this chapter, we introduce a new concept: transformations. A transformation is a mathematical operation that we can apply to the geometric data (points, lines, triangles, camera positions, and so on) that make up our scene so that such data change their positions and shapes. For example, given a mesh, we can apply a transformation to change its position in the scene, rotate it to face other direction, or scale it so that it becomes 2 times or 3 times bigger. We can use transformations to change how the scene is rendered; for examples, changing the zoom level or moving the final rendering around the canvas. Transformation is a fundamental concept in computer graphics, and mastering it is a requirement for a competent graphics practitioner.
Transformation, however, is quite a complicated topic in it self. In the end, we want to cover transformations on 3D objects because WebGL is all about rendering 3D scenes. Nevertheless, such 3D transformations are quite complex by themselves. Moreover, we have not really discussed how to deal with 3D data so far besides setting the $z$-coordinates to zero so as to not worry about the third dimension like in the last chapter. So, in this chapter, we shall limit ourselves to the discussions of 2D transformations. They are much easier to deal with because they are very easy to visualize with what we have learned so far, and there are fewer types of 2D transformations we need to discuss.
Mathematically, a 2D transformation is a function that consumes a 2D point and outputs a 2D point. More formally, we say that $f$ is a 2D transformation if its maps $\Real^2$ to $\Real^2$. In other words, its signature is $$f: \Real^2 \ra \Real^2.$$ Let us look at some examples. One of the simplest transformations is the identity transformation $\mathtt{I}$, which simply outputs whatever the input is: \begin{align*} \mathtt{I}( \ve{x} ) = \ve{x} \end{align*} for every $\ve{x} \in \Real^2$. So, \begin{align*} I((0,0)) &= (0,0), & I((1,2)) &= (1,2),& I((-5,3)) &= (-5, 3), \end{align*} and so on. (To simplify the notation, we will omit double parentheses and write $f(-5, 3)$ in place of $f((-5,3))$ from now on.)
Other transformations are more complicated to define as they involve some parameters to define their behavior. An example of transformations with parameters are the constant functions $\mathtt{C}_{\ve{a}}$ where $\ve{a} \in \Real^2$ is the parameter. The constant function always outputs $\ve{a}$ no matter what the input is: \begin{align*} \mathtt{C}_{\ve{a}}(\ve{x}) = \ve{a} \end{align*} for all $\ve{x} \in \Real^2$. So, \begin{align*} \mathtt{C}_{(2,1)}(10, 15) &= (2,1), & \mathtt{C}_{(-1,1)}(0, 0) &= (-1,1), & \mathtt{C}_{(46,49)}(39, 888) &= (46,49). \end{align*} (Again, when the parameter is a 2D point, we may drop the parantheses around it to make the notation simpler. That is, we may write $\mathtt{C}_{2,1}$ to mena $\mathtt{C}_{(2,1)}$.) Note that, while there is only one identity transformation, there are as many constants functions as there are points in $\Real^2$.
A type of transformation that is used extensively in computer graphics is the translation. Like a constant function, a translation $\mathtt{T}_{\ve{a}}$ is parametered by a point $\mathbf{a} \in \Real^2$. What it does is to add $\ve{a}$ to the input: \begin{align*} \mathtt{T}_{\ve{a}}(\ve{x}) = \ve{x} + \ve{a}. \end{align*} So, \begin{align*} \mathtt{T}_{1,1}(5,6) &= (6,7), & \mathtt{T}_{-2,3}(7,8) &= (5,11), & \mathtt{T}_{-10,-20}(100,200) &= (90,180). \end{align*}
Lastly, another type of transformation that is used extensively in computer graphics is scaling. It is also parameterized by a point $\ve{a} \in \Real^2$, but it is better to treat the points as an ordered pair $(a_1, a_2)$. The scaling $\mathtt{S}_{a_1,a_2}$ simply multiplies $a_1$ to the $x$ component of the input and $a_2$ to the $y$-component of the input. In other words, \begin{align*} \mathtt{S}_{a_1, a_2}\bigg( \begin{bmatrix} x \\ y \end{bmatrix} \bigg) = \begin{bmatrix} a_1 x \\ a_2 y \end{bmatrix} \end{align*} So, \begin{align*} \mathtt{S}_{2,2}(10, 9) &= (20, 18), & \mathtt{S}_{4,5}(-3, 2) &= (-12, 10), & \mathtt{S}_{20,10}(-1,-2) &= (-20, -20). \end{align*}
So far, we have introduced transformation as a mathematical concept. This, however, is very abstract and quite removed from the visual world of computer graphics. However, transformations are used in graphics because they we can apply them to graphics data and see the results with our eyes. In this section, we shall see how we can apply transformations to meshes why they are useful to graphics practioners.
Meshes are made of vertices, and all vertices must have one attribute: their positions. For a 2D mesh, the position is a point in $\Real^2$. If we apply a 2D transformation to it, we get another position. In other words, when we apply a transformation to a vertex, we move it to a new position. So, if we apply the same transformation to all vertices in a mesh, we can change both the mesh's positions and shape. Let's see how the transformations we have learned so far affect 2D meshes.
For the identity transformation $\mathtt{I}$, we know that it does not change any vertex's position at all, so any mesh would remain unchanged if we apply the identity transformation to it. For the constant transformation $\mathbb{C}_{a,b}$, all vertices are moved $(a,b)$, and so the mesh is reduced to a single point. So, these two transformations are not useful on their own.
The translation $\mathtt{T}_{a,b}$ is a little more interesting. We know that it adds the vector $(a,b)$ to all vertex positions. For example, let us say we have a square mesh made with 4 vertices at $(0, 0)$, $(1,0)$, $(1,1)$, and $(0,1)$. If we apply $T_{-1,2}$ to the mesh, then the vertex position becomes $(-1,2)$, $(0, 2)$, $(0, 3)$, and $(-1, 3)$, respectively. The overall effect is presented in the figure below.
| ${\huge \xrightarrow{\mathtt{T}_{-1,2}}}$ |
In general, the effect of applying $\mathtt{T}_{a,b}$ to a mesh is to move the mesh to the right by $a$ units and then to upward by $b$ units. Note that $a$ and $b$ are signed. So, moving to the right by a negative number of units means moving to the left, and moving upward by a negative number of units means moving downward.
Next, let's look at scaling $\mathtt{S}_{a,b}$. When we apply it to the square mesh above, the vertices become $(0,0)$, $(a,0)$, $(a,b)$, and $(0,b)$. What the results looks like depends on the sign of $a$ and $b$. When $a$ and $b$ are both positive, it scales the mesh up $a$ times in the $x$-direction and $b$-times in the $y$-direction. Note that $a$ and $b$ can be less than $1$, which means that it can also shrinks (i.e., scales down) the mesh too.
| ${\huge \xrightarrow{\mathtt{S}_{3,2}}}$ | ||
| ${\huge \xrightarrow{\mathtt{S}_{0.5,0.5}}}$ |
When $a$ is negative, the mesh "flips" horizontally. Any point to the right of the vertical line $x = 0$ is moved to the right side, and any point to the right would move to the left. The coordinate is scaled by a factor of $|a|$. Similarly, when $b$ is negative, the mesh "flips" vertically. Points above the horizontal line $y = 0$ go under, and points under the line go above.
| ${\huge \xrightarrow{\mathtt{S}_{-1,-1}}}$ | ||
| ${\huge \xrightarrow{\mathtt{S}_{-1,2}}}$ | ||
| ${\huge \xrightarrow{\mathtt{S}_{3,-2}}}$ |
One thing to nice is that, for scaling, there is a special point: the origin $(0,0)$. The origin is never changed by a scaling because multipying $0$ with any number always result in $0$. Other points are moved according to the scaling factors $a$ and $b$. It is as though "scape" itself is warped around $(0,0)$. So, we may call $(0,0)$ the center of scaling. To repeat, it is very important to remember that scaling always happen around a point. On the other hand, there is no "center of translation" because a translation move all points in the same way.
From the examples we have seen so far, we can see why transformations are useful to computer graphics. Using translation, we can move a mesh around the scene. Using scaling, we can make a mesh larger or smaller to our liking. Using these two transformations togeter allows us to resize a mesh and place it to where we like in a scene.