I'm trying to write a HLSL shader that will have more detail up close and less detail further away. I want to do this by having the texture tile more up close and gradually reduce the number of times it tiles the further it is away from the camera.
This is for a terrain shader that I'm working on. Does anyone have any ideas. I'm all out.
I tired to use a the basic "fog" principle and use it to compute the tiling amounts. The fog part works great as expected but as soon as I try to apply it to the UV portion. such as In.Tex * tileAmount; funny things happens the textures seem to move over the ground depending on when your moving the camera around. This does not make much sense.
Also I have tried to take the nearPlane and FarPlane and work with those, but again I am having limited results and again the texture seems to move around. Also, This method works good for fog but that doesn't apply to what I want to do, only as a way to test what I thought should have been happening was.
I'm out of ideas, so here is the code I'm using.
// Green Gandalf's Blended Normal Mapping Shader
//
// designed for use with terrain objects
// Multiple Render Target Terrain Shader
//
// Edited and Modified by: David Westfall
//
//float4x4 World;
//float4x4 View;
//float4x4 Projection;
//float4x4 WorldVP:WorldViewProjection;
float4x4 WorldInverseTranspose;
float4x4 tPI : PROJECTIONINVERSE ;
//float4x4 View;
float4x4 WorldView;
float4x4 World;
float4x4 View;
float4x4 Projection;
float3 clippingPlane = {0.0, 10, 0.0};
bool isClip;
float FarPlane1 = 25000.0f - 0.1f;
float2 UVTiling = { 1, 1 };
float vertScale = 0.1; // reciprocal of maximum height of terrain
float contrast = 5.0; // higher values increase the contrast between textures
float specularIntensity = 0.1f; //save to color alpha
float specularPower = 1.0f;
texture detailMap1 < string ResourceName = ""; >;
texture detailMap2 < string ResourceName = ""; >;
texture detailMap3 < string ResourceName = ""; >;
texture detailMap4 < string ResourceName = ""; >;
texture normalMap1 < string ResourceName = ""; >;
texture normalMap2 < string ResourceName = ""; >;
texture normalMap3 < string ResourceName = ""; >;
texture normalMap4 < string ResourceName = ""; >;
sampler2D detail1 = sampler_state
{ texture = <detailMap1>;
MinFilter = linear;
MagFilter = linear;
MipFilter = linear;
AddressU = mirror;
AddressV = mirror;
};
sampler2D detail2 = sampler_state
{ texture = <detailMap2>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = mirror;
AddressV = mirror;
};
sampler2D detail3 = sampler_state
{ texture = <detailMap3>;
MinFilter = linear;
MagFilter = linear;
MipFilter = linear;
AddressU = mirror;
AddressV = mirror;
};
sampler2D detail4 = sampler_state
{ texture = <detailMap4>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = mirror;
AddressV = mirror;
};
sampler2D nMap1 = sampler_state
{ texture = <normalMap1>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
sampler2D nMap2 = sampler_state
{ texture = <normalMap2>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
sampler2D nMap3 = sampler_state
{ texture = <normalMap3>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
sampler2D nMap4 = sampler_state
{ texture = <normalMap4>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
struct VS_INPUT
{
float4 Position : POSITION;
float2 TexCoord : TEXCOORD;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
};
struct VS_OUTPUT
{ float4 Position : POSITION;
float2 Tex : TEXCOORD0;
float4 Blender : TEXCOORD1;
float2 Depth : TEXCOORD2;
float2 D : TEXCOORD3;
float3 ViewPos : TEXCOORD4;
float3 clipping : TEXCOORD5;
float3 CamDistance : TEXCOORD6;
float3x3 TBN : TEXCOORD7;
};
VS_OUTPUT GGBlendVShader(VS_INPUT In, VS_OUTPUT Out)
{ //float4 tempPos = mul(In.Pos, mw);
//Out.Pos = mul(In.Pos, wvp);
//float4 worldPosition = mul(In.Position, World);
//float4 viewPosition = mul(worldPosition, View);
//Out.Pos = mul(viewPosition, Projection);
//Out.Position = mul(In.Position, WorldVP);
//float4 worldPosition = float4(In.Position.xyz, 1);
//float4 viewPosition = mul(In.Position, WorldView);
//Out.Position = mul(viewPosition, Projection);
float4 worldPosition = mul(float4(In.Position.xyz, 1), World);
float4 viewPosition = mul(worldPosition, View);
Out.Position = mul(viewPosition, Projection);
Out.D = Out.Position.z;
Out.ViewPos = viewPosition.xyz;
//view direction = inverse vertexposition in viewspace
float4 PosV = mul(In.Position, WorldView);
float FarPlane = 1/ ( tPI[2][3] + tPI[3][3] ) ;
float NearPlane = 1/ distance( tPI[2][3] , tPI[3][3] ) ;
float Fade = ( PosV.z - FarPlane ) / ( NearPlane - FarPlane ) ;
//float Fade = ( PosV.z - NearPlane ) / ( FarPlane - NearPlane ) ;
//Fade = min( Fade , 1.0 );
//Fade = max( Fade , 0.0 );
//Fade = pow( Fade , 1.0 );
Out.CamDistance = Fade*8;
Out.Tex = In.TexCoord * UVTiling;
Out.clipping = worldPosition.y-10;
//Out.ViewPos.xyz = mul(In.Position.xyz, (float3x3)WorldView);
//Out.PosData.w = mul(In.Position, WorldView).z;
Out.Depth.x = Out.Position.z;
Out.Depth.y = Out.Position.w;
//get TBN matrix
Out.TBN[0] = normalize(mul(In.Tangent, (float3x3)WorldInverseTranspose));
Out.TBN[1] = normalize(mul(In.Binormal, (float3x3)WorldInverseTranspose));
Out.TBN[2] = normalize(mul(In.Normal, (float3x3)WorldInverseTranspose ));
//get TBN matrix
//Out.TBN[0] = normalize(mul(In.Tangent, (float3x3)World));
//Out.TBN[1] = normalize(mul(In.Binormal, (float3x3)World));
//Out.TBN[2] = normalize(mul(In.Normal, (float3x3)World ));
//smooth tangents/binormals - trick copied from Dark Shader samples
//float3 normal = normalize(mul(In.Normal, (float3x3)WorldInverseTranspose ));
//float3 binormal = normalize(cross(normal, normalize( mul(In.Tangent, (float3x3)WorldInverseTranspose))));
//float3 tangent = normalize(cross(binormal, normal));
// float3x3 TSM = {tangent, binormal, normal};
// TSM = transpose(TSM); // tangent space matrix
//Out.TBN = TSM;
//calculate the blend factors
float2 hn = float2 (In.Position.y * vertScale, Out.TBN[2].y);
//hn = saturate(0.5.xx + contrast * (hn - 0.5.xx));
//Out.Blender = float4 (hn.x * hn.y, hn.x * (1 - hn.y),
// (1 - hn.x) * hn.y, (1 - hn.x) * (1 - hn.y));
// e.g. blends = grass, rock, sand, gravel
Out.Blender = In.Position;
return Out;
}
struct PS_OUTPUT
{
float4 Color : COLOR0;
float4 tsNormal : COLOR1;
float4 Depth : COLOR2;
float4 ViewPosition : COLOR3;
};
PS_OUTPUT GGBlendPShader(VS_OUTPUT In, PS_OUTPUT Out)
{
if(isClip)
clip(In.clipping.x);//negaive clip mean above // positive clip means below that point
float u = 0.5;
float v = 0.5;
float2 UVDetail = In.Tex * 40;
//float2 UV1 = float2( In.Tex.x-u,In.Tex.y-v); //grass
//float2 UV2 = float2( In.Tex.x+u, In.Tex.y-v); //sand
//float2 UV3 = float2( In.Tex.x-u, In.Tex.y+v); //dry land
//float2 UV4 = float2( In.Tex.x+u, In.Tex.y+v); //mountian
//float4 base1 = tex2D(detail1, UV2);
//float4 base2 = tex2D(detail1, UV1);
//float4 base3 = tex2D(detail1, UV4);
//float4 base4 = tex2D(detail1, UV3);
// Calculate the slope of this point.
float height = In.Blender.y*0.005;
float slope = 1.0 - In.TBN[2].y;
float dist = In.CamDistance;
//int dist = trunc(dis);
// float dist = abs( (In.Depth.x / In.Depth.y - 0.9f) );
//dist = dist /3;
float FogStart = 50;
float FogEnd = 100000;
float3 FogColor = 0;
float l = saturate((In.D - FogStart) / (FogEnd - FogStart));
l=l*150;
float4 base1 = tex2D(detail1, In.Tex * l );
float4 base2 = tex2D(detail2, In.Tex * l );
float4 base3 = tex2D(detail3, In.Tex * l );
float4 base4 = tex2D(detail4, In.Tex * l );
float blendAmount = 0;
float4 textureColor1 = 0;
float4 textureColor2 = 0;
// Determine which texture to use based on height.
if(slope < 0.25)
{
blendAmount = slope / 0.25f;
textureColor1 = lerp(base1, base2, blendAmount);
}
if((slope < 0.5) && (slope >= 0.25f))
{
blendAmount = (slope - 0.25f) * (1.0f / (0.5f - 0.25f));
textureColor1 = lerp(base2, base3, blendAmount);
}
if((slope < 0.75) && (slope >= 0.5f))
{
blendAmount = (slope - 0.5f) * (1.0f / (0.75f - 0.5f));
textureColor1 = lerp(base3, base4, blendAmount);
}
if(slope >= 0.75)
{
textureColor1 = base4;
}
//***************************************Height based logic
// Determine which texture to use based on height.
if(height < 0.25)
{
blendAmount = height / 0.25f;
textureColor2 = lerp(base1, base2, blendAmount);
}
if((height < 0.5) && (height >= 0.25f))
{
blendAmount = (height - 0.25f) * (1.0f / (0.5f - 0.25f));
textureColor2 = lerp(base2, base3, blendAmount);
}
if((height < 0.75) && (height >= 0.5f))
{
blendAmount = (height - 0.5f) * (1.0f / (0.75f - 0.5f));
textureColor2 = lerp(base3, base4, blendAmount);
}
if(height >= 0.75)
{
textureColor2 = base4;
}
float4 final = lerp(textureColor1,textureColor2,0.5);
float4 fin = textureColor1;// float4(lerp(textureColor1,FogColor, l), 1);
Out.Color = float4(fin.rgb,specularIntensity);
// read the normal from the normal map and //tranform to [-1,1]
float3 normal1 = tex2D( nMap1, In.Tex) * In.Blender.x;
float3 normal2 = tex2D( nMap2, In.Tex) * In.Blender.y;
float3 normal3 = tex2D( nMap3, In.Tex) * In.Blender.z;
float3 normal4 = tex2D( nMap4, In.Tex) * In.Blender.w;
float3 normal01 = tex2D( nMap1, UVDetail) * In.Blender.x;
float3 normal02 = tex2D( nMap2, UVDetail) * In.Blender.y;
float3 normal03 = tex2D( nMap3, UVDetail) * In.Blender.z;
float3 normal04 = tex2D( nMap4, UVDetail) * In.Blender.w;
float3 normalFromMap = (normal1 + normal2 + normal3 + normal4);
float3 normalFromMap1 = (normal01 + normal02 + normal03 + normal04);
normalFromMap = (normalFromMap + normalFromMap1);
//normalFromMap = lerp(normalFromMap, normalFromMap1, 0.6)*2;
//normalFromMap = lerp(normalFromMap, normalFromMap1, 0.6);
//normalFromMap = normalFromMap+normalFromMap+normalFromMap;
//float3 normalDetail = ( normal01 + normal02 + normal03 + normal04 );
//float3 normalFromMap = ((normalDetail/2) + ( normal1 + normal2 + normal3 + normal4 ))/2; //blend all levels and apply the detail map
//transform into world space
//float3 map = normalize(normalFromMap.x*In.TBN[0] + normalFromMap.y*In.TBN[1] + normalFromMap.z*In.TBN[2]);
float3 map1 = normalize(mul(normalFromMap, In.TBN));
float3 map = normalize(In.TBN[2]);
map *= map1;
Out.tsNormal = float4(map*0.5+0.5 ,1);//specularPower);
Out.Depth = In.Depth.x / In.Depth.y;
//float VP = length(In.ViewPos) / FarPlane;
//Out.Depth = float4(VP,0,0 ,1);
Out.ViewPosition = float4(length(In.ViewPos) / FarPlane1,0,0 ,1);
return Out;
}
technique Technique1 // use this for blending only
{ pass p0
{
VertexShader = compile vs_3_0 GGBlendVShader();
PixelShader = compile ps_3_0 GGBlendPShader();
}
}