3D Boids Using Rust and THREE.JS

Click Here for the project

Introduction

Boids is a natural life simulation of the behavior of boids (birds) in flocks. It was first developed by Craig Reynolds in 1986, and was initially implemented in 2D space, but works in 3D space. It's often used to simulate motion of birds or even aquatic life in video games and animations.

Boid Rules

The Boids Simulation uses three simple rules to determine the behavior of the boids, these rules apply to a boid based on all the other boids in it's neighborhood. The neighborhood is a sphere around the boid that is where it can see other boids. In all the pictures the grey area refers to the neighborhood.

Separation

The seperation rule is probably the most simple, and its primary function is to prevent colision between boids. Note that this rule does not disallow collisions, it just applies a force on each boid steering it away from other boids.

Picture by Timm Wong at Stanford CS

Alignment

The Purpose of the Alignment rule is to make all the boids within a boid's neighborhood have similar headings. This makes it to where all the boids are going in a similar direction, creating flocks that appear to have planned movements.

Picture by Timm Wong at Stanford CS

Cohesion

This rule makes the boids go towards the "center of gravity" of their neighborhood. This creates cohesive flocks, but if the boids get too close, they won't continue towards the center of gravity due to the seperation rule mentioned above.

Picture by Timm Wong at Stanford CS

Why Rust?

Rust is a fast language, thats (relatively) easy to use with wasm. I originally wrote the whole thing in TypeScript, but I wasn't getting good performace, so I switched to Rust. Rust is also the fastest memory safe language that I know of, allowing for efficient and correct code.

How does THREE.JS work with Rust

To get THREE.js to work with rust, I kept all the rendering in the main thread of Javascript, but all of the calculations for the position of the Birds is done in a Web Worker using Wasm. To keep my calculations simple, I rewrote part of the THREEJS Vector3 Class in Rust.

Data Synchronization between Web Workers and Main thread

For Data Synchronization between the webworkers and the main thread, I used a SharedArrayBuffer, rather than using the postMessage() Method because with postMessage, a copy of the data is made each time it moves between threads, causing a dramtic slowdown. SharedArrayBuffer actually shares a space in memory between the threads, to where the threads are reading and writing to the same place. The sharedArrayBuffer used the Float64Array TypedArray, and had 9 floats for each boid (posX, posY, posZ, velX, velY, velZ, homeX, HomeY, homeZ).

Different Versions

Here's all the versions of the project I've made.

Rust/wasm multithreaded
Rust/wasm singlethreaded
TypeScript singlethreaded

Github Repo

Technologies Used