通过深度纹理采样消除粒子与场景边界处的"纸片感",让粒子效果自然融入游戏世界
什么是软粒子?
软粒子(Soft Particles)是一种让粒子效果在接近不透明物体时自动淡出的技术。在 Unity 的通用渲染管线(URP)中,通过比较粒子自身深度与场景深度,实现边界处的平滑过渡。

为什么需要软粒子?
没有软粒子时,粒子效果会呈现明显的"纸片感"------粒子与场景物体交界处会有一条生硬的边界线。这在烟雾、火焰、爆炸等粒子特效中尤为明显。
问题效果示意

软粒子的优势
- 视觉真实感:粒子效果自然融入场景,消除"悬浮"感
- 性能友好:仅需采样一张深度纹理,几乎无额外开销
- 易于实现:只需几行 Shader 代码即可启用
- 通用性强:适用于烟雾、火焰、爆炸、水花、魔法特效等各类粒子系统
实现原理
软粒子的核心思想是计算粒子深度 与场景深度之间的差值,当粒子接近场景物体时(深度差趋近于0),自动降低粒子的不透明度。
过渡系数 = saturate( (场景深度 - 粒子深度) / 过渡距离 )
深度差值示意

公式解析
| 参数 | 说明 |
|---|---|
场景深度 |
从 _CameraDepthTexture 采样,表示到不透明物体的距离 |
粒子深度 |
粒子在深度缓冲中的深度值(线性化后) |
过渡距离 |
软粒子生效的范围(通常 0.5~2.0 单位) |
saturate |
将结果限制在 [0, 1] 范围内 |
URP 配置步骤
在 URP 中启用软粒子需要两步:开启相机深度纹理 + 配置 Shader。
Step 1: 开启相机深度纹理
方法 A:修改 URP 渲染器数据(推荐)
在 Project 窗口中找到你的 URP Renderer Data 资产(通常在 Settings 文件夹),勾选 Depth Texture 选项。

💡 提示
开启 Depth Texture 会增加一个深度 Pass,建议在移动端根据需求权衡性能。
Step 2: 相机配置(备选方案)
也可以在相机的 Rendering 选项卡中,将 Depth Texture 设置为 Always 或 On Demand。
Shader 实现
完整的软粒子 Shader 示例,包含逐行注释说明:
完整 Shader 代码
cs
// 软粒子 Shader - URP 版本
Shader "Custom/SoftParticle"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Softness ("Softness", Range(0.1, 5.0)) = 1.0
_Color ("Tint Color", Color) = (1, 1, 1, 1)
}
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
// ----------------------------------------
// Fragment Shader - 核心软粒子逻辑
// ----------------------------------------
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ _
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// ----------------------------------------
// 声明深度纹理
// _CameraDepthTexture 是 URP 自动提供的深度纹理
// ----------------------------------------
TEXTURE2D(_CameraDepthTexture);
SAMPLER(sampler_CameraDepthTexture);
CBUFFER_START(UnityPerMaterial)
float _Softness;
float4 _Color;
CBUFFER_END
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
// 存储变换后的深度值(用于后续比较)
float depth : TEXCOORD1;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
o.uv = v.uv;
// 计算线性深度,范围 [Near, Far] -> [0, 1]
o.depth = -o.vertex.w;
return o;
}
half4 frag(v2f i) : SV_Target
{
// ----------------------------------------
// Step 1: 采样粒子纹理
// ----------------------------------------
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
col *= _Color;
// ----------------------------------------
// Step 2: 采样场景深度纹理
// ----------------------------------------
float rawDepth = SAMPLE_DEPTH_TEXTURE(
_CameraDepthTexture,
sampler_CameraDepthTexture,
ComputeScreenPos(i.vertex / i.vertex.w).xy
);
// ----------------------------------------
// Step 3: 线性化深度值
// 深度纹理存储的是非线性深度,需转换
// ----------------------------------------
float sceneDepth = LinearEyeDepth(rawDepth, _ZBufferParams.x);
// ----------------------------------------
// Step 4: 计算深度差值
// sceneDepth - i.depth 即为粒子到场景物体的距离
// ----------------------------------------
float depthDelta = sceneDepth - i.depth;
// ----------------------------------------
// Step 5: 计算软粒子系数
// saturate 将结果限制在 [0,1] 范围
// ----------------------------------------
float softFactor = saturate(depthDelta / (_Softness + 0.0001));
// ----------------------------------------
// Step 6: 应用淡出效果
// ----------------------------------------
col.a *= softFactor;
return col;
}
ENDHLSL
}
}
}
🔧 代码要点
- 第 41-42 行:必须声明
_CameraDepthTexture才能采样场景深度 - 第 86 行:使用
LinearEyeDepth将非线性深度转换为眼睛空间线性深度 - 第 93 行:核心公式------深度差值除以过渡距离,得到 [0,1] 的淡出系数
- 第 98 行:将系数乘以 Alpha,使粒子边缘自然淡出
使用技巧与注意事项
参数调节建议
| 参数 | 推荐值 | 说明 |
|---|---|---|
_Softness |
0.5 ~ 2.0 | 值越大,软粒子过渡范围越宽 |
| Render Queue | Transparent | 确保粒子在不透明物体之后渲染 |
| Sorting Fudge | 0.1 ~ 0.5 | 有助于粒子正确排序 |
常见问题排查
- 软粒子不生效? 检查 URP Renderer Data 是否勾选了 Depth Texture
- 粒子完全消失? 可能是 _Softness 值过大,或粒子被裁剪了
- 接缝明显? 确保粒子的 Shader 正确处理了深度采样
- 移动端性能? 深度纹理采样有成本,高端效果可考虑 LOD
总结
软粒子是提升粒子特效真实感的关键技术。通过采样场景深度纹理 并与粒子自身深度做差值,在粒子接近不透明几何体时自动淡出边缘,从而消除"纸片感"。
核心实现只需:开启 Depth Texture → 声明 _CameraDepthTexture → 计算深度差并应用 Alpha 三步即可完成。