When people are doing programming exercises, a large number of them make 3D raytracers. While this is a really fun project with exciting results, it also results in people losing interest or typing code that they don’t necessarily understand.

While the end product doesn’t look as nice, I think people should start with 2D ray tracing before moving on to 3D. In this document, I will attempt to go through a simple computer program that can draw 2D shapes.

Outputting an image

To make the implementation simpler, and to follow the raytracer convention, I will be outputting the image in the PPM format.

HEIGHT = 500
WIDTH = 500

print("P3")
print(f"{WIDTH} {HEIGHT}")
print("255")

for x in range(WIDTH):
    for y in range(HEIGHT):
        r, g, b = (100, 100, 200)
        print(f"{r} {g} {b}", end=" ")
    print()

Running this code should result in a 500x500 image with a solid blue-ish colour. The whole point of this exercise will be deciding what to put in the RGB colour values in order to produce interesting results.

Drawable objects

We will have a list of shapes that return whether a given (x, y) coordinate pair falls within it, and what colour it should be. Let’s create that list and replace put the call in our loop.

def solid_red(x, y):
    if y > 150 or x > 150:
        return (230, 100, 100)

shapes = [
    solid_red,
]
shapes.reverse()

# ...

r, g, b = (0, 0, 0)

for drawable in shapes:
    temp = drawable(x, y)
    if temp:
        r, g, b = temp

Running this code should give you an image with a black square on the top left, and a red background.

Drawing a square

def square(x, y, length, colour=(255, 255, 255)):
  def inner(ix, iy):
    if ix > x and iy > y and ix < x + length and iy < y + length:
      return colour
  return inner

def checkerboard(x, y):
  if (x / 50) + (y / 50) % 2 == 0:
    return (100, 100, 100)

shapes = [
  checkerboard,
  square(50, 50, 100)
]