Jump to content

  • Log In with Google      Sign In   
  • Create Account

Improving Terrain Textures (getting banding)


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 AdeptStrain   Members   -  Reputation: 342

Like
0Likes
Like

Posted 02 October 2012 - 07:18 PM

Hey all,

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.

Posted Image

//--------------------------------------------------------------------------------------
// 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;
}



Sponsor:

#2 jefferytitan   Crossbones+   -  Reputation: 2127

Like
0Likes
Like

Posted 02 October 2012 - 08:55 PM

Hmm, that does look quite unusual. The transition from grass to rock looks awful. Adding transitional textures may help. Maybe a problem with the blending? Basing it on the normal y component (and not heightPercentage at all) seems unusual. Great for cliffs, but not much else.

My other thought is that it's too predictable. I'd add some noise, e.g. add some Perlin noise with range 0 to 0.1 to the heightPercentage so the transitions can be a little patchy. You could also use Perlin to mix two different grass textures or rock textures etc so it doesn't tile too badly.

PS - I'm sure you realise that the scale looks crazy wrong because the textures are very coarse relative to the landscape.

Edited by jefferytitan, 02 October 2012 - 08:57 PM.


#3 jmakitalo   Members   -  Reputation: 553

Like
1Likes
Like

Posted 03 October 2012 - 12:35 AM

I've also been working on terrain texturing lately and the greatest problem has been avoiding noticable tiling. Basically I have an array of textures, four noise channels and a mask for up to four "painted" textures. In addition to these pained textures, there is a base texture, cliff texture whose weight is determined by slope and a shore texture whose weight is determined by height. At the moment, I use two slightly different texture maps for each texture type and use carefully chosen noise to mix these. This gives quite nice results and makes tiling quite difficult to notice, but the noise must be well adjusted. The noise should be quite high contrast and patches of 0.0 and 1.0 should occur on the scale of the texture period. I basically used a cloud filter in Gimp and made the contrast higher.

Previously I tried mixing the same texture with different scales. This made tiling much less apparent, but it also makes the texture fuzzy and close up detail is pretty much lost.

As to the banding, it seems that you use slope to smoothly blend between textures, but a strict if condition to switch textures by height. Make some transition height ranges to smoothly blend by height. Insted of if(heightPercentage < 0.05f), define two height values around 0.05f and interpolate two textures along these values.

#4 AdeptStrain   Members   -  Reputation: 342

Like
0Likes
Like

Posted 03 October 2012 - 08:48 AM

Thanks for the replies.

Yea, I know the texturing looks really coarse compared to the geometry. I *think* that has to do with the UVs and such. The terrain is textured as if it's all 1 big texture, rather than saying "oh, this is a rock material, so texture this triangle using UVs from a rock texture." I've seen white papers on how to do this but I need to investigate more. That would give far more fidelity to the texturing.

Also I'll see about adding some noise/range to the height values and what that brings. If you want to help remove tiling effects, I'd really look into Wang tiles. They seem like a great way to get repeatable use of textures without the effects of tiling.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS