I've been re-evaluating my now rather dated first attempt at a terrain engine. I did some good things, and some bad things. Let's discuss them.

Firstly, and most importantly, the terrain was built from an array of 'terrain patches' which allowed me to perform wholesale culling of entire terrainpatches against the view frustum.
This was a good move, as it automatically subdivided the Worldspace and did so in a predictable way (in my case, a regular grid in the XZ plane).

The entire terrain (all patches) obtained their height information from a single heightmap, so the act of generating the vertex data for a single patch of terrain can be described as the sampling of a smaller subsection of the entire world's heightmap (subtexture sampling).
This was a good move, because it made sure that the terrain patches did not require 'stitching', it created what appeared to be a large and seamless terrain with no apparent effort.

Each terrain patch had its own 'base texture' for rendering, which was precalculated based on the heightmap and four input textures.
Mountains had snow, valleys had grass.
In fact, only two textures were blended per texel, as follows:
Four textures were associated with four Heights.
The output pixels were calculated by determining which two textures were closest in Height and performing a weighted blend between them.
You simply can't achieve this level of per-pixel blending without writing a Shader.. I wanted my software to run on low-end hardware, and the pregenerated textures had a hidden benefit of using neither cpu nor gpu time at runtime, meaning more oportunity for other special effects like splat texture overlays.
My world was only 16 x 16 terrainpatches, but already that means 256 textures had to be generated.

What I did wrong really, can be boiled down to the following:
-I was trying to pregenerate all the textures at runtime, which meant a long delay when the application started.
-I was trying to keep all 256 textures loaded, since unloading them meant regenerating them.
-I had no way to dynamically load and unload terrainpatches and/or their basetextures.

Looking back, that last problem was the greatest problem.
If I'd designed the patchmanager to dynamically load and unload patches depending on the player's position in the world, and if I'd pregenerated the textures and stored them to files, basically I would have had something equivalent to the engine used by Morrowind.
I'm simply saying that it doesn't matter how many Textures we have, it only matters how many we have LOADED at any moment.

My terraindemo had one other vexing limitation: our basetextures were comrpised ONLY of the four input textures, with blending controlled by the heightmap texture.
There was no way to blend in regional textures, for example all terrain at a similar height would display a similar texture.. you couldn't have swamp in one region and desert sands in another region of roughly the same altitude.
The ONLY control you had over the blending was the heightmap.
In fact, we used very little information from the heightmap.
I used a colored heightmap rather than a greyscale one, but nonetheless, I simply determined the Brightness of each heightmap pixel and called that the Height.. I made no attempt to encode more information into the heightmap.

That's what this thread is about.
This time around, I'd like to be able to encode texturing information directly into the heightmap.
For example, I'd like to be able to paint roads on my heightmap, and see those roads textured regardless of their height, while seamlessly blending the edges of the roads into the wilderness.
Essentially, I'd like to be able to override my blending equation for specific heightmap regions, or even describe which four input textures to apply to a given heightmap texel.

I'd like to hear your ideas for heightmap pixel encoding schemes.
Remeber that we're always going to require Height information, I suggest that one of the color components (say, Red) always be used to infer Height - that would leave us 16 bits for encoding texturing info in a 24bit color system, and 24 bits in a 32bit color system.

Don't you think it would be relatively easy to encode n texture IDs into 16 bits, or even use the entire 16 bits to index one of 65536 sets of n texture ids?
It seems to me that four textures are PLENTY if they are being applied on a per-pixel basis.. in fact, even TWO textures would be enough if that is the case.

Your thoughts?

Posted on 2006-08-10 06:06:57 by Homer
You might want to read what Carmack is doing for their next engine... each level basically has one large 2^32 x 2^32 terrain, but it can index "virtually" (re-use patches etc), so you don't need multiple gigabytes per map.

Don't have an URL handy, sorry.
Posted on 2006-08-10 07:19:44 by f0dder
I like to download and read all kinds of documents on shaders, from all kinds sources, both ati/nvidia
and just stumbled on one doc in one sdk about blending terrain with shaders, this doc shows a different approach of blending two different rock textures, one is generally for normals facing upwards to the sun, the second cliffs that go up vertically, blending is made between these are made dependent on normals

so I revaluated your textureblending, because we are like craftsmen at we do, unfamiliar with work in hightech new material like those that they made F1 racing cars in, we are like mastersmiths at forging steel when it comes to asm

no you shall have at runtime generation of textures, but conditional if the textures dont yet exist
but write out textures to files as intermediate step, instead direct to memory

while you are processing textures anyway, process light from main lightsource sun according to normals

who says you are limited to 24bit image data?
use dx texturetool that comes with dx sdk and you have all range up to 128bit textures
for example it lets you load 24bit image and separatly load another image into the 8bit alpha channel, why dont use such a 32bit format and use alpha channel instead of red channel?
you even can convert your 8bit heightmap into a red 32bit red fp texture and you an read Y's directly from that, if you want that

Dungeon siege II for example has a overall theme for the area you move in, jungle,elven forest, desert, snow and intown, how many textures do you need? hex encoded file names for textures and switch to an area is simple switch to a different texturefolder
65536 different textures for a terrain seems too much, better encode terrain in a heriarchy of 256 sets of terrains and 256 textures for each set/heighmap

Posted on 2006-08-10 08:18:14 by daydreamer
I am loathe to use the alpha channel for one reason alone: most 3D image editors don't allow for per-pixel alpha editing.
Even though I'm happy to use 32 bit textures for things like heightmaps, I'm loathe to actually use the alpha channel at the development level, purely because it's too difficult to edit without special tools.
I'm going to pretend I'm stuck with 24 bit images.

Right now I'm leaning towards using the Red channel to infer Height, which leaves the Blue and Green channels.
I was tempted to use those as a 16 bit key into an array of textureblending combinations, but I ended up deciding that I am unlikely to ever require such a vast amount of blending control.
I've decided to use the Blue and Green channels to index a pair of textures for our perpixel blending... that means for each terrain texel, we can choose from 256 pairs of source textures from which we'll sample one pixel and perform weighted blending on it.
512 textures being blended down into one texture.
These 512 textures don't get included in the release version of the demo or game, they are a development tool.
Yes, we'll generate n textures and this time we'll save them to output files which will be loaded and unloaded on demand.
Yes, we can take lighting into account, although it's not my priority.
Do I care what Carmack is doing?
Not really, heh.
(I worked for IDG for a while, I learned a lot about property law).
Posted on 2006-08-10 08:49:50 by Homer

Do I care what Carmack is doing?
Not really, heh.
(I worked for IDG for a while, I learned a lot about property law).

Not saying it's the only (nor even right) way to do things, but it was an interesting read nonetheless. And really, would you be able to get into legal problems from implementing something he's spoken of publicly?

EDIT: Ah, there it was.
Posted on 2006-08-10 09:51:22 by f0dder
I'm happy to read whatever... and read I shall.
I'm just a little cautious when it comes to that particular employer.

When I began working at IDG, I was coerced into signing a NDA (non-disclosure agreement) which is a legally binding contract.
Its terms were open-ended and possibly not binding outside the USA, but the thrust of it was that anything I worked on while I was working for IDG, including my own material, remained the property of IDG.
If I was to implement anything remotely similar to them, and it turned out to be even remotely successful, you can bet your pants that their legal team would descend on me like the vultures that they are.

I'd rather twist myself into pretzel shapes than give them the opportunity to make a dollar at my expense.

Posted on 2006-08-10 10:55:47 by Homer
OK, I've read it, and it sounds like baloney to me.
This is essentially a 'superbmp', which is certainly NOT NEW.

What we're really saying is "let's take all the textures we'll ever use and lay them out as a single massive texture", then we're saying "let's manipulate all of our UV values to map to this single larger texture".

What are the benefits? What are the costs?

The most obvious benefit is that we effectively eliminate texture switches - EVERYTHING is now being rendered using just ONE TEXTURE, with UV values being manipulated according to the layout of the superbmp.

The most obvious cost is that we can't load and unload textures as we travel around our world - we better have EVERY TEXTURE IN THE WORLD in that superbmp, because there's no chances later to upload them to the gpu.

This is highly suitable for games with relatively small levels (think of games like Wolfenstein and Quake), but it would totally suck ass in a large, complex mmorpg.

It sounds to me like IDG are putting their money into smalltime games, the kind where you spend 20 to 30% of your life preloading the next level, shoot a few critters and coplayers, then back to loading the next level.. remarkably shortsighted, but then I remember the C64 too :P

Posted on 2006-08-10 11:10:44 by Homer

The most obvious benefit is that we effectively eliminate texture switches - EVERYTHING is now being rendered using just ONE TEXTURE, with UV values being manipulated according to the layout of the superbmp.

One "logical" texture, yes, but obviously not one "physical" texture... You'd be hard pressed to fit a 32.000 x 32.000 (dunno where I got the 2**32 figure) into any GPU... hell, even any normal system memory (think RGBA in FP format, as well as normal maps etc... how many gigabytes would that be? ;)).

The most obvious cost is that we can't load and unload textures as we travel around our world - we better have EVERY TEXTURE IN THE WORLD in that superbmp, because there's no chances later to upload them to the gpu.

Well, to me the design sounded relatively flexible... while you *could* make one monstrous texture for each level, it would also be possible to make it out of (large) patches, and re-use a bit. And have undefined regions where the player can't go (to reduce memory/disk usage (dramatically)).

This is highly suitable for games with relatively small levels (think of games like Wolfenstein and Quake), but it would totally suck ass in a large, complex mmorpg.

I'm not sure about that - think location-dependant "paging" of terrain data. I think this could be made pretty efficient.

Btw, how large would you reckon the WoW world is?
Posted on 2006-08-10 11:27:19 by f0dder
If we're uploading chunks of texture, not one huge texture, we're right back where we started from, and this is nothing more than an exercise in marketing. Yes, the huge texture sounded fishy to me, but then I don't develop on prerelease hardware (anymore).
Virtualize - abstract - manage - the texture machinery as much as you like, you're still going to wind up copying chunks of texture data into physical textures and uploading them to the gpu in the conventional sense. That being the case, we're back to standard UV mappings and texture switch avoidance mechanisms.
What the heck did we accomplish?

I just finished writing some code to perform per-pixel multi-texture blending in the way I described... Here's a demo output, it's just to test the blending algorithm, not what we'd expect as final output..here are two source textures, the 'heightmap' I used to control the blending (all pixels are 128,0,0 which means "50% blending of uppertexture #0 and lowertexture #0) and the output. It's a simple example, but a powerful system - any two textures can be blended for each output pixel, with blend weighting and texture pair selection all controlled by the heightmap.
The size of the input textures is not relevant - sampling is performed via UV coordinates, not pixel coordinates, we're working with Texels here.

Note that no brightness control is implemented.

Posted on 2006-08-10 12:22:48 by Homer
I found a problem in my blending algorithm, it was losing a lot of brightness (in fact almost 50 percent!)
Also there was a numerical bug which led to attempts to read source pixels outside the image bounds, both problems have been fixed.
I am still not performing brightness correction, but I know that the brightness error is now quite acceptable.
I've removed and replaced the output image in the previous posting.

Posted on 2006-08-11 01:47:51 by Homer
I hereby contribute with a heightmap, testrendered it with a 3d app
its inspired by DS II terrain, which brings up the question if you should store where in the terraindata bridges between the platues is?
if you have 3 types of bridges, use 2 bits for that, zero= no bridge, 1-3 is where in the terrain there is a bridge above, if not use extra data  to show where a bridge starts, you need code that searches for edge of bridge starts to get at what height the bridge are to be rendered
Posted on 2006-08-12 01:03:01 by daydreamer
Please explain what you refer to when you say 'bridges' and 'plateaus' - I think I understand, but I'd like you to clarify anyway.

I'll try now to explain exactly what I've done, so you can make necessary corrections to your heightmap.

First and most important, be aware that I am ONLY USING RED for the Height information.
Red channel is performing actually two jobs, because the height information is ALSO being used to describe a blending weight..
For each pixel on the heightmap:
-RED channel describes height and texture blending weight
-GREEN channel is used to index one of 256 'upper' textures
-BLUE channel is used to index one of 256 'lower' textures

If we use an example, RED=255, we are describing not just a very high place in the 3D terrain, but we are also saying "the texture for this region must be sourced from the 'upper' blending texture".

RED=128 creates a 50% blend of the two textures described by Green and Blue channels.

RED=0 will use only the 'lower' texture.

In this way, we have encoded not only height information per heightmap pixel, we are also describing a blend between a pair of textures - we are in fact describing the regional texturing of the terrain.

Now imagine we have two arrays of 256 textures called 'upper array' and 'lower array' and this will all slowly begin to make more sense.

Our RGB heightmap is used as instructions for generating the terrainpatch textures, I'll supply a standalone texturegenerator within the next few days.

If you have questions regarding this encoding scheme, just ask :)

Posted on 2006-08-12 03:29:16 by Homer
bridges between those heigh areas, because of previous bad experience on encoding texture indirection in .jpgs lossy compression I zip a bmp instead
this can be improved, its just for testing purposes, values used for easiness creating them: 0,64,127-128,192,255 is painted on green and blue channels differently. 0 restrictly used on bottom and 255 ontop
64 I thought some kind of roadtexture
Posted on 2006-08-15 14:19:06 by daydreamer
Here is a beta version of my Terrain Texture Generator v1.0
It uses Biterider's brand spanking new Pixelmap object for bmpfile and pixel manipulation, but the blending code is all mine, since Pixelmap only supports integer operations, and I needed to do weird stuff like get pixels via their UV coordinate rather than their pixel coordinate.

The only controls not hooked up are the load/save config buttons.
It's working well, provided that your heightmap's Blue and Green channels are encoding texture ID's, and the Red channel is encoding both Height and Blend Weight as I described.

The attached zip ALSO includes a demo heightmap whose pixels are mostly (128,0,0) except for some that are (255,1,1), which you can experiment with.

(128,0,0) means "50% mix of textures,blending lowertex #0 and uppertex #0"
(255,1,1) means "100% of uppertex, blending lowertex#1 and uppertex#1" (ie, ignores the lowertex in this case)

Since the demo heightmap uses blendcombos 0/0 and 1/1, you'll need to load at least two lower textures, and two upper textures.

The demo detects "undefined blend combos" (ie the green/blue channels contain values that don't correspond to loaded textures), but currently doesn't ask you what to do about it.

The output quality is a product of the input files, especially the Heightmap, but there's a known problem in Pixelmap that it can't load really large images (eg 1024x1024), which I think needs to be addressed... it's really the fault of the LoadImage api, not Pixelmap.
Another thing that affects the output quality is the fact that my UV-based getpixel is not returning 'filtered' pixels, its returning 'real' pixels, adding bilinear filtering would make this app so much better!

I've included the binary so you can play with it, and I *THINK* I included all the files you'll need to build it yourself, if I missed any, please let me know.

Also if you have ideas, requests, or think I'm an idiot, let me know!

Anyway, have fun :)
Posted on 2006-08-16 07:23:28 by Homer
I probably should have explained, if you wanna play with this demo, grab the jpegs I posted previously in this thread and convert them to bmp in paint.exe or whatever.

Sorry, I meant to mention it.. since I already posted those images, it seemed unreasonable to send them once more and waste my band and the host's diskspace.
Posted on 2006-08-16 07:42:51 by Homer
Hey Homer

I'd personally look a little further ahead than simple texture generation for the terrain. The regional data could not only specify the terrain textures but also the type of vegetation that grows in the area, the creatures present, and even the weather. If we assume the RED channel is the height map, the GREEN channel could be used to hold the regional index which could give us 256 possible regions. The region index would reference a REGION struct/class which could contain a horizontal and vertical texture for base blending, plant textures, tree foliage textures, etc, as well as creature and weather tables.

The easiest way to create the region maps would be to paint each region with a different color. The colors would have to be converted to REGION indices and merged with the heightmap so a custom tool would probably be needed. The REGION information could be loaded from a text script or the like so we have complete control over the landscape texturing, vegetation generation, and creature encounters. We could then create a magical world with snow filled valleys full of bikini wearing smurfs and lush green mountain peaks with elephants in hot pants :shock:

And we still have the BLUE and ALPHA channels available for other stuff.

Posted on 2006-08-17 21:29:36 by Maelstrom

I absolutely agree.. having decided in the end NOT to use the heightmap to encode regional textures, the options are still open.
I intend to use a color-mapping system to describe 'the probability of vegetation types', at the very least.
For example, if we said that "tufts of grass = XXFFFFFF", we can paint white wherever we want grass to grow, we can use the alpha channel (XX) to describe the chance that it grows there (FF means highly likely, 00 means impossible), and we can further control where it grows by looking at the SLOPE of those triangles in the terrain (if its too steep, grass won't grow there). Then we can generate all the vegetation instances ONCE and store them in our TER file for future reference, saving many hours of tedius placement of our vegetation.
Other 'rules' can also be implemented, such as enforcing the non-intersection of tree canopies, while still allowing grass to appear beneath that canopy :)
Posted on 2006-08-24 12:17:00 by Homer
HMM V engine is what I wanted todo a long time
mix of raycast castlewalls/scan heightmap w hardware acceleration
fences and different buildings in the terrain would also be suitable for this and should be lighter load, because for example a city w citywall reduces a big amount terrainmesh to be rendered
Posted on 2006-08-31 17:39:54 by daydreamer