UE5 魔法阵特效制作:用 Niagara 和材质实现动态符文

上周刚结束的进阶班答疑课上,有位学员举着《原神》里芭芭拉的水环问我:“老师,这种脚下魔法阵,用贴图旋转做出来总是发虚,边缘锯齿也明显,有没有办法让它像游戏里那样有能量流动感?” 这个问题很有代表性。大多数入门教程会教你用一张 `T_Radial_Gradient` 贴图配合 `Panner` 节点做无限循环滚动,但那种做法有两个硬伤:一是UV平铺导致边缘接缝明显,二是只能做整体旋转,无法实现符文独立旋转、缩放、浮现等动态效果。今天这篇文章,我们就用 UE5.3 的 Niagara 粒子系统配合材质函数,从零搭建一个可复用的动态魔法阵资产。全程不涉及蓝图,纯材质与粒子配合,你能直接拿到项目里用。

一、材质基础:用 Custom 节点生成程序化符文

我们先解决“边缘发虚”和“符文动态”这两个核心痛点。传统贴图方案的瓶颈在于纹理分辨率固定,放大必糊。而程序化生成则完全不受分辨率限制,且每个符文都可以独立控制。

步骤 1:创建材质函数 MF_RuneShape

在 Content Browser 中右键 → `Materials & Textures` → `Material Function`,命名为 `MF_RuneShape`。打开后,我们用一个 `Custom` 节点写 GLSL 代码来生成符文轮廓。双击 Custom 节点,在 Code 框输入:

float angle = atan2(LocalPosition.y, LocalPosition.x);
float radius = length(LocalPosition);
float runeMask = 0.0;

// 主圆环 runeMask += smoothstep(0.9, 0.85, radius) * (1.0 - smoothstep(1.0, 0.95, radius));

// 六芒星(两个三角形叠加) float tri1 = step(0.5, abs(sin(angle * 3.0 + 0.5))); float tri2 = step(0.5, abs(sin(angle * 3.0 - 0.5))); runeMask += (tri1 tri2) smoothstep(0.4, 0.35, radius);

// 外圈符文点阵(8个圆点) float dotAngle = floor(angle / (2.0 3.14159 / 8.0)) (2.0 * 3.14159 / 8.0); float dotDist = length(LocalPosition - float2(cos(dotAngle), sin(dotAngle)) * 1.2); runeMask += smoothstep(0.1, 0.08, dotDist);

return runeMask;

这里 `LocalPosition` 是材质函数内部默认提供的局部坐标,范围 -1 到 1。`smoothstep` 用于抗锯齿边缘,`atan2` 计算角度,`floor` 做环形阵列。把这个函数的 `Material Function Output` 连到 Emissive Color。

步骤 2:主材质设置

新建材质 `M_MagicCircle`,材质域设为 `Deferred Decal`(延迟贴花),混合模式 `Translucent`,着色模型 `Unlit`。这样魔法阵可以贴在任何表面(地面、墙壁甚至��色身上)。把 `MF_RuneShape` 拖入,并乘上一个 `VectorParameter` 控制颜色。关键参数:

  • `Emissive Color`:`(RuneColor * 2.0)` 让亮度超过1,产生HDR辉光
  • `Opacity`:`RuneMask * OpacityParam`(默认0.8)
  • `Blend Mode`:`Translucent`,`Decal Blend` 选 `Stain`
  • 此时你按下 `Apply`,在视口里拖一个 Decal 组件,已经能看到静态的符文圆环。但这是死的,我们需要让符文动起来。

    二、Niagara 粒子驱动:让符文旋转、缩放、浮现

    Niagara 在这里不是用来生成粒子,而是作为“动态参数驱动器”。我们创建一个 Niagara 系统,它不发射可见粒子,而是通过 `Particle Attribute Reader` 把每帧的旋转角度、缩放比例传给材质。

    步骤 3:创建 Niagara 系统

    在 Content Browser 右键 → `FX` → `Niagara System`,选择 `New system from a template`,选 `Empty`。打开后:

    1. 在 `Emitter Update` 中添加 `Spawn Rate`,设为 1(每帧更新一次)
    2. 添加 `Particle State`,设置 `Life Cycle` 为 `Infinite`(无限循环)
    3. 在 `Particle Spawn` 中添加 `Set Variables`:初始化 `RuneAngle` = 0.0,`RuneScale` = 1.0
    4. ��� `Particle Update` 中添加 `Add Float`:`RuneAngle += DeltaTime * 30.0`(每秒旋转30度)
    5. 再添加 `Sine` 表达式:`RuneScale = 0.8 + 0.2 sin(DeltaTime 2.0)`(呼吸缩放效果)

    步骤 4:通过 Renderer 传递参数到材质

    在 Niagara 的 `Renderer` 中,选择 `Light Renderer`(不显示网格体)或直接留空。关键在 `Material Binding`:

  • 在 `Parameters` 面板中,点击 `+ Parameter Binding`,选择 `Material` → `Scalar Parameter`
  • 把 `RuneAngle` 绑定到材质参数 `AngleParam`
  • 把 `RuneScale` 绑定到材质参数 `ScaleParam`
  • 回到材质 `M_MagicCircle`,添加两个 `ScalarParameter`:`AngleParam`(默认0)和 `ScaleParam`(默认1)。在 `MF_RuneShape` 中,把 `LocalPosition` 乘上 `ScaleParam`,再把整个坐标旋转 `AngleParam`:

    float2 rotatedPos = float2(
        LocalPosition.x  cos(AngleParam) - LocalPosition.y  sin(AngleParam),
        LocalPosition.x  sin(AngleParam) + LocalPosition.y  cos(AngleParam)
    ) / ScaleParam;
    

    注意要除以 ScaleParam 而不是乘,这样缩放是中心向外扩散的视觉。重新编译材质,把 Niagara 系统拖入场景,你会看到魔法阵开始整体旋转并呼吸缩放。

    三、进阶:多符文独立控制与流动能量

    上面的效果还比较单调。真正高级的魔法阵,每个符文应该有自己的节奏。我们扩展 Niagara 系统,使用 `Particle Attribute Reader` 和 `Index` 来区分不同符文。

    步骤 5:多粒子系统分层

    创建三个 Niagara Emitter(分别命名 `OuterRing`、`InnerRing`、`CenterCore`),每个 Emitter 独立控制。以 `OuterRing` 为例:

  • `Initialize Particle` 中设置 `Particle Count` = 8(8个符文点)
  • 每个粒子的 `Spawn` 时,用 `Index` 计算初始角度:`BaseAngle = Index / 8 * 2π`
  • `Update` 中:`FinalAngle = BaseAngle + GlobalRotation * 1.5`(外层转得快)
  • 材质端,我们改用 `TextureCoordinate` 的 `TexCoord` 数组传递多组参数。在 Niagara Renderer 中,绑定 `TexCoord` 为 `(Angle, Scale)`,材质里用 `TextureCoordinate` 节点分别提取 R 通道和 G 通道作为角度和缩放。

    步骤 6:流动能量线

    在材质中,我们加一条螺旋线。修改 `MF_RuneShape` 的代码,增加:

    float spiral = smoothstep(0.8, 0.6, abs(frac(angle / (2.0  3.14159) + Time  0.5) - 0.5));
    runeMask += spiral  smoothstep(0.7, 0.5, radius)  0.5;
    

    这里的 `Time` 是材质内置节点 `Time`(需要勾选 `Used Time` 或通过 `Time` 节点传入)。这样会有一条从中心向外旋转的亮线,类似能量汇聚。

    最终效果是:外圈8个符文点以不同速度旋转,中圈六芒星呼吸缩放,内圈螺旋能量线顺时针流动,整体再叠加一层慢速旋转。所有参数都由 Niagara 实时驱动,不消耗贴图内存,分辨率无限。

    常见问题 FAQ

    Q1:为什么我的 Decal 材质显示全黑?
    检查 `Deferred Decal` 是否勾选了 `Decal Response` 中的 `Color` 和 `Normal`。另外,确保材质是 `Unlit` 且 `Emissive Color` 大于1,否则在默认光照下会显得很暗。

    Q2:Niagara 参数绑定后材质没反应?
    在 Niagara 的 Renderer 中,必须选择一种 Renderer 类型(如 `Light Renderer`),否则参数绑定不会生效。另外,材质参数名要完全一致,包括大小写。

    Q3:魔法阵边缘有锯齿?
    检查 `smoothstep` 的宽度参数。建议 `smoothstep(0.9, 0.85, radius)` 的第二个值比第一个小0.05左右,这样过渡带约2-3像素,足够抗锯齿。如果还不行,在材质设置中开启 `Temporal AA`。

    Q4:如何让魔法阵跟随角色移动?
    使用 `Attach Actor` 组件或 `Set World Location` 每帧更新。更高效的方式是使用 Niagara 的 `Local Space` 模拟,勾选 Emitter 的 `Local Space` 后,系统会自动随组件移动。

    Q5:性能开销大吗?
    程序化材质无贴图采样,Niagara 粒子数极少(最���几十个),整体开销比同分辨率贴图方案低30%左右。但注意不要在移动端使用过多 `Custom` 节点,建议移动端用简化版(减少三角形数量)。

    学习建议

    这篇文章只是冰山一角。Niagara 真正的威力在于它可以把任何参数(时间、位置、速度)映射到材质,实现“数据驱动特效”。建议你按以下路径深入学习:

    1. 先跑通本文案例,然后修改参数观察效果(比如把 `Sine` 改成 `Noise`,看看随机缩放的效果)
    2. 研究 `Particle Attribute Reader`,它是 Niagra 与材质通信的桥梁,掌握 `Index` 和 `Tag` 用法
    3. 尝试用 `Skeletal Mesh` 的顶点位置驱动粒子,实现角色身体上的魔法纹路
    4. 结合 AIGC 工具(如 Stable Diffusion 生成符文贴图素材),用本文程序化方法做动态,两者互补

    如果你在练习中遇到问题,欢迎在评论区贴出你的节点截图,我会逐一解答。下期文章我们讲如何用 `Particle Attribute Reader` 实现“粒子沿魔法阵轨迹飞行”的拖尾效果,到时见。

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。