嘗試MatCap類型shader


聽說MatCap能在低端機上做出很漂亮的pbr效果,就嘗試了一下。

MatCap全稱MaterailCapture,里面存的是光照信息,通過法線的xy分量去采樣matcap,得到在該方向法線的光照信息,因為不是實時光照,所以性能好,好不好看就看你的Matcap做得好不好了。下面是簡單的matcap嘗試:

Shader "Unlit/SimpleMatCapShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _MatCap("MatCap", 2D) = "white" {}
        _MatCapFactor("MatCapFactor", Range(0,5)) = 1
        _EnvTex("EnvTex (CubeMap)", Cube) = "_SkyBox" {}
        _EnvFactor("EnvStrength", Range(0,1)) = 0.8
    }

    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
            {
                float4 twoUv : TEXCOORD0;//主紋理uv存xy,matCapUv存在zw,這算一種優化
                float4 vertex : SV_POSITION;
                float3 RefDir : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _MatCap;
            half _MatCapFactor;
            samplerCUBE _EnvTex;
            half _EnvFactor;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.twoUv.xy = TRANSFORM_TEX(v.uv, _MainTex);
                //matcap存的其實是:法線中xy分量作為uv,對應的光照顏色信息,即用xy去采樣就好,注:xy必須是歸一化法線中的分量,故z才沒必要
                o.twoUv.zw = UnityObjectToWorldNormal(v.normal).xy;
                o.twoUv.zw = o.twoUv.zw * 0.5 + 0.5;//(-1,1)->(0,1)
                float3 wolrdN = UnityObjectToWorldNormal(v.normal);
                o.RefDir = reflect(-WorldSpaceViewDir(v.vertex), wolrdN);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.twoUv.xy);
                fixed4 mapCapCol = tex2D(_MatCap, i.twoUv.zw);
                fixed4 reflection = texCUBE(_EnvTex, i.RefDir);
                col.rgb = col.rgb * mapCapCol.rgb * _MatCapFactor + reflection.rgb * _EnvFactor;
                return col;
            }
            ENDCG
        }
    }
}

各種效果如下:

matCap貼圖的獲取:

這邊提供幾個可以獲取MatCap貼圖的網址:

[1] https://www.pinterest.com/evayali/matcap/

[2]https://www.google.com.hk/search?q=MatCap&newwindow=1&safe=strict&hl=zh-CN&biw=1575&bih=833&tbm=isch&tbo=u&source=univ&sa=X&ved=0ahUKEwju8JDTpZnSAhUGn5QKHawODTIQsAQIIg

[3]http://pixologic.com/zbrush/downloadcenter/library/#prettyPhoto

 

總結,如果matcap做得好,確實能得到非常漂亮的效果,關鍵是,只是多一張tex就能獲得如此效果,不錯不錯。

  許多資料都沒有講到,但我個人以為,matcap其實是繽紛多彩的高光效果。普通高光一般是單一的白色,或其他單色,matcap因為用圖片存不同“斜率”的法線的高光顏色,所以可以做得更加漂亮,這個可以看下圖:

                            

                                一個matcap紋理圖

               (因為法線先x,y,z歸一化(一個單位球體),后取其中的x,y采用,所以[x,y]必定束縛在圓中,

                        所以matcap都是圓,即使不是,也只有圓內紋理有效)

從上面shader可知我們先把法線從[-1,1]映射到[0,1]后再采樣,這個是由於matcap坐標是從0開始的,為了更加直觀的理解,我們反其道行之:

  把matcap圖片的坐標從[0,1]映射到[-1,1]。

則,明顯地,圖片中間就是[0,0],即普通笛卡爾坐標系的原點,此時,法線區間是[-1,1],matcap圖的坐標區間也是[-1,1],一一對應,每個像素的法線根據其大小和方向在matcap圖中取值,得到的就是這個像素的高光顏色,這樣,matcap的效果也變得很直觀了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM