1. 为什么选择ShaderGraph制作烟雾特效?
在Unity中实现烟雾效果,传统方式需要编写复杂的Shader代码,这对美术人员和技术美术来说门槛较高。ShaderGraph的出现彻底改变了这一局面——它让特效制作变成了可视化的连线操作。我最初接触ShaderGraph是在2018年,当时为了给一个恐怖游戏制作篝火烟雾,手动编写Shader花了整整三天调试参数。而用ShaderGraph后,同样的效果只需2小时就能完成,还能实时调整看到变化。
ShaderGraph的核心优势在于:
- 节点化编辑:将数学运算、纹理采样等操作转化为直观的节点
- 实时预览:任何参数调整都能立即看到效果变化
- 跨平台兼容:自动处理不同平台的Shader语法差异
- 非编程友好:美术人员可以不写代码创建复杂效果
烟雾特效特别适合用ShaderGraph实现,因为:
- 需要多层噪声纹理混合
- 涉及复杂的透明度变化
- 对动态效果要求高
- 需要频繁调整视觉表现
提示:Unity 2021 LTS版本后,ShaderGraph已内置为默认安装组件,无需额外下载包。
2. 基础烟雾效果搭建
2.1 创建ShaderGraph资源
在Project窗口右键 → Create → Shader → Universal Render Pipeline → Sub Graph(URP项目推荐选择此选项)。命名为"SmokeEffect_Base"。
关键节点说明:
- Sample Texture 2D:加载噪声纹理(推荐使用Perlin噪声)
- Time:获取游戏时间用于动画驱动
- Multiply/Add:数学运算节点组合
- Vertex Position:影响顶点位移
2.2 核心参数配置
// 示例节点参数设置 [NoiseTexture] Wrap Mode = Repeat [Time] Speed = 0.5 [Multiply] B = 0.32.3 基础烟雾材质设置
- 将创建的ShaderGraph拖到Material上
- 调整渲染模式为Transparent
- 设置混合模式:
- SrcAlpha → SrcAlpha
- OneMinusSrcAlpha → OneMinusSrcAlpha
常见问题排查:
- 如果烟雾显示为纯黑:检查噪声纹理是否正常导入
- 边缘出现锯齿:开启材质的Alpha Clipping
- 移动设备上失效:确认使用URP/HLSL版本
3. 动态效果增强技巧
3.1 多层噪声混合技术
通过叠加3层不同尺度的噪声纹理实现更真实的烟雾动态:
| 层级 | 纹理尺寸 | 移动速度 | 影响范围 |
|---|---|---|---|
| 底层 | 256x256 | 慢(0.2) | 整体形状 |
| 中层 | 128x128 | 中(0.5) | 细节波动 |
| 高层 | 64x64 | 快(1.0) | 表面扰动 |
实现步骤:
- 创建3个Sample Texture 2D节点
- 分别连接不同的Time节点控制移动
- 使用Blend节点混合结果
3.2 顶点动画控制
通过修改顶点位置实现烟雾升腾效果:
// 伪代码示例 vertexOffset = noise.r * normal * intensity; positionOS += vertexOffset;参数调节心得:
- 强度值建议0.01-0.05之间
- 配合粒子系统的Force Over Lifetime使用效果更佳
- 在移动设备上需要降低计算精度
4. 高级视觉效果优化
4.1 光照与阴影处理
虽然烟雾通常是半透明物体,但适当的光照响应能增强真实感:
- 添加Custom Lighting节点
- 设置散射光系数(0.3-0.7)
- 开启Receive Shadows选项
- 使用Light Probe影响
注意:透明物体的阴影需要额外处理,建议使用Shadow Pass专门处理烟雾投影。
4.2 颜色渐变控制
通过Ramp Texture控制烟雾颜色变化:
- 创建Gradient节点
- 设置关键色标(通常为灰→白→透明)
- 连接至Base Color输入
进阶技巧:
- 使用Curve节点控制渐变速度
- 添加顶点颜色影响局部色调
- 结合粒子系统的Color over Lifetime模块
5. 性能优化方案
5.1 移动端适配策略
| 优化项 | 桌面级设置 | 移动端设置 | 效果损失 |
|---|---|---|---|
| 噪声层数 | 3层 | 2层 | 细节减少 |
| 采样精度 | Bilinear | Point | 锐度降低 |
| 顶点动画 | 开启 | 关闭 | 动态减弱 |
| 阴影计算 | 开启 | 关闭 | 立体感降低 |
5.2 实例化渲染方案
对于大量重复烟雾效果:
- 创建Instanced Shader变体
- 使用GPU Instancing
- 通过脚本批量控制参数
实测数据(Redmi Note 10 Pro):
- 非实例化:最多30个烟雾实例
- 实例化后:可达200+实例
6. 实战案例:篝火烟雾实现
6.1 场景布置
- 创建粒子发射器
- 设置发射速率为15-20
- 生命周期2-3秒
- 初始大小0.1-0.3
6.2 ShaderGraph配置细节
- 主噪声:Tiling (2,2,0)
- 次级噪声:Tiling (4,4,0)
- 动画速度:X=0.3, Y=0.5
- 透明度曲线:0.3→0.8→0.2
调试技巧:
- 先调大参数观察效果,再逐步细化
- 使用Debug节点检查中间值
- 保存多个材质变体做对比
7. 常见问题解决方案
7.1 烟雾边缘闪烁
可能原因:
- 深度测试冲突
- 透明度计算错误
- 相机近裁剪面设置不当
修复步骤:
- 调整材质的Render Queue(3000以上)
- 检查ZWrite/ZTest设置
- 修改相机Clipping Planes
7.2 性能热点分析
使用Unity Profiler定位:
- 查看GPU耗时
- 检查Draw Call数量
- 分析Shader.Lab占用
优化案例: 某项目烟雾特效从7ms降至2.3ms的调整:
- 减少噪声采样次数
- 简化顶点动画计算
- 合并相似材质
8. 扩展应用方向
8.1 环境氛围烟雾
- 洞穴雾气:低高度、慢速移动
- 战场硝烟:加入褐色色调
- 魔法效果:彩色烟雾+发光边缘
8.2 交互式烟雾
通过脚本控制Shader参数:
material.SetFloat("_WindStrength", windForce); material.SetVector("_Direction", windDirection);实现原理:
- 在ShaderGraph暴露参数
- 添加[SerializeField]标记
- 通过代码动态修改
在VR项目中,我们曾用这种技术实现玩家挥手驱散烟雾的效果,实测延迟控制在2帧以内就能获得良好的交互体验。关键是要在Update中平滑过渡参数值,避免突变造成视觉不适。