Ray marching in Rust !
I’m currently learning Rust for fun and re-writing my ascii-renderer from Python . I’m using Ray Marching this time, here’s how it looks (if you are on mobile, use desktop version of the site):
You can see that Ray Marching allows for some cool stuff like smooth surface blending and proper shadowing.
Ray marching
Usually 3d renderers use a triangular mesh to describe objects in a scene. In Python version of ascii-renderer
I defined each object as a set of points
(i.e object is defined by a function __contains__
that determines whether the given point is in this object). It allowed me for some cool Ray Tracing stuff, but that was just me toying around.
Behold - Ray Marching! It’s a cool rendering technique where you describe your scene with a Distance Field - each point in this field contains a distance from that point to the scene. Well, actually it’s a Signed Distance Field - the distance to the object is considered negative inside the object, and positive outside.
What’s cool about Ray Marching is that since the whole scene is defined with mathematical expression, I can apply any mathematical transformations to it. For example I can make an object wavy
using a sin
, or make it repeat forever with %
operator. Also, SDF
allows for different ways to combine objects - I can find a union
, difference
, and intersection
for free!
Performance
Currently it’s rendering 4 shapes at ~19 FPS, which is pretty bad. That’s probably due to my dirty and inefficient code 😆 - I’m nowhere near a good understanding of Rust patterns.
My goal is to render 8 shapes at 24 FPS:
- 24 FPS is OK for a human eye
- 8 distinct shapes is usually enough to create a complex scene (ray marching allows for cool tricks that can multiply amount of your shapes without performance decrease)
Plans
- Cleanup the code and increase performance
- Build an actually usable API
- Use
ncurses
instead of just printing toSTDOUT
- Create an
ncurses
GUI for building a scene - Allow importing/exporting scenes in
JSON
- Do some magic ⭐ and expose API to the browser using
WebAssembly