- Home /
Meat5000 found the problem. He posted it as a comment instead of an answer but my question has been answered.
Weird artifacts in cg shader with lerp()
Hello there,
I'm making a shader that takes the height of the world and matches it with a certain texture. Between each defined height there is a blend zone that blends two textures with a lerp from 0 to 1.
The shader is working perfect except for 1 thing, the lerp function adds a weird line of artifacts at the edge of each blend zone, as you can see on the screenshot below:
The weird thing is, this shader works perfectly with pragma target 2.0 but doesn't with pragma target 3.0. Sadly I have to use target 3.0 because the 2.0 runs out of memory if I use more than 3 textures..
My question is, how can I resolve the artifacts in 3.0 or is it possible to make this shader in 2.0 with some optimization?
Any help is greatly appreciated, thank you :)
Edit
I've applied the shader to a simple cube and noticed the artifacts only appear after a certain distance from the camera. Close to the camera everything looks ok and the blending is smooth.. Does anyone have an idea what this could be? I think it might have something to do with LOD but don't know how to fix this..
See screenshot below:
The code for the shader is as follows:
Shader "Custom/TerrainHeight"
{
Properties
{
_Color("Color",Color) = (1.0,1.0,1.0,1.0)
_GroundHeight ("GroundHeight", Float) = 0
_FadeDistance ("FadeDistance", Float) = 0.5
_Height1 ("Height1", Float) = 2
_Height2 ("Height2", Float) = 4
_Height3 ("Height3", Float) = 6
_Tex1("Tex1", 2D) = "white"{}
_Tex2("Tex2", 2D) = "white"{}
_Tex3("Tex3", 2D) = "white"{}
_Tex4("Tex4", 2D) = "white"{}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
#pragma target 3.0
float _GroundHeight;
float _FadeDistance;
float _Height1;
float _Height2;
float _Height3;
float4 _Color;
sampler2D _Tex1;
sampler2D _Tex2;
sampler2D _Tex3;
sampler2D _Tex4;
struct Input
{
float3 customColor;
float3 worldPos;
float2 uv_Tex1;
float2 uv_Tex2;
float2 uv_Tex3;
float2 uv_Tex4;
};
void surf (Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D(_Tex1, IN.uv_Tex1).rgb;
if(IN.worldPos.y > _GroundHeight && IN.worldPos.y < _Height1-_FadeDistance)
{
o.Albedo = tex2D(_Tex1, IN.uv_Tex1).rgb;
}
else if(IN.worldPos.y >= _Height1-_FadeDistance && IN.worldPos.y <= _Height1)
{
fixed4 tex1 = tex2D(_Tex1, IN.uv_Tex1);
fixed4 tex2 = tex2D(_Tex2, IN.uv_Tex2);
fixed4 output = lerp(tex1,tex2,(IN.worldPos.y-(_Height1-_FadeDistance))/_FadeDistance);
o.Albedo = output.rgb;
}
else if(IN.worldPos.y > _Height1 && IN.worldPos.y < _Height2-_FadeDistance)
{
o.Albedo = tex2D(_Tex2, IN.uv_Tex2).rgb;
}
else if(IN.worldPos.y >= _Height2-_FadeDistance && IN.worldPos.y <= _Height2)
{
fixed4 tex2 = tex2D(_Tex2, IN.uv_Tex2);
fixed4 tex3 = tex2D(_Tex3, IN.uv_Tex3);
fixed4 output = lerp(tex2,tex3,(IN.worldPos.y-(_Height2-_FadeDistance))/_FadeDistance);
o.Albedo = output.rgb;
}
else if(IN.worldPos.y > _Height2 && IN.worldPos.y < _Height3-_FadeDistance)
{
o.Albedo = tex2D(_Tex3, IN.uv_Tex3).rgb;
}
else if(IN.worldPos.y >= _Height3-_FadeDistance && IN.worldPos.y <= _Height3)
{
fixed4 tex3 = tex2D(_Tex3, IN.uv_Tex3);
fixed4 tex4 = tex2D(_Tex4, IN.uv_Tex4);
fixed4 output = lerp(tex3,tex4,(IN.worldPos.y-(_Height3-_FadeDistance)/_FadeDistance);
o.Albedo = output.rgb;
}
else if(IN.worldPos.y > _Height3)
{
o.Albedo = tex2D(_Tex4, IN.uv_Tex4).rgb;
}
o.Albedo *= _Color.rgb;
}
ENDCG
}
FallBack "Diffuse"
}
Are uv_Tex1, uv_Tex2, uv_Tex3, and uv_Tex4 actually different? If you're using the same scale and offset for all the textures, they're probably the same, so you could save yourself some instructions by getting rid of the extra declarations in the Input structure and just looking up all the textures using uv_Tex1. (i.e. fixed4 tex2 = tex2D(_Tex2, IN.uv_Tex1);
)
Also, I see you're using four textures, but only using the RGB components of them - you're never using the alpha channel. So, you could take the RGB components of _Tex4 and put them in the A component of _Tex1, _Tex2, and _Tex3 respectively, saving yourself a texture lookup. It might not work in your case because it will probably make the lerping difficult, but just a thought.
You make a very good point, the textures are all 512x512 so I can indeed use the same uv for all of them. Unfortunately it's still not enough optimization to make the shader work with 2.0.. But I really appreciate your input, it takes me a step further to a better optimized shader, thanks! +1 :)
Also thank you for the idea of using the alpha channel, I'm gonna give that a try as well :)
This is the result of conditional sampling. I have the same problem. To verify the problem use tex2Dlod ins$$anonymous$$d of tex2D and you'll see the artifacts gone
Answer by Bunny83 · Jun 29, 2014 at 11:38 AM
Your fade "t" value is between "0" and "_FadeDistance" and not between 0 and 1. You have to divide it by _FadeDistance.
Thank you very much for the response! You've pointed me to something I didn't notice and you're right! I'm checking out your solution and if it works I'll accept your answer :) For now I'll already vote you up for pointing me at the mistake.
I applied your solution, I believe the lerp now goes from 0 to 1 but the artifacts remain.. I've updated the code in my question with your fix.
The artifacts are a result of your chosen Aniso level and $$anonymous$$ip $$anonymous$$apping of the texture and how they are kicking in, in my opinion.
I say this as you mention distance from the camera. You are crossing the threshold of when the lower detail texture is being used.
Aniso affects how textures look when viewed from shallow angles, I do believe.
This answer solved an issue I was having where I was tiling a texture based on vertex world positions (normalising all vertices xz to between 0-1 so one large plane could have a tiled look). Turning off $$anonymous$$ip $$anonymous$$apping for the texture in question solved artefacts appearing where the world position was approximate 1 or 0 for x or z.
$$anonymous$$udos!
EDIT: in fact I turned on the "border mip maps" option when in the "Advanced" settings for my texture. This allowed mipmap generation and got rid of the artefacts.
Hi meat5000, in fact you are spot on! When I disable mip map generation for the textures the artifacts disappear! It looks kinda noisy if I do so but now I know where the artifacts come from, thanks you so much, I was breaking my head on this :) Could you post your comment as an answer so I can accept it as the answer to the question? That way I can also close this question.
Follow this Question
Related Questions
How to force the compilation of a shader in Unity? 5 Answers
Light direction based Lerp 0 Answers
How to determine shader center? 0 Answers
Strange artifacts on Vertex Color Shader 0 Answers
Why does this IOS / OGLES shader not match PC version? 0 Answers