Computer graphics is the study of generating images with software. I studied it in Introduction to Computer Graphics at Boğaziçi University, taught by Lale Akarun. Over three homework assignments, we wrote a ray tracer in plain C++, with no libraries.
At the lowest level, an image is just a rectangular table of colors. A 1920×1080 image is simply 2,073,600 color values, one for each pixel. If a program chooses an RGB color for every pixel in that table, it has drawn an HD image.
The question is how to compute a color for every pixel. There are two main approaches: rasterization and ray tracing. This class used ray tracing, which produces very realistic images but is much slower than rasterization.
The core idea is simple: cast a ray from a hypothetical eye point through each pixel of an image plane. If the ray hits an object, write that object’s color into the pixel.
Everything beyond that builds on the same trick with more rays. Where is the light source? Can the hit point see it, or is another object in the way, so the point is in shadow? Does the light arrive head-on or at a grazing angle? Is the surface shiny, so the ray should bounce off it and continue into the scene?
Homework 1
The first program rendered only spheres, lit by one point light. Each pixel got one ray, and the nearest sphere intersection decided the pixel’s flat color. From that hit point, a second ray was cast toward the light: if it hit any sphere, the point was treated as shadowed and its color was multiplied by 0.1.

Homework 2
The second assignment added a ground plane and replaced flat colors with a simple illumination model. Every object still has one RGB color; what changes is how strongly that color shows up at each hit point. The final RGB is the sum of three contributions:
- Ambient light: the object’s color multiplied by a small constant, the same everywhere, so nothing in the scene is ever pitch black.
- Diffuse light: the object’s color multiplied by a brightness factor. The factor is the cosine of the angle between the surface normal and the direction to the light, so head-on light is bright, grazing light is dim, and light from behind contributes nothing. It also weakens with the square of the distance to the light.
- Specular light: pure white multiplied by how well the light’s mirror reflection lines up with the viewing direction, raised to a high power so it collapses into a small sharp highlight.
The three are summed channel by channel and clamped to the displayable range.
The diffuse and specular contributions are dropped whenever the shadow ray from the surface point hits another object, leaving only ambient.
Reflections were implemented by continuing the ray after a hit. The renderer bounced each ray this way up to a maximum depth, shaded every hit along the path with the model above, and blended the bounces into one color. It is an educational reflection model rather than a physically based energy model, but it is enough to make objects appear in shiny surfaces.


Homework 3
The final assignment added triangles. Triangles matter because almost any surface can be approximated by enough of them. For example, the Utah teapot is a combination of 28 cubic Bézier surface patches, each controlled by a 4×4 grid of points and evaluated by
To render those smooth patches with the triangle ray tracer, the program sampled each patch on an grid and split each grid cell into two triangles, so the whole teapot becomes
triangles. Increasing makes the silhouette and highlights smoother, but it also gives every ray more triangles to test.



The final scene combined all the pieces: spheres, a ground plane and three walls, the triangulated teapot, ambient/diffuse/specular shading, hard shadows, reflections, anti-aliasing, and BMP output. The body of the teapot and its rim, handle, spout, and lid got different material colors, assigned by patch index.

Read the original homework reports: HW1 PDF, HW2 PDF, HW3 PDF
Check out the source code on GitHub: github.com/sinaatalay/RayTracing