做游戏的人都知道,镜头是玩家和游戏世界之间的那层玻璃。镜头稍微抖一下,爆炸就有了重量;镜头处理得太平,再猛的场面也像在放幻灯片。UE5里实现摄像机抖动的方式不少,但最常用、最可控的路线,还是Perlin噪点这套——从代码层面把随机抖动变得平滑自然,再接到Sequence里做轨道化控制。这篇攻略就是围绕这条主线的完整实操记录:Perlin噪点的原理怎么理解、参数怎么调、Sequence里怎么接,以及我把这套方案落地到项目里踩过的那些坑。适合刚接触UE5镜头系统的朋友照着做,也适合已经能跑通基本流程、但觉得手感不够对的人用来做参数校准。
1. 内容整体设计与方案选型:为什么首选Perlin噪点
先别急着打开UE5找节点,想清楚一个问题:你需要的究竟是"随机的晃动",还是"看起来可信的抖动"?这两个目标在实现路径上差得非常远。
1.1 纯随机值、正弦波、Perlin噪点的真实差异
很多新手第一次做抖动,直接用每帧Random节点,给相机位置或旋转一个随机偏移。结果是镜头像得了帕金森一样高频乱颤,玩家看两眼就头晕。原因很简单:真实世界的震动是有惯性的。爆炸冲击波传递到镜头,先是一个猛烈峰值,然后渐渐衰减,过程中会有连续的小幅震荡,轨迹是平滑曲线,不是每帧从+10跳变到-10的离散点。
Perlin噪点做的事情,就是把这些离散的随机点"连接"成一条平滑曲线。它本质上是一种连续伪随机算法:在时间轴上取若干个随机梯度值,再用插值方式填补中间位置,输出的是一个随时间流动、连续变化的值。你把这个值加到相机旋转或位置上,得到的抖动就是"有情绪的",既保留了随机性,又不会出现突兀的帧间跳变。
正弦波叠加看起来也是平滑的,但它太规律了。sin(frequency * time)算出来的波形永远是同一个周期、同一个幅度,重复播放几次玩家就能看出破绽。Perlin噪点每次采样的曲线都不同,持续时间越长越难预测,观感上更接近物理冲击。
1.2 新老两套抖动系统的取舍
UE5里存在两套摄像机抖动API,很多教程混着讲,实际用起来容易踩坑。
第一套是UE4时代就有的Legacy Camera Shake,基类是UMatineeCameraShake。它用OscillationDuration、RotOscillation、LocOscillation这类参数控制抖动,特点是参数直接、直观,很多老项目迁移到UE5时还在用,网上搜到的旧教程也基本都在讲这套。
第二套是UE5正式主推的UCameraShakeBase派生的新系统,其中最常用的是UPerlinNoiseCameraShake。它把振幅和频率拆成"Multiplier"倍率形式,配合BlendIn/BlendOut来控制抖动渐入渐出。新系统的好处是支持衰减机制(Falloff),也更容易在Sequence里按轨道精确控制。
如果你是全新项目,建议直接用新系统。原因有三:第一,官方对老系统的维护基本停留在兼容层面,新功能都在新系统上;第二,新系统在Sequence中的集成度更高;第三,新系统的倍率设计配合曲线调节,比老系统的手写参数更容易做多级反馈(比如手枪、步枪、狙击枪分别给不同的倍率)。
1.3 我需要哪种抖动:反馈型、持续型、冲击型?
动手前先明确抖动类型,因为不同类型参数逻辑完全不同。
- 反馈型抖动:开枪、受击、踩到机关,要求短促有力。核心是"峰值来得快、收得也快",BlenIn约0.02~0.05秒,BlendOut约0.1~0.2秒,持续时间不超过0.4秒。
- 持续型抖动:地震、载具行驶、机械运转,要求低频且稳定。振幅不宜太大,频率可以压到10~20之间,一般配合循环播放。
- 冲击型抖动:爆炸、坠落、剧情关键点,要求"先给一个明显的单帧大位移,然后持续衰减"。可以靠单次高振幅和较长的BlendOut实现,也可以用Sequence里多段Shake Section叠加出冲击波效果。
我的习惯是,在项目里为这三类各做一个UPerlinNoiseCameraShake子类,互不混用。后期调起来只需要改对应类的参数,不会出现"改了这个参数结果所有抖动都变味"的问题。
2. 核心细节解析:从Perlin噪点参数到完整节点链
方案定了,接下来需要真的把Perlin噪点抖动做出来。这里先把参数吃透,后面设置才不会靠瞎猜。
2.1 PerlinNoiseCameraShake每个参数到底在控制什么
新建一个蓝图类,搜索PerlinNoiseCameraShake作为父类,你会看到以下关键属性:
LocationAmplitudeMultiplier:位置抖动振幅倍率。单位是UE默认的厘米,数值1代表约1厘米幅度的位移。做爆炸时可以给到5~10,做脚步声0.1就够。LocationFrequencyMultiplier:位置抖动频率倍率。控制每秒位置震荡的周期数,频率越高,画面"碎"的感觉越强。通常位置频率别超过30,否则变成高频震颤。RotationAmplitudeMultiplier:旋转抖动振幅倍率。单位是度,控制相机绕三个轴转动的幅度。1度玩家能感知到,3度已经开始有"失控感",超过6度基本是灾难镜头。RotationFrequencyMultiplier:旋转抖动频率倍率。控制旋转震荡快慢。旋转频率通常比位置频率高一些,因为人眼对旋转变化更敏感,用高频小幅旋转表现撞击比用大幅平移更真实。
还有一个容易忽略的:Duration。0表示无限循环,正数表示单次抖动持续秒数。做反馈型抖动时务必设一个明确时长;做持续型抖动(地震、引擎震动)则设0,靠外部逻辑主动停止。
2.2 蓝图里怎么创建一个可复用的Perlin抖动
在内容浏览器里右键 → 蓝图类 → 搜索"PerlinNoiseCameraShake",命名比如BP_ExplosionShake。打开后不需要写任何逻辑,直接在Class Defaults面板里填参数。
这里有一个新手容易搞错的地方:PerlinNoiseCameraShake的"振幅"和"频率"都是Multiplier倍率,这意味着它内部还有一套基础基准值。你写进去的数值不是绝对厘米数或度数,而是缩放系数。实际调参时,通常从1.0开始试,再按手感倍增或减半,不要盯着数值看"3是不是等于3厘米"。
使用场景在玩家控制器或角色蓝图中调用:
- 获取
PlayerController,从中获取PlayerCameraManager。 - 调用
StartCameraShake节点。 Shake Class选择你新建的BP_ExplosionShake。Scale参数用来临时控制整体强度,不改动量级时保持1.0。PlaySpace根据需求选Camera或World。默认Camera模式,意思是抖动坐标系绑定在相机自身旋转上;World模式则固定在世界坐标系。
蓝图连线时注意,StartCameraShake的返回值是UCameraShakeBase,你可以保存在变量里,方便后面手动调用StopCameraShake停止持续型抖动。
2.3 C++方向:一个干净的可调子类怎么写
如果项目用C++,写一个自定义抖动类也很快。新建一个继承自UPerlinNoiseCameraShake的类,在构造函数里设置默认参数,外部只需传入Scale即可控制强弱:
UCLASS() class UMyPerlinShake_M4 : public UPerlinNoiseCameraShake { GENERATED_BODY() public: UMyPerlinShake_M4() { Duration = 0.12f; BlendInTime = 0.02f; BlendOutTime = 0.09f; LocationAmplitudeMultiplier = 0.3f; LocationFrequencyMultiplier = 12.0f; RotationAmplitudeMultiplier = 0.8f; RotationFrequencyMultiplier = 18.0f; } };调用时:
GetWorld()->GetFirstPlayerController()->PlayerCameraManager->StartCameraShake( UMyPerlinShake_M4::StaticClass(), 1.0f );相比蓝图,C++的好处是参数天然与代码管理,方便按武器或事件类型派生子类。而且可以通过StartCameraShake的Scale参数,在运行时根据玩家距离爆炸中心的距离动态缩放力度,不需要额外写一套距离判断逻辑。
3. Sequence实战:把抖动接到过场动画里
到了最关键的部分。Sequence里加摄像机抖动,听起来就是给轨道加个Section,实际做起来有挺多细节,尤其是"为什么我加了轨道却没反应"这种问题。
3.1 在Level Sequence中添加Camera Shake Track
先把Level Sequence创建好,把用来取景的CineCameraActor拖拽进去,或者通过Sequence的"摄像机绑定"功能快速插入。选中CineCamera的轨道,点击右键,在菜单里找到Add Camera Shake Track。
注意:这个轨道不是加在普通的Actor轨道上,而是加在摄像机的Transform轨道旁边。如果你在CineCamera的Track列表里找不到"Camera Shake Track",很可能是选中的不是摄像机本身,而是摄像机下面的子组件。先确认选择了CineCameraActor根节点。
添加Camera Shake Track后,会看到一条空的轨道区域。按住鼠标左键在轨道上拖拽,创建一段新的Camera Shake Section,然后在Section的细节面板中指定Shake类,也就是你创建的BP_ExplosionShake。
3.2 Section参数:让抖动的起止更自然
Section创建后,细节面板里最关键的三个区域:
Shake:指定要播放的抖动类。Play Scale:倍率,1.0为原强度,0.5为一半,2.0为双倍。这个参数非常适合在同一段镜头里做"距离减弱"效果,比如先震一下,然后随着镜头远离场景,手动K帧把Play Scale从1.0降到0.0。Blend In / Blend Out:这一段摄像机抖动在Section起止处的融合时间。实测建议:Blend In给0.05~0.1秒,Blend Out给0.3~0.5秒。否则抖动的起始和结束都像"砸墙",很突兀。
一个实战场景:C4炸药爆炸的过场。我在爆炸发生的关键帧上放置一段0.5秒的Shake Section,Shake类用冲击型参数(RotationAmplitudeMultiplier给4.0,Duration约0.5秒),Section的Blend Out拉到0.5秒。这样播放出来是"轰"的一下开始,然后镜头还有余震般的收尾感,而不是突然结束。
3.3 用多段Section叠加出复杂震动效果
Sequence真正的优势在于时间轴可视化,可以同时压多段震荡。
比如表现"陨石砸向地面"的完整冲击:我通常会放三段Shake Section。
第一段是提前量,用低振幅、低频率的"预震",时长0.2秒,告诉玩家"要出大事了"。第二段是主冲击,紧贴爆炸点,振幅拉满,频率略高。第三段是余震,振幅下降到主冲击的1/4,频率也下降,持续时间可以到1秒以上。
由于多个Shake Section在同一轨道上会自动叠加,这样形成的整体抖动曲线会比单段更饱满。前提是每段Section的Blend时间处理好,否则在交界处会出现参数跳变。
3.4 Sequence中控制持续型震动的停止
持续型抖动在Sequence里有个常见需求:角色长时间在震动平台上,镜头要保持震动,但停下来或动画结束时,震动要可控地消失。
做法是:给Camera Shake Section设置循环播放。在Section细节面板中,把"Duration"设为0,或者直接让Section长度覆盖整个震动过程的时长。要停止时,可以在Sequence中另起一个关键帧,把该Section的Play ScaleK成0,并在Blend Out给一个缓出时间。
这里容易犯的错是:直接用Sequence的"停止播放"去关,结果整个镜头序列都被终止了。正确的逻辑不是停掉Sequence,而是把摄像机抖动这条轨道单独收掉。用Play Scale控制,而不是删除Section。
4. 参数调优技巧与高频问题排查实录
参数调优是"手感"层面的问题,我给不出一个适用所有项目的固定公式,但可以分享一套可复用的调试流程和几组经过项目验证的初始参数。
4.1 常用参考参数表
这组数据来自我个人项目的调优结果,覆盖了最常见的几种场景。作为起点使用,基本不会离谱:
| 抖动场景 | 位置振幅乘数 | 位置频率 | 旋转振幅乘数 | 旋转频率 | 持续时间 | BlendOut |
|---|---|---|---|---|---|---|
| 手枪射击 | 0.1~0.2 | 10~12 | 0.4~0.8 | 15~20 | 0.08~0.12s | 0.05s |
| 步枪连发 | 0.2~0.4 | 12~15 | 0.8~1.2 | 18~25 | 0.15~0.25s | 0.08s |
| 近身受击 | 0.5~1.0 | 10~15 | 1.5~2.5 | 15~20 | 0.15~0.3s | 0.1s |
| 爆炸冲击 | 3.0~6.0 | 15~20 | 2.0~5.0 | 20~30 | 0.4~1.0s | 0.3~0.5s |
| 地震持续 | 1.0~2.0 | 10~15 | 1.0~2.0 | 12~18 | 0(循环) | 手动控制 |
4.2 衰减机制:用距离控制抖动强度
新系统的另一个优势是内置了Falloff衰减。我要做一个爆炸冲击,但炸弹距离主角的远近会影响镜头晃动幅度。以前需要在蓝图中计算玩家与爆炸点的距离,再手动设置Scale,现在可以在PerlinNoiseCameraShake的细节面板中调整衰减参数。
具体操作:在抖动类的衰减设置里,开启Falloff,指定Falloff Distance为最大影响距离(比如1000厘米)。这样镜头离震动源越近,实际抖动强度越接近原始振幅;越远,抖动按比例缩小。注意它默认用的是"到Camera的距离",以播放CameraShake的摄像机本身为基准,而不是玩家的Pawn位置。如果你要让第三人称角色的Pawn位置作为距离基准,需要额外接入Shake Target的偏移逻辑。
4.3 Play Space:相机空间与世界空间的选择
大多数时候用默认的Camera空间就够了。镜头抖动是相对自身方向进行的,不管相机朝向哪里,抖动表现一致。
但在某些固定机位过场里,如果用Camera空间,镜头朝向改变时抖动方向也会跟着变,容易导出莫名其妙的运镜抖动。这时候把Play Space改为World,抖动方向固定在世界坐标系,播放效果更可控。
4.4 通用排障速查表
根据我自己的排查经验,整理了一份常见问题对照,按"症状→原因→解决"的方式快速定位:
| 症状 | 可能原因 | 解决方式 |
|---|---|---|
| StartCameraShake调用了但画面没反应 | PlayerCameraManager为空;Scale为0;或者玩家控制器被Sequence接管 | 打印Log确认PlayerCameraManager有效;检查Scale传入值;确认Sequence是否切换了主动摄像机 |
| Sequence预览时抖动不显示 | 编辑器预览不默认激活Camera Shake | 点击Sequence界面的Play按钮进入游戏预览模式,或在运行时触发Sequencer播放 |
| 抖动太"碎"、刺眼 | 频率过高 | 降低RotationFrequencyMultiplier,优先压到12~15 |
| 抖动结束像硬切 | BlendOut太短或为0 | 至少给0.2~0.4秒融合时间 |
| 爆炸时镜头"漂移"而不是"震动" | 位置振幅大于旋转振幅,相机整体被平移走 | 提高旋转振幅、降低位置振幅,用"转"代替"移" |
| 抖动在Sequence中看起来比Gameplay里弱 | Play Scale被默认设为0.5或更低 | 检查Camera Shake Section的Play Scale值,必要时直接设为1.0 |
4.5 调优实操流程与个人心得
我实际项目里调出一套手感满意的抖动,通常要经过五轮反复修改:
第一轮,先不管参数,搭好触发点和逻辑链路,确保每次事件都稳定触发抖动。连触发都没保证,调半天参数也白搭。第二轮,用参考参数把抖动跑起来,感受大致方向。这个时候不要细调,只判断"这参数能不能接受"。第三轮,开始针对单帧截图和慢速播放观察峰值。把Sequence里的播放速度临时调到0.1倍速,逐帧看相机位置和旋转,找出最强的一帧在哪里,强度是否合理。
第四轮,做对比版本。我会复制同一个抖动类,改成两套参数,在Sequence里放置两个几乎相同的镜头段落,只切换不同抖动类,让角色或同事盲测挑选。人的手感直觉比自己盯着曲线猜准确得多。
最后一轮,把参数与项目的伤害数值、摄像机FOV、镜头动画统一起来。举个例子,FOV越大,同样的旋转振幅视觉冲击越强。所以做大视场角镜头的过场时,旋转振幅乘数要比普通视角下调30%左右,否则容易晕。
做这套东西时间长了,我养成了一个习惯:每个抖动子类都带一个简洁的注释,说明使用场景、最大振幅限制、推荐BlendOut时间。项目交接或者隔几个月自己回来改,都能一眼记住当初的设计意图。
还有一个小技巧:持续型抖动不要死板地用固定频率。在Sequence里给Section的Play Scale加一个缓慢的、不规则的曲线变化,比如从0.8到1.2到0.7再到1.0,抖动强度就有了"呼吸感",比恒定震动自然得多。这些微妙的不规则变化,恰恰是Perlin噪点方案最擅长承载的东西。