Julia fractals in Rust wasm
I like to write programs to render fractals, and especially Julia set fractals. I also like the Rust programming language. Among other advantages it happens to be great for compiling to wasm, the new format for executing code in a web browser. And I like to code stuff for the webb. So how come I haven’t written a wasm Julia renderer in Rust yet?
Well, now I have.
If your browser supports wasm, you should see an animated jula set here.
Rust has a bit of a bad reputation for creating large binaries, but that is not true for wasm binaries. The fractal renderer on this page is 907 bytes (not kilobytes). A lot smaller than a jpeg of a single frame.
Performance and cheating
The first is obvious: The julia set is symetric, so I can draw two pixels, (x,y) and (-x,-y), for each one I calculate.
requestAnimationFrame will typically trigger at 60 Hz
(as long as a frame can render in 16.6 ms or less).
On my machine, it is fast enough, so I get 60 fps, but then
one core is pretty much occupied and the fan starts to sound.
If I draw a new frame only on every other call, I get 30 fps
and no fan, which I find nicer.
On a slower machine, it may gake upwards of 33 ms to draw a
frame, and then I skip 1/60 s, giving an effektive
20 fps, which I also think is quite ok.
I also draw a relatively small image (only 360 by 270 pixels), the html canvas element automatically scales it up to the width given by css.
The last optimization requires a bit of explanation:
The Julia set is closely related to the Mandelbrot set. The parameter that I’m animating here is a point in the complex plane. If that point is inside the Mandelbrot set, then by definition the origo of that Julia image is inside the Julia set.
But not only that; if origo is inside the set, there will be a continous area around the origo that is inside the set, and otherwise there will be no areas in the set (there may be some points approaching infinite iteration, but iteration counts will fall steeply beside them, so the number of pixels with very high iteration count will be small). But the usefull thing here is that when there is a continous area reaching maximum iteration counts, an image as scaled out as this wont be noticably distracted by settig a lower max iteration value. So either a high maximum iteration count won’t be too computationally expensive, or it isn’t really interesting (in an animation like this). So I start by checking if my c value is inside the Mandelbrot set, and set a lower or higher max iteration value accordingly.
If you are interested, the code is available on github.