钢铁侠Unlit光照Shader,三种效果变化
返回目录
大家好,我是阿赵。这里是钢铁侠材质制作的第四部分,反射效果叠加。
我一直说光照模型的构成是
环境光+漫反射+高光。
其实最后一个高光,应该理解成是光线的反射。
所以最后光照模型的构成就变成了
环境光+漫反射+光线反射颜色
在之前的基础光照模型的漫反射和高光颜色之后,这一步需要加入反射的效果。
光线反射的实现有很多种,比如像Unity引擎官方例子的水面反射,或者是用CubeMap、反射探针(reflection probe)等都是可以的。
由于这个综合的例子本身已经有点复杂,出于性能考虑,这里选用了MatCap作为模拟反射的手段。为了能让模型的边缘有一些类似于补光的效果,所以我还加入了一点边缘光。
怎样使用MatCap材质之前已经介绍过,这里也不再多说,先看看效果,然后直接上代码。
这里主要使用了2张贴图,一张是金属感比较强的MatCap材质,另外一张是之前用的高光遮罩贴图的G通道。
可以看到,加了MatCap模拟反射之后,模型的细节会变得更加的丰富。
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
_AmbientStength("AmbientStength",float) = 1
_MainTex("BaseCol",2D) = "white"{}
_NormalMap("NormalMap",2D) = "black"{}
_NormalScale("NormalScale",float) = 1
_SpecCol("SpecCol",Color) = (1,1,1,1)
_Shininess("_Shininess",float) = 1
_SpecStength("SpecStength",float) = 1
_SpecMask("SpecMask",2D) = "white"{}
_MatCapTex("_MatCapTex",2D) = "black"{}
_MatCapStength("MatCapStength",float) = 1
_MatCapPow("MatCapPow",float) = 2
_RimAddStength("RimAddStength",float) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//简化版的转换法线并缩放的方法
half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
{
half3 normal;
//由于法线贴图代表的颜色是0到1,而法线向量的范围是-1到1
//所以通过*2-1,把色值范围转换到-1到1
normal = packednormal * 2 - 1;
//对法线进行缩放
normal.xy *= bumpScale;
//向量标准化
normal = normalize(normal);
return normal;
}
//获取HalfLambert漫反射值
float GetHalfLambertDiffuse(float3 worldPos, float3 worldNormal)
{
float3 lightDir = UnityWorldSpaceLightDir(worldPos);
float NDotL = saturate(dot(worldNormal, lightDir));
float halfVal = NDotL * 0.5 + 0.5;
return halfVal;
}
//获取BlinnPhong高光
float GetBlinnPhongSpec(float3 worldPos, float3 worldNormal,float shininess)
{
float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
float3 halfDir = normalize((viewDir + _WorldSpaceLightPos0.xyz));
float specDir = max(dot(normalize(worldNormal), halfDir),0);
float specVal = pow(specDir, shininess);
return specVal;
}
float2 GetMatCapUV(float3 normalWorld)
{
float3 normalView = mul(UNITY_MATRIX_IT_MV, normalWorld);
return normalView.xy*0.5 + 0.5;
}
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldPos :TEXCOORD1;
float3 worldNormal : TEXCOORD2;
float3 worldTangent :TEXCOORD3;
float3 worldBitangent : TEXCOORD4;
};
float _RimBias;
float _RimPow;
float4 _RimlCol;
sampler2D _NoiseMap;
float4 _NoiseTiling;
float _NoiseSpeed;
sampler2D _MainTex;
sampler2D _NormalMap;
float _NormalScale;
float _AmbientStength;
float4 _SpecCol;
float _Shininess;
float _SpecStength;
sampler2D _SpecMask;
sampler2D _MatCapTex;
float _MatCapStength;
float _MatCapPow;
float _RimAddStength;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldTangent = UnityObjectToWorldDir(v.tangent);
o.worldBitangent = cross(o.worldNormal, o.worldTangent);
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 RimLineRGBA = _RimlCol * (fresnelVal+noiseCol.r);
*/
half4 RimRGBA = _RimlCol * fresnelVal*_RimAddStength;
half4 baseCol = tex2D(_MainTex,i.uv);
half4 normalCol = tex2D(_NormalMap, i.uv);
//得到切线空间的法线方向
half3 normalVal = UnpackScaleNormal(normalCol, _NormalScale).rgb;
//构建TBN矩阵
float3 tanToWorld0 = float3(i.worldTangent.x, i.worldBitangent.x, i.worldNormal.x);
float3 tanToWorld1 = float3(i.worldTangent.y, i.worldBitangent.y, i.worldNormal.y);
float3 tanToWorld2 = float3(i.worldTangent.z, i.worldBitangent.z, i.worldNormal.z);
//通过切线空间的法线方向和TBN矩阵,得出法线贴图代表的物体世界空间的法线方向
float3 worldNormal = float3(dot(tanToWorld0, normalVal), dot(tanToWorld1, normalVal), dot(tanToWorld2, normalVal));
float diffuseVal = GetHalfLambertDiffuse(i.worldPos, worldNormal);
float4 specMaskVal = tex2D(_SpecMask, i.uv);
float specVal = GetBlinnPhongSpec(i.worldPos, worldNormal, _Shininess)*specMaskVal.r*_SpecStength;
float2 MatCapUV = GetMatCapUV(worldNormal);
float4 MatCapCol = pow(tex2D(_MatCapTex, MatCapUV)*_MatCapStength*specMaskVal.g, _MatCapPow);
half3 finalRGB = UNITY_LIGHTMODEL_AMBIENT * _AmbientStength + baseCol.rgb*diffuseVal+ _SpecCol.rgb*specVal + MatCapCol+ RimRGBA.rgb;
return half4(finalRGB,1);
}
ENDCG
}
}
}