
Matcap Shader是一种在某些层面能替代甚至超越PBR的次世代渲染方案。
Matcap,全称为Material Capture,翻译过来就是材质捕获。简单来说就是预先生成的一种存储了光照和反射等信息的贴图,运行时使用法线方向进行采样。Matcap仅对于固定相机视角的情况较好,这也是Matcap的原理决定的。
Matcap的原理
物体的法线是三维的,采样的贴图是二维的,所以我们需要去掉一个维度。在相机空间下的物体法线,我们可以不考虑Z轴的指向,即不考虑Z轴本身对屏幕空间的XY平面的贡献。因为法线是一个单位向量,如果法线在XY方向上的投影权重很大,那么说明在Z方向的权重就很小,对应到二维的Matcap上采样的位置越靠近边缘;而如果法线在XY方向的投影权重很小,那么Z方向的权重就很大,对应到二维的Matcap上的采样位置就越靠近中心。
Shader "Custom/MatcapShader"
{
Properties
{
_MatcapTex ("Matcap Tex", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 matcapuv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MatcapTex;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
//UNITY_MATRIX_IT_MV 用于 将法线从模型空间转化到视觉空间
//乘以逆转置矩阵将normal变换到视空间
float3 viewnormal = mul(UNITY_MATRIX_IT_MV, v.normal);
//需要normalize一下,否则保证normal处在(-1,1)区间,否则有scale的object效果不对
viewnormal = normalize(viewnormal);
o.matcapuv = viewnormal.xy * 0.5 + 0.5;
//如果缩放模型,这种方式会出现问题,一定要保证ViewNormal处在(-1,1)区间
//o.matcapuv.x = mul(UNITY_MATRIX_IT_MV[0], v.normal) * 0.5 + 0.5;
//o.matcapuv.y = mul(UNITY_MATRIX_IT_MV[1], v.normal) * 0.5 + 0.5;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MatcapTex, i.matcapuv);
return col;
}
ENDCG
}
}
}
网友评论