What is Ray Tracing?
Ray tracing is a graphics technique for generating realistic-looking images by using vectors to trace pixels in an image plane and rendering the effect each ray’s encounter with other parameters such as objects, lights, shadows, and reflections.
The first step in any ray tracer is ray generation. A ray is a line in 3D space that begins at one endpoint and extends infinitely in one direction. The first rays a ray tracer makes are called viewing rays. These rays generate from the viewer’s eye (sometimes called the “camera”) and extend outward towards the viewing plane. We can call the viewer’s eye e.
The next step is to specify a point where our eye will point to on the image plane. The image plane is the 2D rendering that will be our ray traced output. Our eye will generate a vector to each pixel on our image plane, but we have to specify just one point for each formula calculation. Let’s call this point s.
We now have a vector from point e to point s on our image plane. We can now compute the ray’s direction. We do this by doing (s - e). This result we can call d.
Our goal is to find a point beyond our image plane that will intersect some object in the scene. This is the point that will be hitting our object in the scene (i.e. a sphere or cube). We can call this point p.
The last variable we have is called t. This is the fractional distance along the vector we will use to compute point p. See below:
Our final equation for a ray generation to calculate an intersection will be:
p(t) = e + t(s - e)or you could do...p(t) = e + (t * d)
A perspective view operates by having all viewing rays generation from a single point. This is our viewpoint eye vector (e).
From here, we can specify the u, v, and w axes for our eye origin. These coordinates allow our viewpoint to move around in space and render our scene from a different perspective.
As we established, viewing rays are generated from the viewpoint and shot through each pixel on the image plane, looking for an object to intersect.
The dimensions of the image plane are represented by: [l,r] x [t,b] or [left, right] x [top, bottom]
An individual pixel will have the coordinates (i, j) on the image plane. The resolution of our final picture is specified by the variables Nx and Ny. So, the resolution 800x600 is represented by (Nx) x (Ny).
Now we have to find the formulas for u and v. These will be:
u = l + (r - l)(i + 0.5)/Nx
v = b + (t - b)(j + 0.5)/Ny
Now that we have u and v, we can calculate each ray direction that will be pointed towards each pixel.
Ray direction → -d*(w-axis) + u*(u-axis) + v*(v-axis)
Ray origin → e
Now that we know how to generate rays, we can calculate an intersection in our scene.
Depending on the object you are intersecting, there will be varying equations to calculate the proper vector intersection and normalization of that specific object. There is Ray-Sphere intersection, Ray-Cube intersection, etc. Each has their own specific formulas. For this example, we will compute Ray-Sphere intersection.
We need to find the function f(p(t)) = 0 or f(e + td) = 0 so that we can calculate the hit point of our ray on our sphere. In order to find an instance where p(t) = 0, we can use the equation:
(p - c) * (p - c) - R² = 0
p → point being intersected
c → sphere center
R → sphere radius
We can change this equation once again to:
(e + td - c) * (e + td - c) - R² = 0
Rearrange the terms:
(d * d)t² + 2d * (e - c)t + (e - c) * (e - c) - R² = 0
You might notice that this is a standard quadratic formula At² + Bt + C = 0, where:
A = (d * d)
B = 2d * (e - c)
C = (e - c) * (e - c) - R²
We can now use the quadratic formula to discover the missing value, t.
Now that we have all variables, we can compute the hit point with f(p(t)) = 0.
The last thing we must do is calculate the discriminant of our At² + Bt + C = 0 function. The discriminant can be calculated using the formula: B² - 4AC
There are 3 possible outcomes of the discriminant:
- If the discriminant is negative, the ray does not intersect with the sphere.
- If the discriminant is positive, the ray hits the sphere on one end, continues through the sphere, and intersects the sphere again on the opposite side. This means that there will be two hit points.
- If the discriminant is 0, the ray touches the sphere at exactly one point.
Now we can begin coloring pixels!
Coloring Pixels on the Image Plane
Pixels on the image plane are colored based on the information computed upon intersection. Once we know that a ray intersected our sphere, we can color that pixel the color of the sphere. If there is no intersection, we can color that pixel the color of the background in our scene. The coloring of the pixels would look something like this:
With the information we have so far, we can expect to get an output like this:
Shading allows you to compute the colors of each pixel as it responds to the properties of the scene in three-dimensional space. Each pixel is shaded a certain color based on different properties such as the object color, shadows, reflections, and opacity.
To compute the final color of the sphere we use the following formula: ambient + diffuse + specular = final color
Ambient shading is a fixed-intensity and fixed-color. The is the simplest form of shading, as it’s a singular color through the entire object.
Diffuse shading theorizes that the amount of energy from a light source that falls on an object depends on the angle of the surface to the light. A surface facing directly towards the light will receive the maximum illumination. A surface not facing the light source, the surface receives no light. In between those two surfaces, the illumination is proportional to the cosine of the angle (𝛳) between the surface normal and the light source.
Specular shading is a technique to produce the shininess of an object. The formula produces a reflection that is at its brightest when v and l are symmetrically positioned across the surface normal. The reflection then decreases smoothly as the vectors move away from a mirror configuration.
When we combine these shadings together, we can create a realistic looking image.
There you have it, this is a basic explanation about how ray tracing creates realistic looking scenes using linear algebra expressions. Here is a picture generated from a ray tracer I built using Python:
I hope this article gives you an understandable explanation about ray tracing and the scenes you can create with this technique.