Hey folks,

Just posting a screenshot from the engine me and a buddy are working on. Currently we're tackling terrain generation. I just wanted to say two big thanks to Bubba and Perspective who've helped out tons through this whole process (Perspective not as knowingly).

I used the blending texture method from the article discussed here. I would've wanted to contribute this to the discussion, but since it's almost a year gone, and I know the stigma surrounding the revival of old threads, I'll post my two cents here (hopefully worthwhile pennies).

If you look through the article, you'll notice that the water darkens to black at the lowest regions, which is a pretty cool effect, but not completely realistic. For the purpose of our engine, we're leaving water for a whole other day, and strictly leaving the terrain to be just that, terrain. So instead of a water texture, you can see below, I used a "stone"ish texture.

Before I continue, just to note, when I say something "doesn't work well", or anything of the like, I mean for the purpose of the engine we're developing.

Now, a little background on the blending, there are height regions for when each texture is used, and instead of cutting between textures as you move to the next region, this method blends the textures for a smooth, more natural look.

Now, as for the darkening problem. As you get to the lower height values of a region, it uses less of the specified texture. This works well for every transition, save for the very lowest, because there is no texture to blend the bottom with, so it become black.

Previously, I was cycling through the textures from the lowest region, to the highest region. But this left me at a very difficult point in knowing what has previously been blended. So, I changed my for loop to begin with the highest region, and blend if necessary, before moving down to the lower region.

By doing this, I know exactly where I stand when it comes time to blend the lowest region. Here's a slightly modified version of Perspective's code:
Code:
//CYCLING THROUGH EACH PIXEL
...
unsigned long Colour = 0;
unsigned long B = 0;
unsigned long G = 0;
unsigned long R = 0;
for(char I = (NUM_TEXTURES - 1); I >= 0; I = I - 1)
{
	float dT = TERRAIN_HEIGHT / NUM_TEXTURES;

	float dY = Height - ((I + 1.0f) * dT - 1.0f);
					
	if(dY < 0.0f)
		dY = dY * -1;

	float Weight = (dT - dY) / dT;

	if(Weight >= 0.0f)
	{
		if(I == 0)
		{
			if(B == 0 && G == 0 && R == 0)
			{
				Weight = 1.0f;
			}
		}

		//Find the correct coordinates in our texture
		unsigned long T = (unsigned long)(fX * (float)Widths[I]);
		unsigned long U = (unsigned long)(fZ * (float)Heights[I]);

		Colour = Data[I][U * Pitchs[I] / 4 + T];

		B = B + (unsigned long) ((Colour        & 255) * Weight);
		G = G + (unsigned long)(((Colour >> 8)  & 255) * Weight);
		R = R + (unsigned long)(((Colour >> 16) & 255) * Weight);
	}
}
...
//CONTINUE CYCLING
I use B, G, and R to keep track of each channel. Now, since I start at the highest region (I == NUM_TEXTURES - 1), I know where I stand once I'm checking my very lowest region. If, at the lowest region (I == 0), B, G, and R are still 0, that means I have not blended any other region in yet because they don't apply. So I use all of the lowest region, without any blending. If they are not 0, then I know they already contain another texture, and the lowest texure should only be blended with the weighting that was assigned. That is done with the two if statements nested deep within the algorithm. This can be easily changed to cut off at a specific weight (I.e. If the Weight is less than 0.5f, set it to 0.5f), which will reduce how dark it gets.

Hopefully that makes some sense. If it doesn't, and you haven't read Perspective's article (and this interests you), then read Perspective's article. It's top-quality, and the discussion surrounding it also generated some good ideas. If you have read the article, I guess I'm not too good at conveying my ideas.

My code probably won't directly translate to other projects (though it is very similar in purpose, the style is a bit different), but if you read the article, I hope I managed to keep this concept clear enough.

Thanks again to all that helped along the way. It's a good benchmark we've gotten to here, but definitely no time to stop. See you at the next milestone.

The payoff from this is posted below (along with a closer-up of the stone).