Jump to content

'Slope Lighting' Terrain

lighting terrain map_shade slope #define way it' sun vertex
Describes a fast terrain lighting technique.

4: Adsense

I have noticed lately that terrain engines are the 'in' thing when it comes to engine development. That and raytracing engines, but we won't go there. Lighting terrain isn't hard, that is of course if you know your way around normal vectors and dot products and all that mumbo-jumbo - but what about efficiency? I have never seen anything similar to slope lighting, so I guess you could say I invented it, that includes the name too. It's a way to easily light terrain. In my first implementation of slope lighting I setup my engine to just statically generate lighing values for each vertex when it loads up the heightmap. But I have also realized it can be used on the fly as you draw the terrain. This would make for a much more dynamic environment which expands the horizon of possibilities. You could have environmental effects easily manipulate the terrain lighting automatically like craters, tremors, morphing scenery (scary dream effects, etc).

Here I will give a short piece of code on how to use slope lighting to retrieve a extremely accurate approximation of the lighting value of a vertex. This example will create a value from 0-1, since most terrain engines today are in OpenGL, and lighting is done within that range.

If you want to check out my first implementation of slope lighting, check out my terrain engine Heylow, which was mostly inspired by Halo, by Bungie Software.

Slope lighting simply takes the difference between two vertices (height-wise) and determines a lighting value. If you think about it, it's simple, fast, and even the most elite coder would overlook something this simple. To determine which vertices you are working with, simply run through them all, and at each one simply subtract the vertex's height from the closest vertex that is on the side closer to the sun. So lets say your imaginary sun is casting light in the direction of (1, 1). You could define that in a 2D vector for simplicity's sake. Then just use map_shade[x][y] = 1 - (map_height[x-sun_dir.x][y-sun_dir.y] - map_height[x][y]). Simple. The only problem is the sun's angle can only change at 45 degree increments, but the avid game player doesn't sit down and analyze the direction of the sun every minute, so it's not a problem.

Here's a piece of code that runs through a grid layout of a heightmap (square) of MAX_SIZE width and length, and lights it.

//the good stuff
#define MAP_SIZE 128      	//your map size
#define LIGHT_SOFTNESS 25 	//makes lighting more transitive, smooth, and less abrupt
#define MAX_BRIGHT 0.8    	//maximum brightness
#define MIN_BRIGHT 0.2    	//minimal brightness (hillsides are never pitch black during the day)

float map_height[MAP_SIZE][MAP_SIZE], map_shade[MAP_SIZE][MAP_SIZE];


  //lighting, could be placed immediately after map loading/generation, etc.
  // any elite coder could put this where he wanted.
  for(y = 0; y < MAP_SIZE; y++)
	for(x = 0; x < MAP_SIZE; x++)
  	map_shade[x][y] = 1 - (map_height[x-1][y-1] - map_height[x][y]) / LIGHT_SOFTNESS;

  	if(map_shade[x][y] > MAX_BRIGHT)
    	map_shade[x][y] = MAX_BRIGHT;

  	if(map_shade[x][y] < MIN_BRIGHT)
    	map_shade[x][y] = MIN_BRIGHT;

I am sure people will debate over why this is a bad why to light terrain. I am not saying this is the right way to do it. But I am not saying it's the wrong way either. There are lots of ways to do everything, and this is one way to light terrain ;)


Note: GameDev.net moderates article comments.