One Week of Ray Tracing in Rust
I started this year with one week of learning Rust and implementing a ray tracer from scratch using test-driven development.
My primary goal was to learn more about Rust. I had a look at the language before, but I did not yet find the time to work on any substantial project.
Writing a ray tracer from scratch is an ideal project for learning a new language. The task itself is straightforward, but you can go arbitrarily deep and sophisticated. Plus, working on something that gives instant visual results is always a pleasure.
The Ray Tracer Challenge
I followed the book The Ray Tracer Challenge by Jamis Buck, a test-driven guide to ray tracing. The book is written in an approachable style and does not assume any previous knowledge. As long as you have basic knowledge in any programming language you should be able to follow the text without problems.
The book is unique in the sense that it follows a test-driven approach independent of a particular programming language. Tests are described in easy to understand Gherkin language. Here’s an example:
Scenario: The magnitude of a normalized vector
Given v ← vector(1, 2, 3)
When norm ← normalize(v)
Then magnitude(norm) = 1
It’s up to you to either implement the corresponding unit tests or to hook up the Gherkin files as test cases. I chose to write unit tests myself for sake of simplicity (at the expense of tedious repetition).
I admit: Learning a new language and following a test-driven approach slowed me down somewhat in the beginning. However, once I figured out the basics, things went smoothly. By the end of the week, I was comfortable enough to do much of the work without looking up things all the time.
Rust Experience
My experience working with Rust was consistently positive. This applies to both the language and the ecosystem around it. Rust prides itself for being a performant, reliable, and productive language. And Rust delivers.
If you have a C++ background like me, you’ll find that learning the basics is not that difficult. You’ll likely find the build system, package management, and IDE integration to be an absolute blessing. Having a minimal unit testing framework readily available was great for a quick start. Personally, I found generic programming in Rust to be much more enjoyable than in C++.
I won’t go down the rabbit hole of writing a comprehensive comparison between Rust and C++. You can find enough of them online. Instead, I’ll briefly list the pros and cons that I came across during this week.
The Good
- Memory-safe and thread-safe by default
- Immutable by default: Only allow change when necessary
- Strict by default: No implicit type conversions
- Concise yet expressive syntax: Sometimes Rust feels like a wild mix of C++ and Haskell, but in a positive sense.
- Trailing function return types: Feels much more natural and closer to mathematical notation.
- Traits system and generic programming: Helpful error messages!
- Error reporting: The
Result<T,E>
type is cleaner than normal error codes and much simpler than exceptions. - Cargo package management and build system
- IDE integration with VS Code and
rust-analyzer
- Static analysis with
clippy
- Straightforward parallelization with
rayon
The Annoying
- Working with strings. Although everything is consistent if you know the rationale behind, it is more cumbersome than in other languages
- Having to type dots for floating point numbers (
0.
instead of0
) is a pain. At least in the beginning. Now it’s in muscle memory. - No
operator()
to overload. Therefore, no conventional matrix notationA(i,j)
for element access. - No default constructors, cumbersome
struct
initializers - No function overloading
- No default arguments
- No variable argument lists
- Const generics: As a recent addition to the language, this feature is incomplete.
Summing Up
Learning Rust and working with the language was a breeze of fresh air. Writing a ray tracer from scratch is a great programming exercise, and the book by Jamis Buck provides a low-barrier entry. The test-driven approach is well thought out and encourages using TDD in practice. I haven’t finished all the chapters yet, but I’m sure I’ll continue.
Likewise, I’ll deepen my knowledge about Rust. I was skeptical at first because of all the hype. However, the more I work with the language the more I enjoy it.
I encourage you to try Rust yourself. Stop reading blog posts about Rust! Head over to the Rust homepage, learn the basics, and use the language for a side project.
Keep an open mind.