深入理解 Unity URP 渲染队列的排序机制、关键分界点与实际应用策略,彻底解决半透明物体渲染顺序问题。
什么是渲染队列 (Render Queue)
在实时图形渲染中,渲染队列 (Render Queue)是控制物体绘制先后顺序的核心机制。Unity 中每个 Shader 都可以通过 Queue 标签指定一个整数值,这个数值决定了该 Shader 所在的物体在渲染管线中的绘制时机。
核心排序规则非常简单:
🔑 核心规则
数值越小,越先渲染;数值越大,越后渲染。 后渲染的像素会覆盖先渲染的像素。这一机制是保证半透明物体正确混合的前提。
Unity 预定义了五个关键的队列分区,每个分区对应一个默认数值范围和特定的渲染语义。理解这些分区的含义和分界点,是掌握渲染顺序的基础。
URP 渲染管线完整流程
在深入各个队列之前,我们先看 URP Forward 渲染路径的完整阶段划分。理解整体流程有助于定位渲染队列在其中扮演的角色。

从图中可以看出,渲染队列在 Opaque (不透明物体)和 Transparent (透明物体)阶段之间扮演着关键的分流角色。数值 2500 是这两大阶段的分界点,也是半透明渲染问题的核心所在。
五大关键队列分区详解
Unity 将渲染队列划分为五个预定义分区,每个分区拥有默认的数值基准和特定的渲染语义:

| 队列名称 | 默认值 | 数值范围 | 典型用途 | 深度写入 | 排序方式 |
|---|---|---|---|---|---|
| Background | 1000 |
0--1499 | 天空盒、远景、背景色 | ✅ 开启 | 从前往后 |
| Geometry | 2000 |
1500--2399 | 不透明物体(墙体、地面、角色模型) | ✅ 开启 | 从前往后 |
| AlphaTest | 2450 |
2400--2649 | Alpha 测试(镂空植被、栅栏纹理) | ✅ 开启 | 从前往后 |
| Transparent | 3000 |
2500--3999 | 半透明物体(玻璃、粒子、水、火焰) | ❌ 关闭 | 从后往前 |
| Overlay | 4000 |
4000+ | UI 叠加层、镜头光晕、最顶层特效 | ❌ 关闭 | 不排序 |
关键要点
- Geometry(2000) 是默认队列。大多数不透明材质无需额外设置。
- Transparent(3000) 是半透明渲染的核心队列。此队列中的物体关闭深度写入(
ZWrite Off),仅依赖深度测试。 - AlphaTest(2450) 位于分界点附近,既需要 Alpha 裁剪又需要深度写入,是处理镂空效果的关键。
- Unity 允许在默认值基础上偏移,例如
"Queue"="Transparent+100"表示 3100。
半透明物体为什么渲染顺序如此重要
半透明渲染的核心在于 Alpha Blending(Alpha 混合),其公式为:
Alpha 混合公式Formula
// 最终颜色 = 源颜色 × 源Alpha + 目标颜色 × (1 - 源Alpha)
C_final = C_src × α_src + C_dst × (1 - α_src)
这个公式揭示了一个关键问题:混合结果依赖于"目标颜色"(即已经绘制在帧缓冲区中的颜色)。这意味着半透明物体必须在其"背景物体"渲染完毕之后才能进行正确的混合计算。

⚠️ 深度写入冲突
半透明物体如果开启了深度写入(ZWrite On),会阻止其后面更远的半透明物体被渲染------因为深度测试会失败。因此 Transparent 队列默认关闭深度写入,但这同时引入了半透明物体之间的排序问题。
为什么不透明物体可以从前往后渲染?
不透明物体完全不透明(Alpha = 1),不存在混合需求。从前往后渲染可以充分利用 Early-Z 优化:近处的物体先写入深度缓冲,远处的物体在逐像素测试时因深度失败而被直接丢弃,从而避免无效的光照计算,减少 Overdraw。
在 Shader 中设置渲染队列
渲染队列通过 ShaderLab 的 Tags 块设置。以下是一个完整的半透明 Shader 示例:
cs
Shader "Custom/TransparentObject"
{
Properties
{
_BaseColor ("Base Color", Color) = (1,1,1,0.5)
_MainTex ("Main Texture", 2D) = "white" {}
}
SubShader
{
// ★ 关键:设置渲染队列为 Transparent
Tags
{
"RenderType" = "Transparent"
"Queue" = "Transparent" // 默认值 3000
"RenderPipeline" = "UniversalPipeline"
}
// ★ 关键:设置混合模式
Blend SrcAlpha OneMinusSrcAlpha
// ★ 关键:关闭深度写入(半透明物体必须)
ZWrite Off
// 深度测试仍然开启(利用不透明物体的深度信息)
ZTest LEqual
Pass
{
Name "Forward"
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _BaseColor;
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = TRANSFORM_TEX(input.uv, _MainTex);
return output;
}
float4 frag(Varyings input) : SV_Target
{
float4 texColor = tex2D(_MainTex, input.uv);
return texColor * _BaseColor;
}
ENDHLSL
}
}
}
📌 Queue 偏移语法
可以在默认队列值上添加偏移量来控制同类型材质之间的渲染顺序。
"Queue" = "Transparent+100" → 渲染队列值 = 3100
"Queue" = "Transparent-50" → 渲染队列值 = 2950
偏移范围为 −249 到 +249(不超过相邻默认值的间距)。
Shader 中渲染队列相关设置一览
| 设置项 | 值 | 说明 |
|---|---|---|
Queue |
"Transparent" |
设置渲染队列为 Transparent(默认 3000) |
Blend |
SrcAlpha OneMinusSrcAlpha |
标准 Alpha 混合模式 |
ZWrite |
Off |
关闭深度写入,避免遮挡后续透明物体 |
ZTest |
LEqual |
保留深度测试(默认值),用于被不透明物体正确遮挡 |
RenderType |
"Transparent" |
渲染类型标签,用于 Shader Replacement 和材质分类 |
通过代码动态修改渲染队列
在某些运行时场景下,你可能需要通过 C# 脚本动态修改材质的渲染队列:
cs
using UnityEngine;
public class RenderQueueController : MonoBehaviour
{
public Renderer targetRenderer;
public int customQueue = 3000;
void Start()
{
// 通过 Material 直接设置渲染队列
targetRenderer.material.renderQueue = customQueue;
}
}
URP 还引入了独有的 Priority 属性,用于控制同一渲染队列内材质的排序优先级:
cs
using UnityEngine;
using UnityEngine.Rendering;
public class URPRenderPriority : MonoBehaviour
{
public Material transparentMat;
void Start()
{
// Priority 值越小,渲染越晚(越在上面)
// 适合让特定透明物体显示在其他透明物体之上
transparentMat.renderQueue = (int)RenderQueue.Transparent;
transparentMat.SetPropertyBlock(null);
// URP Renderer 中的 priority 属性
// material.renderQueue 控制队列分组
// Renderer.priority 控制同组内的微调排序
}
}
⚠️ Material 实例化警告
直接修改 renderer.material.renderQueue 会创建材质实例,导致额外的内存开销。如果只是修改渲染队列,建议使用 Renderer.sharedMaterial.renderQueue(谨慎使用,会影响所有使用该材质的物体)或 MaterialPropertyBlock。
URP 中的渲染顺序控制进阶
除了基础的渲染队列设置,URP 还提供了多种高级机制来精细控制渲染顺序:
7.1 Sorting Layer 与 Order in Layer
URP 支持基于 Sorting Layer 的分层渲染,主要用于 2D 和 UI 元素:
cs
/ 在 URP 中,Sorting Layer 在以下范围内生效:
// - RenderQueue 在 [0, 2500] 范围内(不透明物体)
// - RenderQueue 在 [2501, 5000] 范围内(透明物体)
// 注意:跨越 2500 分界点时 Sorting Layer 不生效
var renderer = GetComponent<Renderer>();
renderer.sortingLayerName = "TransparentFX";
renderer.sortingOrder = 10; // 值越大越后渲染(越在上面)
7.2 RenderObjects Renderer Feature
URP 的 RenderObjects Renderer Feature 允许你在渲染管线的特定位置插入自定义渲染通道:
cs
// 在 URP Renderer Asset 中添加 RenderObjects Feature:
// 1. Event: 选择插入时机
// - BeforeRenderingOpaques (不透明物体之前)
// - AfterRenderingOpaques (不透明物体之后)
// - AfterRenderingSkybox (天空盒之后)
// - BeforeRenderingTransparents (透明物体之前)
// - AfterRenderingTransparents (透明物体之后)
//
// 2. Filters: 选择渲染的对象
// - Layer Mask: 指定渲染哪些 Layer
// - Rendering Layer Mask: 指定 Rendering Layer
//
// 3. Settings: 覆盖渲染状态
// - Depth: 深度测试/写入设置
// - Stencil: 模板测试设置
7.3 多摄像机 Base-Overlay 模式
URP 支持通过 Camera Stack 实现多摄像机分层渲染。Base Camera 先渲染场景,Overlay Camera 在其上叠加渲染 UI、特效等:
cs
using UnityEngine;
using UnityEngine.Rendering.Universal;
public class CameraStackSetup : MonoBehaviour
{
public Camera baseCamera;
public Camera overlayCamera;
void Start()
{
// 获取 Base Camera 的 Universal Additional Camera Data
var cameraData = baseCamera
.GetComponent<UniversalAdditionalCameraData>();
// 将 Overlay Camera 添加到 Camera Stack
cameraData.cameraStack.Add(overlayCamera);
}
}
常见问题与解决方案
问题 1:半透明物体之间的渲染顺序不正确
症状
两个重叠的半透明物体 A 和 B,当摄像机从不同角度观察时,A 和 B 的遮挡关系不正确,甚至出现闪烁。
调整 Queue 偏移
在 Shader 中通过 "Queue"="Transparent+10" 让需要后渲染的物体获得更大的队列值。
使用 Sorting Order
对于 Sprite 或 Particle System,通过 Inspector 面板调整 Sorting Layer 和 Order in Layer。
拆分为多个渲染通道
对于相交的半透明网格体,考虑使用 RenderObjects Feature 在特定时机分批渲染。
问题 2:半透明物体被不透明物体遮挡但显示异常
症状
半透明物体在不透明物体后面时应该完全不可见,但仍然显示了半透明的颜色。
原因 :半透明物体关闭了深度写入但保留了深度测试(ZTest LEqual),问题可能出在物体的 渲染顺序 上------如果半透明物体先于不透明物体渲染,深度缓冲区中还没有不透明物体的深度信息。
cs
/ 不透明物体 Shader(保持默认队列即可)
Tags { "Queue" = "Geometry" } // 2000,先渲染
// 半透明物体 Shader(队列值必须 > 2500)
Tags { "Queue" = "Transparent" } // 3000,后渲染
问题 3:Alpha Test 与 Transparent 混合使用导致渲染错误
AlphaTest(Queue 2450)和 Transparent(Queue 3000)是两种不同的半透明处理方式:
| 特性 | Alpha Test (裁剪) | Alpha Blend (混合) |
|---|---|---|
| 效果 | 像素要么完全显示,要么完全丢弃 | 像素与背景颜色混合 |
| 边缘 | 锯齿感(硬边缘) | 平滑过渡(软边缘) |
| 深度写入 | ✅ 开启 | ❌ 关闭 |
| 性能 | 较好(Hi-Z 友好) | 较差(需要排序和混合) |
| 适用场景 | 镂空树叶、栅栏、字符轮廓 | 玻璃、水、粒子、烟雾 |
💡 最佳实践
如果材质需要镂空效果且不涉及半透明混合,使用 AlphaTest 队列 + clip() 函数。这比 Transparent 更高效,因为保留了深度写入,可以正确参与 Early-Z 优化。在 URP 中可通过 AlphaClipping 属性或 clip(discard) 指令实现。
问题 4:粒子系统与其他半透明物体排序冲突
粒子系统的每个粒子是独立的四边形面片,排序非常复杂。常见解决方案:
- 使用
"Queue" = "Transparent+100"让粒子在普通半透明物体之后渲染。 - 使用加法混合
Blend One One避免排序依赖(加法混合结果与顺序无关)。 - 使用深度预通道(
Depth Prepass)确保粒子被不透明物体正确遮挡。
总结与最佳实践

🎯 核心要点回顾
- 渲染队列值越小越先渲染,这是所有排序的基础。
- 2500 是不透明与半透明的关键分界点,务必确保半透明物体的队列值 ≥ 2500。
- 半透明物体必须 ZWrite Off,否则会遮挡同层其他半透明物体。
- 不透明物体从前往后渲染 (利用 Early-Z),半透明物体从后往前渲染(保证混合正确)。
- 能使用 AlphaTest 就不要用 Transparent,前者保留深度写入,性能更优。
- 加法混合(Blend One One)不受排序影响,适合火焰、光晕等粒子效果。
掌握 Unity URP 的渲染队列机制,是解决半透明物体渲染问题的关键。理解每个队列分区的含义、深度写入与测试的关系、以及不同排序策略的适用场景,能够帮助你在项目中有效避免透明渲染的常见陷阱,同时兼顾视觉正确性与渲染性能。