效果图:
基于高度的权重混合 , 效果描述:
(1)混合:三层混合, 例如 第一层是草,第二层是石头,第三层是沙子,三者混合显示
(2)权重: 三层的权重的和 为1, 三者是此消彼长的关系
(3)高度:高度会限制或者说是 束缚 着 效果
关于混合,再多说几句:
(1)基于权重的混合:权重 ,跟顺序没有关系 只跟权重的大小有关系(在一层一层界限不清晰的地方,特别适用!!效果极好!!!!)
(2)基于叠加的混合: 叠加 就是 一层一层的往上加。。。。 所以顺序特别重要(在雪地等效果中使用:因为一层一层界限清晰)
接下来是刷图:用顶点色的三个通道来直接影响三个层的权重 或者 用一张BlendMap的三个通道来控制
至于权重是如何计算的,在代码中会详细的贴出来:
下面是绘制的过程截图:
(2)优化: 再补一张 根据高度混合 和 斜率来 叠加的颜色
(用到两个函数: HeightLerp 和 AutoSlope)
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Unlit/BlendCode"
{
Properties
{
_Layer1_BaseColor ("_Layer1_BaseColor", 2D) = "white" {}
_Layer1_HRA("_Layer1_HRA",2D) = "white"{}
_Layer1_Normal("_Layer1_Normal",2D) = "white"{}
_Layer2_BaseColor ("_Layer2_BaseColor", 2D) = "white" {}
_Layer2_HRA("_Layer2_HRA",2D) = "white"{}
_Layer2_Normal("_Layer2_Normal",2D) = "white"{}
_Layer3_BaseColor ("_Layer3_BaseColor", 2D) = "white" {}
_Layer3_HRA("_Layer3_HRA",2D) = "white"{}
_Layer3_Normal("_Layer3_Normal",2D) = "white"{}
_BlendContrast("_BlendContrast",range(0,1)) = 0.1
_SlopeRange("slopeRange",range(0,1)) = 0.69
_HeightContrast("_HeightContrast",range(0,1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 vertexColor : TEXCOORD1;
float4 tTow0 : TEXCOORD2;
float4 tTow1 : TEXCOORD3;
float4 tTow2 : TEXCOORD4;
};
sampler2D _Layer1_BaseColor,_Layer2_BaseColor,_Layer3_BaseColor;
sampler2D _Layer1_HRA,_Layer2_HRA,_Layer3_HRA;
sampler2D _Layer1_Normal,_Layer2_Normal,_Layer3_Normal;
float _BlendContrast;
float _HeightContrast,_SlopeRange;
///基于高度的权重的混合: 核心算法
float3 BlendWeight(float4 vertexColor,float height1,float height2,float height3,float blendContrast)
{
float layer1 = vertexColor.r + height1;
float layer2 = vertexColor.g + height2;
float layer3 = vertexColor.b + height3;
float max12 = max(layer1,layer2);
float maxFactor = max(max12,layer3);
float contrastFactor = maxFactor - blendContrast;
float layer1Value = saturate(layer1 - contrastFactor);
float layer2Value = saturate(layer2 - contrastFactor);
float layer3Value = saturate(layer3 - contrastFactor);
float sumLayerValue = layer1Value + layer2Value + layer3Value;
float weightLayer1 = layer1Value / sumLayerValue;
float weightLayer2 = layer2Value / sumLayerValue;
float weightLayer3 = layer3Value / sumLayerValue;
return float3(weightLayer1,weightLayer2,weightLayer3);
}
/// 高度混合: 根据高度得出的 混合因子
/// transition: 过渡
// height : 高度
/// blendContrast : 混合的对比度
float HeightLerp(float transition,float height,float blendContrast)
{
float lerpFactor = saturate((height - 1.0) + (transition * 2));
float lerpSourceA = 0 - blendContrast;
float lerpSourceB = blendContrast + 1;
float endRes = saturate(lerp(lerpSourceA,lerpSourceB,lerpFactor));
return endRes;
}
自动斜率
float AutoSlope(float3 worldNormal,float slopeRange)
{
float3 up = float3(0,1,0);
float slopeMask = saturate(1 - dot(up ,worldNormal));
slopeMask = pow(slopeMask,slopeRange);
return slopeMask;
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.vertexColor = v.vertexColor;
float3 worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
float3 worldBinormal = cross(worldNormal,worldTangent) * v.tangent.w;
o.tTow0 = float4(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
o.tTow1 = float4(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
o.tTow2 = float4(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 tNormal = UnpackNormal(tex2D(_Layer2_Normal,i.uv));
float3 worldNormal = normalize(float3(dot(i.tTow0.xyz,tNormal),dot(i.tTow1.xyz,tNormal),dot(i.tTow2.xyz,tNormal)));
// sample the texture
fixed4 col1 = tex2D(_Layer1_BaseColor, i.uv);
fixed4 col2 = tex2D(_Layer2_BaseColor, i.uv);
fixed4 col3 = tex2D(_Layer3_BaseColor, i.uv);
float height1 = tex2D(_Layer1_HRA,i.uv).r;
float height2 = tex2D(_Layer2_HRA,i.uv).r;
float height3 = tex2D(_Layer3_HRA,i.uv).r;
float3 blendWeight = BlendWeight(i.vertexColor, height1, height2, height3, _BlendContrast);
float4 endColr = blendWeight.x * col1 + blendWeight.y * col2 + blendWeight.z * col3;
// return endColr;
/// 下面的步骤是根据高度和斜率 做了一个插值: 用高度斜率来控制 endCol 和 陡峭山崖 的颜色
// 这里偷懒了 直接用 endColr 和 第二层的颜色做的插值。
float transition = AutoSlope(worldNormal,_SlopeRange);
float heightLerpFactor = HeightLerp(transition,blendWeight,_HeightContrast);
float4 col = lerp(endColr,col2,heightLerpFactor);
return col;
}
ENDCG
}
}
}