点击量:384

Github

https://github.com/l2xin/ZT_ShaderLearning/tree/master/Assets/L2xin/005_MatcapBase


Matcap是什么

Unity Community Wiki上的定义:

MatCap (Material Capture) shader, for displaying objects with reflective materials with uniform surface colouring, like Zbrush or Mudbox can. It uses an image of a sphere as a view-space environment map. It’s very cheap, and looks great when the camera doesn’t rotate.

qianmo的文章:

MatCap Shader的基本思路是,使用某特定材质球的贴图,作为当前材质的视图空间环境贴图(view-space environment map),来实现具有均匀表面着色的反射材质物体的显示。考虑到物体的所有法线的投影的范围在x(-1,1),y(-1,1),构成了一个圆形,所以MatCap 贴图中存储光照信息的区域是一个圆形。基于MatCap思想的Shader,可以无需提供任何光照,只需提供一张或多张合适的MatCap贴图作为光照结果的“指导”即可。


效果gif


Matcap优缺点

优点

运算效率极高,计算成本极低,在很多场合却能够替代PBR。用Unlit级别的计算成本,获得3A级的渲染效果。

简单情况:只需简单更换Matcap贴图就能实现各种神奇的渲染效果。

复杂模型:可以通过几张简单的Matcap贴图组合来实现模型上各部位细节差异。

缺点

Matcap无法响应光源与相机位置的变化,原因很简单——Matcap采样贴图是静态的,通过相机空间映射的。


Matcap贴图获取

一般可以在Zbrush/MarmosetToolbag等软件中自己制作。

也可以在网上直接下载一些别人制作好的(pinterest.com有非常多):

在这里插入图片描述


Shaderlab实现

第一种:

v2f vert (a2v v)
{
    v2f o;
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.viewNormal = mul(UNITY_MATRIX_IT_MV, v.normal);
    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed4 matcapColor = tex2D(_MatcapTex, i.viewNormal.xy* 0.5 + 0.5);
    return col * matcapColor;
}

第二种:

v2f vert (a2v v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);

    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
    viewNormal = mul((float3x3)UNITY_MATRIX_V, worldNormal);
    o.matcapUV = viewNormal.xy * 0.5 + 0.5;

    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed4 matcapColor = tex2D(_MatcapTex, i.matcapUV);
    return col * matcapColor;
}

UNITY_MATRIX_IT_MV

把normal转换到view视图以获得一个(-1,1)区间的数值:

o.viewNormal = mul(UNITY_MATRIX_IT_MV, v.normal);

首先,看一下Unity Doc中的描述:

||||
|-|-|-|
UNITY_MATRIX_IT_MV |float4x4 |Inverse transpose of model * view matrix.

然后我们来看一下UNITY_MATRIX_IT_MV实际的变换意义:

The transpose of World2Object is the transpose of the inverse of the Object2World matrix.

  • MV transforms points from object to eye space
  • IT_MV rotates normals from object to eye space

And similarly:

  • Object2World transforms points from object to world space
  • IT_Object2World (which, as you point out, is the transpose of World2Object) rotates normals from object to world space

If it is orthogonal, the upper-left 3×3 of Object2World will be equal to that of IT_Object2World, and so will also rotate normals from object to world space.

之所以法线不能直接使用UNITY_MATRIX_MV进行变换,是因为法线是向量,具有方向,在进行空间变换的时候,如果发生非等比缩放,方向会发生偏移。我们可以简单的把法线和切线当成三角形的两条边,显然,三角形在空间变换的时候,不管是平移,还是旋转,或者是等比缩放,都不会变形,但是如果非等比缩放,就会发生拉伸。所以法线和切线的夹角也就会发生变化。(而切线在变换前后,方向总是正确的,所以法线方向就不正确了)。

结论

对顶点Object2View变换使用MV矩阵,对normal变换使用IT_MV矩阵。

公式

  • 顶点变换矩阵:\vec{M}

  • 法向量变换矩阵: \vec{G} = ({\vec{M}^{-1}})^{T}

详细推导过程

Normal Matrix – 对法向量(Normal)的变换矩阵的推导


其他

如何利用Matcap实现基本PBR光照模型以及混合材质还没尝试,后面和TA交流请教一下。


参考