• Advertisement
Sign in to follow this  

Automatic terrain texturing advice

This topic is 3032 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I am trying to add an automatic texture option to my terrain editor. The terrain is rendered (and saved) using a colourmap (r,g,b,a channels so four textures to work with, I'm thinking grass, dirt, stone/rock, and snow (r,g,b,a respectively) I am just having trouble thinking out the algorithm to achieve this, I have access to the mesh data per vertex (height and normal). I'm thinking :
...
if(height < stoneStartHeight)
     use grass
else if(height < grassEndheight)
     use blend of grass and stone
else if(height < stoneEndHeight)
     use stone
...
How should I go about blending the texture over the overlap for a smooth transition between textures? How should the normal data be incorporated? (e.g. grass will not grow on steep slopes so use dirt, same for snow and stone). Is there anything else I'm overlooking? I am tied to just the four textures due to the use of a colourmap, I know more can be done with a shader, but I really want to keep the colourmap for simplicities sake. (I also know I could have another texture for r+g+b+a = 0, but again for simplicity I don't want to alter any code outside the function for altering the colourmap. I have tried searching but cannot find any relevant sources for this (the ones I can find all seem to go too far in depth, or keep it too simple). Any help/advice would be appreciated. Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by p0is0n
How should the normal data be incorporated? (e.g. grass will not grow on steep slopes so use dirt, same for snow and stone).

Use the normal's up component (e.g. normal.y or normal.z depending on which way is "up" for you) as one of your rules.
e.g.
if( normal.y > 0.5 )
use rock
else if( height < 100 )
use grass
else
use snow
Quote:
How should I go about blending the texture over the overlap for a smooth transition between textures?
Instead of writing the rule as "if this condition is true, use this texture", generate a weighting for "how true" each rule is.

In the code below, saturate is a function like:
float saturate( float in ) { return min( 1, max( 0, in ) ); }
e.g. Instead of a grass/snow transition at height==100, make the weights blend from 90 to 110.
grassWeight = saturate( (height-90) / (110-90) )
snowWeight = 1 - saturate( (height-90) / (110-90) )
You can do the same for the slope rule to get a nice blend:
rockWeight = saturate( (normal.y-0.5) / 0.01 )
Lets say you want the slope rule to override the height rules. We can multiply the height-based weights by the inverse slope-weight.
invRockWeight = 1-rockWeight;
grassWeight *= invRockWeight;
snowWeight *= invRockWeight;
Finally, you normalise all your weights:
totalWeight = grassWeight + snowWeight + rockWeight;
grassWeight /= totalWeight;
snowWeight /= totalWeight;
rockWeight /= totalWeight;

Share this post


Link to post
Share on other sites
Thanks a lot for the help.

I ended up using :

//Declare and initialise the weights
float dirtWeight(0.0f), grassWeight(0.0f), snowWeight(0.0f), rockWeight(0.0f);

//Set the weightings based on heights
if(height < 190.0f)
dirtWeight = 1.0f;
else if(height > 190.0f && height < 250.0f)
{
dirtWeight = 1 - Saturate((height - 190.0f) / (250.0f - 190.0f));
grassWeight = Saturate((height - 190.0f) / (250.0f - 190.0f));
}
else if(height < 440.0f)
grassWeight = 1.0f;
else if(height > 440.0f && height < 490.0f)
{
grassWeight = 1 - Saturate((height - 440.0f) / (490.0f - 440.0f));
snowWeight = Saturate((height - 440.0f) / (490.0f - 440.0f));
}
else if(height > 490.0f)
snowWeight = 1.0f;

//Set the weightings based on normals
rockWeight = Saturate((0.6f - normal) / 0.01f);

//Override the height rules with the normal rules
float invRockWeight = 1 - rockWeight;
dirtWeight *= invRockWeight;
grassWeight *= invRockWeight;
snowWeight *= invRockWeight;

//Get the final weightings
float totalWeight = dirtWeight + grassWeight + snowWeight + rockWeight;
dirtWeight /= totalWeight;
grassWeight /= totalWeight;
snowWeight /= totalWeight;
rockWeight /= totalWeight;



I have played about with the values and found that these values give the best results, although I might make the grass section end higher up.

Thanks for the help, I was confused about the weightings and first but think I've got a handle on it now.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement