径向模糊(Radial Blur)是一种经典的后处理效果,它能够创建出动态的速度感或聚焦效果。在游戏开发中,径向模糊常用于:
- 高速运动的速度线效果
- 聚焦中心的视觉引导
- 爆炸或冲击波的视觉表现
- 特殊技能释放的炫酷效果
本教程将带你一步步在Unity URP(Universal Render Pipeline)环境下,通过屏幕颜色抓取技术实现径向模糊效果。

💡 核心概念
什么是屏幕颜色抓取?
屏幕颜色抓取(Screen Color Grab)是一种后处理技术,它允许Shader访问当前渲染的屏幕内容,并将其作为纹理进行处理。在Unity中,这通过_CameraColorTexture或自定义的Render Texture来实现。
什么是径向模糊?
径向模糊是一种从中心点向外辐射的模糊效果。不同于高斯模糊的全方向模糊,径向模糊只沿着从中心到边缘的径向方向进行采样和混合,创造出动态的视觉冲击。

完整的径向模糊Shader
以下是一个完整的URP径向模糊Shader实现,包含详细的注释:
cs
Shader "Hidden/RadialBlur"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/PostProcessing.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
// 模糊参数
float _BlurStrength; // 模糊强度 0.0-1.0
float _BlurRadius; // 模糊半径 0.0-0.5
float2 _Center; // 模糊中心 (屏幕UV坐标)
float _SampleCount; // 采样次数 1-32
// 顶点着色器
Varyings Vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
return output;
}
// 片段着色器 - 径向模糊核心算法
half4 Frag(Varyings input) : SV_Target
{
float2 uv = input.uv;
float2 center = _Center;
float2 dir = uv - center; // 计算从中心到当前像素的方向
float dist = length(dir); // 计算距离中心的距离
// 如果在中心点附近,直接返回原样,避免不必要的计算
if (dist < 0.001)
{
return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
}
dir = normalize(dir); // 归一化方向向量
half4 finalColor = half4(0, 0, 0, 0);
float totalWeight = 0;
// 沿径向方向多次采样
for (int i = 0; i < (int)_SampleCount; i++)
{
// 计算采样偏移量 (0到1之间均匀分布)
float t = (float)i / (_SampleCount - 1);
// 沿径向方向的偏移
float2 offset = dir * t * _BlurRadius * _BlurStrength;
// 从中心向外采样
half4 sampleColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv - offset);
// 距离越远,权重越小 (可选的加权策略)
float weight = 1.0 - t * 0.5;
finalColor += sampleColor * weight;
totalWeight += weight;
}
// 归一化颜色
finalColor /= totalWeight;
return finalColor;
}
ENDHLSL
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
}
Cull Off
ZWrite Off
ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
ENDHLSL
}
}
}
💡 Shader代码要点解析
- 方向计算: 使用 `normalize(uv - center)` 计算径向方向
- 多次采样: 通过循环沿径向方向采样不同位置的颜色
- 权重混合: 使用权重因子 `1.0 - t * 0.5` 让靠近中心的采样点权重更高
- 性能优化: 在中心点附近直接返回,避免不必要的计算
创建渲染特效脚本
创建RadialBlurEffect.cs文件,用于控制Shader的参数和渲染流程:
cs
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace RenderPipelineEffects
{
///
/// URP径向模糊效果 - Renderer Feature
/// 通过屏幕颜色抓取实现径向模糊效果
///
public class RadialBlurEffect : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
[Header("基础设置")]
public Shader shader;
public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
[Header("模糊参数")]
[Tooltip("模糊强度 (0.0 - 1.0)")]
[Range(0f, 1f)]
public float blurStrength = 0.5f;
[Tooltip("模糊半径 (0.0 - 0.5)")]
[Range(0f, 0.5f)]
public float blurRadius = 0.2f;
[Header("质量设置")]
[Tooltip("采样次数 (1 - 32)")]
[Range(1f, 32f)]
public float sampleCount = 16f;
[Header("中心点设置")]
[Tooltip("模糊中心X坐标 (屏幕UV空间 0.0 - 1.0)")]
[Range(0f, 1f)]
public float centerX = 0.5f;
[Tooltip("模糊中心Y坐标 (屏幕UV空间 0.0 - 1.0)")]
[Range(0f, 1f)]
public float centerY = 0.5f;
[Header("控制")]
[Tooltip("启用/禁用效果")]
public bool enableEffect = true;
}
public Settings settings = new Settings();
private RadialBlurPass m_ScriptablePass;
///
/// 创建渲染通道
///
public override void Create()
{
m_ScriptablePass = new RadialBlurPass(settings);
m_ScriptablePass.renderPassEvent = settings.renderPassEvent;
}
///
/// 将渲染通道添加到渲染器
///
public override void AddRenderPasses(
ScriptableRenderer renderer,
ref RenderingData renderingData)
{
if (settings.shader == null || !settings.enableEffect)
return;
renderer.EnqueuePass(m_ScriptablePass);
}
///
/// 径向模糊渲染通道
///
class RadialBlurPass : ScriptableRenderPass
{
private Settings settings;
private Material m_Material;
private RTHandle m_TemporaryColorTexture;
public RadialBlurPass(Settings settings)
{
this.settings = settings;
if (settings.shader != null)
{
m_Material = new Material(settings.shader);
m_Material.hideFlags = HideFlags.HideAndDontSave;
}
}
///
/// 摄像机设置 - 分配临时渲染纹理
///
public override void OnCameraSetup(
CommandBuffer cmd,
ref RenderingData renderingData)
{
var desc = renderingData.cameraData.cameraTargetDescriptor;
desc.depthBufferBits = 0; // 不需要深度缓冲
RenderingUtils.ReAllocateIfNeeded(
ref m_TemporaryColorTexture,
desc,
FilterMode.Bilinear,
TextureWrapMode.Clamp,
name: "_RadialBlurTemp"
);
}
///
/// 执行渲染通道 - 应用径向模糊效果
///
public override void Execute(
CommandBuffer cmd,
ref RenderingData renderingData)
{
if (m_Material == null)
return;
// 获取摄像机颜色目标
var source = renderingData.cameraData.renderer.cameraColorTargetHandle;
// 设置Shader参数
m_Material.SetFloat("_BlurStrength", settings.blurStrength);
m_Material.SetFloat("_BlurRadius", settings.blurRadius);
m_Material.SetFloat("_SampleCount", settings.sampleCount);
m_Material.SetVector(
"_Center",
new Vector2(settings.centerX, settings.centerY));
// 第一次Blit: 应用模糊效果到临时纹理
Blitter.BlitCameraTexture(
cmd,
source,
m_TemporaryColorTexture,
m_Material,
0
);
// 第二次Blit: 将结果拷贝回源纹理
Blitter.BlitCameraTexture(
cmd,
m_TemporaryColorTexture,
source
);
}
}
}
}
参数详解
| 参数 | 类型 | 范围 | 作用 | 默认值 |
|---|---|---|---|---|
| blurStrength | float | 0.0 ~ 1.0 | 控制模糊的整体强度 | 0.5 |
| blurRadius | float | 0.0 ~ 0.5 | 控制采样的最大半径 | 0.2 |
| sampleCount | float | 1 ~ 32 | 采样次数,影响质量与性能 | 16 |
| centerX | float | 0.0 ~ 1.0 | 模糊中心的X坐标(屏幕空间) | 0.5 |
| centerY | float | 0.0 ~ 1.0 | 模糊中心的Y坐标(屏幕空间) | 0.5 |
使用步骤
-
步骤1: 导入Shader
将RadialBlurShader.shader文件拖入Unity项目,Unity会自动编译并生成Shader资源
-
步骤2: 添加Renderer Feature
在Project窗口找到URP Renderer Data资源,点击Add Renderer Feature,选择RadialBlurEffect
-
步骤3: 配置参数
在Inspector面板中设置Shader引用,调整模糊强度、半径和中心点位置
-
步骤4: 测试效果
运行场景,观察径向模糊效果。如果需要动态调整,可以编写C#脚本来控制参数
💡 性能优化建议
- 在移动平台上,建议将sampleCount控制在8-12之间
- 可以使用mipmap降低采样成本
- 考虑使用half精度而非full精度
- 在不显示效果时设置enableEffect为false
⚠️ 常见问题
- 效果不显示:检查URP Renderer Data是否正确添加了Renderer Feature
- 性能下降明显:降低sampleCount或blurRadius
- 中心点不对:确保centerX和centerY在0-1范围内
- Shader编译错误:确认URP版本兼容性,使用正确的include路径
📚 总结
本教程详细介绍了在Unity URP环境下实现径向模糊效果的完整流程,包括:
- ✅ 屏幕颜色抓取的基本原理
- ✅ 径向模糊的算法实现
- ✅ URP Renderer Feature的使用
- ✅ 性能优化技巧
- ✅ 动态效果实现方法