This is a go implementation of the Ray Tracing in One Weekend book.
After following the book in C++ and wanting to learn go, I decided to use it at my first real hands on project with go. I wanted to make the code parallel and display the progress.
- displays the image as it is being rendered (uses SDL)
- processes the image in multiple goroutines and multiple passes (for example, a first pass with 1 ray per pixel so that the rendering happens very quickly, and then further passes with more rays per pixel to enhance the result)
- choose the seed so that the end result is reproducible
go get -v github.com/ypujante/ray-tracing
The only dependency is on the SDL2 Binding for Go library which also requires that you install SDL for your system.
go install
Love the simplicity...
-
ray-tracing
will render the final scene in 800x400 pixels in 2 passes (a quick 1 ray per pixel pass and a 99 rays per pixel pass) using all the cores on your machine and a seed of 2017 -
ray-tracing -r 1 -r 10 -r 50 -r 100 -w 1600 -h 800 -cpu 4 -seed 12345
will use 4 passes (1/10/50/100 rays each so a total of 161 rays per pixel) using4
cores and a width/height of1600x800
and a seed of12345
-
rand.Float64()
is (in hindsight for obvious reasons) synchronized and really killed the performances of the program since it is heavily used by each computation. Abstracted it into aRnd
interface (see model.go) and each goroutine creates its own non synchronized version to fix the issue. -
using goroutines and channels really rocks. A few very powerful set of primitives are all it takes to make asynchronous programming a joy again :).
-
goroutines are fast... try
-cpu 200
... which will create 200 goroutines and, although you obviously do not gain by having more goroutines than the number of cores (since it is 100% CPU bound), it is pretty fascinating to also see that it is not dramatically slowing it down by having to time slice all those goroutines -
go implements interface/object orientation in a very different manner than any other language. Although it takes some time to get used to it, I really enjoyed it after a while. My
Rnd
interface is a good example, since I could make thernd.Rand
class magically implement it even if it is a type not defined by me. -
I do miss generics :( As far as I can tell there is no way to implement the
split
function I wrote in a generic fashion which is a shame.
Apache 2.0