Exploding Coffee » Game of Life
(This one of some older posts of mine, originally written on 2012-11-05.)
Conway’s Game of Life is somewhat of a rite of passage for programmers (at least the scientifically inclined I suppose). And having just started my experiments with WebGL I of course had to make a GPU-accelerated version.
The WebGL canvas below runs Game of Life on a 2048×2048 grid that wraps at the edges. You can drag the view around with the mouse as well as zoom using the mouse wheel.
I have made many Game of Life implementations over the years, ranging from a small, (comparatively) slow version in C on a DOS console to a gigantic version using CUDA (and a previous one using GLSL, so this technically isn't the first time). I don’t remember the exact grid size or update rate but I believe the CUDA version did about ten billion cell-updates per second. This one only does about 250 million @ 60 frames per second, but I figure that’s enough really.
The algorithm in this case is quite simple, uses two shader programs and renders back and forth between two textures to update. Each frame the code does:
- Load the first GLSL program: the Game of Life program. This reads the current state from a texture, applies the rules and outputs the new state for each cell (pixel).
- Activate the texture containing the current state.
- Activate a framebuffer bound to a second texture that will receive the new state.
- Adjust the viewport to match the texture size and render a quad filling the view, thus performing an update.
- Load the second, rendering, GLSL program. This mostly just reads the current state from a texture and outputs a white or black pixel as appropriate. It does however also apply some scaling and moving so that one can navigate the simulation.
- Activate the texture containing the (newly computed) current state.
- Deactivate the framebuffer so as to render to the screen again.
- Adjust the viewport to match the canvas size and render a quad filling the view, thus showing the current state.
There’s a bit more to it than that but not much. The only thing I can think of worth mentioning is that the Game of Life program also receives a uniform vector telling the fragment shader how far it is between texels in the texture space.
This is needed because there is no such thing as integer addressing of textures. So in order to sample the state of the neighboring cells the texture space distance to these cells is needed.
On the other hand a nice bonus with the textures is that wrapping comes free.