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

透明度混合

一、透明度混合式用来处理的需求

主要是和透明测试区分
透明测试只存在看得见和看不见两种状态,不能实现半透明效果,一般用于处理镂空效果
透明度混合 就是用来弥补这种问题,主要用来实现半透明效果

二、基本原理

关闭深度写入,开启混合,让片元颜色和颜色缓冲区中颜色进行混合

三、实现

1.书写思路

  1. 实现颜色纹理结合光照模型的 Shader
  2. 申明一个[0,1]区间的 _AlphaScale 用于控制对象的整体透明度
  3. 将渲染队列设置为 Transparent,并且配合 IngnoreProjector 和 RenderType 一起设置
  4. 关闭深度写入ZWrite off
  5. 采用半透明的混合因子进行混合 Blend SrcAlpha OneMinusSrcAlpha 目标颜色 = SrcAlpha * 源颜色 + (1 - ScrAlpha) * 目标颜色 = 源颜色透明度 * 原颜色 + (1 - 源颜色透明度) * 目标颜色
  6. 在片元着色器获取颜色贴图颜色后,修改最后的颜色 A 值,为 (纹理.a * _AlphaScale)

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
125
Shader "Unlit/Trasnparent"
{
Properties
{
//光照相关属性
_MainColor("MainColor",Color) = (1,1,1,1)
_specularColor("specularColor",Color) = (1,1,1,1)
_specularNum("specularNum",Range(0,20)) = 15
//单张纹理
_MainTex("MainTex",2D) = ""{}
//法线纹理
_BumpMap("BumpMap",2D) = ""{}
_BumpMapScale("BumpMapScale",Float) = 1
//透明度
_AlphaScale("AlphaScale",Range(0,1)) = 1

}
SubShader
{
//设置透明度混合的 渲染队列 为 透明的Transparent
Tags{"Queue" = "Transparent" "IngnoreProjector" = "true" "RenderType" = "Transparent"}

Pass
{
Tags { "LightMode"="ForwardBase" }
//关闭深度写入
ZWrite off
//将混合因子 设置为半透明效果 的搭配
Blend SrcAlpha OneMinusSrcAlpha

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;//凹凸程度
//---透明度---//
fixed _AlphaScale;
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光照模型---//

//取出纹理当中的RGBA
fixed4 texColor = tex2D(_MainTex,i.uv.xy);

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

//修改我们的Alpha返回值 决定透明度
return fixed4(color.rgb , texColor.a *_AlphaScale );
}
ENDCG
}
}
}

3.实现效果

2024-09-12 230349.png

评论