I’m trying to implement blending of mesh and terrain with deferred rendering without alpha-channel. In the mesh shader I use terrain input data – global heightmap, global normalmap and one set of terrain splat textures. There were problems with mixing normals.
Colors are mixed in the fragment shader correctly, while the normals are processed first in the vertex shader, and second in the fragment shader. In fragment, I can mix them by the texture mask, but in the vertex, they are interpolated between the vertices, this creates artifacts.
I think that the normals obtained from the terrain need to be fully calculated in the fragment shader, ignoring the vertex shader, then the blending will be correct.
How can I ignore the values of the normals from the vertex shader and calculate them full in fragment shader to blend correctly with the mask?
This is my shader:
Shader "Custom/MainBlend"
{
Properties {
[Header(Standard Shader Setup)]
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
[NoScaleOffset]_BumpMap("Normal Map (RGB)", 2D) = "bump" {}
_BumpScale("Normal Scale", Range(-1,1)) = 1.0
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
[Header(Intersection Maps)]
_FadeHeight("Fade Height", Range(0,10)) = 1.28
_FadeScale("Fade Scale", Range(0,10)) = 0.97
_IntersectionColor("Intersection Color", Color) = (1,1,1,1)
_IntersectionMap("Intersection Albedo(RGB), Blend (A)", 2D) = "white" {}
_IntersectionScale("Intersection Scale", Float) = 0.2
[NoScaleOffset]_IntersectionBump("IntersectionNormal", 2D) = "bump" {}
[Header(Blending Masks)]
[NoScaleOffset]_MaskOne("Mask One", 2D) = "white" {}
_MaskOneStrength("Mask One Strength", Range(0.0, 1.0)) = 1.0
_MaskOneScale("Mask One Scale", Float) = 2.31
_VertexOffset("Vertex Offset", Float) = -0.37
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD 200
ZWrite On
CGPROGRAM
#pragma surface surf Standard vertex:vert addshadow
#pragma target 3.0
sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _IntersectionMap;
sampler2D _IntersectionBump;
sampler2D _MaskOne;
float _FadeHeight;
float _FadeScale;
struct Input
{
float2 uv_MainTex;
float2 uv_IntersectionMap : TEXCOORD2;
float3 worldPos;
};
half _Glossiness;
half _BumpScale;
half _Metallic;
half _IntersectionScale;
half _MaskOneScale;
half _MaskOneStrength;
half _VertexOffset;
fixed4 _Color;
fixed4 _IntersectionColor;
#pragma multi_compile __ BLEND_TERRAIN_BLEND_NORMAL_INDEX_FIRST
#include "Utility/TerrainHeightMap.cginc"
UNITY_INSTANCING_CBUFFER_START(Props)
UNITY_INSTANCING_CBUFFER_END
void vert(inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input, o);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
float blendMask = o.worldPos.y- SampleTerrainHeightMap(o.worldPos) - _VertexOffset;
blendMask = saturate( (blendMask) / _FadeHeight );
blendMask = saturate(pow(blendMask, _FadeScale));
float diff = blendMask;
v.vertex = mul(unity_ObjectToWorld, v.vertex);
o.worldPos = v.vertex;
float3 terrainNormals = mul(SampleTerrainNormal(o.worldPos), (float3x3)unity_ObjectToWorld);
v.normal = float4(normalize(lerp(terrainNormals, v.normal, diff)),0);
v.vertex = mul(unity_WorldToObject, v.vertex);
}
void surf (Input IN, inout SurfaceOutputStandard o)
{
float2 intersectionUVs = IN.worldPos.xz * _IntersectionScale;
float2 intersectionUV2s = IN.uv_IntersectionMap * _MaskOneScale;
float4 baseAlbedo = tex2D(_MainTex, IN.uv_MainTex) * _Color;
float3 baseNormal = lerp(half3(0, 0, 1), UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex)), _BumpScale);
float4 intersectionMap = tex2D(_IntersectionMap, intersectionUVs) * _IntersectionColor;
float4 intersectionBump = tex2D(_IntersectionBump, intersectionUVs);
float maskOne = lerp(1, tex2D(_MaskOne, intersectionUV2s).r, _MaskOneStrength);
float blendMask = IN.worldPos.y - SampleTerrainHeightMap(IN.worldPos);
blendMask = saturate( (blendMask) / _FadeHeight );
blendMask = saturate(1 - pow(blendMask, _FadeScale));
float diff = blendMask;
float smallPitches = saturate(blendMask + blendMask *(pow(maskOne * 2, 3) * 2.0 - 1.0));
diff = saturate(smallPitches);
float3 n=0;
fixed3 col=0;
col = intersectionMap.rgb;
#if BLEND_TERRAIN_BLEND_NORMAL_INDEX_FIRST
n.xy=((intersectionBump.rg)*2-1);
#else
n.xy=((intersectionBump.ba)*2-1);
#endif
n.z = sqrt(1 - saturate(dot(n.xy, n.xy)));
o.Albedo = lerp(baseAlbedo.rgb, col, diff);
o.Smoothness = lerp(_Glossiness, 0, diff);
o.Metallic = lerp(_Metallic, 0, diff);
o.Normal = normalize(lerp(baseNormal, n, diff));
o.Occlusion = 1;
o.Alpha = 1.0f;
}
ENDCG
}
FallBack "Legacy Shaders/VertexLit"
CustomEditor "BlendShaderGUI"
}