Haskell Renderer

Overview

In my first semester of University we had a course on functional programming where we learnt haskell. We were all challenged to write a haskell program that produced an image, with the added challenge of making it interactive. For this challenge I partnered with two friends to make a 3D version of Conway's Game of Life, my friends worked on the Game of Life code while I worked on the rendering code. I decided that I didn't want to use the in built 3D renderer in OpenGL (GLUT) as I wanted to learn more about rendering algorithms.

Note: The gif to the right (or above) is sped up to make it shorter, the real program runs slower.

First steps

The first stage of development was simply to try and get to grips with The graphics library. To do this I decided that I would write code that would take in a 2D Game of Life world and display that. I used this to learn how to shapes to the screen and learn about how openGL's callbacks and structure worked (display callback, reshape callback, keyboard and mouse callback, idle callback and the mainloop) along with OpenGL's buffers. I also started to learn about IORef from haskell, which honestly I still don't fully understand.

All of this code can be found in the Rendering2D.hs file.

To The Renderer

The first stage of making the rendering engine was to take in a series of points that represented the centers of each alive cell, turn them into cubes and draw the corners onto the screen.

This was the hardest part of the projects as I had never learnt about rendering before so I had to wrap my head around the maths. I also decided to make the cubes rotate to make it easier to for the eye to 'pick out' the cubes, this functionality was then used for keyboard controls to "move around the environment" (the quotation marks will make sense later).

The next stage was to draw the faces of the cubes, as I knew I would only be drawing cubes in this renderer I decided to simplify this job by drawing each face as a quad rather than two triangles as would be done with proper renderers. I was at this time aswell that I implemented movement control from the keyboard. The colours of the eacg cube was determined using its location.

At this stage I was able to start taking in acutal Game of Life generations and displaying them. I implemented a timer into the idle callback to control progressing through the generations of the Game of Life.

Issues

Once I did this I ran into a three main problems:

  1. Cubes were being drawn over other cubes that were meant to be infront of them.
  2. If any Cubes were behind the camera, stange artifacting was occuring.
  3. The renderer ran very VERY slowly.
  1. My solution to the first problem was to order all of the (center) points by distance to the camera (which was locked to point (0,0,0)).
  2. My solution to the second problem was to lock the camera looking in the positive direction, move and rotate the environment instead of the camera and to discard any and all (center) points that would be behind the camera (this would aid in problem 3 too).
  3. My further solution to the third problem was to throw the 3 faces of all cubes that would never be seen by the camera.

There was an alternative solution to the speed issue which invovled moving and rotating the camera instead of the environment. I implemented this camera's projection matrix and found the render's speed increased significantly. The issue with this method was the problem of removing cubes that were behind the camera became a lot more complex, and I would nobe able to solve it within the alloted time so sadly I had to abandon this solution.

The Finished Thing

Final Thing

The final version was compiled with optimisation to further improve performance. If you're interested you can find this code on my github (We used my friend's github but I've forked it), It's precompiled for windows, but you can run and/or compile it yourself if you so desire (you will need to install the libraries, I do not have a guide for this).

When you run it, you will see a blank screen, pressing '2' will open the 2D version and '3' the 3D version. The 3D version will look like it's not responding, give it a couple minutes the Game of Life generation code is very slow. Rotation controls use 'W', 'A', 'S' and 'D' and movment controls use the arrow keys, generation change can be sped up and slowed down with '-' and '+'.