LOD Texture Transition

Hello :slight_smile:
I have a textured terrain (with RGBA splatmap and 4 textures) which I want to enable normal mapping on. The base map distance of this terrain is set to 1000 and when it transitions from the detailed area (<1000 away from camera) to the low LOD area, the texture transition is very sharp when specular shader is enabled, as opposed to when there is no material. Please see below comparison:

From the way it looks, it seems like the difference between two areas is mainly the color saturation. I guess I can either lower the saturation in the specular shader or somehow raise the saturation of the LOD area, but I don’t know what kind of shader is used by Unity to draw the low LOD distant terrain. Does anyone know whether this shader can be accessed and modified?

Here’s the shader I’m using for the terrain. It’s from Dvornik’s Terrain Toolkit and I added some texture uv mixing in the surface shader. Maybe there’s something I can change in there to make the transition more smooth :slight_smile:

Shader "Dvornik/Terrain/Bumped Specular" {
Properties {
	_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
	_Shininess ("Shininess", Range (0.03, 1)) = 0.078125
	_NormalGlobal ("Normal Global", 2D) = "bump" {}

	// set by terrain engine
	[HideInInspector] _Control ("Control (RGBA)", 2D) = "red" {}
	[HideInInspector] _Splat3 ("Layer 3 (A)", 2D) = "white" {}
	[HideInInspector] _Splat2 ("Layer 2 (B)", 2D) = "white" {}
	[HideInInspector] _Splat1 ("Layer 1 (G)", 2D) = "white" {}
	[HideInInspector] _Splat0 ("Layer 0 (R)", 2D) = "white" {}
	[HideInInspector] _Normal3 ("Normal 3 (A)", 2D) = "bump" {}
	[HideInInspector] _Normal2 ("Normal 2 (B)", 2D) = "bump" {}
	[HideInInspector] _Normal1 ("Normal 1 (G)", 2D) = "bump" {}
	[HideInInspector] _Normal0 ("Normal 0 (R)", 2D) = "bump" {}
	// used in fallback on old cards  base map
	[HideInInspector] _MainTex ("BaseMap (RGB)", 2D) = "white" {}
	[HideInInspector] _Color ("Main Color", Color) = (1,1,1,1)
}
	
SubShader {
	Tags {
		"SplatCount" = "4"
		"Queue" = "Geometry-100"
		"RenderType" = "Opaque"
	}
CGPROGRAM
#pragma surface surf BlinnPhong vertex:vert
#pragma target 3.0

void vert (inout appdata_full v)
{
	v.tangent.xyz = cross(v.normal, float3(0,0,1));
	v.tangent.w = -1;
}

struct Input {
	float2 uv_Control : TEXCOORD0;
	float2 uv_Splat0 : TEXCOORD1;
	float2 uv_Splat1 : TEXCOORD2;
	float2 uv_Splat2 : TEXCOORD3;
	float2 uv_Splat3 : TEXCOORD4;
};

sampler2D _Control;
sampler2D _NormalGlobal;
sampler2D _Splat0,_Splat1,_Splat2,_Splat3;
sampler2D _Normal0,_Normal1,_Normal2,_Normal3;
half _Shininess;

void surf (Input IN, inout SurfaceOutput o) {
	fixed4 splat_control = tex2D (_Control, IN.uv_Control);
	fixed4 col;
	col  = splat_control.r * tex2D (_Splat0, IN.uv_Splat0) * tex2D (_Splat0, IN.uv_Splat0 * -0.1) * 1.5;
	col += splat_control.g * tex2D (_Splat1, IN.uv_Splat1) * tex2D (_Splat1, IN.uv_Splat1 * -0.1) * 1.5;
	col += splat_control.b * tex2D (_Splat2, IN.uv_Splat2) * tex2D (_Splat2, IN.uv_Splat2 * -0.1) * 1.5;
	col += splat_control.a * tex2D (_Splat3, IN.uv_Splat3) * tex2D (_Splat3, IN.uv_Splat3 * -0.1) * 1.5;
	o.Albedo = col.rgb;

	fixed4 nrm;
	nrm  = splat_control.r * tex2D (_Normal0, IN.uv_Splat0) * tex2D (_Normal0, IN.uv_Splat0 * -0.1) * 1;
	nrm += splat_control.g * tex2D (_Normal1, IN.uv_Splat1) * tex2D (_Normal1, IN.uv_Splat0 * -0.1) * 1;
	nrm += splat_control.b * tex2D (_Normal2, IN.uv_Splat2) * tex2D (_Normal2, IN.uv_Splat0 * -0.1) * 1;
	nrm += splat_control.a * tex2D (_Normal3, IN.uv_Splat3) * tex2D (_Normal3, IN.uv_Splat0 * -0.1) * 1;
	fixed4 global = ( tex2D (_NormalGlobal, IN.uv_Control) );
	nrm.b = 0.0;
	// Sum of our four splat weights might not sum up to 1, in
	// case of more than 4 total splat maps. Need to lerp towards
	// "flat normal" in that case.
	fixed splatSum = dot(splat_control, fixed4(1,1,1,1));
	fixed4 flatNormal = fixed4(0.5,0.5,1,0.5); // this is "flat normal" in both DXT5nm and xyz*2-1 cases
	nrm = lerp(flatNormal, nrm, splatSum);
	
	
	o.Normal = UnpackNormal( (global + nrm  ) * 0.5 );

	o.Gloss = col.a * splatSum;
	o.Specular = _Shininess;

	o.Alpha = 0.0;
}
ENDCG  
}

Dependency "AddPassShader" = "Hidden/Nature/Terrain/Bumped Specular AddPass"
Dependency "BaseMapShader" = "Specular"

Fallback "Nature/Terrain/Diffuse"
}

Actually, I just saw the line that says Dependency “BaseMapShader” = “Specular”
I think it’s using the Specular shader that came with unity to do the basemap. It’s a compiled shader so I can’t change it to do uv mixing. I guess I’ll need a non-compiled shader to act as the basemap shader, and then modify it with uv mixing.

But I tried making a copy of this shader and point to it as BaseMapShader, but as a result the basemap area of the terrain is just all white. Can someone tell me if there’s any specific requirement or format for a shader to work as a base map shader :slight_smile: