I always wanted an interactive Crowd portfolio where, instead of being just a few seconds of curated footage, visitors could actually stress-test the behaviors I usually use in my crowds. I feel it would let visitors see, firsthand, the intricacy in the work I'm producing.
- Display a decent amount of visually distinct characters on screen
- Create an interesting environment for these characters to interact with
Obviously, it's Crowd—you need a lot of characters, but it's also the scariest part. My website needs to run well on most computers and smartphones because the last thing I want is to lose an opportunity as a result of a laggy portfolio on a recruiter's phone.
Here's what I did to overcome these hurdles :
The Uncanny Valley is a tough hill to climb and the results often age badly. Instead, I opted for a stylized look as I feel, if done right, doesn't age as quickly and doesn't require as much ressources to make it look nice.
I got really inspired by Valve's promotional material for Portal 2 : simple pictogram characters, but full of personality. They can be achieved with a low amount of polygons, variations can be a simple texture swap and they don't need to be affected by lights since they're a flat black color.
For the environment, I went with something similar. Super minimalistic shapes to keep it low poly and white textures not to distract too much from the crowd. The only compromise I opted for is enabling shadows to create depth and contrast.
A more technical way to handle a large number of objects in Three.js is to use a single Instanced Mesh with X instances, instead of cloning the same object X times.
Here's the results of a test I did on my machine with 10 000 cloned Suzannes vs 10 000 instances of Suzanne:
| Cloned (min-max) | Instanced (min-max) | |
|---|---|---|
| FPS | 13-23 | 39-43 |
| Frame Time (ms) | 3-776 | 2-81 |
| Memory (mb) | 130-282 | 9-20 |
As you can see, the max FPS is nearly doubled with the instances, they load 10x faster and use less than 10% of the cloned memory.
The only problem, every instanced characters must look the same and play the same animation...
Like I mentioned before, instances comes with a major constrain—they all need to be indentical. Pretty hard to create an interesting crowd when everyone looks and acts the same. This is where custom shaders come into play.
By overriding each agent's vertices position in the Vertex Shader, you can have everyone play a different clip. Additionally, to lower the CPU's calculation load, the vertex animations can be read by the GPU through a texture where each pixel's RGB values represent a XYZ transforms :
- Pedestrians
- Spectators
- Flock
- Traffic
- Mugen87 for the Yuka Game AI library


