Posted By: Zelek
Modified Terrain Shader (auto-texturing) - 03/19/08 16:36
I'm new to shaders, but I've been working on a modified version of the popular terrain multitexturing shader (I think the version I started with was last modified by Loopix). I've made it possible to texture the terrain without providing a blendmap. Instead, it uses a normal map to locate "steep" areas of the terrain and gives those areas a different texture than flat areas. Here's how that looks:
Now it's not too exciting to have only two textures for a terrain, so I implemented three different texture "levels" (low/med/high) so you can have a mountain texture on high areas and maybe dirt on low areas:
I wanted to see if anyone had ideas on ways to improve this or make it more efficient. Currently, the normal map has to be added as a skin to the terrain ahead of time. If I passed the normal information from the vertex shader to the pixel shader, it seems I could find this information automatically (for texturing dynamically generated terrain?). Is this more or less efficient than including a normal map skin?
Here's the important part of the code (the only difference in the vertex shader is that it passes the xyz position):
Code:
Now it's not too exciting to have only two textures for a terrain, so I implemented three different texture "levels" (low/med/high) so you can have a mountain texture on high areas and maybe dirt on low areas:
I wanted to see if anyone had ideas on ways to improve this or make it more efficient. Currently, the normal map has to be added as a skin to the terrain ahead of time. If I passed the normal information from the vertex shader to the pixel shader, it seems I could find this information automatically (for texturing dynamically generated terrain?). Is this more or less efficient than including a normal map skin?
Here's the important part of the code (the only difference in the vertex shader is that it passes the xyz position):
Code:
// pixelshader
float4 ps( TMULTI_VS_OUT In ) : COLOR {
float tex1_max = 110.0; //the upper boundary of the first texture
float tex2_middle = 100.0; //the middle texture will be strongest at this height
float tex2_width = 120; //the total height the middle texture should cover
float tex3_min = 90; //the height that the top texture will begin at
float tex3_max = 270; //the heightest point of your terrain
float impassable_strength = 8.0; //the strength of the steep texture
float brightness = 0.2; //the overall brightness
float4 NormalMap = tex2D(sTex1,In.Tex1);
float4 ShadowMap = tex2D(sTex2,In.Tex2);
float4 LowTex = tex2D(sTex8,In.Tex8);
float4 MidTex = tex2D(sTex9,In.Tex9);
float4 HighTex = tex2D(sTex10,In.Tex10);
float4 SteepTex = tex2D(sTex11,In.Tex11);
float4 FinalColor;
float theHeight = In.Pos_xyz.y; //the height of the current position
float tmpHeight = theHeight; //for use by each of the textures
//this is how you uncompress a normal map
float3 normal = 2.0f * NormalMap.rgb - 1.0f;
//show the SteepTex in areas with a very low normal.z
normal.z = pow(normal.z, impassable_strength);
normal.z = saturate(normal.z);
FinalColor = lerp(SteepTex, MidTex, normal.z);
//draw the low textures at low heights
if(tmpHeight <= tex1_max) {
tmpHeight /= tex1_max;
FinalColor = lerp(LowTex, FinalColor, tmpHeight);
}
//blend in the middle texture
tmpHeight = theHeight;
float tex2_min = tex2_middle - (tex2_width/2.0);
float tex2_max = tex2_middle + (tex2_width/2.0);
if (tmpHeight > tex2_min && tmpHeight < tex2_max) {
tmpHeight -= tex2_middle;
tmpHeight = abs(tmpHeight)*2.0;
tmpHeight /= tex2_width;
FinalColor = lerp(MidTex, FinalColor, tmpHeight);
}
//draw the high texture
tmpHeight = In.Pos_xyz.y;
float tex3_width = tex3_max-tex3_min;
if (tmpHeight >= tex3_min && tmpHeight <= tex3_max) {
tmpHeight -= (tex3_width/2.0);
tmpHeight /= tex3_width;
FinalColor = lerp(FinalColor, HighTex, tmpHeight);
}
//blend in the shadow map and prevent transparency
FinalColor = FinalColor*(ShadowMap+brightness);
FinalColor.a = 1.0f;
return FinalColor;
}