大家好,我是阿赵
之前介绍过各种光照模型的实现方法。那些光照模型的实现虽然有算法上的不同,但基本上都是灯光方向和法线方向的计算得出的明暗结果。
下面介绍一种叫做MatCap的模拟光照效果,这种方式计算非常简单,脱离灯光的计算,并可以实现比较好的高光阴影效果。
一、什么是MatCap
1、MatCap的介绍:
MatCap是Material Capture的缩写,意思是“材质捕获”。
听名字好像很高端并且深奥,实际上却并不是什么很深奥的东西。
MatCap贴图的样子一般是这样的:
2、MatCap的实现原理
MatCap实现的原理很简单,把物体的世界空间法线,转换到观察空间,然后用这个值作为UV,采样MatCap贴图。所以,如果当物体是一个球体的时候,它的法线角度应该是刚刚好和MatCap贴图完全一样,所以,如果把MatCap材质赋给一个球体,它应该是会得到和MatCap贴图一样的效果,比如我拿上面那张MatCap贴图放到MatCap材质球里面,会得到这样的效果:
如果物体不是一个球形,由于各个面的法线变化,所以会得到这样的效果:
不过如果直接算世界法线转观察空间法线,会存在一个问题,如果物体偏离视窗中心点之后,会在物体边缘出现一些奇怪的颜色
这是因为我们的MatCap贴图只有中间圆形绘制了光影颜色,在贴图的边缘的颜色是不对的
在计算观察空间的时候,如果偏离屏幕中心点太多,会不小心采样到了贴图的边缘。
要解决这个问题其实也很简单,给算出来的MatCap的UV用一个变量来控制一下缩放,让UV坐标不要超出一定范围就行了。
二、MatCap实现的代码
下面是Unity引擎的shader
Shader "AzhaoMatCap"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_MatCapTex("MatCapTex", 2D) = "white" {}
_MatCapIntensity("MatCapIntensity",Range(0,2)) = 1
_MatCapPow("MatCapPow",Range(0,5)) = 1
_MatCapUVScale("MatCapUVScale",Range(0,1)) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal:TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _MatCapTex;
float _MatCapIntensity;
float _MatCapPow;
float _MatCapUVScale;
float2 GetMatCapUV(float3 objNormal)
{
float3 normalWorld = mul(unity_ObjectToWorld, objNormal);
float3 normalView = mul(UNITY_MATRIX_IT_MV, normalWorld);
return normalView.xy*0.5+0.5;
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal = v.normal;
return o;
}
float4 frag (v2f i) : SV_Target
{
// sample the texture
float4 col = tex2D(_MainTex, i.uv);
float2 MatCapUV = GetMatCapUV(i.normal)*_MatCapUVScale;
float4 MatCapCol = tex2D(_MatCapTex, MatCapUV)*_MatCapIntensity;
MatCapCol = pow(MatCapCol, _MatCapPow);
float3 finalCol = col.rgb*MatCapCol.rgb;
return float4(finalCol,col.a);
}
ENDCG
}
}
}
代码很简单,通过法线方向获取MatCap的UV,都写在GetMatCapUV方法里面了,就2、3行代码而已。
然后我个人习惯,为了控制一个叠加颜色的强度和对比度,我都是先乘再pow。
最后再给了一张MainTex贴图,作为混合固有色的例子。
三、MatCap的优缺点和应用
1、优点
1.比起真实的光照模型,MatCap计算量很少,只是算个UV采样一张贴图就可以了
2.光照效果非常的可控,可以自己绘制喜欢的高光、阴影和补光的效果
在固定摄像机角度和光照方向的情况下,用MatCap模拟物体的材质,通过使用不同的MatCap贴图,可以达到很强的质感
2、缺点
MatCap的缺点也很明显,因为它的光照效果是假的,所以从不同的角度观察物体,它的光照是不会变化的,也不能做到跟随灯光旋转变化而变化。
所以MatCap的效果一般只能用于固定摄像机和灯光角度的情况下。
3、应用
下面换了几张不同的MatCap贴图,可以看出,物体有了非常强的质感。
上面的shader代码里面,我最后是用乘法来和MainTex颜色叠加,是因为我想MatCap同时产生亮部和暗部的效果。其实我们也可以单纯用MatCap来叠加某个部分的效果,比如,可以改成用加法,然后MatCap贴图只绘制高光部分,其余部分都涂黑。这样我们可以通过MatCap来单纯的叠加高光部分,然后暗部使用烘焙贴图或者顶点颜色来实现,也是可以的。
虽然说MatCap只能用于固定角度,但如果通过贴图遮罩,只限于模型的某些小局部的金属之类强高光的地方显示,其实也能在模型转动或者运动的时候,产生比较不错的质感。
MatCap的其他应用,各位可以再发挥一下想象力。