# Ray Tracer

## Ray Tracer§

## Camera§

### Coordinate System§

In order to generate the orthonormal bases for the camera coordinate system, we require the following points given in world coordinates:

- $E(x, y, z)$ - the camera position,
- $L(x, y, z)$ - the point that the camera will look towards,
- $\vec{u}$ - the vector denoting the upward direction for the camera.

Then, the bases for camera coordinates are given by

$$ \begin{align*} \vec{w} &= ||E - L||,\\ \vec{u} &= ||\vec{u} \times \vec{w}||,\\ \vec{v} &= \vec{w} \times \vec{u}. \end{align*} $$

We say that $\vec{u}$ is the “up” direction and $\vec{v}$ is the “right” direction.

### Focal Plane§

In order to generate the focal plane, we require the two additional parameters:

- $\theta_y$ - the vertical component of the field of view,
- $f$ - the focal distance of the camera.

The part of the focal plane within the viewing frustum has a height $H$ given by

$$ H = 2f \tan\left(\theta_y\right). $$

In ray tracing we wish to subdivide the viewable focal plane into pixels in a one-to-one correspondance with the viewport. Here, we make the assumption that the pixels of the viewport are uniform squares, and we let $V_w$ and $V_h$ denote the width and height of the viewport in pixels, respectively.

The pixel width is given by

$$ p_w = H / V_h. $$

From this, we can get the width of the viewable portion of the focal plane by multiplying the pixel width by viewport width in pixels,

$$ W = p_w \cdot V_w. $$

Let $I_c$ denote the middle of the focal plane,

$$ I_c = E + f\cdot||L - E||. $$

The *origin* of the focal plane, or its bottom left corner, is given by

$$ \mathcal{O} = I_c - \frac{f}{2}\left(\vec{u} + \vec{v}\right). $$

Finally, we can represent the centre of a pixel by

$$ I(x, y) = \mathcal{O} + \vec{u}\cdot(x + 0.5) + \vec{v}\cdot(y + 0.5). $$

## Rays§

Rather than emitting a ray from a light source and hoping that it will hit our focal plane, we can instead emit a ray from each pixel and see how it interacts with the scene to get its color; i.e. we trace the ray backwards. This is a simple but very powerful optimization.

A ray can be written as

$$ \vec{R}(t) = \mathfrak{O} + \vec{d}\cdot t, $$

where $\mathfrak{O}$ is the origin of the ray and $\vec{d}$ is a vector denoting the direction of the ray; here it is helpful to think of $t$ as time.

A *primary ray* is a ray that is emitted from the pixel, it can be given by the function

$$ \vec{R}(x, y, t) = I(x, y) + \vec{d}\cdot t, $$

where $\vec{d}$ is the direction of the ray given by

$$ \vec{d} = ||I(x, y) - E||. $$

### Ray-Object Intersection§

To get the color of a ray, we must detect if it hits off an object in the scene.

We use the `Hit(ray, min, max)`

function on the scene to find the first intersection the ray and the scene, where

`ray`

is a ray given by $\vec{R}(t) = \mathfrak{O} + \vec{d} \cdot t$,`min`

is the minimum $t$ value in the`ray`

equation,`max`

is the maximum $t$ value.

The `min`

and `max`

restrict us to a certain line segment along the path of `ray`

this is useful for objects that are not transmittant, i.e. light does not pass through the object (we will not consider transmittance for this ray tracer).

The `Hit`

function returns a `Record`

object which holds the material properties ($k_a, k_d, k_s, k_m$), the time, point, and normal at the intersection between the ray and surface.

A given ray need not intersect an object, in this case we return an empty record.
Otherwise, a ray can intersect an object multiple times given its geometry, as such we want to get the record at the smallest time value between `min`

and `max`

.

```
Hit(ray, min, max)
time = max
for object in scene
# Find time of intersection of this ray with this particular object
intersection = object.Intersect(ray, min, max)
# Keep record of this object if intersection time is
# greater than min but smaller than current time
if intersection > min and intersection < time
time = intersection
point = ray.origin + ray.direction * time
record = Record(
material = object.material,
time = time,
point = point,
normal = object.NormalAtPoint(point)
)
if time != max
return record
return EmptyRecord
```

### Color§

To compute the color of the ray, we use a recursive function `ComputeColor(ray, min, max, depth)`

, where `ray`

, `min`

, `max`

mean the same as they do in `Hit()`

and `depth`

is the maximum recursive depth.

Because light rays can theoretically reflect infinitely many times, we want to terminate the recursion after a certain number of reflections.

to be completed.