Project 1: Life

CS 195V: Advanced GPU Programming

Justin Ardini (jardini)

2D Visualization

The first part of the project was implementing a 2D visualization of John Conway's Game of Life, using the standard set of rules (a cell is alive next turn if it was alive and has 2 or 3 neighbors or was dead and has 3 neighbors). Each cell is represented as a texel on a 2D texture. To run the simulation, I bind a framebuffer representing the next state, then bind the current state as a texture and use texture look-ups in the fragment shader to determine the next state. This current state is drawn to the screen as a fullscreen quad with alive cells drawn white, and dead cells drawn black.

In order to make the simulation as efficient as possible, I do a few simple optimizations in the simulation fragment shader. First, I use the textureGatherOffsets function to do texture lookups. I gather neighboring cell information with 2 calls to textureGatherOffsets, as opposed to 8 calls to textureOffset. Secondly, I avoid branching as much as possible, so my expression for determining the final color is simply:

out_Color = (liveNeighbors == 3.0 || liveNeighbors + texture(tex, v_TexCoord) == 3.0) ? 1.0 : 0.0)

This only has 1 branch, so it's faster than checking the current state, then checking the number of neighbors.

2D simulation. Pretty boring, right?

3D Visualization

I implemented a couple 3D visualizations of my 2D life simulation. The simpler visualization represents each cell as a cube, and the entire simulation field as a flat plane. This was done used instanced drawing of a cube primitive, where I use the current gl_InstanceID in the vertex shader to determine the location and cell state of the current vertex.

3D simulation over a plane. Slightly less boring.


I also implemented a visualization that maps the simulation around a sphere. This is done in the simplest way possible, treating my x-y cube offsets as yaw and pitch and converting these from spherical coordinates to rectangular coordinates. I also added a light source in the middle and implemented crepuscular rays for a cool lighting effect. The crepuscular rays are implemented by first drawing the scene to a framebuffer object with all occluding objects drawn black, then drawing the scene normally to the screen, and finally additive blending the framebuffer object using a custom shader. This shader "blends" the light rays based on the screen-space distance between the current pixel and the light source.

3D simulation over a sphere. Super exciting!