前言
上篇文章《Matcap Shader 详解【1】 - 基础思想与Unity中实现》中提到 基础Matcap 有很多“缺陷”,其中第一个缺陷是:
- 只适用于单一材质、单一固有色且没有法线贴图细节的模型
本文目的便是讲解一下如何在保留Matcap特性的情况下解决这个缺陷。
固有色贴图与法线贴图
基础Matcap只有光照模型,但没有固有色(Albedo)贴图,这个问题很容易解决,只要把固有色贴图通过“正片叠底”的算法——乘法,与光照信息融合,便可得到“上色”的结果——就像用水彩笔在石膏像上涂鸦一样简单。
如下图所示:
这里还有一点小问题——渲染的结果好像有点暗,其实根本原因在于缺乏高光信息,这个问题我们在下一章节解决。
相比传统光照模型,我们的Matcap目前还少了一个次时代利器——法线贴图。法线贴图的添加相比固有色贴图要复杂一些。
在上一章节的 基础Matcap 中,物体法线是在顶点着色器里计算的,但法线贴图只能在片元着色器里计算,所以算法上有一些改动。
先上源码:
Shader "TJia/Matcap_Albedo_Normal" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex("Albedo Tex", 2D) = "white" {} _BumpMap ("Normal Tex", 2D) = "bump" {} _BumpValue ("Normal Value", Range(0,10)) = 1 _MatCapDiffuse ("MatCapDiffuse (RGB)", 2D) = "white" {} } Subshader { Tags { "RenderType"="Opaque" } Pass { Tags { "LightMode" = "Always" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float4 uv : TEXCOORD0; float3 TtoV0 : TEXCOORD1; float3 TtoV1 : TEXCOORD2; }; uniform float4 _BumpMap_ST; uniform float4 _MainTex_ST; v2f vert (appdata_tan v) { v2f o; o.pos = UnityObjectToClipPos (v.vertex); o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex); o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap); TANGENT_SPACE_ROTATION; o.TtoV0 = normalize(mul(rotation, UNITY_MATRIX_IT_MV[0].xyz)); o.TtoV1 = normalize(mul(rotation, UNITY_MATRIX_IT_MV[1].xyz)); return o; } uniform fixed4 _Color; uniform sampler2D _BumpMap; uniform sampler2D _MatCapDiffuse; uniform sampler2D _MainTex; uniform fixed _BumpValue; float4 frag (v2f i) : COLOR { fixed4 c = tex2D(_MainTex, i.uv.xy); float3 normal = UnpackNormal(tex2D(_BumpMap, i.uv.zw)); normal.xy *= _BumpValue; normal.z = sqrt(1.0- saturate(dot(normal.xy ,normal.xy))); normal = normalize(normal); half2 vn; vn.x = dot(i.TtoV0, normal); vn.y = dot(i.TtoV1, normal); fixed4 matcapLookup = tex2D(_MatCapDiffuse, vn * 0.5 + 0.5); fixed4 finalColor = matcapLookup * c; return finalColor; } ENDCG } } }
左:Matcap_Basic 右:Matcap_Albedo_Normal+法线贴图
说明:
- 相比 Matcap_Basic(见上一章),我们去掉了顶点着色中的 NtoV 向量,因为法线贴图是片元级别的。
- 由于法线贴图基于切线空间,所以这里增加了 TtoV 矩阵(切线空间转化为视觉空间的矩阵),此处用到了 TANGENT_SPACE_ROTATION 中的 rotation,具体定义可在UnityCG.cginc自行查询。
- 在片元着色器中,我们按传统方法对法线贴图进行了解码,然后通过 TtoV 矩阵转化到了视觉空间,此时得到vn(视觉空间中的法线)。
之后的映射上一章中已经讲解,不再赘述,最后得到含有固有色贴图和法线贴图的shader: