It is real long since I studied coordinate geometry or computer graphics. This last week, dusting the very little remains of what I knew, I decided to work on a ray tracer. When I started, I did not know what a ray tracer was. Slowly, I understood that it was one algorithm that is used to construct a 3D scene on a 2D screen. Broadly, this is how it works
```julia
Define the eye/camera/viewpoint
Define the screen in m*n pixels
Shoot a ray for each pixel in the screen from the eye. For each ray,
Find nearest intersected surface
Find a color for the point based on surface reflection/refraction or the light source and shading model
Plot the color on the pixel
```
I decided to build one that would trace spheres, so I had to define 3 major types - Vector, Ray, Sphere, and a helper type Intersection to store where an object intersected with the screen.
```julia
type Vector
x::Real
y::Real
z::Real
end
type Ray
origin::Vector
direction::Vector
end
type Sphere
center::Vector
radius::Real
color::Vector
end
type Intersection
point::Vector
distance::Real
normal::Vector
object
end
```
Interestingly when I went about defining methods for the vector, I found Julia had inbuilt support for finding dot and cross products, so all I had to do was piggyback on those implementations and build my vector class. Also, thanks to Julia's multiple dispatch mechanism, overriding inbuilt operators was as simple as this:
```julia
function +(a::Vector, b::Vector)
return toVec(toList(a) + toList(b))
end
```
That done, I went about implementing the core algorithm, and a couple of simple shading models, being Lambertian and the Blinn Phong shading models.
Once I'd implemented it all, and fixed all bugs that produced seemingly awesome but wrong images, the main loop consisted of this:
```julia
for x in 1:imageWidth, y in 1:imageHeight
traceWorker(x, y, imageArray, cameraPos, lightSource, objects)
end
//See full implementation here
```
I used Images.jl plugin, to build the image, and ImageView to display it, and when I ran my code with the above main loop I got something like this:
```
☁ ray-tracer [master] ⚡ time julia tracer.jl
julia tracer.jl 11.55s user 0.26s system 98% cpu 11.933 total
```
But having used Julia, I had to put it's parallel processing capabilities to test. And because each of the calculations in ray tracing are independent of each other, I could put this, to use. And now my loop became...
```julia
@parallel for x in 1:imageWidth, y in 1:imageHeight
traceWorker(x, y, imageArray, cameraPos, lightSource, objects)
end
//See full implementation here
```
Sweet! Let's check the new running time.
```
☁ ray-tracer [master] time julia tracer.jl
julia tracer.jl 6.44s user 0.11s system 99% cpu 6.566 total
```
Yay! Down by almost 50%. Pretty sure there are more ways to optimize my code, but this is how far I've gotten till now.
**Now, for our final showdown.**
Woah, but no...
Ummm, circles or spheres?
Yes this.
Thanks to fellow HackerSchooler Lita Cho for patiently explaining how ray tracers work :) Check it out at: https://github.com/madhuvishy/ray-tracer/