views:

851

answers:

5

How do computer games render their ground? I will be using a heightmap for geometry (though I will later optimize it) but I am wondering what the best technique is, for example, to 'paint' my ground; grass most everywhere, dirt paths here and there, gravel inside towns, and smooth transitions between each type of material.

Do I just use a huge pre-baked texture? That seems very inefficient, when I could tile existing textures. So then do I use a huge alpha map for each existing texture? In theory it sounds okay to me but how do I actually go about doing that and what are the consequences? I really don't know where to start, and my Google searches aren't proving very effective.

I'd rather not have to 'snap' the texture to the grid (i.e. space (0,0) is grass, space (0,2) is dirt, space (0,1) is grass-dirt transition); I'd rather be able to arbitrarily paint so that it looks more convincing. Of course that would be the easy way but it's too much of a sacrifice in graphics quality and 'realism'.

I'm mostly just looking for theory and options here. I'm using OpenGL so if you can provide tips as far as OpenGL's way of doing things, and functions that I may never have heard of, that would be great.

Just for clarification, Oblivion is a good reference as to what I'm looking for. I don't know how the ground's geometry is (heightmap, static 3D models, etc) but their terrain has different ground types and smooth transitions between them, like I'm talking about. Here's an example image, notice how the cobblestone blends into the grass, unrealistically but smoothly: http://www.elitistsnob.com/images/Oblivion%202006-05-21%2008-38-25-15.jpg

Also I think I read about this in one of the Game Programming Gems books, but I didn't pay much attention to it at the time, and now that it's summer I don't have access to my university's library to check! I'm looking for tables of contents right now and will edit if I find it, but I will still not be able to read it until mid August.

EDIT: Ah man, Game Programming Gems 7 has a chapter 5.8 titled "Mapping Large Textures for Outdoor Terrain Rendering", that sounds like exactly what I need, but my U's library doesn't even have that book! I couldn't find anything exactly like this in the other Game Programming Gems books, though a couple had some terrain geometry articles.

A: 

prebaking is most certainly not inefficient. it's the most efficient in fact because your runtime code doesn't have to do any blending or other calculations. it just renders the texture. Of course, the dynamic techniques offer a simplification of the toolchain and more options.

Joel Martinez
However, bear in mind that simple blending operations are essentially free on most hardware. The main cost trade-offs here come from the amount of texture memory you're using and how often you change between them, and that makes pre-baked textures expensive in many situations.
Kylotan
A: 

Generally, transition areas are precreated, although it's possible to do some things with alpha channels and blending of textures.

McWafflestix
+5  A: 

I have recently written a small terrain rendering engine in OpenGL that does something similar to what you are talking about. The technique I use is best described as texture splatting.

I use five textures to accomplish this. Four of these textures are detail textures: grass, rock, water, and sand. These textures are smallish, 512x512 textures, and they are tiled across the terrain. The fifth texture is a mixmap. The mixmap is a giant texture that covers the entire terrain, in my case is 4096x4096.

MixMap

This mixmap uses all 4 color channels (r,g,b,a) to describe how much of a detail texture to display at that specific location. I am using the red color channel to determine how opaque the sand is, green is for grass, blue is for water, and alpha is for rock. This mixmap is calculated based off of the heightmap at initialization and I use altitudes to determine these values. For instance, close to the sea level, I mostly want water, so I set a high value in the blue channel and low values in the other channels. As I get higher into the mountains, I set the alpha color channel to a high value since I want a lot of rock texture, but I set all of the other color channels to lower values.

Fragment Shader

This mixmap is then put to use in the fragment shader, where I take these color channels of the mixmap and use them to combine the detail textures. Here is the GLSL code I am using for the fragment shader:

uniform sampler2D alpha;
uniform sampler2D grass;
uniform sampler2D water;
uniform sampler2D rock;
uniform sampler2D sand;
uniform float texscale;

varying vec3 normal, lightDir ;

void main()
{
   // Get the color information
   vec3 alpha    = texture2D( alpha, gl_TexCoord[0].st ).rgb;
   vec3 texSand  = texture2D( sand, gl_TexCoord[0].st * texscale ).rgb;
   vec3 texGrass = texture2D( grass,  gl_TexCoord[0].st * texscale ).rgb;
   vec3 texWater = texture2D( water, gl_TexCoord[0].st * texscale ).rgb;
   vec3 texRock  = texture2D( rock,  gl_TexCoord[0].st * texscale ).rgb;

   // Mix the colors together
   texSand *= mixmap.r;
   texGrass = mix(texSand,  texGrass, mixmap.g);
   texWater = mix(texGrass, texWater, mixmap.b);
   vec3 tx  = mix(texWater, texRock,  mixmap.a);

   // Lighting calculations
   vec3 dl = gl_LightSource[0].diffuse.rgb;   
   vec3 al = gl_LightSource[0].ambient.rgb;
   vec3 n = normalize(normal);
   vec3 d = tx * (dl * max( dot ( n, lightDir), 0.0 ) + al );   

   // Apply the lighting to the final color   
   vec4 finalColor = vec4( min(d, 1.0), 1.0);
   gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor);
}

The uniform texscale is a value that determines how many times the detail textures are tiled across the terrain. Higher values will make the detail textures look more crisp at the risk of making them look more repetitious.

Andrew Garrison
Yours was most popular and most similar to what I ended up doing so I'll mark it as the accepted answer. However, instead of using shaders, I used OpenGL texture combining. I made a Google Doc of all the pages I used while researching this technique and put them here: http://docs.google.com/View?id=ajk9hxnz95qm_107fndcp6c8 The best part of it is that it doesn't require a shader, and it allows as many textures and alphamaps as you want. Hopefully it'll be a valuable resource to someone out there.
Ricket
+1  A: 

ID seem to have made the single large "megatexture" (we're talking 32K^2-128K^2) work in QuakeWars.

There's an interesting Q&A with Carmack about it at

http://web.archive.org/web/20080121072936/http://www.gamerwithin.com/?view=article&article=1319&cat=2

(original link seems dead currently, but not not making the above a link because SO seems to have problems with Internet Archive links; they look good in the edit preview, then break on the main page).

timday
that... seems impossibly huge though.(128 000 * 128 000 * 3) * bytes = 46 875 megabytesthat's assuming 3 bytes per pixel (24-bit color, no alpha)... even if you downgrade and say 1 byte per pixel (which would just be crappy), that's still 15,625 MB of data. And I presume they compress it, but even with really good compression, the final size must still be about the size of a DVD (or two) with only 8-bit pixels... That's just insane. Am I missing something?
Ricket
32k x 32k is less phenomenal, at 2.86 GB for 3 bytes per pixel. After compression, that would be reasonable; assuming the landscape texture is so important that it should take up such a large amount of space. But with hard drives being so big today, and games now naturally being 5+ GB at the high end, I suppose it's acceptable.
Ricket
Thanks for the link as well. I read through it a bit. I think I will go for a different approach though. While one large texture is feasable, it's a waste unless I wanted to manually tweak the whole thing. Most of the time I would just want to spray a few tileable images on it anyway, so there's no need to have a pixel-perfect "MegaTexture". I'm going to keep looking at alternate solutions.
Ricket
+1  A: 

you cant run away from tiling but maybe if you use a base texture which makes a little noise on ground, it looks like there is no tiling...

use base texture with the same texture coordinates of alpha texture. base texture can be anything.. a sattelite picture, or a grass texture.. it would match perfect if it is related to your ground shape..

and try to use seamless textures for your grass, rock textures... it does not solve but makes it look as there is no problem

ufukgun