# 【MatCap】
材质捕捉(material capture)简称 MatCap。
预先计算单个摄像机角度的渲染结果,映射于模型上。
摄像机空间的法线 的x和y 作为坐标
优点:
- 运算速度快。
- 不需要光照,但需要光照贴图。
- 让移动设备也能显示高质量高性能的效果。
缺点:摄像机一旦切换角度,则会穿帮。
适用情景:
- 换装游戏。
- 商城角色展示。
- 等固定摄像机角度的情况。
Shader "AP01/L09/Matcap" {
Properties {
_NormalMap ("法线贴图", 2D) = "bump" {}
_Matcap ("Matcap", 2D) = "gray" {}
_FresnelPow ("菲涅尔次幂", Range(0, 10)) = 1
_EnvSpecInt ("环境镜面反射强度", Range(0, 5)) = 1
}
SubShader {
Tags {
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
// 输入参数
uniform sampler2D _NormalMap;
uniform sampler2D _Matcap;
uniform float _FresnelPow;
uniform float _EnvSpecInt;
// 输入结构
struct VertexInput {
float4 vertex : POSITION; // 顶点信息
float2 uv0 : TEXCOORD0; // uv信息
float3 normal : NORMAL; // 法线信息
float4 tangent : TANGENT; // 切线信息
};
// 输出结构
struct VertexOutput {
float4 pos : SV_POSITION; // 屏幕顶点位置
float2 uv0 : TEXCOORD0; // uv信息
float4 posWS : TEXCOORD1; // 世界顶点位置
float3 nDirWS : TEXCOORD2; // 世界法线方向
float3 tDirWS : TEXCOORD3; // 世界切线方向
float3 bDirWS : TEXCOORD4; // 世界副切线方向
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; // 新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex );
o.uv0 = v.uv0; // 传递uv信息
o.posWS = mul(unity_ObjectToWorld, v.vertex); // 顶点位置 OS>WS
o.nDirWS = UnityObjectToWorldNormal(v.normal); // 法线方向 OS>WS
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 切线方向 OS>WS
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w); // 根据nDir tDir求bDir
return o; // 将输出结构 输出
}
// 输出结构>>>像素
float4 frag(VertexOutput i) : COLOR {
// 准备向量
float3 nDirTS = UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb;
float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
float3 nDirWS = normalize(mul(nDirTS, TBN)); // 计算nDirVS 计算Fresnel
float3 nDirVS = mul(UNITY_MATRIX_V, nDirWS); // 计算MatcapUV
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz); // 计算Fresnel
// 准备中间变量
float vdotn = dot(vDirWS, nDirWS);
float2 matcapUV = nDirVS.rg * 0.5 + 0.5;
// 光照模型
float3 matcap = tex2D(_Matcap, matcapUV);
float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);
float3 envSpecLighting = matcap * fresnel * _EnvSpecInt;
// 返回值
return float4(envSpecLighting, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
两张matcap贴图示例。