Unity Shader 学习 MatCap
简介
MatCap全称MaterailCapture,纹理存储光照信息,通过法线的xy分量去采样MatCap纹理,得到在该方向法线的光照信息,性能好,但表现依靠于纹理制作的好坏。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| 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; 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); o.twoUv.zw = UnityObjectToWorldNormal(v.normal).xy; o.twoUv.zw = o.twoUv.zw * 0.5 + 0.5; float3 wolrdN = UnityObjectToWorldNormal(v.normal); o.RefDir = reflect(-WorldSpaceViewDir(v.vertex), wolrdN); return o; } fixed4 frag (v2f i) : SV_Target { 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的图是圆的?
物体的法线归一化之后可能朝向各个方向(忽略背面),以顶点为原点,朝向各个方向,就会形成一个半圆。
为什么直接就可以使用法线的xy就可以做uv呢?
参考
[1] 尝试MatCap类型shader
[2] 对SSS Matcap贴图的研究 - Chain
[3] MatCaps - A huge library of MatCap textures in PNG and ZMT. - github
[4] Matcap Shader 详解【6】-平面渲染与更佳的反射// 需要学习一下
[5] matcap 的制作与渲染