尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Unity3D特效TA实战:粒子、Shader、TimeLine与脚本工具全链路

发布时间:2026/9/28 18:46:47

资讯中心
01
ARTICLE

Unity3D特效TA实战:粒子、Shader、TimeLine与脚本工具全链路

Unity3D特效TA实战:粒子、Shader、TimeLine与脚本工具全链路
游戏特效这个方向很多人第一反应是“酷炫”“烧显卡”“大厂专属”但真正做过项目的人都知道特效师和TA之间的那道墙往往不是审美而是技术实现路径的断裂。我见过太多特效同学粒子调得飞起一碰到Shader就卡壳也见过程序出身的TA脚本写得漂亮但粒子节奏和视觉层次完全不对味。这篇内容就是想把这两端打通——围绕Unity3D这套工具链把粒子系统、Shader、TimeLine和脚本工具这四块拼图按照实际项目里TA最常走的流程串起来讲。不管你是刚入行的特效新人还是想往TA方向转的老手下面这些内容都是我踩过坑、返过工、在项目上线前夜改到凌晨三点之后攒下来的东西不是教科书式的功能罗列。1. 先搞清楚游戏TA在特效管线里到底管什么1.1 特效师和TA的分工边界在哪里很多团队在招人的时候会把“特效师”和“特效TA”混着写但实际干活的时候差别很大。特效师的核心产出是视觉效果本身——粒子怎么爆、拖尾怎么飘、节奏怎么卡点这些偏艺术感知。而特效TA的核心产出是让这些效果能被高效、稳定、可复用地生产出来。举个具体的例子特效师说“我想要一个火焰从地面往上烧边缘带溶解中间有热扭曲”特效师负责调出这个感觉TA负责把这个效果做成一个可配置的预制体让特效师改几个参数就能出红火、蓝火、毒火三个变体而不是每个都从头调一遍。这个边界决定了TA必须同时懂两件事一是渲染管线的基本原理知道一个粒子从发射到显示在屏幕上经过了哪些环节二是工具链的搭建能力能把重复劳动封装成脚本或工具。Unity3D里这两件事的交汇点就是粒子系统、Shader、TimeLine和编辑器脚本这四块。1.2 为什么这四块技术必须一起学单独看每一块都不难难的是它们之间的数据流转。粒子系统负责生成和驱动粒子Shader负责决定每个粒子长什么样TimeLine负责把多个特效和动画按时间轴编排脚本工具负责把前面三者的配置自动化。我见过一个典型的翻车场景特效师在粒子系统里调好了颜色随生命周期变化的曲线结果TA写了一个自定义Shader把顶点颜色通道占用了粒子的颜色变化直接失效。这就是因为只懂单点技术不懂数据在管线里的传递关系。再比如TimeLine很多人觉得它就是个做动画的工具但实际上在特效管线里TimeLine是特效节奏的总控台。一个Boss的技能特效可能包含粒子爆发、模型溶解、屏幕后处理、音效触发四个部分这四个部分的时间对齐如果靠手动调改一次需求就要重新对一遍。用TimeLine把这些轨道绑在一起改总时长的时候所有子效果自动缩放这才是TA该做的事。1.3 一个合格的特效TA需要具备哪些底层认知我总结下来是三个层面的认知。渲染层面知道Draw Call是怎么产生的知道Overdraw为什么在移动端是性能杀手知道Alpha Blend和Alpha Test的区别以及各自适用的特效类型。工具层面知道Unity的编辑器扩展能做什么、不能做什么知道ScriptableObject怎么用来做配置资产知道Prefab Variant怎么管理特效变体。协作层面知道怎么把技术方案翻译成特效师能听懂的语言知道怎么设计参数暴露让美术同学不会调崩。这三层认知里渲染层面是基础工具层面是手段协作层面是目的。下面几个章节会按照实际项目里TA最常走的流程把这四块技术逐一拆开讲。2. 粒子系统不只是调参数而是理解数据流2.1 粒子系统的模块化思维Unity的粒子系统看起来是一堆勾选框和参数但它的设计逻辑是模块化叠加。每个模块负责一个维度的控制模块之间通过粒子属性互相影响。理解这一点很重要因为很多特效师调效果是“凭感觉试”而TA应该知道每个参数改的是哪个数据通道。举个具体的例子。Main模块里的Start Color和Color over Lifetime模块两者都影响粒子颜色但作用方式不同。Start Color是粒子出生时赋一个初始值Color over Lifetime是在生命周期内对颜色做插值。如果两个都开了最终颜色是相乘的关系。这意味着如果你在Start Color里给了一个深红色在Color over Lifetime里又给了一个从白到透明的渐变最终效果是深红色逐渐变透明而不是从深红变白再变透明。这个细节在调火焰特效的时候特别关键很多新人调出来的火焰发灰就是因为没搞清楚这个乘法关系。再比如Velocity over Lifetime和Limit Velocity over Lifetime这两个模块。前者是给粒子一个速度曲线后者是限制粒子的最大速度。如果两个同时开Limit Velocity会在Velocity计算完之后再做一个钳制。这个顺序在Unity的文档里没有明确写出来但实际测试可以验证当Limit Velocity的Dampen参数大于0时粒子速度超过阈值的部分会被逐渐削减而不是硬截断。这个特性在做烟雾扩散效果的时候很好用可以让烟雾边缘自然减速。2.2 粒子数据在Shader里怎么被读取粒子系统生成的每个粒子本质上是一组顶点数据。Unity的粒子渲染器会把粒子的位置、大小、旋转、颜色、生命周期进度等信息打包成顶点属性传给Shader。默认的粒子Shader会读取这些属性来渲染。但如果你要写自定义Shader就必须知道这些数据存在哪个通道里。Unity内置的粒子顶点数据结构大致是这样的vertex.xyz是粒子中心位置vertex.w是粒子大小texcoord0.xy是粒子的UVtexcoord1.xy是粒子的生命周期进度0到1color是粒子的颜色包含Alpha。这个布局不是固定的取决于粒子系统里开启了哪些模块。比如你开了Custom Vertex Streams就可以自定义哪些数据传到哪个通道。这里有一个非常实用的技巧如果你想让Shader根据粒子的生命周期进度做颜色变化但又不想用Color over Lifetime模块因为那个模块是在CPU端计算的粒子多了会有性能开销可以在Shader里直接读texcoord1.x用这个值去采样一张渐变纹理。这样做的好处是颜色变化在GPU端完成CPU只需要传一个固定的进度值性能会好很多。我在一个移动端项目里用这个方法把火焰特效的CPU耗时从2.3ms降到了0.8ms效果几乎看不出差别。2.3 粒子碰撞和触发模块的实战取舍粒子碰撞Collision和触发Trigger这两个模块在实际项目里用得不多因为性能开销大但在某些特定场景下又绕不开。比如地面上的雨水溅射效果如果不用碰撞粒子会直接穿到地面以下如果用了碰撞每个粒子都要做一次物理检测粒子数一多就卡。我的经验是能用假碰撞就不用真碰撞。所谓假碰撞就是在Shader里根据粒子的世界坐标Y值做一个判断如果Y小于地面高度就把粒子裁剪掉或者改变颜色。这个方法不需要物理引擎参与性能几乎为零。具体做法是在顶点着色器里计算粒子的世界坐标然后跟一个预设的地面高度做比较如果低于地面就输出一个退化三角形所有顶点重合这样粒子就不会被渲染出来。真碰撞只在一种情况下必须用粒子需要跟动态物体发生交互。比如一个角色走过水面水花要溅到角色身上然后滑落这种就需要真实的碰撞检测。但即便如此也要把碰撞的粒子数控制在很小的范围内比如只让距离角色最近的20个粒子参与碰撞其余的用假碰撞处理。2.4 粒子系统的性能陷阱与优化手段粒子系统的性能问题主要来自三个方面粒子数量、Overdraw、CPU端的模块计算。粒子数量是最直观的但很多人不知道的是Unity的粒子系统在CPU端有一个固定的更新开销即使粒子数为零只要粒子系统处于激活状态就会有大约0.1ms的耗时。所以在做对象池的时候不用的粒子系统一定要SetActive(false)而不是只把Emission关掉。Overdraw是移动端特效的头号杀手。一个全屏的爆炸特效如果粒子都是大面积的半透明面片Overdraw可能达到10层以上GPU填充率直接爆掉。解决办法有两个一是用Alpha Test代替Alpha Blend虽然边缘会有硬边但可以通过提高纹理精度来缓解二是用粒子裁剪在Shader里根据粒子的屏幕空间位置把屏幕边缘的粒子裁剪掉减少无效填充。CPU端的模块计算是另一个容易被忽略的点。Color over Lifetime、Size over Lifetime、Rotation over Lifetime这些模块如果曲线复杂度高CPU计算量会明显上升。一个实用的优化手段是把曲线烘焙成一张纹理在Shader里采样。Unity的粒子系统支持把曲线导出为纹理但需要手动操作。更彻底的做法是直接用Custom Vertex Streams把生命周期进度传给Shader在Shader里做所有的曲线计算。这样做的前提是你对Shader足够熟悉否则调试成本会很高。3. Shader特效视觉的上限由它决定3.1 特效Shader和普通Shader的区别普通场景Shader的目标是正确特效Shader的目标是好看且高效。这个区别决定了特效Shader可以牺牲一些物理正确性来换取视觉冲击力。比如一个火焰Shader不需要考虑能量守恒只需要让颜色从黄到红到黑过渡得自然一个溶解Shader不需要考虑材质真实的溶解过程只需要让边缘有烧焦的辉光。Unity里写特效Shader最常用的是表面着色器Surface Shader和顶点片元着色器Vertex/Fragment Shader。表面着色器写起来简单Unity会自动处理光照和阴影但可控性差而且生成的代码比较臃肿。顶点片元着色器写起来麻烦但每一行代码你都知道它在干什么性能也更好控制。我的建议是特效Shader一律用顶点片元因为特效通常不需要复杂的光照模型而且你需要精确控制每一个渲染状态。3.2 双面材质Shader在特效里的应用双面材质是特效里非常常见的一个需求。比如一个飘动的旗帜、一片旋转的树叶、一个从中间裂开的护盾这些效果都需要模型的正反两面都能被渲染。Unity默认的Shader是背面剔除的也就是说从背面看过去是透明的。要实现双面渲染最简单的方法是在Shader里加上Cull Off指令。但Cull Off只是让背面也被渲染并没有解决背面的光照问题。如果直接用同一个法线背面的光照会是错的。正确的做法是在片元着色器里判断当前渲染的是正面还是背面如果是背面就把法线取反。判断的方法是用VFACE语义这个值在正面是1背面是-1。具体代码大概是这样fixed4 frag(v2f i, fixed facing : VFACE) : SV_Target { float3 normal i.normal * (facing 0 ? 1 : -1); // 用normal做后续光照计算 }这个技巧在做护盾特效的时候特别有用。护盾通常是一个半透明的球体从外面看和从里面看需要有不同的颜色和透明度。用VFACE区分正反面正面用偏蓝的颜色背面用偏紫的颜色叠加起来就有一种能量流动的感觉。3.3 溶解Shader的核心原理与参数暴露溶解效果是特效TA的必修课。它的原理其实很简单用一张噪声纹理采样把采样值和溶解进度做比较小于阈值的像素裁剪掉。但要做好看有几个细节需要注意。第一是噪声纹理的选择。Perlin噪声比较柔和适合做自然的消散Voronoi噪声有块状感适合做破碎效果FBM分形布朗运动噪声层次丰富适合做火焰燃烧的边缘。我通常会在项目里准备三四张不同风格的噪声纹理根据效果需求切换。第二是边缘辉光的处理。单纯的裁剪边缘是硬的不好看。需要在裁剪阈值附近做一个过渡带在这个带里的像素加上辉光颜色。过渡带的宽度可以通过一个参数控制太窄了辉光不明显太宽了会显得糊。我的经验值是过渡带宽度在0.05到0.15之间比较合适具体取决于噪声纹理的频率。第三是参数暴露的设计。溶解Shader至少需要暴露这几个参数溶解进度0到1、边缘颜色、边缘宽度、噪声纹理、噪声强度。如果要做多方向的溶解还需要暴露溶解方向。这些参数最好用[Header()]和[Space()]分组让特效师在材质面板里一目了然。3.4 顶点动画与UV动画的配合特效Shader里经常需要做顶点动画比如让一个面片像波浪一样起伏或者让一个模型沿着某个方向扭曲。顶点动画在顶点着色器里做UV动画在片元着色器里做两者配合可以做出很丰富的效果。一个典型的例子是冲击波。冲击波通常是一个圆环面片从中心向外扩散。顶点动画负责让圆环在扩散方向上有一个轻微的隆起UV动画负责让圆环上的纹理流动起来。具体实现的时候顶点动画用sin函数根据顶点到中心的距离做偏移UV动画用_Time变量做滚动。两者叠加之后视觉上就是一个有厚度、有流动感的冲击波。这里有一个性能上的注意点顶点动画的计算量跟顶点数成正比所以做顶点动画的模型面数不能太高。一个圆环面片用32个分段就够了再高的话视觉提升不明显但顶点计算量翻倍。UV动画的计算量跟像素数成正比所以UV动画的纹理不要太大256x256通常就够用了512x512在移动端就有点浪费了。3.5 Shader性能优化的几个硬指标特效Shader的性能优化核心是控制填充率和指令数。填充率的问题前面讲Overdraw的时候提过了这里重点说指令数。移动端GPU的ALU指令数是有硬性限制的一个片元着色器如果超过一定数量的指令就会触发降级或者直接编译失败。减少指令数的几个实用手段一是合并计算比如把多个lerp合并成一个mad指令二是用查找表代替计算比如把复杂的数学函数预计算到一张纹理里用UV采样代替实时计算三是降低精度移动端可以用half代替float虽然精度低一些但指令吞吐量翻倍。还有一个容易被忽略的点是变体数量。Unity的Shader变体Shader Variant如果太多打包时间会很长运行时也可能因为变体切换导致卡顿。特效Shader通常不需要支持太多变体把不需要的关键字比如阴影、光照贴图关掉可以显著减少变体数量。我一般会在Shader开头加上#pragma skip_variants指令把用不到的关键字全部跳过。4. TimeLine特效节奏的总控台4.1 TimeLine在特效管线里的定位TimeLine在Unity里经常被当作一个“做动画的工具”但在特效管线里它的定位应该是多轨道效果的时间编排器。一个复杂的技能特效往往包含粒子、动画、Shader参数、音效、后处理等多个部分这些部分如果各自独立播放时间对齐全靠手动改一次需求就要重新对一遍。用TimeLine把这些轨道绑在一起改总时长的时候所有子效果自动缩放这才是TA该做的事。TimeLine的核心概念是轨道Track和片段Clip。轨道是同一类型效果的容器片段是轨道上的一个具体效果。比如一个“粒子轨道”上可以放多个粒子片段每个片段控制一个粒子系统的播放。TimeLine还支持信号Signal可以在特定时间点触发事件比如在特效爆发的瞬间触发屏幕震动。4.2 用TimeLine编排复杂特效的实操流程假设我们要做一个Boss的死亡特效包含四个阶段Boss身体发光、身体溶解、粒子爆发、地面裂开。用TimeLine编排的流程大概是这样的。第一步创建一个TimeLine资产绑定到Boss的GameObject上。第二步添加一个激活轨道Activation Track控制Boss模型的显示和隐藏。第三步添加一个动画轨道Animation Track控制Boss的死亡动画。第四步添加一个粒子轨道Particle Track把粒子爆发的粒子系统拖上去。第五步添加一个信号轨道Signal Track在粒子爆发的瞬间触发屏幕震动和后处理效果。这里的关键是时间对齐。Boss身体发光和溶解是同时开始的粒子爆发是在溶解进行到一半的时候开始的地面裂开是在粒子爆发之后。这些时间点如果靠手动拖拽改总时长的时候会全部乱掉。正确的做法是用TimeLine的片段缩放功能把所有片段的时间长度设成相对于总时长的比例这样改总时长的时候所有片段自动缩放。4.3 TimeLine与脚本的交互方式TimeLine本身是一个资产但它的播放控制需要通过脚本。Unity提供了PlayableDirector组件来播放TimeLine你可以通过脚本调用Play()、Pause()、Stop()等方法。更高级的用法是通过PlayableGraphAPI在运行时动态构建TimeLine但这种方式比较复杂一般项目里用不到。实际项目里最常用的交互方式是信号Signal。你可以在TimeLine上添加信号发射器Signal Emitter然后在脚本里监听这个信号触发相应的逻辑。比如在特效爆发的瞬间通过信号触发一个屏幕震动脚本或者通过信号触发音效播放。信号的好处是解耦——TimeLine不需要知道屏幕震动是怎么实现的只需要在正确的时间点发出信号具体的逻辑由脚本处理。还有一个实用的技巧是用TimeLine控制Shader参数。Unity的TimeLine支持材质轨道Material Track可以动画化材质的属性。比如你可以用材质轨道控制溶解Shader的溶解进度让溶解效果跟TimeLine的时间轴精确对齐。这个功能在做Boss死亡特效的时候特别好用因为溶解进度需要跟粒子爆发的时间点精确匹配。4.4 TimeLine在移动端的性能考量TimeLine在移动端的性能开销主要来自两个方面轨道数量和片段复杂度。轨道数量越多TimeLine的更新开销越大。一个包含10条轨道的TimeLine每帧的更新开销大约在0.2ms左右在移动端这个开销不算小。所以移动端项目里TimeLine的轨道数量要尽量精简能合并的轨道就合并。片段复杂度是另一个考量点。动画轨道上的动画片段如果关键帧太多采样开销会很大。我的经验是移动端项目里动画片段的关键帧密度不要超过每秒10帧超过的部分用曲线插值代替。粒子轨道上的粒子片段如果粒子系统本身很复杂TimeLine的更新开销也会增加。这种情况下可以考虑把粒子系统从TimeLine里独立出来用脚本控制播放TimeLine只负责发信号。还有一个容易被忽略的点是TimeLine资产的加载。TimeLine资产如果太大加载时间会很长。移动端项目里TimeLine资产最好做成按需加载不要跟场景一起加载。可以用Addressables系统把TimeLine资产做成远程加载用到的时候再加载进来。5. 脚本工具把重复劳动自动化5.1 特效TA最常写的几类脚本特效TA写的脚本跟程序写的脚本不太一样。程序写的脚本偏逻辑TA写的脚本偏编辑器扩展和批处理。我统计了一下自己过去两年写的脚本大概可以分成四类。第一类是批量修改工具。比如批量修改选中粒子的材质、批量设置粒子的渲染层级、批量替换粒子使用的纹理。这类工具的核心是Selection.gameObjects和Undo.RecordObject前者获取选中的对象后者记录修改以便撤销。第二类是配置生成工具。比如根据一张Excel表格生成粒子系统的配置或者根据一个ScriptableObject生成多个Prefab变体。这类工具的核心是AssetDatabase和PrefabUtility前者管理资产后者管理预制体。第三类是预览工具。比如在编辑器里预览粒子在不同光照条件下的效果或者预览Shader在不同参数下的表现。这类工具的核心是EditorWindow和Handles前者创建自定义窗口后者在场景视图里绘制辅助图形。第四类是性能检测工具。比如统计场景里所有粒子系统的粒子总数、统计所有特效的Overdraw、检测Shader的变体数量。这类工具的核心是ProfilerAPI和ShaderUtil前者获取性能数据后者获取Shader信息。5.2 用编辑器脚本批量处理粒子配置批量处理粒子配置是TA最常做的自动化任务。假设美术同学做了50个特效预制体现在需要把所有特效的粒子渲染层级从“Default”改成“Effect”手动改的话要改50次用脚本的话几秒钟就搞定。[MenuItem(Tools/Effect/Set Particle Render Queue)] static void SetParticleRenderQueue() { var selected Selection.gameObjects; foreach (var go in selected) { var systems go.GetComponentsInChildrenParticleSystem(); foreach (var ps in systems) { var renderer ps.GetComponentParticleSystemRenderer(); Undo.RecordObject(renderer, Set Render Queue); renderer.renderQueue 3000; // Effect队列 } } AssetDatabase.SaveAssets(); }这段代码的核心是Undo.RecordObject它让修改可以被撤销。如果没有这一行美术同学改错了就没法回退会来找你麻烦。另一个关键是AssetDatabase.SaveAssets()它把修改保存到磁盘否则重启Unity之后修改就丢了。5.3 ScriptableObject在特效配置管理中的角色ScriptableObject是Unity里做配置管理的利器。它的好处是资产化——配置数据可以像普通资产一样被引用、被版本管理、被打包。特效TA可以用ScriptableObject来管理特效的全局配置比如不同品质等级下的粒子数量上限、不同平台下的Shader变体选择、不同场景下的渲染层级设置。举个具体的例子。我们可以创建一个EffectQualityConfig的ScriptableObject里面定义低、中、高三个品质等级每个等级对应一组参数[CreateAssetMenu(fileName EffectQualityConfig, menuName Effect/Quality Config)] public class EffectQualityConfig : ScriptableObject { [System.Serializable] public class QualityLevel { public string name; public int maxParticles 100; public int maxOverdraw 3; public bool useAlphaTest false; public bool useVertexAnimation true; } public QualityLevel[] levels; }然后在运行时根据设备性能选择对应的品质等级把参数应用到所有粒子系统上。这样做的好处是配置和逻辑分离改配置不需要改代码策划同学也能参与调整。5.4 脚本工具与TimeLine、Shader的联动脚本工具的价值不仅在于单独使用更在于跟TimeLine和Shader联动。比如你可以写一个脚本在TimeLine播放到特定时间点时动态修改Shader的参数。这个功能在做动态难度调整的时候特别有用——根据玩家的设备性能动态调整特效的复杂度。具体实现方式是通过TimeLine的信号系统。在TimeLine上添加一个信号发射器然后在脚本里监听这个信号在信号触发的时候修改Shader的全局参数。比如public class EffectQualitySignal : MonoBehaviour { public EffectQualityConfig config; public int currentLevel 2; void OnEnable() { var director GetComponentPlayableDirector(); director.signalReceived OnSignalReceived; } void OnSignalReceived(SignalAsset asset) { var level config.levels[currentLevel]; Shader.SetGlobalInt(_MaxParticles, level.maxParticles); Shader.SetGlobalFloat(_OverdrawLimit, level.maxOverdraw); } }这个脚本在TimeLine发出信号的时候把当前品质等级的参数设置到Shader的全局变量里。Shader里根据这些全局变量做相应的裁剪和降级。这样就实现了TimeLine驱动、脚本控制、Shader执行的完整链路。6. 把四块技术串起来一个完整的特效管线案例6.1 案例背景一个Boss技能特效的完整制作流程假设我们要做一个Boss的“暗影爆发”技能效果是Boss身体变暗、地面出现暗影裂缝、暗影能量从裂缝中喷涌而出、最后形成一个暗影球爆炸。这个特效涉及粒子、Shader、TimeLine和脚本工具四块技术正好可以串起来讲。第一步是Shader准备。Boss身体变暗需要一个“暗化Shader”原理是在片元着色器里把颜色乘以一个小于1的系数同时增加一点紫色偏移。地面裂缝需要一个“裂缝Shader”原理是用一张裂缝纹理做Alpha Test同时让裂缝边缘有辉光。暗影球需要一个“能量球Shader”原理是菲涅尔效应加上流动的噪声纹理。第二步是粒子系统制作。暗影能量从裂缝喷涌需要三个粒子系统一个负责喷涌的主体一个负责边缘的烟雾一个负责地面的残留。主体粒子用Stretched Billboard模式让粒子沿着运动方向拉伸烟雾粒子用Billboard模式让粒子始终面向相机残留粒子用Horizontal Billboard模式让粒子平躺在地面上。第三步是TimeLine编排。创建一个TimeLine资产添加四条轨道Boss暗化轨道控制暗化Shader的参数、裂缝出现轨道控制裂缝Shader的溶解进度、粒子喷涌轨道控制三个粒子系统的播放、暗影球轨道控制暗影球的出现和爆炸。四条轨道的时间关系是Boss暗化先开始0.5秒后裂缝出现1秒后粒子喷涌2秒后暗影球出现3秒后暗影球爆炸。第四步是脚本工具辅助。写一个批量工具把三个粒子系统的渲染层级统一设置为“Effect”把三个Shader的变体数量统一降到最低把TimeLine资产的加载方式设置为Addressables按需加载。6.2 每个环节的踩坑记录与解决方案这个案例在实际制作过程中踩了不少坑挑几个有代表性的讲一下。第一个坑是Shader参数和TimeLine的时间对齐。暗化Shader的暗化进度是一个0到1的参数TimeLine的材质轨道可以动画化这个参数。但问题是材质轨道动画化的是材质实例的参数如果多个Boss共用同一个材质一个Boss的暗化会影响所有Boss。解决办法是在运行时给每个Boss创建一个材质实例用Renderer.material而不是Renderer.sharedMaterial。但这样做会增加Draw Call因为每个材质实例都是一个独立的渲染批次。最终的解决方案是用MaterialPropertyBlock它可以在不创建材质实例的情况下修改材质参数而且不会打断合批。第二个坑是粒子系统的播放和TimeLine的同步。粒子系统在TimeLine上播放的时候如果TimeLine暂停粒子系统也会暂停。但粒子系统的暂停和恢复有一个延迟导致TimeLine恢复播放的时候粒子会跳一下。解决办法是把粒子系统的main.simulationSpace设置为World这样粒子在暂停期间的位置不会因为TimeLine的暂停而改变。另一个办法是用ParticleSystem.Simulate()手动控制粒子的模拟但这需要把粒子系统的main.playOnAwake关掉完全由脚本控制。第三个坑是Shader变体在移动端的编译时间。能量球Shader用了菲涅尔效应和噪声流动涉及多个关键字组合变体数量一度达到200多个打包的时候编译了将近10分钟。解决办法是用#pragma skip_variants把用不到的关键字全部跳过同时把一些运行时分支改成静态分支。最终变体数量降到了30个左右编译时间降到1分钟以内。6.3 性能验收怎么判断一个特效是否达标特效做完之后怎么判断它是否达标我通常从四个维度来验收。帧率维度在目标设备上跑看特效播放期间的帧率波动。移动端的话帧率波动不能超过5帧否则玩家会有明显的卡顿感。如果波动超过5帧就要检查是CPU瓶颈还是GPU瓶颈。CPU瓶颈通常是粒子数量太多或者脚本逻辑太重GPU瓶颈通常是Overdraw太高或者Shader指令数太多。内存维度看特效占用的纹理内存和网格内存。一个特效的纹理内存通常控制在2MB以内网格内存控制在500KB以内。如果超过这个范围就要考虑压缩纹理或者减少网格面数。Draw Call维度看特效产生的Draw Call数量。一个特效的Draw Call通常控制在10个以内超过10个就要考虑合并材质或者使用GPU Instancing。视觉维度看特效在不同光照条件下的表现看特效在不同分辨率下的表现看特效在不同视角下的表现。视觉验收没有硬性标准但有一个基本原则特效在任何情况下都不能穿帮。比如粒子不能穿到地面以下Shader的溶解边缘不能出现硬边TimeLine的时间对齐不能有肉眼可见的偏差。6.4 从特效TA到技术美术的进阶路径特效TA做久了很容易陷入一个舒适区只会做特效相关的工具和Shader对场景、角色、UI的技术美术工作不了解。但真正的技术美术应该是跨领域的特效只是其中一个方向。如果你想从特效TA进阶到技术美术我建议从三个方面扩展。第一是渲染管线深入了解URP和HDRP的渲染流程知道每个Pass在做什么知道怎么自定义Render Feature。第二是性能分析学会用Profiler、Frame Debugger、RenderDoc等工具做深度性能分析知道怎么定位GPU瓶颈和CPU瓶颈。第三是工具链设计学会设计完整的工具链而不只是单个工具。比如设计一个从模型导入到特效生成到性能检测的完整管线让美术同学在一个界面里完成所有操作。这三个方向里渲染管线是基础性能分析是手段工具链设计是目标。我自己的经验是从特效TA到技术美术的转变最难的不是技术而是思维方式的转变——从“怎么实现这个效果”变成“怎么让这个效果被高效地生产出来”。这个转变需要时间但一旦完成你的价值会翻倍。最后分享一个我个人的小习惯每次做完一个特效我都会花10分钟写一个简短的复盘记录这个特效用了哪些技术、踩了哪些坑、下次可以怎么改进。这个习惯坚持了两年攒了上百条记录现在遇到新特效的时候翻一翻之前的记录大部分问题都能找到参考方案。特效TA这个岗位技术更新很快但踩过的坑和攒下的经验是不会过时的。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。