Today we are porting a ray tracer from Peter Shirley’s mini book, into a Swift playground. Since I am not going to describe what Ray Tracing is and how it works, I am inviting you to go ahead and read this book as it’s free for Kindle subscribers. If you are not a subscriber, just buy the book like I did. Paying $2.99 is absolutely worth your every penny if you are interested in this topic.
The first thing we would want to do is create a data structure to hold pixel information. In the playground, create a new file named pixel.swift under the Sources folder. Next, let’s write the Pixel struct. It’s just a simple struct with one variable for each of the RGBA channels. We initialize the alpha channel to 255 which means completely opaque on a [0 - 255] scale:
Next, we need to create an array to hold all the pixels on the screen. To compute the color for each pixel we just set Red to be 0 for all pixels, while Green goes from 0 (no Green at all) in the left corner of the screen, to 255 (full Green) in the right corner of the screen. Similarly, the Blue color goes from 0 at the top of the screen, to 255 at the bottom of the screen.
Finally, we need a way to create a drawable image from pixels. The Core Image framework provides the CGImageCreate() method, which takes in several parameters necessary for image rendering:
Next, in the main playground page create the set of pixels for a window with given width and height, and then create the rendered image using this set:
You should see the following image:
Ok, you might be wondering, but where does ray tracing come into play? Let’s deal with that next. Under the Sources folder again, let’s create a convenience class named vec3.swift where we will have a few math helper methods:
Next, we need to create a ray struct. It has as members an origin, a direction and a method that computes the ray tracing equation for any given parameter:
Then we need to compute the color based on whether the ray hits a sphere which we create in the center of the screen:
You noticed that we used another method, called hit_sphere() to determine whether we hit the sphere with the ray, or whether we miss it:
Back in the pixel.swift file, change the makePixelSet(:) to include creating a ray for each pixel and compute its color before adding the pixel to the set:
In the main playground page, see the generated new image:
Stay tuned for a part 2 of this article, where we will calculate lights and shades for a more realistic image rendering. The source code is posted on Github as usual.