尝试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/
[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的效果也变得很直观了。