【从UnityURP开始探索游戏渲染】专栏-直达
Unity URP内置的Particles Lit着色器是专为粒子系统设计的高质量光照模型,其核心作用是为火焰、烟雾、雨雪等动态粒子效果提供逼真的光照交互。该着色器采用URP的物理光照计算模型,支持透明混合、深度碰撞检测等高级特性,但会带来较高的性能开销。
原理与特性
- 光照模型:基于URP的PBR光照计算,支持方向光、点光源和聚光灯的实时交互,通过表面法线计算高光反射
- 混合模式:提供Alpha、Premultiply、Additive和Multiply四种混合模式,分别适用于云雾(Alpha)、玻璃反射(Premultiply)、全息效果(Additive)等场景
- 深度交互:可与深度纹理比对实现粒子碰撞效果,通过CS脚本在渲染管线中同步深度数据
发展沿革
- 2019年:随URP 7.x版本首次推出,最初仅支持基础光照模型
- 2021年:URP 12.x加入深度纹理交互支持,实现粒子碰撞效果
- 2023年:优化移动端性能,在URP 14.x中成为粒子系统默认推荐着色器
Particles Lit 对比 Lit
渲染模式选择
ParticlesLit专为粒子系统设计,提供更灵活的混合模式(如Additive、Multiply等),适合处理透明粒子的叠加效果,而Lit通常用于不透明或标准透明物体渲染。ParticlesLit支持通过Color Mode控制粒子颜色与材质颜色的混合方式(如Multiply、Additive等),可减少过度混合导致的性能损耗。
性能敏感功能裁剪
ParticlesLit默认关闭了Lit中部分高消耗特性(如复杂光照计算),采用简化的光照模型。例如,它避免使用完整PBR计算,转而使用预乘混合(Premultiply)保留高光的同时降低透明渲染开销。此外,粒子系统通常禁用碰撞检测和物理交互,进一步降低CPU负载。
资源复用与批处理
ParticlesLit鼓励材质共享和纹理图集化,通过减少DrawCall提升性能。建议多个粒子系统共用同一材质,且纹理尺寸不超过256x256。相比之下,Lit可能涉及更多独立材质实例,尤其在复杂场景中。
渲染参数优化
ParticlesLit提供针对粒子的特定参数控制:
- 通过Alpha Clipping实现硬边透明(如草叶效果),避免全透明混合的计算开销
- 推荐小尺寸粒子去除Alpha通道,改用Opaque渲染以减少Overdraw
- 限制粒子数量(单发射器<50,屏幕总数<200)以控制顶点处理压力
底层实现差异
ParticlesLit在Shader代码中显式优化了类型转换和初始化(如half4 color = (half4)0),避免编译器警告并提升执行效率。而Lit更侧重通用物体渲染的精度和功能完整性。
综合来看,ParticlesLit通过简化光照模型、优化混合策略、限制资源消耗等方式,在保证粒子视觉效果的同时实现比Lit更高的渲染效率.
Particles Lit 的四种混合模式
ParticlesLit着色器提供了四种混合模式,主要用于控制粒子效果与背景的视觉融合方式
Alpha混合模式
通过材质的Alpha值控制透明度,0为完全透明,1为视觉上不透明但仍参与透明渲染通道。适用于需要渐变消失的效果,如云朵消散。其特点是保持粒子颜色纯度,但可能丢失高光细节。
Premultiply(预乘Alpha)
保留反射和高光特性,即使表面透明时仍能显示镜面效果。典型应用是透明玻璃或冰晶材质,仅反射光可见而本体透明。该模式需配合预乘处理的纹理使用,避免边缘黑边问题。
Additive(叠加)
将粒子颜色与背景色相加,产生增亮效果。适用于发光体如火焰、全息投影,能突出高亮区域但易导致过曝。火星特效常采用此模式增强核心亮度。
Multiply(相乘)
使粒子颜色与背景色相乘,产生变暗效果。模拟彩色玻璃透光或阴影叠加,适合风格化场景的氛围营造。需注意暗部细节可能丢失。
应用选择建议
- 性能考虑:Additive和Multiply计算量较低,Premultiply消耗较大
- 视觉特性:动态火焰推荐Additive,半透明物体用Alpha,材质反射需求选Premultiply
- 移动端优化:可改用Mobile/Particles/Additive等简化着色器
混合模式可通过材质Inspector面板的"Blending Mode"下拉菜单切换,需配合Render Face(渲染面)和Alpha Clipping(透明剪切)等参数调整最终效果
深度纹理比对实现深度交互的碰撞效果
深度纹理获取与处理
首先需启用相机的深度纹理渲染功能,通过勾选RenderPipelineAsset中的DepthTexture选项生成场景深度图。深度纹理存储的是归一化设备坐标(NDC)的z分量值,经过非线性透视投影变换后,使用公式d=0.5*z+0.5将深度值映射到[0,1]范围。正交投影的深度计算则是线性的,需区分处理。
碰撞检测原理
通过比较屏幕空间中的顶点距离与场景深度缓冲区的值来实现碰撞判定。具体步骤包括:
- 访问屏幕位置:获取当前顶点在屏幕空间的坐标和深度值。
- 深度差值计算:用场景深度值减去顶点深度值,得到两者间的距离差。
- 边缘梯度控制:通过调整场景位置的偏移量,可精确控制碰撞边缘的渐变效果。
效果增强技术
- Alpha混合修正 :将碰撞区域的Alpha值通过
1-操作反转,并与菲涅尔效应叠加,可生成发光边缘的视觉效果。 - 纹理变形技术:参考流体模拟中的UV坐标动画方法,通过动态扭曲纹理贴图增强交互的真实感。例如Valve在《Portal 2》中采用滑动表面着色器,对UV坐标进行时间驱动的位移计算。
性能优化
- 纹理复用:使用小块纹理通过重复平铺实现大范围覆盖,减少内存占用。
- 简化几何体:对于背景物体,可用带纹理的简单几何体替代高模,结合Billboard技术保持视觉一致性。
具体使用示例
创建火焰粒子材质:
- 新建材质并选择Shader路径:
Universal Render Pipeline > Particles > Lit - 设置Surface Type为Transparent,Blending Mode为Additive
- 绑定粒子贴图并调整颜色参数:
- _MainTex: 火焰序列帧贴图 _Color: RGBA(1,0.5,0,0.8) _Emission: 2.0
雨打到地上和物体上碰撞产生水花
-
雨水粒子基础配置:
- 使用Rectangle发射器形状并旋转90度使粒子垂直下落
- 设置Velocity over Lifetime的World空间模式确保雨滴始终朝Y轴降落
- 通过Linear参数添加XYZ方向偏移模拟风力效果
-
碰撞检测模块:
- 启用粒子系统的Collision模块,选择World碰撞模式
- 设置Dampen参数为1使碰撞后粒子完全停止
- 调整Bounce参数控制水花溅射力度
-
水花效果生成:
- 使用Sub Emitters模块在粒子消亡时触发子发射器
- 子粒子系统采用Horizontal Billboard渲染模式保持水平显示
- 通过Size over Lifetime曲线控制水花扩散动画
-
RainCollisionController.cs
csharpusing UnityEngine; [RequireComponent(typeof(ParticleSystem))] public class RainCollisionController : MonoBehaviour { private ParticleSystem _mainSystem; private ParticleSystem _splashSystem; void Start() { _mainSystem = GetComponent<ParticleSystem>(); var collision = _mainSystem.collision; collision.enabled = true; collision.type = ParticleSystemCollisionType.World; // 获取子发射器系统 _splashSystem = transform.GetChild(0).GetComponent<ParticleSystem>(); } void Update() { // 动态调整粒子发射速率 var emission = _mainSystem.emission; emission.rateOverTime = Mathf.Lerp(50, 500, WeatherManager.Instance.RainIntensity); } } -
RainCollisionController.cs
cShader "Custom/Ripple" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _Speed ("Animation Speed", Range(0,5)) = 1.0 } SubShader { Tags { "Queue"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag // 着色器代码... ENDHLSL } } } -
性能优化
-
纹理数组替代:使用Texture2DArray将多张纹理合并为单一资源,通过索引值(存储在SplatMap的R/G通道)选择纹理,减少采样次数。例如:
chlsl half4 var_Main = SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, uv, splat.r * 255) * splat.b; half4 var_Sec = SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, uv, splat.g * 255) * (1 - splat.b); half4 finalRGB = var_Main + var_Sec; -
高度混合增强:结合高度图(存储在SplatMap的B通道)实现更自然的过渡效果,通过比较各层高度值动态调整权重
-
Shader Graph应用
实现雨滴效果:
- 创建新的Shader Graph,选择URP Particle Lit模板
- 添加Texture Sample节点连接Main Texture输入口
- 使用Custom Function节点实现法线扰动:
c
hlsl
void RainDistortion_float(float2 uv, out float3 normal){
normal = float3(frac(uv.x * 10), frac(uv.y * 5), 1);
}
-
输出口连接Normal和Base Color通道
-
RainParticle.shadergraph
c{ "m_Nodes": [ { "m_Type": "UnityEditor.ShaderGraph.Texture2DNode", "m_Outputs": [{ "m_Name": "Out" }], "m_Inputs": [{ "m_Name": "Texture", "m_DefaultValue": "Assets/Textures/RainDrop.png" }] }, { "m_Type": "UnityEditor.ShaderGraph.CustomFunctionNode", "m_Outputs": [{ "m_Name": "normal" }], "m_Code": "RainDistortion_float" } ], "m_Edges": [ { "m_OutputSlot": 0, "m_InputSlot": "BaseColor" }, { "m_OutputSlot": 1, "m_InputSlot": "Normal" } ] }
该示例通过Shader Graph创建动态雨滴效果,包含纹理采样和法线扰动功能,需配合粒子系统使用
【从UnityURP开始探索游戏渲染】专栏-直达 (欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)