Assignment 5: Introduction to Computer Graphics

In this assignment you will write a ray tracer to draw a simple 3D scene. We will use Shadertoy, a website that lets you write shader programs (i.e. programs for doing image-order rendering) in your browser.

Shadertoy

Open Shadertoy and click the “New” link in the top right menu to create a new program. Modify the default code to the following, and click the ▶ button at the bottom-left of the editor to compile and run it.

void mainImage (out vec4 fragColor, in vec2 fragCoord) {
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Time varying pixel color
    vec3 col = vec3(uv.x, uv.y, 0.5 + 0.5*cos(iTime));

    // Output to screen
    fragColor = vec4(col,1.0);
}

Looking at this program, we can understand a few things:

GLSL

Shader programs in Shadertoy are written in GLSL (short for OpenGL Shading Language), a C-like language that runs on the GPU. You should be able to get an idea of how to write GLSL by reading the example code, and using the “?” button at the bottom right of the Shadertoy editor to see a quick reference for the available operations and functions.

Here are some additional notes on the GLSL language that you should know:

Ray tracing

Shader programs are ideally suited for ray tracing, since we compute the colour of each pixel independently. Some starter code for this is provided here: code_for_assignment.txt. It is a little more complicated than the example code above, but should not be too hard to follow if you have experience with C, C++, or Java. The main function is at the bottom of the file, and we have provided a few helper functions to create the ray for each pixel, and to intersect a ray with a rectangle. However, the program does not do much right now except shoot a ray, fail to hit anything, and return the background colour of the sky. Your task is to make it render a scene with some shapes in it.

  1. Modify the castRay function to perform a ray intersection test with a green rectangle with vertices at (±2, −1, −4±2).

  2. Fill in the raySphereIntersect function to check for the intersection of a ray with a sphere. Call it in the castRay function as well, adding a sphere of unit radius centered at (0, 0, −4).

  3. Right now, the scene probably looks very flat. Modify the shadeHit function to compute diffuse (Lambertian) shading from a light of unit intensity coming from the direction (1, 1, 1).

  4. Add shadow testing to shadeHit, so that the sphere now casts a shadow on the rectangle. You may assume that the light source is infinitely far away.

  5. Optional, easy: Add more objects (in castRay) and light sources (in shadeHit) to create an interesting scene with multiple spheres and walls.

  6. Optional, hard: Change the sphere to a coloured mirror, by tracing a reflected ray from the hit point and multiplying the resulting colour by the sphere’s own colour. Unfortunately GLSL does not allow recursion, so you may have to reorganize the code using a loop.