As you might have noticed from pretty much all battlefield-related screenshots I’ve posted over the last months (or even years), the battlefield was always surrounded by water (and earlier on by some kind of bowl), and I was never really happy with it. Especially when fighting in a desert scenario, surrounding it with water looked pretty odd, and adding a sandshader didn’t make things any better. But just having the battlefield floating in the air didn’t look good either, so I recently sat down and finally decided to add real 3D terrain surrounding the battlefields, with different terrains depending on the setting you’re fighting in.
Since this involved some technical stuff that could be interesting to some other (game) developers out there, this posting dwelves a bit deeper into the technical backgrounds than usual, so (work-in-progress) screenshots first and technical stuff after the break (in case you’re interested) :
And now on to the technical stuff…
Creating and rendering the terrain itself is pretty basic and forward. I used my own TerrainTextureGenerator to create different terrain textures for each of the battlefield settings, and also made a heightmap for it, with the center part being flat and some surrounding mountains. When a setting is loaded, the texture assigned to it is loaded and a display list for the terrain is created.
Now you might think it’s enough to just render the battlefield at the floor level ot the terrain at it’s center, right? Sadly it isn’t that easy. The problem is that I want the base height of the hex tiles to be the same height as the floor level of the terrain, and since hex tiles can be lower than the base height (e.g. water hex tiles), the terrain’s floor plane would shine through in those spots, making those lowered hextiles invisible and giving an odd look.
So to fix this I (once again) used the stencil buffer, an OpenGL buffer that allows you to mask out certain parts of the framebuffer, allowing for a lot of different effects. So when creating the display list for the hex fields I also create a (simplified) version of them for stencil rendering. Now before rendering the terrain, I render these simplified hex fields into the stencil buffer without touching any other buffers (color, depth or alpha) :
glColorMask(False, False, False, False);
glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
After this, the stencil is set for all fragments covered by the stencil displaylist for the hextiles of the battlefield. The next step is to setup a stencil compare function that’ll only render where the stencil doesn’t equal 1 when rendering the terrain :
[delphi]glColorMask(True, True, True, True);
glStencilFunc(GL_NOTEQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
Now rendering the terrain will spare out all fragements with a stencil value of one, resulting in a cutout where the hextiles have been drawn into the stencil buffer :
As you can see the terrain’s base height is aligned with the floor height of the terrain and rendering hex tiles below floor level works as expected, and no terrain will shine through. The final step (see the right screenshot) now was to add bordering hexes that fade into the surrounding terrain texture to get a nice and (mostly) seamless look :
And although the terrain isn’t overly detailled or using any fancy shaders this looks already much more realistic and atmospheric than the old version with the surrounding water plane.
Oh, and I btw. noticed the my very own glCapsViewer was mentioned in the OpenGL 4.3 Overview-BOF at SIGGRAPH’12. Pretty nice…