news 2026/9/3 2:47:04

Mesh-Based VFX实战:让角色特效紧贴模型并跟随骨骼动画

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mesh-Based VFX实战:让角色特效紧贴模型并跟随骨骼动画

给角色做燃烧、冰冻、电光、符文觉醒这类实时特效时,最容易出现的问题不是缺素材,而是特效浮在角色表面、不贴合模型轮廓、也不跟随骨骼动画。很多初期方案是在角色身上叠加一团粒子,再配一张 Tiling 贴图,静止看有点效果,可角色一动起来,粒子就明显跟模型脱节。Mesh-Based VFX 这类技术路线,把角色 Mesh 本身当作特效数据的来源:从网格顶点取位置、法线、UV、顶点色,再用这些数据驱动粒子系统、VFX Graph 或自定义 Shader,让特效在真实贴近模型表面的位置出现和变化。以 Realistic Mesh VFX 为代表的这类方案,核心思路就是把几何数据变成表现力,而不是单纯叠贴图。

下面按一条完整链路展开:先理解 Mesh-Based VFX 是如何把几何数据变成视觉效果的,再准备 Unity 环境和角色 Mesh,从最小示例开始让粒子按网格顶点发射,接着解释顶点色、法线、UV 这些参数如何影响最终表现,最后补齐运行验证、性能观测和常见问题排查。整个流程不绑定具体商业插件,核心思路和 API 在 Unity 内置渲染管线、URP 和 HDRP 下都适用。

1. 理解 Mesh-Based VFX:为什么特效要跟 Mesh 数据发生关系

1.1 传统角色特效的两个瓶颈

传统特效方案在静态模型上表现尚可,一旦进入角色动画场景,通常会遇到两个问题。

第一个问题是贴合度差。角色表面不是平面,有衣领、袖口、脸型、铠甲接缝。粒子发射器如果挂在某个骨骼下,发射出来的粒子只会围绕一个固定点位扩散,无法精确覆盖模型表面。贴图方案更明显,平面贴图投影到复杂网格上会出现拉伸、错位和穿模。

第二个问题是动画跟随差。角色骨骼在运动,手臂摆动、身体旋转、表情变化,皮肤顶点每帧都在移动。如果特效只是挂在 Transform 上,或者粒子发射器绑定在骨骼节点上,特效会出现明显的延迟和漂移。真正常用的做法是先取出当前动画姿势下的 Mesh 顶点数据,再基于这些数据生成特效,这就是 Mesh-Based VFX 的核心场景。

1.2 Mesh 能提供哪些几何数据

Mesh 在图形学里表示三维几何体,不只是外观模型,更是一份可以反复采样的数据表。一个 Mesh 通常包含以下数据:

数据含义在特效中的典型用途
Position顶点位置粒子出生坐标、碎片爆裂点、贴花投影位置
Normal顶点法线粒子喷射方向、表面朝向、远离模型表面的速度
Tangent顶点切线粒子旋转方向、沿表面流动的方向
UV1 / UV2贴图坐标采样遮罩纹理、控制特效出现的区域
Color顶点色控制强度分区、颜色权重、粒子大小分布
Triangle Index三角形索引按面片随机、控制部分区域优先产生特效

这些数据在 Mesh Asset 里天然存在,可以在模型导入时配置,也可以在运行帧里刷新。Mesh-Based VFX 的本质就是把这些数据结构读出来,传给粒子系统、VFX Graph 或者 Shader,让几何体本身成为特效的“发射器”和“控制器”。

1.3 Mesh-Based VFX 的完整工作链路

一个基于 Mesh 的角色实时特效,从数据到画面通常经过这五步:

  1. 模型阶段:在 3D 软件里规划好顶点色、UV、材质 ID。
  2. 导入阶段:确认 Unity 导入设置保留了顶点色、法线和切线。
  3. 采样阶段:运行时从 Mesh 或 SkinnedMeshRenderer 读取顶点数据。
  4. 计算阶段:粒子系统、VFX Graph 或 C# 脚本把这些数据转成粒子位置、速度和朝向。
  5. 渲染阶段:自定义 Shader 读取顶点色、UV 等信息,输出最终颜色和透明度。

只要这条链路是通的,角色表面出现火焰、冰霜、电流、符文时,特效就能紧贴模型,并且跟随骨骼变化实时更新。这里要注意,Mesh 在无线组网领域也指网状网络,但本文讨论的是 Unity 图形学里的网格数据。

1.4 适合与不适合的场景

Mesh-Based VFX 适合的场景有这些:

  • 角色身上持续燃烧、结冰、通电的状态特效。
  • 符文在装备表面浮现、流动、消失。
  • 受伤时伤口位置发光或产生碎片。
  • 数字孪生场景中,设备 Mesh 表面显示温度、压力、运行状态。
  • 怪物、BOSS 在某个部位蓄力、产生辐射效果。

不太适合的场景包括:远处的大范围天气特效、全屏后期效果、高粒子量的弹幕。这些场景更适合使用公告牌粒子、体积雾或全屏 Shader,因为它们的表现重点不是贴合某个具体模型,而是覆盖整个空间。

2. 环境准备与技术选型:先定管线,再动特效

2.1 确认 Unity 版本和渲染管线

不同渲染管线对 VFX Graph 和 Shader Graph 的支持程度不一样,这里先给出一份保守的选型建议,落地时再结合项目版本确认。

项目推荐选择说明
Unity 版本优先 Unity 2021.3 LTS 或更新版本2022.3 LTS 对 VFX Graph 更稳定
渲染管线URP / HDRP / 内置管线VFX Graph 在内置管线支持有限,建议 URP 或 HDRP 项目使用
特效工具Visual Effect Graph 或 Particle SystemVFX Graph 适合 GPU 粒子,Particle System 适合兼容性优先的场景
Shader 工具Shader Graph 或手写 ShaderLabURP 项目建议 Shader Graph,内置管线可手写
角色模型FBX / OBJ,带蒙皮和骨骼以 SkinnedMeshRenderer 为主

这里有一点要强调:如果输入材料没有给出项目具体的 Unity 版本,不要直接假设某个版本能跑通全部功能。工程里常见的做法是先打开 Unity Hub 确认编辑器版本,再在 Package Manager 里查一下 VFX Graph 包和 URP 包的版本兼容表。

2.2 安装依赖包和激活检查

在 Unity 中打开Window -> Package Manager,在搜索框输入以下包名并安装:

  • Visual Effect Graph
  • Shader Graph

如果项目使用 URP,还需要确认Universal RP包已经安装。安装完成后,在 Project Settings 中把项目的渲染管线资产切到 URP Asset。

打开工程时,控制台如果出现No valid Unity Editor license found. Please activate your license.,说明当前机器没有有效许可证。处理方式不是去下载第三方工具,而是回到 Unity Hub 登录账号,检查许可证绑定状态,再重新激活。公司内网环境还要确认网络能正常访问 Unity 的许可证服务。这里先把激活检查放在环境准备阶段,后面排查问题时会少一个变量。

2.3 角色 Mesh 的准备要求

角色模型不是随便拿一个高模就能直接做特效。为了让顶点色、UV、法线在后期可控,模型制作阶段最好按下面的要求整理。

  • 顶点数:角色特效采样用的 Mesh 不需要太高精度,建议控制在 2000 到 10000 顶点以内,具体取决于目标平台。
  • 顶点色:在 3D 软件里预先烘焙顶点色,例如 Red 通道控制燃烧强度,Green 通道控制扩散速度,Blue 通道控制贴花透明度。
  • 法线:确保法线方向正确,否则粒子喷射方向会反。
  • 切线:如果需要沿表面流动的效果,需要切线数据,FBX 导入设置里不要勾选错误的切线计算选项。
  • UV:特效遮罩图和流动方向通常依赖第二套 UV,建模阶段就要分配好。
  • 网格布局:三角形尽量均匀,不要出现大量极小面和退化面,否则粒子密度会不均匀。

模型导入到 Unity 后,右键模型资源,在导入设置的 Model 标签页确认Read/Write Enabled按需开启。如果运行时需要读取顶点数据,开启这个选项;如果只给 VFX Graph 采样静态网格,可以保持关闭以节省内存。

2.4 性能预算要按平台分层

Mesh-Based VFX 不是无代价的方案,性能开销主要在顶点数据读取、粒子数量、Shader 复杂度三块。建议在学习环境里先把功能跑通,到开发环境再调性能,进入生产环境前必须做真机评估。

目标平台粒子预算Mesh 顶点预算采样频率
PC 高端20000 粒子以内10000 顶点以内每帧可采样
PC 低配5000 粒子以内5000 顶点以内每 2 到 3 帧采样一次
移动端中端1000 粒子以内2000 顶点以内每 3 到 5 帧采样一次
移动端低端300 粒子以内1000 顶点以内尽量不每帧采样

这些数值不是绝对标准,只是参考。实际项目里最终以 Profiler 的 CPU 和 GPU 耗时为准。移动端的 URP 项目尤其要注意 VFX Graph 的兼容性,部分节点在移动端 GPU 上不受支持,需要提前做兼容方案。

3. 最小可运行案例:让粒子从角色 Mesh 表面发射

3.1 场景搭建

先创建一个最简单的测试场景。用 Unity 自带的基本几何体也可以,但为了贴合文章主题,建议准备一个带 SkinnedMeshRenderer 的低模角色。

场景里有三个关键对象:

  • 角色模型对象,挂载 SkinnedMeshRenderer。
  • 一个特效对象,可以是 Particle System,也可以是 Visual Effect Graph 对象。
  • 一个脚本对象,负责读取角色 Mesh 数据并同步给特效系统。

静止测试时,也可以先使用 MeshRenderer 代替 SkinnedMeshRenderer。区别在于 MeshRenderer 的 Mesh 是静态的,SkinnedMeshRenderer 需要 BakeMesh 才能拿到当前动画姿势下的网格。

3.2 方式一:Particle System 按 Mesh 发射

在场景中创建空物体,挂上 Particle System 组件。打开 Particle System 的 Shape Module,把 Shape 类型选择为Mesh,再把角色模型的 Mesh 拖到Mesh字段。

此时的发射逻辑是:粒子从 Mesh 表面上随机分布的位置出生。调整 Emission 模块的Rate over Time控制粒子数量,调整 Shape 模块的Random Direction Amount控制粒子飞出方向的变化程度。

这个方式实现简单,但有一个明显限制:Particle System 的 Mesh Shape 只在发射时采样一次网格数据。如果角色做骨骼动画,Mesh 表面在运动,粒子出生点不会随着骨骼变化实时刷新,因此必须换一种方式。

3.3 方式二:VFX Graph 采样网格数据

VFX Graph 的处理方式更灵活。新建一个 VFX Graph,打开 Graph 编辑器,会看到默认的四个上下文:Spawn、Initialize Particle、Update Particle、Output Particle Quad。

要做基于 Mesh 的发射,关键改动在 Initialize Particle:

  1. Spawn 模块设置一个初始生成数量,例如每帧 100 个。
  2. Initialize Particle 中添加节点Sample Mesh PositionSample Mesh Normal
  3. 把 Sample Mesh Position 的输出连到 Initialize Particle 的 Position 属性。
  4. 把 Sample Mesh Normal 的输出连到 Initialize Particle 的 Velocity 方向。
  5. 添加Sample Mesh Color,把顶点色输出连到 Color 属性。

不同 Unity 版本里节点名称可能有差异。新版 VFX Graph 提供了 Skinned Mesh Sampling 相关节点,可以直接绑定 SkinnedMeshRenderer 采样动画蒙皮结果;如果版本较老,就要借助 C# 脚本,先把 SkinnedMeshRenderer 烘焙成普通 Mesh,再传给 VFX Graph。

Particle System 方式适合快速验证,VFX Graph 方式适合正式效果。下面这段 C# 脚本是关键的桥梁。

3.4 用 C# 脚本同步蒙皮网格数据

在角色动画播放过程中,SkinnedMeshRenderer 的 Mesh 数据在每帧都会变化。为了让 VFX Graph 采样到正确姿势,需要调用 BakingMesh API,把蒙皮结果烘焙到一个静态 Mesh 对象上,再传给 VFX Graph。

using UnityEngine; using UnityEngine.VFX; public class SkinnedMeshToVfx : MonoBehaviour { [Header("组件引用")] public SkinnedMeshRenderer skinnedMesh; public VisualEffect vfx; [Header("采样参数")] public int bakeEveryFrames = 3; private Mesh bakedMesh; private int frameCount; void Awake() { if (skinnedMesh == null) { skinnedMesh = GetComponent<SkinnedMeshRenderer>(); } bakedMesh = new Mesh(); frameCount = 0; } void LateUpdate() { frameCount++; if (frameCount < bakeEveryFrames) { return; } frameCount = 0; if (skinnedMesh == null || vfx == null) { return; } skinnedMesh.BakeMesh(bakedMesh); vfx.SetMesh("SourceMesh", bakedMesh); } }

这段脚本做了三件事:

  1. 在 Awake 中创建一个空的 Mesh 对象,作为烘焙结果的缓存容器。
  2. 在 LateUpdate 中按固定帧间隔调用BakeMesh
  3. 把烘焙结果通过vfx.SetMesh传给 VFX Graph 中名为SourceMesh的属性。

使用LateUpdate而不是Update的原因是:骨骼动画和 Animator 的状态在 Update 阶段更新,LateUpdate 阶段再读取数据时,拿到的是当前帧完整更新后的动画姿势。按帧间隔烘焙是为了控制性能,bakeEveryFrames = 3表示每 3 帧才刷新一次网格数据。如果角色动作很快,这个值要调小;如果角色大量发生且特效不明显,可以调大。

脚本里使用了UnityEngine.VFX命名空间,编译前必须先在 Package Manager 安装 Visual Effect Graph 包,否则会报命名空间不存在。

3.5 检查点

跑通最小示例后,用以下三个现象确认流程正常:

  • 场景中能看到粒子从网格表面出生,而不是从原点或某个固定平面出生。
  • 角色播放动画时,粒子出生位置跟随网格表面变化,不出现明显滞后。
  • 角色旋转、移动时,特效仍然贴合模型表面,不漂移。

如果粒子没有出现,优先检查 VFX Graph 属性名是否与脚本里的字符串一致。vfx.SetMesh("SourceMesh", bakedMesh)中的SourceMesh必须在 VFX Graph 中创建对应 Mesh 属性,脚本只是往属性里写数据。

4. 关键参数与 Shader 细节:顶点色、法线、UV 如何变成表现力

4.1 Mesh 数据到特效表现的映射关系

Mesh 数据的价值在于它能把模型表面特征直接转化为粒子表现。下面是常用映射关系:

Mesh 数据特效表现实现方式
Position粒子出生位置Sample Mesh Position
Normal喷射方向把法线乘一个速度系数
Tangent表面流动方向用切线作为粒子 Velocity 基准
UV遮罩和贴图坐标输出到 Shader 的 UV
Color 的 R燃烧强度控制粒子大小或发光强度
Color 的 G扩散速度控制粒子初始速度
Color 的 B贴花透明度控制材质 Alpha
Color 的 A裁剪阈值控制是否生成粒子

实际项目中,这种多通道用途可以显著减少贴图数量,也能让美术在模型阶段就确定特效表现区域。

4.2 粒子系统关键参数速查

在 Particle System 和 VFX Graph 中,参数都会直接影响表现,这里给出一个速查表,方便调试时快速定位问题。

参数作用调大的影响调小的结果典型值
Max Particles粒子总数上限画面更密集,CPU/GPU 压力上升画面稀疏,可能出现粒子突然消失PC 5000,移动端 500
Start Lifetime每个粒子的存活时间拖尾变长,堆积感强粒子快速消失,适合火花0.5 到 2 秒
Start Speed粒子初始速度喷射范围大,飞离模型表面快粒子贴附表面,流动感弱0.5 到 5
Start Size粒子尺寸覆盖面积大,但容易遮挡模型细节精细,但远处不可见0.05 到 0.5
Simulation Space模拟空间是 World 还是 LocalLocal 跟随特效节点,World 不会自动跟随取决于是否想让粒子留在原地角色特效一般选 Local
Rate over Time每秒发射数量粒子更密,开销增加表现断续50 到 500

这里的典型值适用于中等体型的人形角色,不是通用标准。调试时先把 Start Speed 调成 0,看粒子是否贴合表面;再把 Start Speed 逐步加大,观察粒子离开表面的方向。

4.3 自定义 Shader 读取顶点色

粒子系统的内置 Shader 不一定能充分使用顶点色。要精确控制效果,需要自定义 Shader。下面这段 ShaderLab 示例演示了如何读取顶点色并用 Red 通道控制发光强度。

Shader "VFX/VertexColorGlow" { Properties { _BaseColor ("Base Color", Color) = (0.2, 0.2, 0.2, 1) _GlowColor ("Glow Color", Color) = (1, 0.6, 0, 1) _GlowPower ("Glow Power", Range(0, 5)) = 1 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float4 color : COLOR0; }; struct v2f { float4 pos : SV_POSITION; float4 color : COLOR0; }; float4 _BaseColor; float4 _GlowColor; float _GlowPower; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.color = v.color; return o; } fixed4 frag(v2f i) : SV_Target { float glow = saturate(i.color.r) * _GlowPower; fixed3 col = lerp(_BaseColor.rgb, _GlowColor.rgb, glow); return fixed4(col, i.color.a); } ENDCG } } }

代码里最关键的一行是float4 color : COLOR0,它声明了顶点色输入。如果 Shader 里根本没有这个结构体字段,模型表面就算有顶点色也不会对渲染结果产生任何影响。用这个 Shader 可以验证:模型顶点色 Red 通道越高的区域,越接近_GlowColor指定的发光色。

这段示例面向内置渲染管线。URP 项目不建议直接搬运这段 Cg 代码,应当使用 URP Shader 模板和 HLSL 库。在 URP 项目里更快的做法是打开 Shader Graph,添加一个 Vertex Color 节点,把输出接到 Base Color 或 Emission 上。

4.4 Shader 变体与材质管理

Mesh-Based VFX 的 Shader 变体需要提前规划。同一个 Shader 如果既要支持顶点色,又要支持遮罩纹理,还要支持不同的混合模式,会产生较多变体。项目里出现内存陡增、构建时间变长时,先排查特效相关 Shader 的变体数量。

建议做法是:

  • 特效 Shader 单独成一类,不跟普通角色材质共用。
  • 用到顶点色时,把#pragma multi_compile替换成固定关键词,尽量减少组合。
  • 移动端不使用的特性尽量用#pragma shader_feature_local隔离。

4.5 淡出控制用脚本完成,不要直接销毁

角色技能结束、物体消失时,特效应该有一个从浓到淡的消失过程。不要用Destroy直接删除特效对象,因为粒子系统即使在销毁瞬间也会产生视觉跳变。

正确做法是通过脚本插值控制两个参数:

using UnityEngine; public class VfxFadeOut : MonoBehaviour { public ParticleSystem targetParticle; public float fadeDuration = 0.5f; private float startEmissionRate; private float timer; void Start() { ParticleSystem.EmissionModule emission = targetParticle.emission; startEmissionRate = emission.rateOverTime.constant; } public void PlayFadeOut() { StartCoroutine(FadeOutRoutine()); } private System.Collections.IEnumerator FadeOutRoutine() { timer = 0f; while (timer < fadeDuration) { timer += Time.deltaTime; float t = Mathf.Clamp01(timer / fadeDuration); ParticleSystem.EmissionModule emission = targetParticle.emission; emission.rateOverTime = Mathf.Lerp(startEmissionRate, 0f, t); yield return null; } targetParticle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } }

这段脚本的思路是把发射率从初始值平滑降到 0,等现有粒子自然消亡后再停止和清空。实际项目里还可以把材质 Alpha、粒子 Size 一起插值,效果更细腻。

5. 运行验证与性能观测:不能只看屏幕上有没有特效

5.1 功能验证清单

效果做出来后,至少要检查以下五个维度,不能只看粒子是否出现。

  • 贴合度:旋转摄像机,从各个角度看粒子是否都在模型表面附近,而不是贴在某个固定平面。
  • 动画跟随:播放奔跑、攻击、表情动画,确认粒子出生位置随骨骼姿势变化。
  • 顶点色权重:模型阶段如果规划了 Red 控制强度,就要验证高 Red 区域是否确实更亮、低 Red 区域是否更暗。
  • 区域裁剪:用第二套 UV 或顶点色作为遮罩时,验证特效没有出现在模型以外的区域。
  • 生命周期:技能结束、角色死亡、物体隐藏时,特效是否能平滑消失,不残留也不跳变。

5.2 性能观测点

Unity 自带 Profiler 是主要观测工具,打开Window -> Analysis -> Profiler,重点观察两个窗口:

  • CPU:脚本里的LateUpdateBakeMesh、粒子系统更新耗时。
  • GPU:粒子渲染、Shader 复杂度、Overdraw。

除了这两个窗口,还需要检查以下指标:

指标检查方式关注点
Draw Call打开 Frame Debugger特效是否产生了不必要的新批次
粒子数量Particle System 面板或 VFX Graph 输出是否超过性能预算
BakeMesh 调用频率在脚本里加 Log 或 Profiler 标记是否每帧调用,是否无意义刷新
Shader 变体数构建报告或 Shader Explorer特效相关变体是否过多
内存Memory ProfilerMesh 缓存对象是否被反复创建

一个常见的性能坑是在 Update 里每帧都new Mesh(),这会产生大量 GC 压力。正确做法是在 Awake 里创建一次 Mesh 对象,后续每帧只复用这同一个缓存对象。

5.3 学习环境与生产环境的验证差异

学习环境的目标是快速看效果,可以牺牲性能。生产环境必须同时验证功能和资源。

学习环境下建议先使用低模 Cube 或标准资源验证技术链路,不要在美术模型未到位前就把效果完整做出来,否则后面换模型时会重复调参。

开发环境下要验证不同骨骼绑定、不同动画文件、不同 LOD 层级的兼容性。生产环境还需要额外验证移动端真机表现、网络资源加载、热更新资源的管理,以及特效 Shader 在不同 GPU 上的回退情况。

5.4 不同实现方案的效果对比

实现方案贴合度动画跟随移动端压力灵活度实现成本
传统粒子叠加
纯 Shader 特效
Particle System + Mesh Shape
VFX Graph + Mesh 采样
Particle System + 自定义 Shader 读取顶点色

这里不是要说明哪一种方案绝对更好,而是要根据项目目标和平台选型。需要细腻的逐顶点控制,就选择 VFX Graph 方向;平台兼容性优先,就选择 Particle System 配合自定义 Shader。

6. 常见问题排查:漂移、朝向错、不显示、性能抖动

6.1 特效整体不显示

现象:场景一切正常,但特效完全没有粒子。

排查顺序:

  1. 检查 Mesh 是否为空。如果 VFX Graph 的SourceMesh属性没有传入网格,粒子就没有出生位置。
  2. 检查材质 Shader 是否支持需要的数据。如果 Shader 要求顶点色,但模型没有顶点色,输出的颜色可能被裁剪为完全透明。
  3. 检查特效对象的 Layer 和相机剔除掩码。粒子渲染在默认层,而相机只渲染其他层时,粒子不会可见。
  4. 检查 Particle System 的Max Particles。如果粒子数超出限制,新粒子会被丢弃,表现上就是没有粒子。
  5. 检查 VFX Graph 是否处于 Enable 状态,以及可视化面板里是否出现编译错误。

6.2 粒子位置漂移,不跟随骨骼

现象:粒子刚开始贴合角色,角色跑动后粒子留在原地或偏离。

可能原因:

  • 模拟空间设置错误。角色特效应该使用 Local 模拟空间,如果粒子系统选了 World,粒子会留在世界坐标中,不跟随角色移动。
  • 脚本没有在 LateUpdate 中执行 BakeMesh,导致网格数据停留在上一帧姿势。
  • bakeEveryFrames设置过大,动画变化没能及时反映到 Mesh 采样结果中。
  • VFX Graph 中采样的 Mesh 属性没有被脚本更新,一直使用初始静态网格。

处理方式:

  • 把 Simulation Space 改为 Local。
  • 确认脚本更新频率与动画变化匹配。
  • 在 VFX Graph 属性面板中确认SourceMesh每帧都在变化。

6.3 喷射方向反了或朝向错误

现象:粒子朝模型内部喷射,或者粒子朝向与期望方向相反。

排查路径:

  1. 先确认 Mesh 的法线是否朝外。在模型资源或 3D 软件里检查法线方向。
  2. 再确认采样法线时使用的空间。如果采样到的是本地空间法线,而粒子系统使用的是世界空间,方向就会错。
  3. 检查 VFX Graph 中法线乘的速度系数是否为正数。乘了一个负数系数,方向自然反转。
  4. 检查粒子渲染方式。Quad 渲染的粒子如果朝向设置不正确,看起来会变成线或消失。

6.4 顶点色没有生效

现象:模型在 3D 软件里刷了顶点色,但 Unity 里特效完全没有按权重出现。

原因通常有三个:

  • 模型导入设置没有保留顶点色。FBX 导入后,在 Model 选项卡下确认相关选项。
  • Shader 没有声明COLOR0输入,就像上面示例 Shader 里缺失float4 color : COLOR0一样。
  • 项目里美术制作流程本身没有把顶点色烘焙进模型资源,只是把颜色存在贴图里。

检查方式:在模型预览窗口打开顶点颜色通道,确认顶点色数据确实存在。再用一个简单的 Shader 把顶点色直接输出到 Base Color,如果画面呈现彩色,说明数据通道已打通。

6.5 移动端性能抖动

现象:PC 上表现正常,安卓真机上粒子数量不稳定,帧率波动大。

通常原因:

  • 粒子数量超预算,CPU 更新压力大。
  • VFX Graph 某些节点在移动端 GPU 不兼容,回退执行到 CPU 路径。
  • Shader 变体数量过多,渲染时反复编译。
  • 特效贴图没有合图,采样次数过多。

处理建议:

  • 先做真机 Profile,拿到 CPU 和 GPU 的具体耗时,不要凭感觉猜。
  • 把粒子数量降到移动端预算内。
  • 把不支持的 VFX Graph 节点替换成 Particle System 或 Shader 方案。
  • 特效贴图合并到图集中,减少采样切换。
  • 移动端控制 Overdraw,缩小粒子尺寸并减少透明叠加层数。

6.6 问题速查表

问题现象常见原因检查方式处理建议
特效完全不显示Mesh 为空或 Shader 裁剪检查 VFX Graph 属性、材质补材质和 Mesh 数据
粒子漂移模拟空间 World检查 Simulation Space改为 Local
不跟随骨骼BakeMesh 未调用检查脚本 Update 顺序在 LateUpdate 中烘焙
喷射方向反法线空间或系数错误检查法线采样节点校正空间和系数
顶点色无效Shader 未读 COLOR0检查 Shader 输入添加顶点色声明
性能抖动粒子数超预算Profiler 看 CPU/GPU降粒子/换方案

7. 生产落地建议与扩展方向

7.1 从 Demo 到生产需要补齐的工程能力

Demo 和生产的差距通常不在这里技术路线本身,而在资源管理和异常处理。

生产环境要做的事包括:

  • 资源版本管理:特效材质、Shader、Mesh 缓存对象要有明确的命名和目录规范。
  • 按距离和可见性淘汰:角色远离摄像机时降低粒子量,完全不可见时停掉特效。
  • 对象池管理:角色经常被创建和销毁时,特效对象要复用,避免反复实例化造成 GC。
  • LOD 策略:高精度角色使用完整顶点采样,低精度角色切换到普通贴图特效。
  • 异常处理:BakeMesh前后检查 SkinnedMeshRenderer 是否被销毁,避免空引用。
  • 日志和监控:特效异常时输出 Error 日志,记录粒子数和脚本执行耗时。

7.2 发布前检查清单

制作完成后,在提交版本前建议按这个清单过一遍,可以显著减少发布后的意外问题。

| 检查项 | 检查方式 | 失败时的处理 | |

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 2:47:01

阿里云万相3.0:云端AI视频生成平台核心能力与工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 2:46:55

KTransformers:突破显存限制的本地大模型异构推理方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 2:46:36

AI+生信零基础实战:7天用Agent完成数据分析全流程

2026年做生信&#xff0c;最值得投入的一条路线就是把AI和Agent用起来。这篇内容专门聊一套面向零基础的《AI生信》全套学习路线&#xff1a;从AI分析工作站的搭建&#xff0c;到用Agent零代码完成一篇生信分析&#xff0c;再到自动获取数据。核心不是让你背一堆概念&#xff0…

作者头像 李华
网站建设 2026/9/3 2:44:47

光刻仿真入门:从开源工具到完整环境搭建实战指南

简介&#xff1a;本资源为面向半导体工艺工程师与微纳器件研究人员的光刻仿真工具Optolithium安装包及配套源码&#xff0c;用于建模、预测并优化光刻过程中的光学成像、光刻胶响应与显影形貌&#xff0c;解决高精度掩模修正、OPE补偿及EUV/DUV工艺可行性验证等核心问题。压缩包…

作者头像 李华
网站建设 2026/9/3 2:42:47

Python招聘数据爬虫与可视化分析:从ETL到BI的完整项目实战

简介&#xff1a;本资源是一套面向计算机专业本科生的招聘岗位数据挖掘与可视化分析实战项目&#xff0c;专为课程设计与期末大作业打造&#xff0c;覆盖爬虫采集、数据清洗、MySQL存储、多维度统计分析及交互式图表呈现全流程。压缩包共59个文件&#xff0c;包含9个核心Python…

作者头像 李华
网站建设 2026/9/3 2:42:41

C#实现CAN DBC文件解析与编辑工具:从原理到实战

简介&#xff1a;这是一款面向汽车电子、嵌入式通信及CAN总线开发工程师的DBC文件解析与可视化工具&#xff0c;基于C#开发&#xff0c;适用于CAN协议分析、ECU信号调试及车载网络逆向工程等场景&#xff0c;初学者可快速理解DBC结构&#xff0c;资深开发者可直接用于二次集成。…

作者头像 李华