在上一个文章中,使用的shader仍有可以改进的地方。
上一篇中并没有没有对硬边缘做可调整的操作(可以通过参数调整过渡值),同时因为我们不需要对高光进行过渡处理,没有对高光值做Power处理,这会使得高光值的变化不够满足需求,这次加上,同时,我想让渲染效果更佳漂亮,于是决定对于明暗交界线处的颜色增加饱和度,有很多二次元的画师的画中都有表现这一点。
我们看看这次的完成效果。(由于录制gif图的话,很大放不下,于是就以图片的形式看看吧)
明暗分割线处,会采样当前纹理的颜色,增加饱和度。
想要使得边缘变得可以过渡,我们将使用smoothstep来替代step。
smoothstep(x,y,z);(z为漫反射的值)
当y>z>x时,结果z在0-1之间的插值,
当z
一般来说会取x和y为相反数。x,y的绝对值决定了过渡的强度因为[x,y]这个区间的长度决定了插值结果的长度。
float BDedge=(1-smoothstep(-_BDsmooth,_BDsmooth,abs(diffuseV-_BDEdgePos)-_BDEdge));
先来梳理下各变量表达的意思:
diffuseV指的是光方向向量点乘法向量的结果,取值范围是(-1,1)。
有一定数学基础的应该能理解,abs(x-y)绝对值函数,的含义是x和y之间的距离。
在这里指的就是当前的漫反射值与明暗交界线的漫反射值的差值。
于是smoothstep现在表示的意思就是,距离比_BDsmooth这个值要大的设置为1(白色),小于_BDsmooth的设置为1-0之间的差值,而绝对值是一直大于0的,故不会小于-_BDsmooth(假设_BDsmooth不是负数),从而形成了一条可过渡的线在物体上,可以通过_BDEdgePos调整明暗交界线的位置。
最后我们要把这个值用一减去从而得到黑白颠倒的图形,因为我们希望明暗交界线是白色(1,1,1,1)的这样就能和颜色值相乘,同时两边为黑色(0,0,0,0)就不会对其他区域产生影响。
个人对饱和度的理解是,灰阶的rgb+不完全的rgb数值:
在这里插入图片描述
取一个颜色中数值最低的那位,如图即r通道,生成一个灰度rgb即各通道值相同,于是生成了(0.2,0.2,0.2)的向量,然后我们再用原值减去这个值就能够得到不带灰阶的颜色。此时如果把减去后的值乘上一个大于1的常数就能提升饱和度。
在UnityShader中提供了我们float Luminance(fiexd4 color);方法来轻松获取物体的明度。
下面提供完整代码,注意要附上光照贴图,否则会发生高光不可改变的表现
Shader "Unlit/anim2"
{
Properties
{
_MainTex ("主贴图", 2D) = "white" {}
_LightTex("高光贴图",2D)="white"{}
_BaseColor("叠加色",Color)=(1,1,1,1)
_DarkSideEdge("暗部范围",Range(-1,1))=0
_DarksideSmooth("暗部边缘过渡",Range(0,1))=0
_DarkSideBrightness("暗部亮度",Range(0,1))=1
_HighLightEdge("高光范围",Range(-1,1))=0
_HighLightSmooth("高光过渡",Range(0,1))=0.1
_HighLightPower("高光Power值",Range(1,86))=1
_BDEdge("明暗分割线范围",Range(0,1))=0
_BDEdgePos("明暗分割线位置",Range(-1,1))=0
_BDsmooth("明暗分割线过渡",Range(0,1))=0
_BDColorValue("明暗分割线饱和值",Range(0,10))=0
_Factor("描边宽度",Range(0,1)) = 0.01
_OutLineColor("描边颜色",Color) = (0,0,0,1)
}
SubShader
{
Tags { "RenderType"="ForwardBase" }
LOD 100
Pass
{
Cull Front //剔除前面
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 vertex :POSITION;
};
float _Factor;
half4 _OutLineColor;
v2f vert(appdata_full v)
{
v2f o;
//将顶点沿法线方向向外扩展一下
float4 pos=v.vertex+float4(v.normal*_Factor,1.0);
o.vertex=UnityObjectToClipPos(pos);
return o;
}
half4 frag(v2f v) :COLOR
{
//只显示描边的颜色
return _OutLineColor;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
float _BDEdge;
float _HighLightSmooth;
float _DarksideSmooth;
float _BDsmooth;
float4 _BDEdgeColor;
float _BDEdgePos;
float _DarkSideEdge;
sampler2D _MainTex;
sampler2D _LightTex;
float4 _MainTex_ST;
float4 _LightTex_ST;
fixed4 _BaseColor;
float _DarkSideBrightness;
float _HighLightEdge;
float _BDColorValue;
float _HighLightPower;
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv:TEXCOORD0;
};
struct v2f
{
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
float2 uvlight:TEXCOORD3;
float4 vertex : POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;//获取世界空间的顶点位置
o.worldNormal=mul(unity_ObjectToWorld,v.normal);//获取世界空间的法线向量
o.uv=TRANSFORM_TEX(v.uv,_MainTex);
o.uvlight=TRANSFORM_TEX(v.uv,_LightTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 lightTex=tex2D(_LightTex,i.uvlight);
float3 lightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
float3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
// sample the texture
float3 worldNormal=normalize(i.worldNormal);
float diffuseV=dot(worldNormal,lightDir);
fixed4 surfacecolor=tex2D(_MainTex,i.uv)*_BaseColor;
float diffStep=smoothstep(-_DarksideSmooth,_DarksideSmooth,diffuseV-_DarkSideEdge);
float BDedge=(1-smoothstep(-_BDsmooth,_BDsmooth,abs(diffuseV-_BDEdgePos)-_BDEdge));//技术难题1:如何移动此光圈的位置
float tmp=1-diffStep;
float ds=tmp*_DarkSideBrightness;
float highLightV=pow(dot(viewDir,reflect(-lightDir,worldNormal)),_HighLightPower);
float hlvSp=smoothstep(-_HighLightSmooth,_HighLightSmooth,highLightV-_HighLightEdge);
float bv=Luminance(surfacecolor);
fixed4 bv4=fixed4(bv,bv,bv,0);
fixed4 dsColor=(UNITY_LIGHTMODEL_AMBIENT+ds*surfacecolor*_BaseColor);
return (_LightColor0*surfacecolor*diffStep+dsColor+hlvSp*fixed4(1,1,1,1)*_LightColor0*fixed4(lightTex,1))+BDedge*(surfacecolor-bv4)*_BDColorValue;
}
ENDCG
}
}
Fallback "Specular"
}