Friday, 22 August 2014

Shaded Island

After writing the last article I have continued to perfect my island generator. I reimplemented the Gaussian blur to use separated kernels, which resulted in a huge speedup in the generation step, but rendering was still slow when the terrain resolution was big, so I wanted to improve on it.

I spent a long time on looking for the best rendering solution. First I checked out Ogre, which seemed to be a decent rendering engine. Unfortunately the configuration is very complicated and it's hard to find reliable, current documentation. I couldn't get anything get rendered on Linux with OpenGL after several hours of trying, so in the end I just gave up sadly.

Next I tried the bgfx rendering library, which also looked nice and much simpler than Ogre. This time my problem was that I could not get it to cooperate with SFML, and I did not intend to ditch that library.

The next choice was OGLplus, a C++ wrapper around OpenGL, looking good at first glance, but a bit complicated and bloated when I tried to use it. So after looking at options for weeks I kinda gave up. I considered using the vertex buffer and shader facilities provided by OpenGL, but was too lazy for it.

Then one day I accidentally discovered that the 2nd version of SFML, in contrast with the 1st version, has support for shaders. It's easy to load and use them, and the shader language is GLSL. It also supports vertex arrays, but unfortunately only with 2D coordinates for position, while I needed 3D. Luckily the SFML sources are easily readable, so I could figure out what's going on behind the scenes and learn how to use vertex arrays in OpenGL.

Switching to vertex arrays had a huge speed improvement, which is what I expected, since now there are no calls to glTexCoord2f and glVertex3f for every single vertex, only one call per frame to glVertexPointer, glNormalPointer, glTexCoordPointer and then glDrawArrays.

Using shaders enabled me to change from flat shading to Phong shading. It required calculating the vertex normals (which get interpolated in the shader for every pixel), not just the face normals for the triangles. The result is pretty nice:

Flat shading

Phong shading

Playing with shaders is fun, it opens up a lot of possibilities, for example I can modulate the colour of the terrain based on the height value (= z coordinate), e.g. set the lower parts to sandy colour and the higher parts to grassy green. It still needs tweaking, but the basics are done.

Another feature I have is the day night cycle. It was already present in the old renderer, but was very slow. For every frame the colour of every triangle was recalculated, based on the dot product between the sunlight direction and the triangle normal. In the new renderer the light direction is passed in to the shaders, and all the calculation is done on the GPU instead of the CPU.

Next I plan to implement vegetation generation to add trees, bushes, etc., and other features needed to make it into a game.