钢铁侠Unlit光照Shader,三种效果变化
返回目录
大家好,我是阿赵,这里是钢铁侠材质制作第二部分,线条轮廓部分的制作
为了实现这个效果,可以把细节拆分成以下几个部分:
1、轮廓光
1.效果分析
这是一个很基础的轮廓光实现,用到的就是法线和观察方向的点乘(NdotV)。
2.shader实现
Shader "azhao/IronManBodyCode"
{Properties{_RimBias("RimBias", Float) = 1_RimPow("RimlPow", Float) = 2_RimlCol("RimCol", Color) = (0,0,0,0)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldPos :TEXCOORD0;float3 worldNormal : TEXCOORD1;};float _RimBias;float _RimPow;float4 _RimlCol;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldPos = mul(unity_ObjectToWorld, v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);return o;}half4 frag (v2f i) : SV_Target{float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));float NdotV = dot(i.worldNormal, worldViewDir);float fresnelVal = pow((1 - NdotV)*_RimBias, _RimPow);half4 col = _RimlCol* fresnelVal;return col;}ENDCG}}
}
3.说明
这个其实就是菲涅尔的标准算法,在1-NdotV后,乘以一个bias值控制边缘光的强度,再计算一个Pow运算,控制边缘光的边缘厚度。
2、添加横纹
1.效果分析
看到这个效果,可能很多人都在考虑怎样画这个横纹的贴图。其实这个实现方式很巧妙,只需要一张Noise噪声图就可以了。
2.shader实现
Shader "azhao/IronManBodyCode"
{Properties{_RimBias("RimBias", Float) = 1_RimPow("RimlPow", Float) = 2_RimlCol("RimCol", Color) = (0,0,0,0)_NoiseMap("NoiseMap",2D) = "black"{}_NoiseTiling("NoiseTiling",Vector) = (1,1,0,0)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldPos :TEXCOORD0;float3 worldNormal : TEXCOORD1;};float _RimBias;float _RimPow;float4 _RimlCol;sampler2D _NoiseMap;float4 _NoiseTiling;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldPos = mul(unity_ObjectToWorld, v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);return o;}half4 frag (v2f i) : SV_Target{float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));float NdotV = dot(i.worldNormal, worldViewDir);float fresnelVal = pow((1 - NdotV)*_RimBias, _RimPow);float2 noiseUV = i.worldPos.xy *_NoiseTiling.xy + _NoiseTiling.zw;float4 noiseCol = tex2D(_NoiseMap, noiseUV);half4 col = _RimlCol * (fresnelVal+noiseCol.r);return col;}ENDCG}}
}
3.说明
这里多添加了一张Noise贴图
由于我们想要的横纹是永远水平于世界空间,并不是希望会随着角色的动作而变形的,所以我这里并没有使用模型本身的UV坐标来采样,而是使用了模型的顶点世界坐标的xy坐标来模拟了UV坐标,并且添加了一个Tiling值来控制Noise贴图的平铺次数。
如果不调整参数的情况下,添加Noise到材质球,会看到下面的效果。
虽然这个效果看起来也很cool,但并不是我想要的效果,所以再调整一下Tiling值
把平铺y值调大,这个时候,就可以看到,Noise图就变成了横纹了。
3、横纹动画
我希望在显示这个光线轮廓的过程中,身上的横纹是有一个慢慢上升的动画效果的
这个实现起来很简单,只需要给Noise图的uv做一个偏移就可以了,这里用到了_Time,根据时间来让UV偏移。
float2 noiseUV = i.worldPos.xy _NoiseTiling.xy + _NoiseTiling.zw;
noiseUV.y += frac(_Time.y)_NoiseSpeed;
这里还加了一个frac函数,frac函数的作用是去掉数值的整数部分只保留小数部分。由于某些设备的数值精度支持范围有问题,如果_Time不停的累加,达到很大的值时,可能会出问题。所以加一个frac函数让它的值只使用小数部分。
4、完整shader
Shader "azhao/IronManBodyCode"
{Properties{_RimBias("RimBias", Float) = 1_RimPow("RimlPow", Float) = 2_RimlCol("RimCol", Color) = (0,0,0,0)_NoiseMap("NoiseMap",2D) = "black"{}_NoiseTiling("NoiseTiling",Vector) = (1,1,0,0)_NoiseSpeed("NoiseSpeed",float) = 0}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldPos :TEXCOORD0;float3 worldNormal : TEXCOORD1;};float _RimBias;float _RimPow;float4 _RimlCol;sampler2D _NoiseMap;float4 _NoiseTiling;float _NoiseSpeed;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldPos = mul(unity_ObjectToWorld, v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);return o;}half4 frag (v2f i) : SV_Target{float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));float NdotV = dot(i.worldNormal, worldViewDir);float fresnelVal = pow((1 - NdotV)*_RimBias, _RimPow);float2 noiseUV = i.worldPos.xy *_NoiseTiling.xy + _NoiseTiling.zw;noiseUV.y += frac(_Time.y)*_NoiseSpeed;float4 noiseCol = tex2D(_NoiseMap, noiseUV);half4 col = _RimlCol * (fresnelVal+noiseCol.r);return col;}ENDCG}}
}