这个Shader适用于不断加载的大世界地图,因为制作地形的话太大,划动屏幕加载手机会卡
地形.jpg
地形shader面板.jpg
四张纹理+四张法线通过Global来进行混合,+一个大的法线来模拟大的坑洼,支持高光效果,也可扩展成高光贴图,添加水选项,不用的话可以关掉,用mask控制水的范围
以下是源码分享
Shader "Artist/Scene/Terrain Bump Water"
{
Properties
{
_tile0Control("tile0Control (RGB)", 2D) = "red" {}
_tile0Normal("tile0Normal", 2D) = "bump" {}
_tile0Splat0("tile0Splat0 (R)", 2D) = "white" {}
_tile0Splat1("tile0Splat1 (G)", 2D) = "white" {}
_tile0Splat2("tile0Splat2 (B)", 2D) = "white" {}
_tile0Splat3("tile0Splat3 (B)", 2D) = "white" {}
_tile0Splat0Normal("tile0Splat0Normal (R)", 2D) = "white" {}
_tile0Splat1Normal("tile0Splat1Normal (G)", 2D) = "white" {}
_tile0Splat2Normal("tile0Splat2Normal (B)", 2D) = "white" {}
_tile0Splat3Normal("tile0Splat3Normal (B)", 2D) = "white" {}
_Specular ("Specular Color", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
[Toggle] _UseWater("UseWater", Int) = 0
_WaterTex("WaterTex", 2D) = "white" {}
_WaterColor ("Water Color", Color) = (0.0, 0.15, 0.22, 1)
_WaterSpecColor ("WaterSpecColor", Color) = (0.0, 0.15, 0.22, 1)
_FrenelColor ("Frenel Color", Color) = (0.0, 0.15, 0.22, 1)
_WaterTexMask("WaterTexMask", 2D) = "white" {}
_Skybox("skybox", Cube)="white"{}
//_FresnelTex("Fresnel Texture", 2D) = "white" {}
_Smoothness("Smoothness", Range(1, 30)) = 8
_Frenel ("Bump Strength", Range(0, 10)) = 0.5
_BumpDirection ("Bump Direction", Vector)=(0.35,0.35,-0.1,-0.12)
_BumpTiling ("Bump Tiling", Vector)=(0.25,0.25,0.3,0.3)
//_SunDir("Light Direction", Vector)=(0,0,0,0)
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase" }
LOD 200
Pass
{
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma target 2.0
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#pragma shader_feature _USEWATER
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 dataForNormalMap0 : TEXCOORD0;
float4 dataForNormalMap1 : TEXCOORD1;
float4 dataForNormalMap2 : TEXCOORD2;
half4 uv_tile0ControlSplat0 : TEXCOORD3;
half4 uv_tile0Splat1Splat1 : TEXCOORD4;
half2 uv_tile0Splat1Splat2 : TEXCOORD5;
half4 uv_tile0Splat1Splat3 : TEXCOORD6;
half2 uv_tile0Normal : TEXCOORD8;
UNITY_FOG_COORDS(7)
};
sampler2D _tile0Control;
float4 _tile0Control_ST;
sampler2D _tile0Splat0;
float4 _tile0Splat0_ST;
sampler2D _tile0Splat1;
float4 _tile0Splat1_ST;
sampler2D _tile0Splat2;
float4 _tile0Splat2_ST;
sampler2D _tile0Splat3;
float4 _tile0Splat3_ST;
sampler2D _tile0Normal;
float4 _tile0Normal_ST;
sampler2D _WaterTex;
float4 _WaterTex_ST;
sampler2D _tile0Splat0Normal;
sampler2D _tile0Splat1Normal;
sampler2D _tile0Splat2Normal;
sampler2D _tile0Splat3Normal;
fixed3 _Specular;
float _Gloss;
float _Smoothness;
float _Frenel;
fixed3 _WaterColor;
fixed3 _FrenelColor;
sampler2D _WaterTexMask;
fixed3 _WaterSpecColor;
samplerCUBE _Skybox;
sampler2D _FresnelTex;
half4 _BumpDirection;
half4 _BumpTiling;
//half4 _SunDir;
v2f vert(appdata v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f, o);
o.vertex = UnityObjectToClipPos(v.vertex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
half3 wNormal = UnityObjectToWorldNormal(v.normal);
half3 wTangent = UnityObjectToWorldDir(v.tangent.xyz);
half3 wBitangent = cross(wNormal, wTangent) * v.tangent.w;
o.dataForNormalMap0 = float4(wTangent.x, wBitangent.x, wNormal.x, worldPos.x);
o.dataForNormalMap1 = float4(wTangent.y, wBitangent.y, wNormal.y, worldPos.y);
o.dataForNormalMap2 = float4(wTangent.z, wBitangent.z, wNormal.z, worldPos.z);
o.uv_tile0ControlSplat0.xy = TRANSFORM_TEX(v.uv, _tile0Control);
o.uv_tile0ControlSplat0.zw = TRANSFORM_TEX(v.uv, _tile0Splat0);
o.uv_tile0Splat1Splat1.xy = TRANSFORM_TEX(v.uv, _tile0Splat1);
o.uv_tile0Splat1Splat1.zw = TRANSFORM_TEX(v.uv, _tile0Splat2);
o.uv_tile0Splat1Splat2.xy = TRANSFORM_TEX(v.uv, _tile0Splat3);
o.uv_tile0Splat1Splat3.xyzw = (worldPos.xzxz + _Time.yyyy * _BumpDirection.xyzw) * _BumpTiling.xyzw;
o.uv_tile0Normal = TRANSFORM_TEX(v.uv, _tile0Normal);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 c = tex2D(_tile0Control, i.uv_tile0ControlSplat0.xy);
fixed4 c0 = tex2D(_tile0Splat0, i.uv_tile0ControlSplat0.zw);
fixed4 c1 = tex2D(_tile0Splat1, i.uv_tile0Splat1Splat1.xy);
fixed4 c2 = tex2D(_tile0Splat2, i.uv_tile0Splat1Splat1.zw);
fixed4 c3 = tex2D(_tile0Splat3, i.uv_tile0Splat1Splat2.xy);
fixed4 c5 = c0 * c.r + c1 * c.g + c2 * c.b + c3 * c.a;
half4 n0 = tex2D(_tile0Splat0Normal, i.uv_tile0ControlSplat0.zw);
half4 n1 = tex2D(_tile0Splat1Normal, i.uv_tile0Splat1Splat1.xy);
half4 n2 = tex2D(_tile0Splat2Normal, i.uv_tile0Splat1Splat1.zw);
half4 n3 = tex2D(_tile0Splat3Normal, i.uv_tile0Splat1Splat2.xy);
half4 n5 = n0 * c.r + n1 * c.g + n2 * c.b + n3 * c.a;
c5/= c.r+c.g+c.b+c.a;
half3 n6 = UnpackNormal(n5);
half3 tnormal = UnpackNormal(tex2D(_tile0Normal, i.uv_tile0Normal));
half3 worldNormal;
worldNormal.x = dot(i.dataForNormalMap0.xyz, n6.x);
worldNormal.y = dot(i.dataForNormalMap1.xyz, n6.y);
worldNormal.z = dot(i.dataForNormalMap2.xyz, n6.z);
worldNormal = normalize(worldNormal);
half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//平行光坐标点
half3 viewDir = normalize(UnityWorldSpaceViewDir(half3(i.dataForNormalMap0.w,i.dataForNormalMap1.w,i.dataForNormalMap2.w)));
//half3 Ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * c5;
half3 Ambient = ShadeSH9(half4(tnormal, 1.0)) * c5;
half nl = max(0, dot(worldNormal,lightDir ));
half nnl = max(0, dot(tnormal,lightDir ));
c5.rgb *= (nl + nnl)*_LightColor0.rgb;
//c5 *= nl;
half3 halfDir = normalize(lightDir + viewDir);
half3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate( dot(worldNormal, halfDir)), _Gloss);
#ifdef _USEWATER
half2 offset = UnpackNormal(tex2D(_WaterTex, i.uv_tile0Splat1Splat3.xy)) + UnpackNormal(tex2D(_WaterTex, i.uv_tile0Splat1Splat3.zw)) *0.5;//双水纹理采样偏移速度不一
float3 worldNormal1 = float3(0,0,0);
worldNormal1.xz = offset.xy * _Frenel;
worldNormal1.y = 1;
half3 normalDir = normalize(worldNormal1);
half2 fresnelUV = half2( saturate(dot(viewDir, normalDir)), 0.5);
half4 WaterTexMask = tex2D(_WaterTexMask, i.uv_tile0ControlSplat0.xy);
//half fresnel1 = tex2D(_FresnelTex, fresnelUV).r;
half fresnel1 = WaterTexMask.g;
if(IsGammaSpace())
{
fresnel1 = pow(fresnel1, 2.2);
}
half3 specLight = _LightColor0.rgb * _WaterSpecColor;
half3 hd = normalize(lightDir+viewDir);
half d = pow(max(0,(dot(normalDir, hd ))), _Smoothness);
half3 specColor = specLight * d;
half3 reflUV = reflect( viewDir, normalDir);
half3 reflectColor1 = texCUBE(_Skybox, reflUV);
//half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflUV, 0);
//half3 reflectColor1 = DecodeHDR(rgbm, unity_SpecCube0_HDR);
half3 finalreflect = lerp(_FrenelColor, reflectColor1, fresnel1);
//UNITY_APPLY_FOG(i.fogCoord, c5.rgb);
return fixed4((c5.rgb + Ambient + specular )*(1-WaterTexMask.r)+(finalreflect + specColor ) * _WaterColor * WaterTexMask.r, 1.0);
//return fixed4(c5.rgb + Ambient + specular, 1.0);
//return fixed4(finalreflect,1.0);
#endif
//UNITY_APPLY_FOG(i.fogCoord, c5.rgb);
return fixed4(c5.rgb , 1.0);
//return fixed4(1,1,1, 1.0);
}
ENDCG
}
}
CustomEditor "TerrainShaderGUI"
}
using System;
using UnityEngine;
namespace UnityEditor
{
internal class TerrainShaderGUI : ShaderGUI
{
private static class Styles
{
public static GUIContent tile0Splat0Text = new GUIContent("tile0Splat0", "");
public static GUIContent tile0Splat1Text = new GUIContent("tile0Splat1", "");
public static GUIContent tile0Splat2Text = new GUIContent("tile0Splat2", "");
public static GUIContent tile0Splat3Text = new GUIContent("tile0Splat3", "");
public static GUIContent tile0Splat0NormalText = new GUIContent("tile0Splat0Normal", "");
public static GUIContent tile0Splat1NormalText = new GUIContent("tile0Splat1Normal", "");
public static GUIContent tile0Splat2NormalText = new GUIContent("tile0Splat2Normal", "");
public static GUIContent tile0Splat3NormalText = new GUIContent("tile0Splat3Normal", "");
public static GUIContent tile0NormalText = new GUIContent("Global Normal", "Global Normal");
public static GUIContent tile0ControlText = new GUIContent("Global Control", "Global Control");
public static GUIContent specularColorText = new GUIContent("Specular Color", "");
public static GUIContent glossText = new GUIContent("Gloss", "");
public static GUIContent waterTexText = new GUIContent("WaterTex", "");
public static GUIContent waterColorText = new GUIContent("Water Color", "");
public static GUIContent waterSpecColorText = new GUIContent("Water Spec Color", "");
public static GUIContent frenelColorText = new GUIContent("Frenel Color Color", "");
public static GUIContent waterTexMaskText = new GUIContent("Water Tex Mask", "");
public static GUIContent skyboxText = new GUIContent("Skybox", "");
public static GUIContent fresnelTextureText = new GUIContent("Fresnel Texture", "");
public static GUIContent smoothnessText = new GUIContent("Smoothness", "");
public static GUIContent bumpStrengthText = new GUIContent("Bump Strength", "");
public static GUIContent bumpDirectionText = new GUIContent("BumpDirection", "");
public static GUIContent bumpTilingText = new GUIContent("Bump Tiling", "");
public static GUIContent lightDirectionText = new GUIContent("Light Direction", "");
}
MaterialProperty tile0Splat0 = null;
MaterialProperty tile0Splat1 = null;
MaterialProperty tile0Splat2 = null;
MaterialProperty tile0Splat3 = null;
MaterialProperty tile0Splat0Normal = null;
MaterialProperty tile0Splat1Normal = null;
MaterialProperty tile0Splat2Normal = null;
MaterialProperty tile0Splat3Normal = null;
MaterialProperty tile0Normal = null;
MaterialProperty tile0Control = null;
MaterialProperty specularColor = null;
MaterialProperty gloss = null;
MaterialProperty waterTex = null;
MaterialProperty waterColor = null;
MaterialProperty waterSpecColor = null;
MaterialProperty frenelColor = null;
MaterialProperty waterTexMask = null;
MaterialProperty skybox = null;
MaterialProperty fresnelTexture = null;
MaterialProperty smoothness = null;
MaterialProperty bumpStrength = null;
MaterialProperty bumpDirection = null;
MaterialProperty bumpTiling = null;
MaterialProperty lightDirection = null;
MaterialProperty useWater = null;
MaterialEditor m_MaterialEditor;
//private const float kMaxfp16 = 65536f;
//ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, kMaxfp16, 1 / kMaxfp16, 3f);
//bool m_FirstTimeApply = true;
public void FindProperties(MaterialProperty[] props)
{
tile0Splat0 = FindProperty("_tile0Splat0", props);
tile0Splat1 = FindProperty("_tile0Splat1", props);
tile0Splat2 = FindProperty("_tile0Splat2", props);
tile0Splat3 = FindProperty("_tile0Splat3", props);
tile0Splat0Normal = FindProperty("_tile0Splat0Normal", props);
tile0Splat1Normal = FindProperty("_tile0Splat1Normal", props);
tile0Splat2Normal = FindProperty("_tile0Splat2Normal", props);
tile0Splat3Normal = FindProperty("_tile0Splat3Normal", props);
tile0Normal = FindProperty("_tile0Normal", props);
tile0Control = FindProperty("_tile0Control", props);
specularColor = FindProperty("_Specular", props);
gloss = FindProperty("_Gloss", props);
useWater = ShaderGUI.FindProperty("_UseWater", props);
waterTex = FindProperty("_WaterTex", props);
waterColor = FindProperty("_WaterColor", props);
waterSpecColor = FindProperty("_WaterSpecColor", props);
frenelColor = FindProperty("_FrenelColor", props, false);
waterTexMask = FindProperty("_WaterTexMask", props, false);
skybox = FindProperty("_Skybox", props, false);
fresnelTexture = FindProperty("_FresnelTex", props, false);
smoothness = FindProperty("_Smoothness", props, false);
bumpStrength = FindProperty("_Frenel", props, false);
bumpDirection = FindProperty("_BumpDirection", props, false);
bumpTiling = FindProperty("_BumpTiling", props, false);
lightDirection = FindProperty("_SunDir", props, false);
}
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
{
FindProperties(props);
m_MaterialEditor = materialEditor;
Material material = materialEditor.target as Material;
ShaderPropertiesGUI(material);
}
public void ShaderPropertiesGUI(Material material)
{
EditorGUIUtility.labelWidth = 0f;
EditorGUI.BeginChangeCheck();
{
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat0Text, tile0Splat0);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat0NormalText, tile0Splat0Normal);
m_MaterialEditor.TextureScaleOffsetProperty(tile0Splat0);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat1Text, tile0Splat1);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat1NormalText, tile0Splat1Normal);
m_MaterialEditor.TextureScaleOffsetProperty(tile0Splat1);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat2Text, tile0Splat2);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat2NormalText, tile0Splat2Normal);
m_MaterialEditor.TextureScaleOffsetProperty(tile0Splat2);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat3Text, tile0Splat3);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0Splat3NormalText, tile0Splat3Normal);
m_MaterialEditor.TextureScaleOffsetProperty(tile0Splat3);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0NormalText, tile0Normal);
m_MaterialEditor.TextureScaleOffsetProperty(tile0Normal);
m_MaterialEditor.TexturePropertySingleLine(Styles.tile0ControlText, tile0Control);
m_MaterialEditor.ColorProperty(specularColor, Styles.specularColorText.text);
m_MaterialEditor.RangeProperty(gloss, Styles.glossText.text);
EditorGUILayout.Space();
m_MaterialEditor.ShaderProperty(useWater, useWater.displayName);
EditorGUILayout.Space();
DoWater(material);
EditorGUI.BeginChangeCheck();
}
}
void DoWater(Material material)
{
if (useWater.floatValue == 1)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.waterTexText, waterTex);
m_MaterialEditor.ColorProperty(waterColor, Styles.waterColorText.text);
m_MaterialEditor.ColorProperty(waterSpecColor, Styles.waterSpecColorText.text);
m_MaterialEditor.ColorProperty(frenelColor, Styles.frenelColorText.text);
m_MaterialEditor.TexturePropertySingleLine(Styles.waterTexMaskText, waterTexMask);
m_MaterialEditor.TexturePropertySingleLine(Styles.skyboxText, skybox);
m_MaterialEditor.TexturePropertySingleLine(Styles.fresnelTextureText, fresnelTexture);
m_MaterialEditor.RangeProperty(smoothness, Styles.smoothnessText.text);
m_MaterialEditor.RangeProperty(bumpStrength, Styles.bumpStrengthText.text);
m_MaterialEditor.VectorProperty(bumpDirection, Styles.bumpDirectionText.text);
m_MaterialEditor.VectorProperty(bumpTiling, Styles.bumpTilingText.text);
m_MaterialEditor.VectorProperty(lightDirection, Styles.lightDirectionText.text);
material.EnableKeyword("_USEWATER");
}
else
{
material.DisableKeyword("_USEWATER");
}
}
}
}