Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

遮罩纹理

一、遮罩纹理的作用

遮量纹理通常用于控制或限制某些效果的显示范围,它允许我们可以保护某些区域,使它们免于某些修改。 一般情况下,遮罩纹理也会是一张灰度图,其中的 RGB 值会是相同的 我们利用它存储的值参与到

  • 光照(指定某些区域受光影响的程度)
  • 透明度(指定某些区域透明的程度)
  • 特效(指定某些区域出现特效)

等等相关的计算中 从而来让指定区域达到我们想要的效果

我们以高光遮罩纹理举例下图三个胶囊体的对比 就是高光遮置纹理起到的效果 利用高光遮置纹理,我们可以控制模型上的各个区域受到高光影响的强弱 2024-09-09 171228.png

二、基本原理

  1. 从纹理中取出对应的遮罩掩码值(颜色的 RGB 都可以使用)
  2. 用该掩码值和遮罩系数(我们自己定义的)相乘得到遮罩值
  3. 用该遮罩值和高光反射计算出来的颜色相乘

最终呈现出来的高光反射表现就会受到 高光遮罩纹理 和 遮罩系数 的影响 从而表现出最终效果

三、遮罩纹理的基本实现

1.书写思路

  1. 从纹理中取出对应的遮罩掩码值(颜色的 RGB 都可以使用)
  2. 用该掩码值和遮罩系数(我们自己定义的)相乘得到遮罩值
  3. 用该遮罩值和高光反射计算出来的颜色相乘

2.实例代码

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
Shader "Unlit/SpecularMask"
{
Properties
{
//光照相关属性
_MainColor("MainColor",Color) = (1,1,1,1)
_specularColor("specularColor",Color) = (1,1,1,1)
_specularNum("specularNum",Range(0,200)) = 15
//单张纹理
_MainTex("MainTex",2D) = ""{}
//法线纹理
_BumpMap("BumpMap",2D) = ""{}
_BumpMapScale("BumpMapScale",Range(0,200)) = 1
//高光遮罩纹理
_SpecularMask("SpecularMask",2D) = ""{}
_SpecularMaskScale("SpecularMaskScale",Range(0,200)) = 1

}
SubShader
{
Pass
{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

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

struct v2f
{
float4 pos:POSITION;
//我们可以单独申明两个float2成员 用于记录 颜色和法线的uv坐标
/* float2 uvTex:TEXCOORD0;
float2 uvBump:TEXCOORD1; */
//我们也可以直接申明一个float4成员
//xy表示颜色纹理的uv zw表示法线的纹理uv
float4 uv:TEXCOORD0;
//光的方向 相对于切线空间下
float3 lightDir:TEXCOORD1;
//视角的方向 相对于切线空间下
float3 viewDir:TEXCOORD2;
};
//---光照---//
float4 _MainColor;//漫反射颜色
float4 _specularColor;//高光反色颜色
float _specularNum;//光泽度
//---纹理---//
sampler2D _MainTex;//颜色纹理
float4 _MainTex_ST;//颜色纹理缩放和平移

sampler2D _BumpMap;//法线纹理
float4 _BumpMap_ST;//法线纹理缩放和平移
float _BumpMapScale;//凹凸程度

sampler2D _SpecularMask;//高光遮罩纹理
float4 _SpecularMask_ST;//高光遮罩纹理缩放和平移
float _SpecularMaskScale;//高光遮罩纹理的缩放系数
v2f vert (appdata_full v)
{
v2f data;
//将模型空间下的顶点转移到裁剪空间下
data.pos = UnityObjectToClipPos(v.vertex);
//计算纹理的缩放偏移
data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
data.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

//在顶点着色器当中 得到 模型空间到切线空间的转换矩阵
//切线、副切线、法线
//计算副切线————注意乘以切线中的w确定方向
float3 binormal = cross(normalize(v.tangent),normalize(v.normal))*v.tangent.w;
//转换矩阵
float3x3 rotation = float3x3(v.tangent.xyz,
binormal,
v.normal);
//模型空间下的光的方向
data.lightDir = ObjSpaceLightDir(v.vertex);
//转换到切线空间下的光的方向
data.lightDir = mul(rotation,data.lightDir);
//模型空间下的视角方向
data.viewDir = ObjSpaceViewDir(v.vertex);
//转换到切线空间下的视角方向
data.viewDir = mul(rotation,data.viewDir);
return data;
}

fixed4 frag (v2f i) : SV_Target
{
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap,i.uv.zw);
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩运算 得到切线空间下的法线信息
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal *= _BumpMapScale;
//---处理带颜色纹理的 BlinnPhong光照模型---//

//颜色纹理和漫反射颜色的叠加
fixed3 albedo = tex2D(_MainTex,i.uv.xy) * _MainColor.rgb;
//计算兰伯特
fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0,dot(tangentNormal,normalize(i.lightDir)));
//计算半角向量
float3 halfA = normalize(normalize(i.viewDir) + normalize(i.lightDir));

//高光遮罩纹理值的计算
//从遮罩纹理中 取出对应的遮罩掩码值 (颜色的RGB都可以使用)
fixed maskNum = tex2D(_SpecularMask,i.uv.xy).r;
//用该掩码值和遮罩系数(我们自己定义的)相乘得到遮罩值
fixed spcularMaskNum = maskNum * _SpecularMaskScale;


//计算高光反射
//用遮罩值和高光反射计算出来的颜色相乘
float3 specularColor = _LightColor0.rgb * _specularColor * pow(max(0,dot(tangentNormal,halfA)) , _specularNum) * spcularMaskNum;
//计算BlinnPhong
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;


return fixed4(color.rgb , 1 );
}
ENDCG
}
}
}

3.实现效果

2024-09-09 174644.png 2024-09-09 174638.png

四、关于遮罩纹理中的 RGBA 值

对于高光遮量纹理中的 RGBA 值,是非常浪费的 因为我们只使用其中一个值就可以得到我们想要的数据

因此对于遮罩纹理来说 我们可以合理的利用其中的每一个值来存储我们想要的数据 随着以后的学习 我们可以在遮罩纹理当中存储更多信息 比如:

  • R 值代表高光遮罩数据
  • G 值代表透明遮罩数据
  • B 值代表特效遮罩数据
  • 等等 甚至可以用 n 张遮挡纹理存储 4xn 个会参与 每个片元渲染计算的值

评论