Unity法向贴图NormalMap-01

一、法向贴图(Normal Map)

  • 作用:从游戏性能考虑,高维模型->低位模型的转换,由于减少了模型平面数量,将大大提高渲染性能,但是这样的转换将丢失细节,如模型上的纹理,模型的凸起与凹陷等。我们可以将平面上各像素点的法线方向(x,y,z)转换为像素值(R,G,B)进行保存,即法线贴图。这样可以在低模模型中,尽可能地还原高模模型的光影细节,同时也保证了渲染性能
  • 下面这个视频简明介绍了法线贴图:【游戏开发基础知识】深入了解法线贴图
  • 效果对比(无法向贴图):

  • 效果对比(添加法向贴图):

  • 转载自文章Unity Shader - Normal map (Bump mapping) 法线贴图(凹凸映射)

二、法线贴图的shader编程

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
Shader "DC/Shader/ShaderDemo/NormalMap"
{
Properties
{
[Toggle] _UseNormalMap("UseNormalMap",float) = 0
_MainTex ("Texture", 2D) = "white" {}
_NormalMap ("NormalMap", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma shader_feature _USENORMALMAP_ON

#include "UnityCG.cginc"
#include "Lighting.cginc"

struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
float4 tangent : TEXCOORD1;
float4 normal : TEXCOORD2;
};

struct v2f
{
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 lightDir : TEXCOORD1;
float4 TtoW0 : TEXCOORD2;
float4 TtoW1 : TEXCOORD3;
float4 TtoW2 : TEXCOORD4;
};

sampler2D _MainTex;
float4 _MainTex_ST;

sampler2D _NormalMap;
float4 _NormalMap_ST;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap);
o.lightDir = WorldSpaceLightDir(v.vertex);
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent);
float3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

//tbnp
o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv.xy);
#if _USENORMALMAP_ON
fixed3 normal = UnpackNormal(tex2D(_NormalMap, i.uv.zw));
normal = normalize(half3(dot(i.TtoW0, normal), dot(i.TtoW1, normal), dot(i.TtoW2, normal)));
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
// return fixed4(normal,1);
fixed3 finalCol = dot(normal.xyz, normalize(i.lightDir.xyz)) * col.rgb * _LightColor0.rgb;
return fixed4(finalCol, col.a);
#else
// return col;
return fixed4(col.rgb * _LightColor0.rgb, col.a);
#endif
}
ENDCG
}
}
}

三、Unity Editer中的法向贴图

四、PS生成法向贴图

五、Reference