Desert Scene


As part of my 2D Graphics module we worked with Javascript (with JSLint) and the HTML5 Canvas in order to draw a scene. Early lab work taught us about Matrix mathematics, Bezier Curves, Scene Graphs and Animation. Our coursework was titled "Do whatever you want*", with the asterisk mentioning that it has to be work that can be graded against specific criteria.

Initially the idea of using Matrices and Scene Graphs seemed daunting, but as I learnt about it they seemed logical and not-so-scary anymore. Javascript wasn't hard to work in, though the JSLint made errors more pronounced (which has helped me with better JS programming conventions).

After creating a class for Vectors and Matrices, I went on to create a Polygon object which draws a polygon from points passed in. I used this to create a western scene.

I used a simple gradient background, an arc for the sun, polygons with curves for the objects, and a Bezier curve for the ground. It looks good, but not impressive enough. I decided to add tumbleweed and create a Mirage to create a nice shimmering effect - I did this by taking in the data of the background (which is a 1 dimensional array of Uint8, with 4 values for each pixel - RGBA), and doing 2 for loops to create a distortion on the X and Y axis using sin and cosine waves.

This was initially quite slow and CPU intensive, as it was calculating the data on-the-fly. I then redesigned the code so it generates the first 60 frames at the start of the program, then simply loops through them in order to create the animation. This caused the program to halt for ~5 seconds before it started which didn't look very good. It was more efficient, but it didn't appear so to the eye. I then used a web worker to generate the mirage frames so I could show a loading screen whilst it calculates. This worked, but the loading times were pretty long - it turns out web workers don't pass a reference, but instead pass a copy of the data. Why was this a problem?


Remember the original array of pixels, with one for red, one for green, one for blue and one for alpha. The size of each value is a byte. The canvas is 800 x 600. So for each frame there's 800 * 600 * 4 bits, multiply that by 60 (as there are 60 frames) gives us 115200000 bytes, or 115.2 megabytes. This is a problem as it's trying to copy 115mb at the start which is slower than the initial calculation without the web worker.

I discovered that web workers can pass an ArrayBuffer as a reference instead of copying, so I passed the array buffers in order to circumvent this problem.

View it in action here!