# 前言

离正式辞职,已经过去半个多月了吧。这些天埋头苦干,自己的 “游戏” 基本功能算是完成得差不了,就目前而言,应该就还差场景、AI 以及剧情了。随着日子不断过去,心里似乎也变的有些焦虑了起来 —— 本来我以为自己是不会出现这样的心理的,不过一直待着吃老本,果然是越待越不淡定了。真想马上还是去把工作找了...... 不过想想,之前自己可貌似定下了 “雄心壮志” 一般的想法计划,怎么着,也得弄出个可玩的吧?

今天下午准备先画一下场景了,把该用的地形贴图都 assign 上去,然后画了几笔.... 我去,除了前四张贴图,该花的花,该黑的黑,Shader 上的 Texture Scale 也没用了... 虽然之前 “偷懒” 的时候就早已有了心理准备(Unity 的地形 Shader 具有 -base、-FirstPass、AddPass 三个组成的,之前我的那个地形 Shader,只有一份代码,就相当于只写了一个 FirstPass),虽然做其它功能的时候,就已经发现远处的贴图变成红色的了,不过那会儿也没在意。

但如今可不行了,若是只有前四张地形贴图可以用 Tripanar,又有何意义?于是没办法,怕麻烦也得继续该改了。

# 简介

关于介绍的 Triplanar 相关的就不多说了,上次的文章应该写了不少。

这次只是在前文的基础上,添加 AddPass Shader 用于处理超出 4 张地形贴图的情况,以及添加 base Shader 处理超出 Terrain base map dist 的情况。

关于 Base shader 好说,因为不必做出什么处理,用正常模型的算法都行 —— 因为太远了,能把贴图显示一下也就差不多了。或者直接使用 Unity 的 Base Shader 都可以,这儿我就直接使用 Unity 的了。

然后是 AddPass Shader.

地形的 AddPadd Shader 跟普通 Shader 的 AddPass 貌似功能上差不多,都是为了负责渲染前一个 Pass 没法渲染的东西 —— 比如普通 Shader 中额外处理点光源之类的。

所以,这个 Pass 的算法,基本上与前一个 Pass 保持一致,只是因为处理对象不同,会有那么一丢丢的改动。

# 效果

效果

为了表示比较,再上一张使用内置的 Standard Terrain Shader 的效果吧:

内置Shader效果

# 代码

完整代码已上传至 Github,地址:https://github.com/CWHISME/Unity3D-Tripanar-Terrain-Shader

# Base

So,先看看最简单的 Base Shader 吧:

s
Shader "Hidden/TerrainEngine/Splatmap/TriplanarTerrain-Base" {
	Properties {
		_MainTex ("Base (RGB) Smoothness (A)", 2D) = "white" {}
		_MetallicTex ("Metallic (R)", 2D) = "white" {}
		// used in fallback on old cards
		_Color ("Main Color", Color) = (1,1,1,1)
	}
	SubShader {
		Tags {
			"RenderType" = "Opaque"
			"Queue" = "Geometry-100"
		}
		LOD 200
		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows
		#pragma target 3.0
		// needs more than 8 texcoords
		#pragma exclude_renderers gles
		#include "UnityPBSLighting.cginc"
		sampler2D _MainTex;
		sampler2D _MetallicTex;
		struct Input {
			float2 uv_MainTex;
		};
		void surf (Input IN, inout SurfaceOutputStandard o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = 1;
			o.Smoothness = c.a;
			o.Metallic = tex2D (_MetallicTex, IN.uv_MainTex).r;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

嘛.... 就是 Unity 的,而且很简单,跟普通 Shader 都差不多,没什么可解释的。

# FirstPass

s
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
//2016.11.18 by cwhisme
//Note: 在基于 Unity Buildin Terrain Shader 的基础上修改
//Unity 内置的地形 shader 可以在官方网站上进行下载
// 加入了 Triplanar 计算,避免贴图拉伸问题
//Updarte 2016.12.15
// 替换部分内置代码,并添加对 AddPass 与 Base Shader 的引用
// 以提供四张贴图以上的支持,及超出 Base Map Dis 之后贴图变红问题
Shader "CWHISME/TriplannarTerrain"
{
	Properties{
		// 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" {}
		[HideInInspector][Gamma] _Metallic0("Metallic 0", Range(0.0, 1.0)) = 0.0
		[HideInInspector][Gamma] _Metallic1("Metallic 1", Range(0.0, 1.0)) = 0.0
		[HideInInspector][Gamma] _Metallic2("Metallic 2", Range(0.0, 1.0)) = 0.0
		[HideInInspector][Gamma] _Metallic3("Metallic 3", Range(0.0, 1.0)) = 0.0
		[HideInInspector] _Smoothness0("Smoothness 0", Range(0.0, 1.0)) = 1.0
		[HideInInspector] _Smoothness1("Smoothness 1", Range(0.0, 1.0)) = 1.0
		[HideInInspector] _Smoothness2("Smoothness 2", Range(0.0, 1.0)) = 1.0
		[HideInInspector] _Smoothness3("Smoothness 3", Range(0.0, 1.0)) = 1.0
		// used in fallback on old cards & base map
		[HideInInspector] _MainTex("BaseMap (RGB)", 2D) = "white" {}
		[HideInInspector] _Color("Main Color", Color) = (1,1,1,1)
		_TextureScale("Texture Scale",float) = 100
		_TriplanarBlendSharpness("Triplanar Blend Sharpness",float) = 1
	}
		SubShader{
		Tags{
			"SplatCount" = "10"
			"Queue" = "Geometry-100"
			"RenderType" = "Opaque"
		}
		CGPROGRAM
		#pragma surface surf Standard vertex:vert finalcolor:SplatmapFinalColor finalprepass:SplatmapFinalPrepass finalgbuffer:SplatmapFinalGBuffer fullforwardshadows
		#pragma multi_compile_fog
		#pragma target 3.0
		// needs more than 8 texcoords
		#pragma exclude_renderers gles
		#include "UnityPBSLighting.cginc"
		#pragma multi_compile __ _TERRAIN_NORMAL_MAP
		#define TERRAIN_SURFACE_OUTPUT SurfaceOutputStandard
		sampler2D _Control;
		float4 _Control_ST;
		sampler2D _Splat0, _Splat1, _Splat2, _Splat3;
		half4 _Splat0_ST, _Splat1_ST, _Splat2_ST, _Splat3_ST;
		#ifdef _TERRAIN_NORMAL_MAP
		sampler2D _Normal0, _Normal1, _Normal2, _Normal3;
		#endif
		half _Metallic0;
		half _Metallic1;
		half _Metallic2;
		half _Metallic3;
		half _Smoothness0;
		half _Smoothness1;
		half _Smoothness2;
		half _Smoothness3;
		float _TriplanarBlendSharpness;
		float _TextureScale;
		struct Input
		{
			float2 tc_Control : TEXCOORD4;
			float3 wNormal;
			float3 worldPos;
			UNITY_FOG_COORDS(5)
		};
		void vert(inout appdata_full v, out Input o)
		{
			UNITY_INITIALIZE_OUTPUT(Input, o);
			o.tc_Control = TRANSFORM_TEX(v.texcoord, _Control);
			float4 pos = mul(UNITY_MATRIX_MVP, v.vertex);
			UNITY_TRANSFER_FOG(o, pos);
			o.wNormal =normalize(mul(unity_ObjectToWorld, fixed4(v.normal, 0)).xyz);
			#ifdef _TERRAIN_NORMAL_MAP
			v.tangent.xyz = cross(v.normal, float3(0, 0, 1));
			v.tangent.w = -1;
			#endif
		}
		void surf(Input IN, inout SurfaceOutputStandard o) {
			half4 splat_control;
			half weight;
			fixed4 mixedDiffuse=0;
			half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
			//Custom begin=================================================<<<<<<<<<<<<<<<<<<<<<<<<<<<
			splat_control = tex2D(_Control, IN.tc_Control);
			weight = dot(splat_control, half4(1, 1, 1, 1));
			splat_control /= (weight + 1e-3f);
			//triplanar---------------<<<<<<<<<<<<
			// 计算权重
			float3 N =normalize( IN.wNormal);
			//N -= 0.4f;
			half3 blendWeights = pow(abs(IN.wNormal), _TriplanarBlendSharpness);
			blendWeights /= dot(blendWeights, 1.0);
			half2 xUV = IN.worldPos.zy;// / _TextureScale;
			half2 yUV = IN.worldPos.xz;// / _TextureScale;
			half2 zUV = IN.worldPos.xy;// / _TextureScale;
			// 通常 Triplanar 实现,只是多了三张贴图处理
			fixed4 tex0X =  tex2D(_Splat0, (xUV*_Splat0_ST.xy + _Splat0_ST.zw)/ _TextureScale);
			fixed4 tex0Y = tex2D(_Splat0, (yUV*_Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
			fixed4 tex0Z = tex2D(_Splat0, (zUV*_Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
			fixed4 tex1X = tex2D(_Splat1, (xUV*_Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 tex1Y = tex2D(_Splat1, (yUV*_Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 tex1Z =  tex2D(_Splat1, (zUV*_Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 tex2X = tex2D(_Splat2, (xUV*_Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 tex2Y = tex2D(_Splat2, (yUV*_Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 tex2Z = tex2D(_Splat2, (zUV*_Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 tex3X = tex2D(_Splat3, (xUV*_Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 tex3Y = tex2D(_Splat3, (yUV*_Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 tex3Z = tex2D(_Splat3, (zUV*_Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 tex0 = tex0X*blendWeights.x + tex0Y * blendWeights.y + tex0Z * blendWeights.z;
			fixed4 tex1 =  tex1X*blendWeights.x + tex1Y * blendWeights.y + tex1Z * blendWeights.z;
			fixed4 tex2 = tex2X*blendWeights.x + tex2Y * blendWeights.y + tex2Z * blendWeights.z;
			fixed4 tex3 = tex3X*blendWeights.x + tex3Y * blendWeights.y + tex3Z * blendWeights.z;
			// 融合权重,添加高光
			tex0 *= splat_control.r *half4(1.0, 1.0, 1.0, defaultSmoothness.r);
			tex1 *= splat_control.g *half4(1.0, 1.0, 1.0, defaultSmoothness.g);
			tex2 *= splat_control.b *half4(1.0, 1.0, 1.0, defaultSmoothness.b);
			tex3 *= splat_control.a *half4(1.0, 1.0, 1.0, defaultSmoothness.a);
			mixedDiffuse = tex0 + tex1 + tex2 + tex3;
			//--------- 法线 ---------<<<<<<<<<<<<<<<<<<<<<<<<<<<<
			#ifdef _TERRAIN_NORMAL_MAP
			fixed4 nrm = 0.0f;
			fixed4 nm0X = tex2D(_Normal0, (xUV* _Splat0_ST.xy + _Splat0_ST.zw)/ _TextureScale);
			fixed4 nm0Y = tex2D(_Normal0, (yUV* _Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
			fixed4 nm0Z = tex2D(_Normal0, (zUV* _Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
											
			fixed4 nm1X = tex2D(_Normal1, (xUV* _Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 nm1Y = tex2D(_Normal1, (yUV* _Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 nm1Z = tex2D(_Normal1, (zUV* _Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
													  
			fixed4 nm2X = tex2D(_Normal2, (xUV* _Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 nm2Y = tex2D(_Normal2, (yUV* _Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 nm2Z = tex2D(_Normal2, (zUV* _Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
						 								
			fixed4 nm3X = tex2D(_Normal3, (xUV* _Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 nm3Y = tex2D(_Normal3, (yUV* _Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 nm3Z = tex2D(_Normal3, (zUV* _Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 nm0 = nm0X*blendWeights.x +nm0Y * blendWeights.y + nm0Z * blendWeights.z;
			fixed4 nm1 =  nm1X*blendWeights.x + nm1Y * blendWeights.y + nm1Z * blendWeights.z;
			fixed4 nm2 = nm2X*blendWeights.x + nm2Y * blendWeights.y + nm2Z * blendWeights.z;
			fixed4 nm3 = nm3X*blendWeights.x + nm3Y * blendWeights.y + nm3Z * blendWeights.z;
			nm0 *= splat_control.r;
			nm1 *= splat_control.g;
			nm2 *= splat_control.b;
			nm3 *= splat_control.a;
			nrm = nm0 + nm1 + nm2 + nm3;
			o.Normal = UnpackNormal(nrm);
			#endif
			//End Custom=================================================<<<<<<<<<<<<<<<<<<<<<<<<<<<
			o.Albedo = mixedDiffuse.rgb;//max(fixed3(0.001, 0.001, 0.001), mixedDiffuse.rgb); 
			o.Alpha = weight;
			o.Smoothness = mixedDiffuse.a;
			o.Metallic = dot(splat_control, half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3));
		}
		void SplatmapFinalColor(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 color)
		{
			color *= o.Alpha;
			#ifdef TERRAIN_SPLAT_ADDPASS
			UNITY_APPLY_FOG_COLOR(IN.fogCoord, color, fixed4(0, 0, 0, 0));
			#else
			UNITY_APPLY_FOG(IN.fogCoord, color);
			#endif
		}
		void SplatmapFinalPrepass(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 normalSpec)
		{
			normalSpec *= o.Alpha;
		}
		void SplatmapFinalGBuffer(Input IN, TERRAIN_SURFACE_OUTPUT o, inout half4 outGBuffer0, inout half4 outGBuffer1, inout half4 outGBuffer2, inout half4 emission)
		{
			UnityStandardDataApplyWeightToGbuffer(outGBuffer0, outGBuffer1, outGBuffer2, o.Alpha);
			emission *= o.Alpha;
		}
		ENDCG
	}
	dependency "AddPassShader" = "Hidden/TerrainEngine/Splatmap/TriplanarTerrain-AddPass"
	dependency "BaseMapShader" = "Hidden/TerrainEngine/Splatmap/TriplanarTerrain-Base"
	Fallback "Nature/Terrain/Diffuse"
}

解释都在代码最开头,就这样。

# AddPass

s
//2016.12.15 by cwhisme
// 在 FirstPass,即前一份代码基础上,处理超出四张地形贴图
Shader "Hidden/TerrainEngine/Splatmap/TriplanarTerrain-AddPass"
{
	Properties{
		// 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" {}
		[HideInInspector][Gamma] _Metallic0("Metallic 0", Range(0.0, 1.0)) = 0.0
		[HideInInspector][Gamma] _Metallic1("Metallic 1", Range(0.0, 1.0)) = 0.0
		[HideInInspector][Gamma] _Metallic2("Metallic 2", Range(0.0, 1.0)) = 0.0
		[HideInInspector][Gamma] _Metallic3("Metallic 3", Range(0.0, 1.0)) = 0.0
		[HideInInspector] _Smoothness0("Smoothness 0", Range(0.0, 1.0)) = 1.0
		[HideInInspector] _Smoothness1("Smoothness 1", Range(0.0, 1.0)) = 1.0
		[HideInInspector] _Smoothness2("Smoothness 2", Range(0.0, 1.0)) = 1.0
		[HideInInspector] _Smoothness3("Smoothness 3", Range(0.0, 1.0)) = 1.0
	}
	SubShader{
			Tags{
			"Queue" = "Geometry-99"
			"IgnoreProjector" = "True"
			"RenderType" = "Opaque"
		}
		CGPROGRAM
		#pragma surface surf Standard decal:add vertex:vert finalcolor:SplatmapFinalColor finalgbuffer:SplatmapFinalGBuffer fullforwardshadows
		#pragma multi_compile_fog
		#pragma target 3.0
		// needs more than 8 texcoords
		#pragma exclude_renderers gles
		#include "UnityPBSLighting.cginc"
		#pragma multi_compile __ _TERRAIN_NORMAL_MAP
		#define TERRAIN_SPLAT_ADDPASS
		#define TERRAIN_SURFACE_OUTPUT SurfaceOutputStandard
		sampler2D _Control;
		float4 _Control_ST;
		sampler2D _Splat0, _Splat1, _Splat2, _Splat3;
		half4 _Splat0_ST, _Splat1_ST, _Splat2_ST, _Splat3_ST;
		#ifdef _TERRAIN_NORMAL_MAP
		sampler2D _Normal0, _Normal1, _Normal2, _Normal3;
		#endif
		half _Metallic0;
		half _Metallic1;
		half _Metallic2;
		half _Metallic3;
		half _Smoothness0;
		half _Smoothness1;
		half _Smoothness2;
		half _Smoothness3;
		float _TriplanarBlendSharpness;
		float _TextureScale;
		struct Input
		{
			float2 tc_Control : TEXCOORD4;
			float3 wNormal;
			float3 worldPos;
			UNITY_FOG_COORDS(5)
		};
		void vert(inout appdata_full v, out Input o)
		{
			UNITY_INITIALIZE_OUTPUT(Input, o);
			o.tc_Control = TRANSFORM_TEX(v.texcoord, _Control);
			float4 pos = mul(UNITY_MATRIX_MVP, v.vertex);
			UNITY_TRANSFER_FOG(o, pos);
			o.wNormal =normalize(mul(unity_ObjectToWorld, fixed4(v.normal, 0)).xyz);
			#ifdef _TERRAIN_NORMAL_MAP
			v.tangent.xyz = cross(v.normal, float3(0, 0, 1));
			v.tangent.w = -1;
			#endif
		}
		void surf(Input IN, inout SurfaceOutputStandard o) {
			half4 splat_control;
			half weight;
			fixed4 mixedDiffuse=0;
			half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
			//Custom begin=================================================<<<<<<<<<<<<<<<<<<<<<<<<<<<
			splat_control = tex2D(_Control, IN.tc_Control);
			weight = dot(splat_control, half4(1, 1, 1, 1));
			#if !defined(SHADER_API_MOBILE) && defined(TERRAIN_SPLAT_ADDPASS)
				clip(weight == 0.0f ? -1 : 1);
			#endif
			splat_control /= (weight + 1e-3f);
			//triplanar---------------<<<<<<<<<<<<
			// 计算权重
			float3 N =normalize( IN.wNormal);
			//N -= 0.4f;
			half3 blendWeights = pow(abs(IN.wNormal), _TriplanarBlendSharpness);
			blendWeights /= dot(blendWeights, 1.0);
			half2 xUV = IN.worldPos.zy;// / _TextureScale;
			half2 yUV = IN.worldPos.xz;// / _TextureScale;
			half2 zUV = IN.worldPos.xy;// / _TextureScale;
			// 通常 Triplanar 实现,只是多了三张贴图处理
			fixed4 tex0X =  tex2D(_Splat0, (xUV*_Splat0_ST.xy + _Splat0_ST.zw)/ _TextureScale);
			fixed4 tex0Y = tex2D(_Splat0, (yUV*_Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
			fixed4 tex0Z = tex2D(_Splat0, (zUV*_Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
			fixed4 tex1X = tex2D(_Splat1, (xUV*_Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 tex1Y = tex2D(_Splat1, (yUV*_Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 tex1Z =  tex2D(_Splat1, (zUV*_Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 tex2X = tex2D(_Splat2, (xUV*_Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 tex2Y = tex2D(_Splat2, (yUV*_Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 tex2Z = tex2D(_Splat2, (zUV*_Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 tex3X = tex2D(_Splat3, (xUV*_Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 tex3Y = tex2D(_Splat3, (yUV*_Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 tex3Z = tex2D(_Splat3, (zUV*_Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 tex0 = tex0X*blendWeights.x + tex0Y * blendWeights.y + tex0Z * blendWeights.z;
			fixed4 tex1 =  tex1X*blendWeights.x + tex1Y * blendWeights.y + tex1Z * blendWeights.z;
			fixed4 tex2 = tex2X*blendWeights.x + tex2Y * blendWeights.y + tex2Z * blendWeights.z;
			fixed4 tex3 = tex3X*blendWeights.x + tex3Y * blendWeights.y + tex3Z * blendWeights.z;
			// 融合权重,添加高光
			tex0 *= splat_control.r *half4(1.0, 1.0, 1.0, defaultSmoothness.r);
			tex1 *= splat_control.g *half4(1.0, 1.0, 1.0, defaultSmoothness.g);
			tex2 *= splat_control.b *half4(1.0, 1.0, 1.0, defaultSmoothness.b);
			tex3 *= splat_control.a *half4(1.0, 1.0, 1.0, defaultSmoothness.a);
			mixedDiffuse = tex0 + tex1 + tex2 + tex3;
			//--------- 法线 ---------<<<<<<<<<<<<<<<<<<<<<<<<<<<<
			#ifdef _TERRAIN_NORMAL_MAP
			fixed4 nrm = 0.0f;
			fixed4 nm0X = tex2D(_Normal0, (xUV* _Splat0_ST.xy + _Splat0_ST.zw)/ _TextureScale);
			fixed4 nm0Y = tex2D(_Normal0, (yUV* _Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
			fixed4 nm0Z = tex2D(_Normal0, (zUV* _Splat0_ST.xy + _Splat0_ST.zw) / _TextureScale);
											
			fixed4 nm1X = tex2D(_Normal1, (xUV* _Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 nm1Y = tex2D(_Normal1, (yUV* _Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
			fixed4 nm1Z = tex2D(_Normal1, (zUV* _Splat1_ST.xy + _Splat1_ST.zw) / _TextureScale);
													  
			fixed4 nm2X = tex2D(_Normal2, (xUV* _Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 nm2Y = tex2D(_Normal2, (yUV* _Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
			fixed4 nm2Z = tex2D(_Normal2, (zUV* _Splat2_ST.xy + _Splat2_ST.zw)/ _TextureScale);
						 								
			fixed4 nm3X = tex2D(_Normal3, (xUV* _Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 nm3Y = tex2D(_Normal3, (yUV* _Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 nm3Z = tex2D(_Normal3, (zUV* _Splat3_ST.xy + _Splat3_ST.zw)/ _TextureScale);
			fixed4 nm0 = nm0X*blendWeights.x +nm0Y * blendWeights.y + nm0Z * blendWeights.z;
			fixed4 nm1 =  nm1X*blendWeights.x + nm1Y * blendWeights.y + nm1Z * blendWeights.z;
			fixed4 nm2 = nm2X*blendWeights.x + nm2Y * blendWeights.y + nm2Z * blendWeights.z;
			fixed4 nm3 = nm3X*blendWeights.x + nm3Y * blendWeights.y + nm3Z * blendWeights.z;
			nm0 *= splat_control.r;
			nm1 *= splat_control.g;
			nm2 *= splat_control.b;
			nm3 *= splat_control.a;
			nrm = nm0 + nm1 + nm2 + nm3;
			o.Normal = UnpackNormal(nrm);
			#endif
			//End Custom=================================================<<<<<<<<<<<<<<<<<<<<<<<<<<<
			o.Albedo = mixedDiffuse.rgb;//max(fixed3(0.001, 0.001, 0.001), mixedDiffuse.rgb); 
			o.Alpha = weight;
			o.Smoothness = mixedDiffuse.a;
			o.Metallic = dot(splat_control, half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3));
		}
		void SplatmapFinalColor(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 color)
		{
			color *= o.Alpha;
			#ifdef TERRAIN_SPLAT_ADDPASS
			UNITY_APPLY_FOG_COLOR(IN.fogCoord, color, fixed4(0, 0, 0, 0));
			#else
			UNITY_APPLY_FOG(IN.fogCoord, color);
			#endif
		}
		void SplatmapFinalPrepass(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 normalSpec)
		{
			normalSpec *= o.Alpha;
		}
		void SplatmapFinalGBuffer(Input IN, TERRAIN_SURFACE_OUTPUT o, inout half4 outGBuffer0, inout half4 outGBuffer1, inout half4 outGBuffer2, inout half4 emission)
		{
			UnityStandardDataApplyWeightToGbuffer(outGBuffer0, outGBuffer1, outGBuffer2, o.Alpha);
			emission *= o.Alpha;
		}
		ENDCG
	}
	Fallback "Hidden/TerrainEngine/Splatmap/Diffuse-AddPass"
}