3A级游戏中,镜头是一个很重要的因素,跟战斗体验和剧情演出都紧密相关。对于一个有激烈打击感的动作游戏,镜头演出更是十分重要。本文将参考动作游戏鬼泣5的相关镜头功能,进行鬼泣5镜头规则的分析。并在虚幻4引擎下,给出一个基本框架实现,尽量还原一个跟战斗体验强相关的动态镜头效果。

·  正  ·  文  ·  来  ·  啦  ·

1需求目标分析镜头通常有以下几种分类:

1.自动追踪镜头:常规第三人称镜头,镜头跟随玩家;

2.轨道镜头:根据静态轨道信息控制移动的镜头;

3.战斗镜头:考量流程战斗的效果时,需要考虑的镜头控制;

4.定点镜头:固定位置,固定旋转或仅变动旋转的镜头。

在剧情演出时,常出现轨道镜头的运用。而固定场景时,又较常出现定点镜头和轨道镜头的组合。而我们的目标要实现的是:

1.非战斗下镜头表现;

2.战斗场景镜头表现;

3.战斗场景锁定敌人时的镜头表现;

4.特殊主角动作触发的镜头表现。

2镜头简要说明

非战斗下镜头表现

鬼泣5希望在没有敌人时,能充分地向玩家展示场景。因此当玩家操控视野摇杆时,镜头部分参数会发生自动修正,表现(称为表现A)如下:可以看到此时,尼禄默认回到了偏左下角的位置,而将更大的视野留给了场景,当玩家操作移动摇杆时,又将触发镜头默认的动态修正,使其恢复到常规镜头。

摇杆操作的默认镜头修正到常规镜头

无敌人时的场景镜头修正

战斗场景镜头表现

出现敌人时,为保证玩家能更加直观看到尼禄的技能释放和敌人方位,玩家操控视野摇杆时,不会触发表现A,同时会给予视野控制的pitch角更大的限制。其他的镜头表现跟非战斗场景的常规镜头类似。

有敌人出场时的镜头表现,pitch受到了更多限制

战斗场景锁定敌人时的镜头表现

锁定状态下,鬼泣5希望玩家和锁定镜头都在屏幕范围内,同时由于鬼泣5几乎所有攻击技都依赖锁定,因此在鬼泣5在在近距离跟敌人发生战斗时会有较多的镜头规则约束。鬼泣对玩家锁定敌人时的场景进行了分区,玩家踩在不同的区域做出不同的逻辑操作会触发不同的镜头动画。

鬼泣5分区简易示意图

中心平移区进入缓冲区缓冲区进入中心平移区敌人在屏幕区外时进行锁定边缘平移区进入屏幕外区域

分区没有采用复杂的计算方式,使用向量夹角判断即可。敌人的前向向量取镜头前向向量的反向,同时计算敌我向量在XY平面的投影向量,两个直线取夹角(非向量夹角)。这样就可以获取主角相当于敌人的方位来判定所站分区。

特殊主角动作触发的镜头表现

某些动画可能也为影响镜头表现,此时需要动画帧配置通知,通过控制行为树黑板变量以事件驱动的方式控制镜头。

跳跃动作触发镜头

另外,需要注意,三个镜头状态间进行的切换是柔性的,存在缓冲,目的是间接平滑镜头效果。

解除锁定几秒后,镜头才会恢复到非锁定的镜头状态

3UE4相关镜头模块简介

UE4 内部自带PlayerCameraManager对玩家相机进行管理,PlayerCameraManager被playerController引用,PlayerCameraManager管理着所有镜头的修改器。镜头修改器基类为UCameraModifier。ue4自带了镜头抖动的功能,见UCameraModifier_CameraShake,因此自定义扩展UCameraModifier,如控制springarm的UCameraModifier_SpringArmSetter,控制viewRotate的UCameraModifier_ControlRotate,UCameraModifier_CameraShake对shake动画实例进行了管理,相关的代码可以作为我们实现其他类型modifier的参考。

SpringArm弹簧臂是ue4第三人称相机常用组件,用来辅助控制相机的移动,具体可参考官网:https://docs.unrealengine.com/en-US/Gameplay/HowTo/UsingCameras/SpringArmComponents/index.html。

因此我们可以选择在ue4的基础上实现自定义扩展,同时能复用springArm组件的相关功能。

UE4摄像机相关架构

4UE4 CameraShake的管理和实践

UCameraModifier_CameraShake作为控制相机抖动的修改器类型,管理着所有相机抖动动画相关的实例。下面对相机抖动的管理做个简介。

AddCameraShake负责增加一个相机抖动效果,ue4允许同时存在多个抖动动画实例,使用了TArray进行管理。抖动动画是短时生命周期的实例,所以内部使用了对象池进行优化。ue4选择在拿出对象池中的动画实例时进行参数重置,NewObject支持重新初始化。在定制SpringArm弹簧臂和相机rotate等相关设置时可以使用了类似方式实现,唯一的约束在于自定义镜头modifier实例,一个类型只能一个处于running,使用了指针维护链接即可。

Modifier层级自定义扩展

5Camera和Spring Arm的独立管理

默认ue4第三人称相机的实现方式是把弹簧臂挂接在主角身上,主角位移带动弹簧臂位移,但是这样会有很大的缺点,即无法灵活地解绑或绑定其他场景对象,难以实现定点相机或轨道相机等功能。因此抽离springarm和followCamera到单独的actor类进行管理是必要的。

另外,由于战斗镜头使用了行为树相关的AIi功能,因此AIcontroller的继承和扩展必不可少,借鉴ue4的CameraActor,实现了自己的CameraPawn。

CameraPawn必须拥有自己的AIcontroller,同时又需要从依赖的playercontroller获取rotation或设置ViewTarget。

6镜头业务逻辑的管理:行为树 ?状态机?或朴素的数组管理?

思考一下我们的需求,同一时刻只有一个镜头动画触发,镜头动画按镜头动画按时间划分又可以分为单帧动画和长时动画,一个是单帧触发一次则镜头参数修正一次,一个是触发动画runing状态,使之持续一段时间。容易想到,同一时刻,其实可能存在多条镜头动画路径满足条件,因此需要做优先级管理,使同一时刻只触发执行一个节点。

镜头的一大特点就是各个状态之间都可能发生跳转,简言之就是anystate->anystate,因此n个状态的状态机来描述一定会出现n*n的transition,但好在transition同样可以做通用的优先级管理,状态的Exit函数来实现状态本身的中断。大致的思路是,每个状态是否触发都做先置检查,先置检查将check多个条件bool值(每个判定条件value可能通过外部事件驱动设置,也可能通过内部update设置,视具体情况而定)。Transition在条件判定值设定完毕后通过优先级选取当前时刻满足条件判定的最高优先级节点执行。

当然,使用优先队列(或可变数组)管理也是可以实现,大致思路是:将当前时刻满足条件的执行节点全部扔进队列(数组)后,在执行具体镜头动画的时刻从优先队列中弹出优先级最高的节点(或直接数组遍历找出最高优先级的节点)执行即可,如果当前执行节点就是弹出节点直接返回,否则进行跳转,同时对上一执行节点实施中断。每一个执行节点可能组合了几种类型的镜头动画(如同时设置location和rotation)。

其实数组的管理中提到的将当前时刻满足条件的执行节点全部扔进队列(数组)并选出最高优先级执行的操作类似状态机方法中提到的update通用执行方法,而能抽离通用执行的前提是某状态需要满足其跳入条件只依赖自身,不依赖跳出状态,依赖上一跳出状态的跳转也被称作带有上下文的状态跳转方式。状态机的存在主要是能解耦这类复杂逻辑,如果不使用状态机,上下文跳转多半会出现下述情况:

Switch(CurrentState){Case StateA:If(conditionA2B) SwitchState(StateB)Elseif(conditionA2C) SwitchState(StateC)Case StateB:...}

可以预见,如果采用常规数组管理,一旦出现带有上下文的状态跳转方式,在选择执行节点时,难免会出现上述格式的代码。

同时我们也能发现常规状态机的不足,即条件判定难以层次化,如下所示:

Switch(CurrentState){Case StateA:If(condition1&&condition2) SwitchState(StateB)elseif(condition1&&condition3) SwitchState(StateC)elseif(condition1&&condition4) SwitchState(StateD)Case StateB:...}

采用层次化状态机可以将公共变量提到上层作为更前置的判定(类似行为树的黑板装饰节点),附带的福利是还可以把公共逻辑也抽离到上层(类似行为树的Service)。至此我们发现层次化状态机的行为跟行为树已经越来越相似,如果不使用带有上下文依赖的跳转,当你完成行为树的连接时,会发现除了连接线路不同,他们的节点配置高度相同(层次状态机中,非叶子节点也被称为状态,而行为树中,根据功能不同,可能叫服务,也可能叫装饰节点或其他,是比状态更细的粒度)。

如果使用行为树,值得一提的是为了确保最终镜头动画效果可控,尽量减少并行节点的使用。在必须使用的情况下,也务必要使并行节点的放置层级尽量低,越接近叶节点越好,通过这种方式进行约束有利于提高镜头效果的稳定性。

行为树相关指南下可见参考文献列出的官方链接。可以看到,行为树更加强大,支持更复杂的逻辑支持,灵活性极高,但是代价就是容易滥用,导致树的复杂度不受控制,特别对于上下文依赖的跳转似乎也没有优美的解决方案。如果形成了过于复杂的树,再作后续开发的时候可能因为分层过于复杂,粒度过细,导致无法实现线性扩展。

综上,三种方式都能实现目前的需求。当出现上下文依赖跳转的情况,状态机的实现更稳定,可以减少对原代码大刀阔斧修改的概率。如果出现以下情况:1.没有出现上下文依赖 2.能控制行为树层级复杂度(树的层级不宜过深) 3.可视化状态机的跳转连线已成稠密网状结构。在可控的范围内,规范的使用行为树是可行的。另外上述为了严谨起见,用的同一时刻而非同一帧,因为ue4行为树各个路径的条件检查并非是在一帧内完成。

下面简述Ue4下通过行为树进行实现的大致思路。由于镜头控制器使用行为树作为逻辑管理,因此镜头必须依赖自定义AIController,AIController借助BehaviorTree实现控制逻辑管理,BehaviorTree则在内部节点(如服务)简单封装AIController节点。因此,复杂的逻辑可以存放在自定义AIController中,再由行为树进一步调用。下面是一种行为树实现,可以看到除开并行节点层级已经达到4层,所以从复杂度上来说还可以有进一步调整树的层级的空间,这里就不再赘述。

7关于镜头动画:近似的阻尼运动

镜头运动近似模拟一个阻尼运动,例如旋转量0→50,在旋转量接近目标50的时候,tick时每帧的旋转变化量受到离目标的差值作为倍率影响,形成一个越接近目标越慢的移动。因此,目前tick时每帧旋转量的计算方式如下:DesiredRot为目标rotatation,OutViewRotation为当前viewRotation,ActionInterpSpeed为策划配置的速度。

float scale =  (DesiredRot - OutViewRotation).GetNormalized().Yaw;float speed = FMath::Clamp(ActionInterpSpeed*DeltaTime, 0, 1);OutDeltaRot.Yaw = speed * scale ;

此处的speed为相对速率,含义是此帧移动的距离占总距离的比例。接近目标时函数收敛很慢,为了避免逻辑上的bug,在防止overshoot的误差量设置上需要小心。防止overshoot的通常做法是:

if (FMath::IsNearlyZero(Delta.Yaw, RotateTolerance)){  OutViewRotation.Yaw = DesiredRot.Yaw;  bIsFnished = true;}

因此,RotateTolerance设置的精度直接影响了此动作是否完成的逻辑状态。8参考文献资料

1.游戏设计的236个技巧 第5章:让3D游戏更有趣的镜头技巧

2https://www.youtube.com/watch?v=C7307qRmlMI&t=246s GDC关于3A游戏的镜头设计3.https://cowlevel.net/article/1882558

4.https://blog.csdn.net/u012999985/article/details/68947410  ue4摄像机系统解析

5.https://docs.unrealengine.com/zh-CN/Engine/AI/BehaviorTrees/QuickStart/index.html  行为树快速入门指南

6.相关图片视频素材皆来自游戏《鬼泣5》

数天技术

让技术·更有趣

ue4 怎么修改骨骼动画_UE4下动作游戏动态镜头的实现方法相关推荐

  1. ue4 怎么修改骨骼动画_UE4换装系统(合并骨骼模型)

    前面那篇UE4换装系统https://blog.csdn.net/luomogenhaoqi/article/details/88350580,事实上每个身体模型还是各自渲染,现在介绍把每个身体模型合 ...

  2. ue4 怎么修改骨骼动画_它来了,它来了! 游戏角色与动画制作的智能工具 iClone Unreal Live Link 闪耀登场!!!...

    点击蓝字关注我们 它来了,它来了! 游戏角色与动画制作的智能工具 iClone Unreal Live Link 闪耀登场!!! Reallusion研发团队近日最新发布了iClone Unreal ...

  3. ue4 怎么修改骨骼动画_【2017 GDC挖坟】守望先锋动画制作管线(下篇)

    写在前面的话:GDC总是可以挖掘到很多值得学习的分享,今天拆解一下2017GDC上关于动画管线的分享,里面很多东西值得借鉴.思考,文中偶尔会有一点自己的想法.总结,欢迎大佬吐槽.提意见.(文章很长,多 ...

  4. ue4 怎么修改骨骼动画_【UE4】神器!!!动画师必备!!!基于物理的动画制作软件 Cascadeur 使用指南!...

    优点不用说,因为tql,下面全部都是优点 缺点嘛,还是一样的吐槽,整成插件进blender该多好啊,有些操作真不如blender方便,ue4的操作也是. [导图] 重点在 第 6 节 制作人物姿势和 ...

  5. ue4 怎么修改骨骼动画_【UE4】动画重定向

    虚幻4动画重定向 重定向虚幻争霸中两个角色,使用同一套动画. 1.首先我们从虚幻商城下载两个角色到项目内.(我这里选择了Wraith.Revenant) 由于需要使用另外的动画,我这里选择将两个骨架的 ...

  6. ue4 怎么修改骨骼动画_使用Ornatrix来制作Ue4头发流程学习笔记(二)——引导曲线头发...

    前言 4.24出了头发渲染与模拟功能,这真是一件令人兴奋的事,所以我稍微花了点时间进行测试,在此分享一些经验. 使用步骤 使用步骤大致如下,具体的可以参考文档: https://docs.unreal ...

  7. 第六章:3ds max骨骼动画(下)

    动画是由一系列的静态图像的不断更新显示而产生的.一般情况下,1秒钟要显示24张图像,人就会感觉到连续的动态图像.一般情况下使用30帧就足够了.在3ds max可以设置这个FPS值.右下角"时 ...

  8. 第八章 DirectX 3D模型加载和骨骼动画(下)

    接下来,我们介绍一些骨骼动画.我们之前大致讲过骨骼动画,存储骨骼动画的网格文件要比普通的文件复杂一下.主要是增加了骨骼信息,蒙皮信息以及动画帧信息.骨骼动画的实现原理是仿照人体运动学,将3D模型由一种 ...

  9. ue4小白人骨骼定义_UE4同一结构的骨架之间动画共享。

    前言 工作中需要写个文档给其他美术看,所以顺便写成个文章. 这是我们的项目结构,四个点表示这是外部导入的资源包,未打点的则是UE4默认第三人称模板的内容. 这四个包,第一个包是虚幻商城的NPC动画包, ...

最新文章

  1. 程序员MM的自白:磨人小妖精之安卓碎片化
  2. (1)虚拟机管理——在微软云Azure新门户创建虚拟机
  3. linux安装jdk8_Skywalking系列博客1-安装单机版 Skywalking
  4. composer 完整路径才能访问_一份完整的运营方案策划思路,拿走不谢(精华版)
  5. Oracle创建表,并添加默认值和备注
  6. 360安全卫士电脑版_教你降服“流氓头子”正确打开360安全卫士的姿势,还你电脑流畅体验...
  7. Ubuntu下安装配置JDK1.7
  8. C++实现对象序列化和反序列化(读写二进制文件)操作
  9. JAVA仿真之银行出纳员
  10. vsftp匿名访问目录_怎么更改vsftp匿名用户的默认登录目录/var/ftp?
  11. Gradle下载安装教程
  12. undefind_undefined
  13. spring中MessageSource的配置使用方法3--ResourceBundleMessageSource
  14. 2004-2019年分省农产品进出口额
  15. 198.3D商城鞋柜展示特效
  16. 巴旦木即将成为农业的下一个“风口”河南巴旦木生态农业:值得期待
  17. 解决简历模板无法生成下一页
  18. 华为最新智能服务器,曝光:华为最新一代FusionServer Pro 2488H V6智能服务器
  19. 11.22IG客户情绪报告: 黄金、原油、澳元、日元、欧元、英镑
  20. 华硕计算机用户名默认,华硕路由器设置方法_华硕(ASUS)路由器怎么设置?-192路由网...

热门文章

  1. 工业设备远程运维系统平台
  2. String数组的使用
  3. 移除最多的同行或同列石头
  4. 【opengl32.dll下载】找不到opengl32.dll怎么修复
  5. win32小项目之截图软件
  6. 新年扯皮以及一些比较正经的东西
  7. 牛客白月赛27【题解】
  8. 构建自己的即时聊天系统(基于xmpp)(转载)
  9. 查询各个班级男生女生个数(case)
  10. C语言萨博,力求打造“国民奔驰C” 源于萨博基因的绅宝智道到底有何能耐?