前言
在计算机图形学中,透明度混合(AlphaBlend)是一种常用的技术,用于实现透明效果。透明度混合允许将半透明物体与场景进行混合,以产生逼真的视觉效果。在Unity中,通过编写Shader可以实现透明度混合效果,本篇博客将介绍如何在Unity中使用Shader实现透明度混合效果。
一、什么是透明度混合?
- 透明度混合原理
透明度混合(Alpha blending)是一种图形渲染技术,用于在渲染半透明物体时将其颜色与背景进行混合,从而产生透明效果。在透明度混合中,每个像素的输出颜色是由物体颜色和背景颜色按照一定比例混合而成,这一比例通常由物体的透明度值(Alpha值)来控制。
透明度混合的工作原理是将半透明物体的颜色与场景中已经存在的颜色进行混合,从而实现透明效果。在渲染过程中,透明度混合通常涉及两个关键步骤:关闭深度写入和设置混合模式。
- 透明度混合优缺点
优点:
实现透明效果: 透明度混合可以有效地模拟透明物体的视觉效果,使其能够与背景进行逼真的混合,从而呈现出真实的透明感。
增加场景细节: 通过透明度混合,可以在场景中添加半透明的物体,如玻璃、水面等,从而增加场景的丰富程度和细节感。
增强视觉效果: 透明度混合可以用于创建视觉效果,如烟雾、光线透射等,使场景更加生动和引人注目。
缺点:
性能开销: 透明度混合需要对每个像素进行混合计算,这可能会增加渲染的计算开销,尤其是在有大量透明物体的场景中。
深度排序问题: 当存在多个半透明物体时,需要对它们进行正确的深度排序以避免渲染顺序错误导致的混合错误。这一过程可能会增加开发复杂度并影响渲染性能。
图像质量损失: 透明度混合可能导致图像质量损失,特别是在有大量透明物体重叠的情况下,可能会出现颜色混合不均匀、边缘虚化等问题,影响视觉效果
-
纹理图
二、使用步骤
- Shader 属性定义
// 定义属性
Properties {
//主纹理贴图
_MainTex("Main Texture", 2 D) = "white" {}
// 漫反射颜色属性,默认白色
_Diffuse("Diffuse Color", Color) = (1, 1, 1, 1)
// 透明度阈值
_AlphaScale("Alpha Scale",Range(0,1))=1
}
- SubShader 设置
SubShader
{
Tags
{
"Queue" = "Transparent" // 渲染队列为AlphaTest
"IgnoreProjector" = "True" // 忽略投影
"RenderType"="Transparent"
}
LOD 100 // 细节级别
//关闭深度写入
ZWrite Off
//开启混合
Blend SrcAlpha OneMinusSrcAlpha
}
这段代码定义了一个透明材质的SubShader,其中设置了渲染队列为AlphaTest,忽略投影,使用了透明渲染类型,并关闭了深度写入并开启了混合
- 渲染 Pass
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 包含Unity CG库
#include "UnityCG.cginc"
// 包含光照CG库
#include "Lighting.cginc"
// 漫反射颜色属性
fixed4 _Diffuse;
// Alpha阈值
float _AlphaScale;
// 主纹理贴图
sampler2D _MainTex;
float4 _MainTex_ST;
}
这里开始了渲染 Pass 部分。在这里,我们使用了 CGPROGRAM 指令来声明顶点着色器和片元着色器函数。#pragma vertex vert 和 #pragma fragment frag 分别指定了顶点着色器函数和片元着色器函数的名称。
然后,我们包含了 UnityCG.cginc 和 Lighting.cginc,它们提供了许多有用的函数和宏,用于简化编写 Shader。
- 定义结构体和顶点着色器函数
// 定义结构体:从顶点到片段的数据传递
struct v2f {
float4 vertex: SV_POSITION; // 顶点位置
fixed3 worldNormal: TEXCOORD0; // 世界空间法线
fixed3 worldPos: TEXCOORD1; // 世界空间位置
float2 uv: TEXCOORD2; // 纹理坐标
};
// 顶点着色器函数
v2f vert(appdata_base v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); // 顶点位置变换到裁剪空间
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); // 世界空间法线
o.worldNormal = worldNormal;
// 让外部的属性可以影响到uv
//o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
// 简化uv计算函数
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
这个顶点函数的主要功能是将输入的顶点数据从对象空间转换到裁剪空间,并为后续的渲染过程提供必要的信息,包括裁剪空间中的顶点位置、世界空间中的法线、纹理坐标以及顶点的世界空间位置。
- 片元着色器函数
// 片元着色器函数
fixed4 frag(v2f i): SV_Target {
// 获取环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// 纹理采样
fixed4 texColor = tex2D(_MainTex, i.uv);
// 漫反射
// 获取光源方向
//fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
// 简化获取光源方向
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (dot(worldLightDir, i.worldNormal) *
0.5 + 0.5);
// 组合最终颜色
fixed3 color = diffuse + ambient;
return fixed4(color, texColor.a * _AlphaScale); // 输出颜色
}
这段代码是一个片元着色器函数,负责计算每个像素的最终颜色输出。首先,从环境光中获取基础颜色值。然后,从_MainTex纹理中采样颜色值。接着,计算漫反射部分,通过获取光源方向和表面法线的点积来模拟光照对表面的影响。最后,将漫反射颜色和环境光颜色相加,乘以纹理的alpha值,并返回作为输出颜色。
三、效果
四、总结
Unity 中的透明度混合(Alpha Blend)是一种常用的图形渲染技术,它允许将半透明的对象与场景中的其他对象进行混合,以创建逼真的图形效果。以下是关于 Unity 中透明度混合的总结:
基本概念:
透明度混合是指将具有不同透明度的像素合成到最终图像中的过程。
透明度(Alpha)通常表示物体的不透明度,值从 0(完全透明)到 1(完全不透明)。
混合模式:
Unity 支持多种混合模式,包括透明度混合(Alpha Blend)、加法混合(Additive Blend)、乘法混合(Multiplicative Blend)等。
在透明度混合中,新像素的颜色将与背景像素的颜色根据其 Alpha 值进行插值计算,产生最终的颜色。
透明度排序:
在使用透明度混合时,需要正确地排序渲染顺序,以确保透明对象正确地叠加在不透明对象之上。
Unity 中可通过设置渲染顺序(Sorting Order)或手动控制渲染队列(Rendering Queue)来实现透明度排序。
性能考虑:
透明度混合可能会对性能产生一定影响,特别是在移动设备上。
过度使用透明度混合可能导致额外的 GPU 开销,降低渲染性能。
材质设置:
在 Unity 中,可以通过调整材质的 Shader 来控制透明度混合效果。
内置的 Standard Shader 和 Universal Render Pipeline(URP)中的 Lit Shader 都支持透明度混合。
透明度剔除:
透明度剔除(Alpha Cutoff)是一种优化技术,可以根据像素的 Alpha 值进行丢弃,以减少不必要的像素处理。
透明度剔除常用于处理带有透明部分的纹理,如树叶或草地。
总的来说,透明度混合是 Unity 中实现半透明效果的重要技术之一,合理使用并结合透明度排序和性能优化技巧,可以有效地创建逼真的图形效果,并确保良好的性能表现。