Sign in to follow this  
p0is0n

Using HLSL for rendering terrain with multiple textures

Recommended Posts

Hi, I have a terrain engine writen in C++ with directX9. My engine uses the fixed function pipeline. What I want to do is use HLSL to render the terrain with texture blending. At the moment my terrian is textured depending on the height at that point. e.g. if the height is below 50 a grass texture is used, if it is between 50 - 100 a rock texture is used and so on. I have written a simple fx file that uses 2 passes to blend 2 textures together (stretched over the terrain). What I need to do is to change this so that different textures are used depending on the height of the terrain. Does anyone have any pointers on how I would do this?, and what I would need to change to get it to work? I have looked around and found lots of information on how to use HLSL, effect files and so on, but I cannot figure out how to do this. Any help would be appreciated.

Share this post


Link to post
Share on other sites
Couldn't you just pass your textures in your effect and have your shader determine what texture to use:

//vertex shader:
height is TEXCOORD2;

OUT.height = worldPos.xy;

//pixel shader:
if (IN.height.y < grassHeight)
tex2D(grassTexture, IN.tex);
if (IN.height.y >= grassHeight
tex2D(groundTexture, IN.tex);


Would this not work?
Jeff.

[edit was for naming worldPos.y in pixel shader should be IN.height.y (since your passing this from your vertex shader)]

[Edited by - webjeff on March 19, 2008 4:20:30 PM]

Share this post


Link to post
Share on other sites
If in this case definitely the best solution to use dyn. branching? I don't know how how slow it is. Tex2D all the layer textures and blending will be slower I suppose... but using dyn. branching there must be hard transition between layers...

Share this post


Link to post
Share on other sites
webjeff's basic idea would work for selecting a primary texture. If you wanted them blended, you could extend that to pick two textures and lerp between the two based on the coordinate. It would look a little bit like this:



const float grassHeight = 50;
const float rockHeight = 100;
const float snowHeight = 150;

float4 texColor1;
float4 texColor2;
float lerpVal;

if ( height < grassHeight )
{
texColor1 = tex2D( grassSampler, texCoord );
texColor2 = tex2D( grassSampler, texCoord );
lerpVal = 0;
}
else if ( height < rockHeight )
{
texColor1 = tex2D( grassSampler, texCoord );
texColor2 = tex2D( rockSampler, texCoord );
lerpVal = ( height - grassHeight ) / ( rockHeight - grassHeight );
}
else if ( height < snowHeight)
{
texColor1 = tex2D( rockSampler, texCoord );
texColor2 = tex2D( snowSampler, texCoord );
lerpVal = ( height - rockHeight ) / ( snowHeight - rockHeight );
}

float4 terrainColor = lerp( texColor1, texColor2, lerpVal );



Of course, it's important to keep in mind that unless this is compiled to ps_3_0 and also altered in a few ways, the shader won't use any dynamic branching. This means that all of the branches will be taken (and all of the terrain textures sampled), and the desired result is chosen at the end.

Share this post


Link to post
Share on other sites
Quote:
Original post by KEXIK
If in this case definitely the best solution to use dyn. branching? I don't know how how slow it is. Tex2D all the layer textures and blending will be slower I suppose... but using dyn. branching there must be hard transition between layers...


Dynamic branching probably wouldn't bee too bad in this case, at least for terrain that's close to the camera. Dynamic branching generally only good when large groups of adjacent pixels choose the same branch, which you probably would get for most terrain. Also you wouldn't have hard boundaries with something like the code I posted.

I think the ultimate solution in this case might be to use a texture atlas, and have the shader calculate the proper texture coordinate to use from the atlas. This would guarantee that you don't sample more than you have to, but it would also complicate things in a few ways.

Share this post


Link to post
Share on other sites
Thanks for all the replies.

I think i understand everything mentioned, but just to be sure, is a texture atlas just like a sprite sheet?
i.e all of the textures that are going to be used for the terrain are put into one texture, and a texture is picked using the texture co-ordinates for that area.

Share this post


Link to post
Share on other sites
Yes, it's usually called texture atlas... but my another idea is to use volume texture, but I don't know what is the best for your task.

Share this post


Link to post
Share on other sites
Thanks, I think i'll try it using a texture atlas first seeing as that's what I was using for my textures with the fixed function pipeline. I just didnt know that there was a name for it.

Share this post


Link to post
Share on other sites
In my terrain engine I use a 5th opacity map (among grass, sand, snow and rock) where I store the texture weights in the RGBA channels. This way I'm not limited to height-based texturing, but I can put my textures anywhere I like, for example depending on slope, region and other factors. This opacity map requires preprocessing, though.

Share this post


Link to post
Share on other sites
Hey,
I have my terrain engine working so I can texture the terrain based on height, or by using a blend map.
What I'm wanting to do is allow the use of more textures.
As I understand it, a blend map uses the RGB values of a texture only allowing you to use 3 different textures.
When I texture the terrain based on height I need to predefine how many textures are going to be used in the fx file.

Is there a way to use more textures, or any amount of textures?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this