Terrain Lighting

It’s time to take a break from optimizations and to aim to a more user-friendly feature: Terrain Lighting. Although there are several approaches to accomplish this goal, I’ve chosen a simple, yet effective, technique known as Slope Lighting by which the color of a vertex is calculated by considering the height of its neighbors.

My implementation is based on an article written by Philip Dutré for GameDev.net. Below is a sample of a lightmap generated using this technique along with the resulting landscape with and without textures.

 

The lightmap applied to the terrain

 

 

And the texture

 

 

The final result

 

As you can see from the images, the results are far from perfect. The current implementation does not calculate soft shadows and there are artifacts in the shadow edges, but that’s acceptable for the moment.

About the iPhone Extensions

Some of you might have hear about DogFighter, a flight combat game created by TeraCode Games for the iPhone and iPod Touch. If not, check this video out.

DogFighter was the first commercial game based on Crimild. As part of the development team for that game, one of the many things I learnt from it was what works for an iPhone game and what doesn’t in contrast with a typical PC game. My experience with DogFighter left me with several “do” and “don’t” lessons that lead me to create the iPhone extensions for Crimild.

Simply put, the iPhone extensions are a series of classes and tools that make a developer’s life easier when attempting to port Crimild projects to that particular platform:

CrimildGLESRenderer

As the name suggests, this renderer implementation is based on OpenGL ES. In particular, this renderer supports OpenGL ES 1.5, which is the version we can find in any iPhone or iPod Touch. At the moment of this writing there is no OpenGL ES 2.0 support, but considering the power that vertex and pixel shaders provide for a game engine, it has become one of the major tasks to tackle once I finish my review on the Terrain library.

CrimildView

Derived from UIView, this class provides all of the mechanisms required in order to setup a proper drawing context. It configures the OpenGL ES context and the CrimildGLESRenderer itself.

CrimildViewDelegate

Following the iPhone design patterns, the CrimildViewDelegate protocol defines the methods that a class needs to implement in order to configure, update and shutdown a Crimild application.

Here’s a screenshot of the Terrain demo working on the iPhone Simulator:

The terrain demo working on the iPhone Simulator

That’s it for now. Stay tuned for more insights about the iPhone extensions.

Optimizing optimizations

Last week I mention that my next goal with Crimild was to tackle several issues regarding the Terrain Library. And that’s what I’m doing. The goal that I’m trying to accomplish with this code review is to ensure not only a cleaner and more developer-friendly API for terrains, but also to improve some optimization that were implemented in the past but never actually completed. But before discussing about the optimization details let me explain how the Terrain library is composed of:

HeightMap

As its name suggests, the HeightMap class store the elevation information that is later used to build the landscape. But since elevation data might come in different forms, the HeightMap class only declares a common interface for all the actual implementations. As I’m writing this post the library already suports elevation data in the form of raw data files, image files (with support for both 8-bit and 24-bit images) and even a procedural heightmap generated through the use of fractal calculations.

TerrainNode

This class is one of the two terrain implementations available in Crimild. In particular, this is the brute force approach. It just read through all the information contained in the heightmap and creates the entire landscape with the maximum level of detail. Although there is no mesh optimization, this class does provide a couple of tricks in order to speed up rendering. The terrain is divided into several patches and group them in order to create a node hierarchy, allowing for fast culling. For those of you wandering, a patch is just a geometry node that contains only the graphical data for the particular portion of the terrain it represents.

The following picture shows the TerrainNode class in action

The TerrainNode class in action
The TerrainNode class in action

Maximum detail for every patch, even when they are too far away to notice it

Notice that all patches have the same amount of detail regarding their actual position relative to the camera view point.

CLODTerrainNode

In contrast with TerrainNode, the CLODTerrainNode class does provide a mesh optimization in order to reduce the amount of vertex information sent to the graphics card. The algorithm I’m using is based on Geomipmapping (see references) and ensures that the level of detail for a given patch increases as the camera moves closer to it. A LOD value is assigned to each patch based on the viewer’s distance and the patch is tessellated whenever that value changes. The amount of patches that are tessellated between each frame depends on the subdivision policy and the camera movement, but during my testings it was always below ten.

Here’s an example of the the CLODTerrainNode works.

Minimum level of detail (the camera is too far away)

As the camera gets closer...

... some patches gets more detail

As the camera moves closer to the terrain, the patches at the bottom of the screen gain more detail.

Cracks will appear on the borders between patches with different level of details. In this iteration I’m using vertical skirts along the patch border to prevent those holes in the terrain. Instead of avoiding the formation of cracks in the surface, the skirt just fill the blanks.

The results

I still need to perform further tests, but the results so far are optimistic in both performance and memory requirements. Improving the terrain library is imperative for the iPhone extensions due to the hardware limitations. I’m going to freeze any further change in the optimization algorithms in order to make some progress in the remaining subjects. The next step is to provide some lighting for our landscapes as well as improving the texture generator.