on Sep 30, 2009
Games have trouble covering large surfaces so that they can look good at a distance and close-up. This was a huge problem in the past (and basically unsolvable for pre-2000 game engines) that still crops up today under certain circumstances.
Let’s say we have a room. We’ll use our old standby UnrealEd to illustrate. We make a room and adjust the textures so that they look good from a distance. But then they look super blurry when we get close:
|I’m using a tiny texture (this one is really for ledges and such) to make the problem more obvious, but this screenshot doesn’t really do it justice. It’s when you’ve got just a few pixels stretched across your entire monitor that it really starts to look awful.|
You can fix this by making the texture repeat more times. But then the wall will look detailed up close, and monotonously repetitive at a distance:
It’s a tradeoff, really. The problem is that we have lots of space but we can’t afford to fill that space with unique information. Our poor 1999 level graphics card just can’t hold enough texture data to cover this wall with a single ultra-detail texture. The space requires more information than we can afford to provide.
Let’s say I need to texture a wall, but my texture budget only allows me to use a measly 32×32 texture. I dunno. Maybe my boss hates me or something. Here is the texture I have to work with:
Well, I can be an idiot and just stretch that sucker over an entire wall:
Much too blurry. Or, I can cause the texture to repeat a bunch of times:
The obvious tiling is very bad, and ends up making it look like a magic eye picture. Your eye spots the repetition and rejects it. Sure, brick walls are repetitive, but they don’t have the same three bricks with the exact same shape and the exact same shade and the exact same spacing. You can even see tiling problems like this in modern games once in a while. Take Champions Online:
The tiling here is really obvious in-game, although I’m not sure it will show up in this reduced screenshot. So we’ll zoom in a bit. Take a closer look at the ground:
Even the slight color changes can’t hide the tiling, which makes the world look like a big quilt.
The brute force solution has been to make the texture maps bigger, and graphic card makers have been only too happy to oblige with ever-escalating devices with access to larger and larger memory pools. But it’s actually not a great solution. The way the human eye works, if you want something to look twice as detailed, you need to double the resolution of the texture, so that it is both twice as wide and twice as tall. But textures take up memory based on their total area. Width times height and such. So to make a texture look twice as good, it needs to consume four times as much memory.
Making things worse is the fact that games were pushing for more detail in both the close-up and distance scenery. The artist wants to make a telephone where you can actually see the buttons as opposed to a blob of color. And game designers are pushing for ever larger gameworlds, which means we’ll be seeing bigger stuff from even further away. The need for better levels of detail on both ends of the scale, combined with the desire for greater variety, and further combined with the problem of quadrupling the memory use for double the quality, all created a need for so much data that even the preposterous rate of GPU growth couldn’t keep up.
But there turned out to be better solutions than just covering everything in enormous textures. One solution was detail textures. (At least, that’s what they were called in the Unreal Engine. As always, graphics technologies often have different names in different development houses.) Going back to my brick wall: Instead of cranking up the resolution on the bricks in a vain attempt to outpace the ability of the human brain to detect artificial patterns, what if I add just one more 32×32 texture:
Now, I’ll draw the wall twice. Once, I’ll draw it with the brick so that it tiles, then I’ll take that little square of light and dark patterns and stretch it over the entire wall. Blending the two together, we get:
Even though this was made in photoshop, I didn’t cheat here. This image was made with a pair of 32×32 textures. The bricks make it look good up close, while the detail texture creates just enough variance in the pattern to break it up. The brick texture is tiled 18 times across and down this wall, so if I had wanted to fill the whole thing with detail, I would have needed 324 times as much memory. Instead, I got most of the way there with just twice as much.
This is very similar to the problem we have in Fuel. The data needed to cover the entire world would fill over 40 DVDs. Like trying to fill our brick wall with unique data, we just can’t afford to do that. But we can come really, really close by taking small sets of data and mixing them together at different resolutions.
|Completely unrelated to the terrain, but I thought this place was interesting. Elsewhere there’s a city half-buried in the sand that you can explore, but this half-submerged one is unreachable. Shame. The skyline makes me want to check it out. Very forlorn. Love the decaying buildings.|
I believe the overall shape of the world is probably guided by a large-scale, super-low resolution heightmap that puts the big details into place. (I mean “low” resolution in the sense that the points might be 100 meters apart. Even at that, this would still be a big chunk of data. It would be 1280×1280, which would give us over 1.6 million elevation points.) This heightmap would define stuff like mountain ranges and the big bodies of water. Then patches of repeating detail are added to the big map. In my analogy above, the big heightmap is the light and dark noise, and the patches are the brick texture.
This means that you can probably spot the repeating topography if you play long enough. Of course, it won’t be exactly the same. You’ll find yourself on a horseshoe-shaped ridge, looking down the steep drop into a valley of snow and rock. Perhaps a kilometer away this horseshoe bit is repeated. Except here the thing is scaled down vertically, so the valley is shallow, ringed with trees, and filled with water in its basin.
I’ve come across areas like this in the game, where a bit of the land will feel vaguely familiar or remind me of someplace else. It’s a different texture with different foliage and the roads might follow different patterns, but I suspect I’m seeing the data repeat. Note that I doubt you’d notice this unless you were looking for it. Which, now that I’ve pointed it out, you will be. Sorry.
So that’s my take on how I think we get 200GB of world out of a gigabyte or so of data. It’s certainly the approach I’d use.
Shamus Young is an old-school OpenGL programmer, author, and composer. He runs this site and if anything is broken you should probably blame him.