Graphics Notes

Introduction

Graphics

Raster (bitmap) graphics have a fixed array of pixels with values, and a fixed resolution. Vector graphics are driven by display commands. It has a scalable resolution, which makes it ideal for typography and animation.

There are three main disciplines of graphics: modeling shape and appearance, animation, and rendering.

Images and Pixels

An image is a 2D grid of cells called pixels, where each pixel holds some set of values. A pixel (picture + element) is a unit with some kind of value. A pixel value can represent intensity (grayscale), color (RGB), opacity, or depth.

What are the advantages and disadvantages of floating-point vs. integer format?

  • Floating point takes a lot more storage than integer
  • 24 bits is usually enough for the human eye
  • Floating point is usually used as the intermediate format for calculations

How do we store images in memory?

  • Array of structs (AoS), where each struct represents an RGB value
  • Struct of arrays (SoA), where each array represents a R, G, or B channel

Different memory organizations affect cache locality.

Vector Graphics

Vector Graphics Pipeline

To create a 2D vector graphic:

  1. Define object geometry
  2. Transform object (translate, rotate, scale)
  3. Define "window" on the world
  4. Render into raster graphics

In each of the steps of this pipeline, there are different coordinate systems:

  1. Object geometry is defined in terms of object space
  2. Objects are placed into world space
  3. The window is defined in terms of view space
  4. The rendered graphic is defined in terms of normalized device coordinates, which are resolution-specific
  5. The application may only have a subregion of the OS window (viewport), so we might also need to transform into screen space

Why use multiple coordinate systems?

At higher levels of abstraction, we don't want to think about specific device coordinates to draw to. We also want to keep different layers modular, so we can modify each independently.

Scenes

Graphics applications typically represent scenes with a DAG which stores:

  • Objects
  • Attributes (color, texture)
  • Transformations

Scene graph of robot

To get the cumulative transformation matrix of an object, simply walk the node up to the root.

Appendix

Vectors

A vector transforms a scalar into another scalar. Below, we transform the scalar (x,y)(x, y) by shifting it aa units right and bb units up.

(x,y)+[ab]=(x+a,y+b)(x, y) + \begin{bmatrix} a \\ b \end{bmatrix} = (x + a, y + b)

The dot product is an operation that takes in two vectors and produces a scalar:

[ab][cd]=ac+bd\begin{bmatrix} a \\ b \end{bmatrix} \cdot \begin{bmatrix} c \\ d \end{bmatrix} = ac + bd

Geometric interpretations of the dot product:

  • [ab]2=a2+b2\begin{bmatrix} a \\ b \end{bmatrix}^2 = a^2 + b^2 is the squared length of the vector
  • [ab][cd]=0\begin{bmatrix} a \\ b \end{bmatrix} \cdot \begin{bmatrix} c \\ d \end{bmatrix} = 0 when the vectors are perpendicular
  • vw=vwcos(θ)v \cdot w = |v||w|\cos(\theta), where θ\theta is the angle between the arrows

The cross product is an operation that takes in two vectors and produces a vector that is mutually perpendicular to both vectors. By convention, the direction that a×ba \times b points in is determined by the right-hand rule.

a×b=[a2b3a3b2a3b1a1b3a1b2a2b1]a \times b = \begin{bmatrix} a_2b_3 - a_3b_2 \\ a_3b_1 - a_1b_3 \\ a_1b_2 - a_2b_1 \end{bmatrix}

Geometric interpretations of the cross-product:

  • a×b=absin(θ)a \times b = |a||b| \sin(\theta)
  • a×ba \times b also gives the area of the parallelogram with aa and bb as edges. Half of this area gives us the triangle with aa and bb as edges.

Matrices

The identity matrix is a matrix such that MI=IM=MMI = IM = M for all matrices MM. The 2x2 identity matrix is:

[1001]\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}

If we have two matrices MM and KK such that MK=IMK = I, then we say that KK is the inverse of MM. Not all matrices have an inverse. For a 2x2 matrix, we have:

[abcd]1adbc[dcba]=I\begin{bmatrix} a & b \\ c & d \end{bmatrix} \frac{1}{ad - bc} \begin{bmatrix} d & -c \\ -b & a \end{bmatrix} = I

Transformations

A transformation TT is a function that acts on space.

  • A linear transformation respects the property T(au^+bv^)=aT(u^)+bT(v^)T(a\hat{u} + b\hat{v}) = aT(\hat{u}) + bT(\hat{v})
  • A matrix transformation is any transformation that can be written in terms of multiplying a matrix and a vector
  • Every linear transformation is a matrix transformation

Note that matrix transformations can compose. For example, applying MM then KK to vector vv is equivalent to K(Mv)=(KM)vK(Mv) = (KM)v.

We can build matrix transformations using basis vectors. To find a matrix MM that sends:

e1=[10]to[x1x2]ande2=[01]to[y1y2]\begin{equation*} e_1 = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \text{to} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} \quad\mathrm{and}\quad e_2 = \begin{bmatrix} 0 \\ 1 \end{bmatrix} \text{to} \begin{bmatrix} y_1 \\ y_2 \end{bmatrix} \end{equation*}

We need to find a matrix that satisfies:

[abcd][10]=[x1x2]and[abcd][01]=[y1y2]\begin{equation*} \begin{bmatrix} a & b \\ c & d\end{bmatrix}\begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} \quad\mathrm{and}\quad \begin{bmatrix} a & b \\ c & d\end{bmatrix}\begin{bmatrix} 0 \\ 1 \end{bmatrix} = \begin{bmatrix} y_1 \\ y_2 \end{bmatrix} \end{equation*}

Arithmetically, this matrix is

[x1y1x2y2]\begin{bmatrix} x_1 & y_1 \\ x_2 & y_2\end{bmatrix}

To reverse the transformation, we can simply calculate the inverse of MM.

Thus, to send

[a1a2]to[x1x2]and[b1b2]to[y1y2]\begin{equation*} \begin{bmatrix} a_1 \\ a_2 \end{bmatrix} \text{to} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} \quad\mathrm{and}\quad \begin{bmatrix} b_1 \\ b_2 \end{bmatrix} \text{to} \begin{bmatrix} y_1 \\ y_2 \end{bmatrix} \end{equation*}

We can simply calculate the matrix MM that sends

[10]to[a1a2]and[01]to[b1b2]\begin{equation*} \begin{bmatrix} 1 \\ 0 \end{bmatrix} \text{to} \begin{bmatrix} a_1 \\ a_2 \end{bmatrix} \quad\mathrm{and}\quad \begin{bmatrix} 0 \\ 1 \end{bmatrix} \text{to} \begin{bmatrix} b_1 \\ b_2 \end{bmatrix} \end{equation*}

And the matrix KK that sends

[10]to[x1x2]and[01]to[y1y2]\begin{equation*} \begin{bmatrix} 1 \\ 0 \end{bmatrix} \text{to} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} \quad\mathrm{and}\quad \begin{bmatrix} 0 \\ 1 \end{bmatrix} \text{to} \begin{bmatrix} y_1 \\ y_2 \end{bmatrix} \end{equation*}

And then calculate K(M1)K(M^{-1}).

Scale, Rotate, and Translate

Both scale and rotate are linear transformations and can be represented by matrix transformations.

  1. To scale by sxs_x in the x-axis and scale by sys_y in the y-axis, apply the matrix:

    [sx00sy]\begin{bmatrix} s_x & 0 \\ 0 & s_y \\ \end{bmatrix}
  2. To rotate by θ\theta counterclockwise, apply the matrix:

    [cos(θ)sin(θ)sin(θ)cos(θ)]\begin{bmatrix} \cos(\theta) & -\sin(\theta) \\ \sin(\theta) & \cos(\theta) \\ \end{bmatrix}

Translation is not a linear transformation; it is an affine transformation. In order to represent it as a matrix transformation, we add a third coordinate ww.

  • ww is 11 if the value is a scalars and 00 if the value is a vector
  • ww does not affect subtraction of two scalars (which produces a vector), addition of a vector and a scalar (which produces a scalar), or dot product (which is mostly between two vectors)
  • ww also does not affect the linearity of scaling and rotation [abcd][ab0cd0001]\begin{equation*} \begin{bmatrix} a & b \\ c & d\end{bmatrix} \quad\rightarrow\quad \begin{bmatrix} a & b & 0 \\ c & d & 0 \\ 0 & 0 & 1\end{bmatrix} \end{equation*}

To translate dxdx in the x-axis and dydy in the y-axis, apply the matrix:

[10dx01dy001]\begin{bmatrix} 1 & 0 & dx \\ 0 & 1 & dy \\ 0 & 0 & 1\end{bmatrix}

Algorithmically, this works to out be:

[10dx01dy001][xy1]=[x+dxy+dyw]\begin{bmatrix} 1 & 0 & dx \\ 0 & 1 & dy \\ 0 & 0 & 1\end{bmatrix} \begin{bmatrix} x \\ y \\ 1\end{bmatrix} = \begin{bmatrix} x + dx \\ y + dy \\ w\end{bmatrix}

Non-Axis Aligned 3D Rotation

Scaling and translation in 3D is similar to that in 2D. Rotations are more complicated because we can now rotate around an arbitrary axis. There are several ways to do this: Euler angles, axis-angles, and quaternions.

Euler angles are a composition of rotations around the x, y, and z axes. One problem with Euler angles is that they don't trace the shortest rotational path because rotation composition doesn't commute. To fix that, we can linearly interpolate each angle independently with some correction factor. However, this does not get an even angular velocity. Finally, when two rotation axes align, we lose a degree of freedom, causing sudden jumps (gimbal lock).

Axis-angle rotations involve decomposing a point xx into two parts relative to the axis rr:

  • xx_\parallel is the part parallel to rr; rotation does not change it
  • xx_\perp is the part perpendicular to rr; it rotates like a 2D point in a plain perpendicular to rr

To calculate it, we need:

x=x+xsin(θ)+xcos(θ)x' = x_\parallel + x\vdash\sin(\theta) + x_\perp\cos(\theta)

Which can be expanded to:

x=(r^(r^x))+(r^×x)sin(θ)+(r^×(r^×x))cos(θ)x' = (\hat{r}(\hat{r} \cdot x)) + (\hat{r} \times x)\sin(\theta) + (-\hat{r} \times (\hat{r} \times x))\cos(\theta)

The formula for the cross product can be represented as a matrix, so this entire equation can be rewritten in matrix form. Unfortunately, axis-angle rotations also do not sweep the shortest path between two points.

Quaternions are the only rotation method that can correctly do linear interpolation. A quaternion represents a rotation as a point on the surface of a 4D hypersphere. Because we are moving along the sphere, we get shortest path and constant angular velocity.

References: Visualizing quaternions