If you're using a fairly new browser, you should see a cartoonish fire simulation to the left. When you're done playing with it, you can scroll down and read about it.
Also check out my more realistic noise fire simulation.
Run the actual fire simulation.
Run paint updates
Modulate the intensity of the fire over time. This can cause uneven cpu load.
Toggle the optimization settings to see the impact they have on the frame rate.
Don't use the marching squares algorithm to paint smoothed edges, just paint very big pixels.
Horizontally adjactent cells with square geometry are grouped into a rectangle, thus reducing the number of calls to the canvas.
Check this to filter out cells that will be obscured by subsequent paint operations.
The context.fill()
method comes with a lot of overhead. Check this to do one fill()
call per color used.
For the curious ones.
Overlay the simulation with a grid showing the distinct cells.
The implementation and what I learned
The simulation is written in javascript and visualized using HTML5 canvas using the Marching Squares algorithm.
The simulation at a glance:
The action happens in js/objects/firems.js and the method tick()
The algorithm should be pretty common, but I failed to Google a name for it. I based it on what I remember from when a co-worker explained his implementation of a fire in 80x50 char mode ages ago.
I originally wrote this simulation representing it only as pixels. The other day a post on programming reddit about an ASCII fluids simulation inspired me and I learned about the Marching Squares algorithm.
Briefly put, the algorithm generates contours from grids containing numerical values, where values over a threshold value will represent a contour. The algorithm only generates a contour, so I used it several times with different thresholds to create the fire representation.
I apply the algorithm five times, using different thresholds, to create different contours that I overlay.
These are my findings when developing for Google Chrome, but are likely to hold true for other browsers as well.
Draw operations often incur a big overhead, but not all operations are equal:
context.fill()
has a lot of overhead - do your drawRect()
, lineTo()
etc. operations in as big batches as possible.This is something that's always repeated, but here it really hit me: Do measurements!
I have made a framework for my canvas experiments, where I can manipulate a parameters in run-time. I made this originally to manipulate parameters for visualizations. It is, however also a very good way to get immediate feedback if an optimization is doing any good or not, by putting on off switches for optimizations in. If the frame rate rises, it was probably a good idea.
You can fork the code on github: https://github.com/zufallsgenerator/firesimulation