尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Unity ShaderGraph实战:从零构建动态火焰特效的完整指南

Unity ShaderGraph实战:从零构建动态火焰特效的完整指南 1. 项目概述从零到一用ShaderGraph点燃你的第一个动态火焰最近在几个独立游戏开发群里看到不少朋友在问怎么实现一个看起来不“假”的火焰效果。有人用序列帧动画结果包体蹭蹭涨有人用粒子系统调来调去总感觉少了点灵动的“火苗感”。其实对于这种需要实时变化、带有半透明和扭曲效果的特效Shader着色器才是更优雅、更高效的解决方案。但一提到写Shader代码很多美术同学和程序新手就头大。别慌Unity的ShaderGraph可视化着色器编辑器就是为这个场景而生的。今天我就以一个实际项目里用到的“篝火”特效为例手把手带你用ShaderGraph从头搭建一个动态火焰。你完全不需要事先掌握HLSL或CG语言只要跟着节点图连一连就能理解火焰背后的视觉原理并得到一个可以直接用到你项目里的、性能友好的动态材质。我会把完整的节点图拆开揉碎了讲更重要的是分享几个我踩过坑、流过泪才总结出来的关键避坑点比如UV流动的“接缝”问题、透明排序的“打架”现象以及如何让火焰的“内焰”和“外焰”层次分明。无论你是想为你的RPG游戏添加营火还是为魔法技能设计火球术这套思路都能直接套用。2. 核心思路拆解火焰特效的视觉密码在动手连节点之前我们得先想明白现实中的火焰在屏幕上到底是由哪些视觉元素构成的我们不能真的去模拟燃烧的物理化学过程那是科研软件干的事。在实时渲染中我们是通过“欺骗”眼睛的几种图形学手段来组合出火焰的视觉印象。2.1 火焰的视觉构成要素首先一个典型的火焰比如蜡烛或篝火看起来有以下几个特点动态与随机性火苗的形状和高度时刻在变化这种变化是连续且随机的。颜色渐变从底部的亮黄色/白色到中部的橙色再到顶部的暗红色甚至透明有一个平滑的过渡。形状与轮廓底部较宽顶部呈不规则的尖刺状整体轮廓模糊且不断扭曲。内部细节火焰内部并非纯色有更亮的核心内焰和稍暗的边缘外焰并且有类似“纹理”的流动感。半透明与发光火焰是半透明的并且会照亮周围环境发光效果。在ShaderGraph里我们无法直接创造一个“3D火苗”而是通过处理一个2D平面比如一个Quad面片上的纹理让这个平面看起来像火焰。核心思路就是用噪声纹理模拟火焰的动态形状和内部细节用颜色渐变节点控制火焰的色相最后通过Alpha通道控制火焰的透明轮廓。2.2 技术方案选型与节点图蓝图基于以上分析我们的ShaderGraph将围绕以下几个核心模块构建基础形状与动态使用噪声纹理作为所有效果的基础。Perlin噪声或Simplex噪声都很合适它们能产生自然的、连续的随机图案。通过让噪声纹理的UV坐标随时间滚动就能模拟火焰的升腾和扭曲动画。轮廓遮罩我们需要一个从下到上逐渐消失的渐变来定义火焰的大致高度和顶部尖刺轮廓。这通常通过一个渐变Gradient纹理或简单的位置计算将模型空间的Y坐标重映射来实现。颜色映射将噪声值可理解为“火焰强度”映射到一个从亮黄到暗红的颜色渐变条上。这里的关键是噪声值高的区域代表火焰核心显示为亮色噪声值低的区域代表火焰边缘显示为暗色。透明度与融合最终的Alpha值由噪声纹理和轮廓遮罩共同决定。通常是将两者相乘这样既能保证火焰顶部透明消失又能让火焰内部有透明的变化细节避免看起来像一块实心的色块。整个节点图的输入输出流可以简化为时间 - 滚动UV - 采样噪声 - 与轮廓遮罩结合 - 映射颜色 - 输出到片元着色器。3. 核心节点详解与避坑指南理解了蓝图我们开始深入每个核心节点。ShaderGraph的节点成百上千但做这个火焰用到的关键节点也就十来个。我会重点讲清楚每个节点的作用、参数意义以及最容易出问题的地方。3.1 噪声纹理火焰的灵魂没有噪声就没有动态的火焰。在ShaderGraph中我们通常使用Procedural Noise节点或Sample Texture 2D节点引用一张外部的噪声图。Simple Noise与Gradient Noise这是ShaderGraph自带的程序化噪声。Simple Noise更快但图案略显机械Gradient Noise通常是Perlin噪声更自然柔和是火焰效果的首选。其Scale参数控制噪声的“粒度”值越小噪声图案越细碎火焰的细节就越多值越大图案越平滑火焰看起来就越“胖”。外部噪声纹理你也可以导入一张灰度噪声图。这样做的好处是纹理内容完全可控且运行时性能消耗稳定程序化噪声需要实时计算。通常选择一张无缝衔接的TilablePerlin噪声图。避坑点1噪声尺度与平铺新手最容易犯的错是Scale设得太大或太小。对于一个单位大小的Quad面片Scale设置在10到50之间是合理的起点。过小如5会导致噪声过于细碎火焰像静电雪花过大如100则噪声过于平滑失去火焰的细节。另一个关键点是务必确保你的噪声是无缝平铺的否则当UV滚动时会在边界出现明显的接缝破坏火焰的连续性。对于程序化噪声节点内部通常已处理对于外部纹理需要在导入设置中确认Wrap Mode为Repeat。3.2 UV动画让火焰“燃”起来静态的噪声只是一团云让UV动起来火焰才有生命。这里主要用到Time节点和Tiling And Offset节点。Time节点输出自游戏开始以来的时间秒。我们通常使用其Time输出口它是一个稳步增长的值。Tiling And Offset节点Tiling是缩放Offset是偏移。要让火焰向上燃烧我们只需要在V方向垂直方向的Offset上连接一个随时间负向增长的值。例如Offset (0, -Time * Speed)。这样纹理就会不断向下滚动因为V坐标增加是向下视觉上就是火焰在向上涌动。避坑点2动画速度与自然感Speed参数非常敏感。太快了火焰像喷发的火箭太慢了又像凝固的果冻。对于篝火大小的火焰Speed在0.5到2.0之间尝试。更高级的做法是使用两个不同速度和尺度的噪声层进行混合一层慢而大尺度决定火焰主体形状一层快而小尺度增加表面细节的扰动这样动画会更丰富自然。可以用Lerp线性插值节点来混合两层噪声。3.3 形状遮罩控制火焰的边界我们需要一个从上到下从有到无的渐变来剪出火焰的基本形状。这里有两种主流方法基于模型空间位置使用Position节点设置为Object Space取出其Y分量然后通过Remap节点或Saturate节点将其重映射到[0,1]范围。模型底部的点值接近0顶部的点值接近1。但我们希望底部不透明顶部透明所以有时需要用One Minus节点反转一下。使用渐变纹理创建一个从白到黑的垂直渐变纹理。在ShaderGraph中用Sample Texture 2D采样它直接使用其灰度值作为遮罩。这种方法控制更直观你可以直接在PS里绘制特殊的火焰形状比如更瘦长或更蓬松。避坑点3消除硬边与添加扰动直接使用线性渐变遮罩火焰顶部会有一条非常生硬的横切面。为了让顶部轮廓更不规则像火苗我们需要用噪声去扰动这个遮罩的边界。具体做法是将之前采样的噪声值乘以一个很小的系数比如0.2然后加到遮罩的UV的V坐标上或者直接加到遮罩采样结果上。这样遮罩的边界就会随着噪声波动形成参差不齐的火苗尖顶。公式类似FinalMask baseMask (noise * 0.2)然后对结果进行Saturate操作防止超出范围。3.4 颜色映射从数据到视觉这是让火焰看起来“热”起来的关键一步。我们有一个单通道的噪声强度值比如0到1需要把它变成从黄到红甚至到透明的颜色。Color节点与Lerp节点最直接的方法是定义两个颜色比如Color A亮黄RGB约1,0.9,0.5Color B暗红RGB约0.5,0.1,0。然后用噪声强度作为系数对这两个颜色进行线性插值Lerp。强度高的地方更接近A亮黄强度低的地方更接近B暗红。Gradient节点这是更强大和直观的工具。你可以创建一个渐变条从左对应噪声值0到右对应噪声值1定义多个颜色关键点。例如位置0.0为透明黑0.2为暗红0.5为亮橙0.8为亮黄1.0为白色。然后将噪声值输入到Gradient节点的Time端口它就会输出对应的颜色。这种方法可以轻松实现多色渐变。避坑点4颜色过渡与HDR火焰的核心应该是非常亮甚至“过曝”的。在标准LDR低动态范围渲染下颜色的RGB值最大是1这限制了核心的亮度表现。在URP/HDRP管线中我们可以开启HDR让颜色值超过1并结合后期泛光Bloom效果让火焰核心真正“发光”。在ShaderGraph里确保你的输出颜色允许大于1。另外颜色渐变不要太生硬在Gradient节点中多设置几个关键点让过渡更平滑。3.5 透明度与混合模式最终我们需要将形状遮罩和噪声细节结合起来输出到片元着色器的Alpha通道。Alpha合成通常的公式是Final Alpha Noise * ShapeMask。这里Noise最好经过一些处理比如Power幂次节点让它的对比度更强一些Power(Noise, 1.5)这样火焰内部的透明变化会更明显。混合模式在ShaderGraph的Graph Inspector中或者材质球的渲染设置里将Blend Mode设置为Alpha BlendSrcAlpha, OneMinusSrcAlpha。这是处理半透明物体的标准混合方式。对于需要发光的火焰也可以考虑使用AdditiveOne, One混合它会使得重叠部分更亮适合表现强烈的光效但要注意控制整体亮度避免过曝。避坑点5透明排序与渲染队列这是3D场景中半透明物体最常见的坑当多个火焰或者火焰与其他半透明物体如烟雾重叠时可能会出现错误的遮挡关系看起来闪烁或破碎。这是因为GPU渲染半透明物体时通常需要从后往前排序绘制。解决方案在ShaderGraph的Graph Inspector中将Surface Type设为TransparentRender Queue可以尝试设为Transparent100或更高确保火焰在其他透明物体之后渲染。尽量避免半透明物体在三维空间深度上大量交叉。对于篝火可以尽量使用Billboard始终面向相机的Quad减少复杂的空间交错。在材质球上可以勾选Alpha Clipping并设置一个阈值将透明度低于某个值的像素直接丢弃不参与混合这能在一定程度上硬化边缘减少排序问题但可能会让火焰边缘出现锯齿。4. 完整节点图搭建与参数调试理论说得差不多了我们打开Unity创建一个Unlit Shader Graph开始动手连接。4.1 节点图步骤分解以下是按数据流顺序的节点搭建步骤创建属性首先在Blackboard创建几个方便调节的属性。NoiseScale(Vector1): 默认值30控制噪声纹理的缩放。ScrollSpeed(Vector1): 默认值1.0控制火焰滚动速度。ColorGradient(Gradient): 编辑一个从暗红到亮黄到白的渐变。DistortionStrength(Vector1): 默认值0.15控制噪声对遮罩边界的扰动强度。生成动态UV添加Texture Coordinate节点使用默认UV0。添加Time节点。添加Multiply节点计算Time * ScrollSpeed。添加Vector2节点设为 (0, -1)。再添加一个Multiply节点将上一步的速度标量乘以这个向量得到垂直方向的滚动偏移量(0, -Time*Speed)。添加Tiling And Offset节点将Texture Coordinate连入UVTiling设为(1,1)将计算好的偏移向量连入Offset。输出即为滚动的UV。采样噪声添加Gradient Noise节点或Sample Texture 2D引用你的噪声图。将上一步得到的滚动UV连入其UV端口。将NoiseScale属性连入其Scale端口。输出的是一个单通道的灰度值我们将其命名为BaseNoise。创建形状遮罩添加Position节点将Space设置为Object。添加Split节点将Position的Y分量分离出来。假设你的火焰模型底部在Y0顶部在Y1。添加Remap节点将Y分量的原始范围例如模型的实际范围重映射到[0,1]。更简单的方式是直接用Saturate钳制但用Remap更精确。假设模型Y从-0.5到0.5则Remap的In Min Max为(-0.5, 0.5)Out Min Max为(0,1)。得到基础的垂直渐变BaseMask。扰动遮罩边界添加Multiply节点将BaseNoise乘以DistortionStrength属性。添加Add节点将BaseMask与上一步的结果相加。添加Saturate节点钳制结果到[0,1]范围。输出为最终的FinalMask。生成颜色添加Sample Gradient节点如果使用Gradient属性则用Property节点引用ColorGradient。将BaseNoise连入其Time端口。输出颜色FireColor。合成最终输出添加Multiply节点计算BaseNoise * FinalMask结果作为最终的Alpha值FinalAlpha。你可以在这之前对BaseNoise用Power节点处理一下增加对比度。添加Fragment节点或直接设置Master Stack的输入。将FireColor连入Base Color。将FinalAlpha连入Alpha。将Surface Type设置为TransparentBlend Mode设置为Alpha。4.2 关键参数调试心得节点连好了但效果可能还不理想。这时就需要微调参数这是一个感性的过程但有一些规律可循整体形态胖瘦/高低主要由NoiseScale和BaseMask的重映射范围控制。NoiseScale小则火苗细碎高挑大则火焰敦实饱满。BaseMask的Out Min Max如果设为(0, 0.8)火焰高度会降低。动态剧烈程度由ScrollSpeed和噪声的Scale共同决定。速度快、噪声尺度小则火苗跳动剧烈速度慢、噪声尺度大则火焰缓慢涌动。颜色温度在ColorGradient中调整。想让火焰看起来更“热”就把中间亮部向黄色/白色移动想让它看起来更“冷”或更神秘可以加入一些蓝色或紫色到渐变条的左侧低强度端。轮廓清晰度由DistortionStrength和FinalAlpha计算前的Power节点控制。扰动强、对比度高则火苗尖刺更明显、更“野”反之则火焰轮廓更柔和、更“稳”。我的经验是先调出一个大概满意的静态形状关闭UV滚动然后再开启动画调速度最后微调颜色。可以保存多个材质球预设对应“小火苗”、“篝火”、“熊熊大火”等不同参数组。5. 性能优化与进阶技巧一个基本的火焰Shader做好了但如果要在移动端或大量使用我们还得关心性能并让它更出彩。5.1 性能优化要点纹理采样优化如果使用外部噪声纹理确保它的大小合适如512x512并压缩为合适的格式如ASTC。避免在Shader中使用过多不同的大纹理。计算复杂度Gradient Noise节点比Simple Noise计算量稍大。如果效果可以接受优先使用Simple Noise。减少不必要的复杂节点比如多个Power或Remap。简化版Shader对于远处或背景中大量重复的小火焰可以做一个简化版只使用一层噪声、更简单的颜色渐变、甚至去掉遮罩扰动。通过LOD细节层次或根据距离切换材质来管理。利用顶点动画我们目前做的全是片元着色器里的像素计算。对于简单的火焰也可以考虑在顶点着色器里根据噪声轻微移动顶点的Y轴位置让火焰的网格本身也有起伏增加立体感。但这会增加顶点计算量需权衡。5.2 效果增强技巧多层噪声叠加这是提升质感的关键。除了主噪声层再添加一层尺度更小、速度更快的噪声将其以较小的强度如0.1加到主噪声或颜色采样之前可以为火焰表面增加细小的、快速跳动的细节让火焰看起来更“活”。扭曲背景Heat Haze真实的火焰会使它后面的景物看起来扭曲。我们可以用这个火焰Shader的噪声来扰动一张渲染背景的屏幕纹理需要用到Scene Color节点但这通常在后处理中完成。简单实现是采样当前像素上方的UV用噪声轻微偏移它模拟热空气上升的扭曲感。粒子系统结合Shader负责火焰主体的视觉表现而火星、飞溅的小颗粒、燃烧的烟雾则非常适合用粒子系统VFX Graph或Shuriken来完成。将Shader材质赋予粒子可以做出非常绚丽的综合火焰效果。与灯光互动在URP/HDRP中可以确保Shader输出Emission自发光颜色这样火焰就能作为光源照亮周围的场景物体需要配合后处理Bloom。将FireColor连入Emission端口即可注意控制发光强度。6. 常见问题排查与解决方案实录即使跟着教程做也难免会遇到各种奇怪的问题。这里我列几个最典型的问题1火焰是黑色的或者颜色不对。检查点确认Base Color端口连接正确并且颜色节点的值不是黑色或接近黑色。检查ColorGradient的渐变条确认在噪声输入值范围内通常是0-1颜色不是黑色。检查噪声输出是否正常。可以临时将BaseNoise直接连到Base Color作为一个灰度图和Alpha设为1看看是否有一个黑白的噪声图案在流动。如果没有说明UV或噪声节点有问题。问题2火焰没有动画是静止的。检查点确认Time节点正确连接到了UV的Offset计算上。检查ScrollSpeed是否为0。在Unity编辑器里确保没有暂停游戏。可以检查Time节点的预览窗口看输出值是否在增长。问题3火焰边缘有难看的硬边或锯齿。检查点这是Alpha混合的经典问题。尝试在FinalAlpha计算后添加一个很小的Saturate或Clamp确保Alpha值在非常小的范围内如0.01到0.99而不是精确的0或1有时能缓解。检查用于Alpha合成的Noise和FinalMask值确保它们的变化是平滑的而不是二值的非0即1。Power函数可以让中间过渡更平缓。在材质球上尝试开启Alpha to Coverage如果使用MSAA或使用软粒子Soft Particles技术但这通常需要深度纹理支持。问题4多个火焰叠加时排序错乱看起来破碎。检查点这是半透明排序问题。确保所有火焰材质的Render Queue一致且合理例如都设为3000。尽量让火焰物体在场景中的深度不要过于交叉。对于Billboard广告牌这很难避免可以考虑将多个小火苗合并到一个稍微复杂的网格上只用一份材质。终极方案之一是考虑使用Alpha TestCutout替代 Alpha Blend。设置一个透明度阈值低于阈值的像素完全丢弃高于的完全不透明。这样就没有了混合排序问题但火焰边缘会变成锯齿状需要通过一张高分辨率的噪声图和使用Anti-Aliasing技术来弥补。这属于性能和效果的权衡。问题5在移动设备上帧率下降明显。检查点使用Unity的Frame Debugger或Profiler查看GPU耗时确认是Shader开销。简化Shader尝试换用Simple Noise减少数学运算节点降低噪声纹理分辨率。减少使用此材质的物体数量或屏幕覆盖面积。检查是否错误地开启了不必要的功能如Depth Write对于纯半透明物体通常应关闭。调试Shader是一个耐心活最有效的方法就是“隔离法”逐步断开节点看中间每一步的预览结果是否符合预期把复杂问题分解成一个个小步骤来定位。
返回列表