Recently trying to get back into terrain rendering and I'm having a bit of trouble with improving my texturing and unsure of where I should focus my efforts. I've been reading a lot of white papers by DICE's Johan Andersson(the various techniques like PN Triangles, slope based blending, Wang tiles, etc), but I'm not sure where to start. Right now I have a 257 x 257 coherent noise generated heightfield and I'm using a simple 2D texture array to texture things based on height. The banding is pretty autrocious and the fact that my UVs are set like they are 1 texture stretched over a quad is causing all the resolution to be lost in my texture samples (at least that's my current theory...).
Would increased tessellation (i.e. via a hull/domain shader) help? Or what would you recommend I would get the biggest bang for my buck as I go forward with this system?
Pic of current banding and shader code below.
//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
cbuffer WVPConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
}
cbuffer DebugLight : register ( b1 )
{
float3 LightDir;
}
Texture2DArray txDiffuse : register( t0 );
Texture2D txNormal : register( t1 );
SamplerState samLinear : register( s0 );
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
};
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float3 Tex : TEXCOORD0;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
};
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS_Terrain(VS_INPUT input )
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul( input.Pos, World );
output.Tex = float3(input.Tex, input.Pos.y);// Cache off the world height value.
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
// Normal/Tan to World space.
output.Normal = mul(float4(input.Normal, 0.0f) , World).xyz;
output.Tangent = mul(float4(input.Tangent, 0.0f), World).xyz;
return output;
}
float4 PS_Terrain( VS_OUTPUT input ) : SV_Target
{
float4 darkDirt = txDiffuse.Sample(samLinear, float3(input.Tex.xy, 1.0f));
float4 lightDirt = txDiffuse.Sample(samLinear, float3(input.Tex.xy, 2.0f));
float4 grass = txDiffuse.Sample(samLinear, float3(input.Tex.xy, 3.0f));
float4 rock = txDiffuse.Sample(samLinear, float3(input.Tex.xy, 4.0f));
float4 snow = txDiffuse.Sample(samLinear, float3(input.Tex.xy, 5.0f));
float4 color;
float heightPercentage = input.Tex.z / 100.0f; // current max height allowed, need to move this to a constant buffer.
float blend = 1.0f - input.Normal.y; // slope value between the layers. Closer to 90 degrees, we blend more of that texture.
if(heightPercentage < 0.05f)
{
color = darkDirt;
}
else if (heightPercentage < 0.15f)
{
color = lerp(darkDirt, lightDirt, blend);
}
else if(heightPercentage < 0.4f)
{
color = lerp(lightDirt, grass, blend);
}
else if(heightPercentage < 0.7f)
{
color = lerp(grass, rock, blend);
}
else
{
color = lerp(rock, snow, blend);
}
// Normal mapping.
float3 normalMapVal = txNormal.Sample(samLinear, input.Tex.xy).rgb;
// From Texel to -1.0f -> 1.0f
normalMapVal = 2.0f * normalMapVal - 1.0f;
float3 N = input.Normal;
float3 T = normalize(input.Tangent - dot(input.Tangent, N)*N).xyz;
float3 B = cross(N, T).xyz;
float3x3 TBN = float3x3(T, B, N);
// Transform from tangent space to world space.
float3 bumpedNormal = normalize(mul(normalMapVal, TBN)).xyz;
color *= dot(bumpedNormal, -LightDir.xyz);
color.a = 1.0f;
return color;
}