Skip to content

Lab 1: Raytracing a Sphere

drebain edited this page May 11, 2017 · 6 revisions

Lab 1: Raytracing a Sphere

In this lab, you will learn how to implement a very simple ray tracer that does the following things:

  • Set up a pinhole camera
  • Generate primary rays for this camera
  • Ray-trace a sphere

Getting set up

If you haven't done so, please clone icg into some folder. For this example, it will be cloned into the Desktop (~/Deskop). We can do this by opening a terminal and entering the following (alternatively, you can download the source code zip archive to the Desktop and extract it):

~: git clone https://github.com/drebain/icg.git ~/Desktop/icg

Once it is cloned (or unzipped) do one of the following:

  • In the same terminal, type:
~: cd Desktop/icg
~/Desktop/icg: open -a "Qt\ Creator.app" CMakeLists.txt
  • or, open Qt Creator, and go to "File > Open File or Project..." and select Desktop/icg/CMakeLists.txt.

Starter Code

You are provided with skeleton code in icg/raytrace/main.cpp that you can fill in to complete this exercise. This code should compile and show a simple image with some coloured boxes. This code uses the Eigen and OpenCV libraries, which provide vector, matrix, and image data types. Note that these data types use the () (function call) operation to access elements rather than the [] operation, and are zero-indexed. For example, accessing the z-component of a 3-vector v would be done using v(2).

The Camera

Here we will implement a simplified version of a pinhole camera. This camera is defined by a position and an orientation (up and forward directions), and allows us to create a primary ray for each pixel in the output image. As a simplification, we can assume that the camera is located at the origin and that its forward and up vectors are the unit y and z vectors.

A simple way to calculate the rays can be derived from the pinhole camera model. We know that all light rays that contribute to the image pass through the (infinitely small) pinhole at the camera's origin. If we imagine that there is an image sensor placed behind the pinhole, we can find the direction of the ray for a given pixel by subtracting the pixel's position in space (on the imaginary sensor) from the pinhole's position.

The Image Plane

A drawback of using the pinhole camera model with the sensor behind the hole is that the resulting image will appear flipped. This can be avoided by mirroring the coordinates of the pixels in the image, but can also be avoided by using the image plane which lies in front of the pinhole, and flipping the directions of the rays. Calculating the position of a pixel on an image plane for a forward facing camera is simple as the plane is defined by a lower left and an upper right corner:

/// Position of the pixel in image space
vec2 pixelUV = vec2((float)col / image.cols, (float)row / image.rows);

/// Lower and upper corners of the image plane in world space
vec3 llc = vec3(-1, 1, -1);
vec3 urc = vec3(1, 1, 1);

vec3 pixelPos = vec3(
    llc(0) + pixelUV(0) * (urc(0) - llc(0)),
    1,
    llc(2) + pixelUV(1) * (urc(2) - llc(2))
);

Now that we have the pixel's position in the image plane, we can build the ray for each pixel. The origin of each ray is the position of the pinhole ((0,0,0) in our simplfication), and the direction is the pixel position in the image plane minus the pinhole position.

The Sphere

With the parameters of the ray and sphere, you can now test each ray for intersection with the sphere. To do this you must compute the intersection points of the sphere and the line associated with the ray. You can find the equation of this intersection here. For this exercise you can show your results by setting the colour value of any pixel with an intersection to a solid colour different from the background, though it is simple to use the intersection position to calculate the normal vector and a proper lighting value.