一、引言
Unreal Engine4(简称UE4)被大家广为熟知应该是在游戏应用领域,之前玩过的《堡垒之夜》、《八方旅人》,《底特律:变人》,还有最近出的《龙珠战士Z》、《血迹:暗夜仪式》,以及即将推出的《赛博朋克2077》、《最终幻想7重置版》,不管是3A的还是独立制作人的,大家都可以通过UE4实现自己的游戏创作梦。UE4放开了游戏制作的门槛,也给其他领域,如设计包装、机械生产、广电影视打开了新的大门,只要你有想法肯花时间,就可以花最小的代价做最有趣的事情。
本人从事广播电视制作相关工作,之前我们接触的包装最多的还是Vizrt、Orad、Dayang、新奥特这类传统广电包装。有专门的美编人员负责包装的设计制作,也有专门的播控系统对接演播室播出,包装设计相对封闭,播出操作简单易学,以至于很多传统做广电在线包装的人转UE4时都有个疑惑-在UE4里面,我到底时设计还是技术还是播控?我的答案是,在UE4里面,我就是上帝,我负责一切。
二、UE4学习入门
UE4我也是刚接触学习将近一个月,我并非美编从业人员,不会3DMAX和MAYA,算是小白中的小白,学习心得有不当之处还望高手指正。
2.1、搞清楚一些常用单词及术语
UE4虽然内置了一些模板,而且有很多“入门到精通”的书,我也买了几本,但是不建议上手直接开干,之前没有基础的话先做好一些相关术语的功课,略微总结如下:
1.蓝图(Blueprint)——传说中不会编程的用了蓝图就能轻松上手UE4,我觉得是扯淡,蓝图是图像化的编程语言,如果没有编程的逻辑,不知道类、对象、继承这些,也没法用蓝图,蓝图广义上理解就相当于程序模块,包含三种类型关卡蓝图(Level Blueprint)、蓝图类(Blueprint Class)、蓝图插件(Widget Blueprint)、蓝图接口(Blueprint Interface)、蓝图函数库(Blueprint Function Library)、蓝图宏库(Blueprint Macro Library)。学过编程的从字面意思上就能很好理解,关卡蓝图相当于关卡场景的入口函数,蓝图类相当于函数中的类,可继承重定义,蓝图插件相当于图形化编程,添加类似按钮、画布、文本类的内容。这些类的详细的用法在书本或者操作手册上都会提及,最重要的还是需要用编程的思维去设计场景。
2.静态网格和BSP——静态网格也称作(static mash),即固定大小、形状的物体骨架,用3D Max或者MAYA做好的模型,可直接导入UE4,相当于一个静态网格;BSP是UE4内部的几何模型,新版本里面也称为Geometry,它和静态网格的区别是,BSP放开了对几何形状的调整,可自由的拼接拆分,而静态网格不行。因此BSP渲染上的开销要比静态网格大很多,BSP可以转成静态网格。
3、Actor——通用的一个基类,支持三维变化、平移、旋转、缩放,UE4里面所有的类都从继承它而来。
4、Pawn、Play Controller、Character——很多场景中都会出现这几类对象,字面上看着都差不多,Play Controller相当于一个控制器,玩家可以通过控制器去操作对象,Pawn是一个接收控制器输入的Actor,Charactor是一个人形(或者动物)的Pawn,它包含的行走,跑步,跳跃。Pawn是看不到的,但是它通过Play Controller可以帮助你(第一人称)在3D场景中做各种移动,Character是一个有型的物体(第三人称),你可以去控制这个物体在3D场景中移动。
5、Game Mode——直译为游戏模式,指定游戏(项目)的规则,预加载的文件等,可以设置玩家和观众数量,如何进入游戏,游戏状态和玩家状态等,可以理解为整个项目的初始化过程。
6、材质(Material)——UE4说的最多,吹的最多的就是材质,其他引擎里也有材质,但更UE4相比真实感上还是会差很多。材质本质上对贴图(Texture)进行加工,模仿出类似金属、木材、玻璃等各种不同的表面,让模型看上去更真实。
7、粒子(Particle)——类似于火焰、雨滴、爆炸这类特效,每个粒子都有发射器(Spawn),用来控制例子发射的状态,粒子也是最考虑运算材质,一般放在GPU里面运算,如果电脑或者手机的GPU运算不够的话,也可以通过材质贴图来模仿粒子的运动。
2.2、用编程的思维去做场景
UE4内部自带的类以及通过网上下载的插件中,包含中无数种的方法,就像学习编程一样,你是没法搞清楚这里面所有的方法和功能,只有随着不停的做项目去积累,取自己所需的那部分就够了。UE4本质上是一款编程工具,最先需要了解的是程序的入口和程序的实现方式。
1、项目的开始——UE4项目文件后缀为“uproject”,一个项目里面可以包含很多个关卡(Level),关卡相当于一个个游戏场景,当编译运行项目时,首先确定Game Mode,即对应加载项目初始化需要的特定模块,Game Mode和对应加载模块可自定义,初始化时运行Game Mode下的模块。
2.关卡的入口——Level Blueprint,关卡程序的入口,当进入关卡后首先执行对应关卡的Level Blueprint,在Blueprint里面可以指定事件,制定相关的事件操作,也有人会在关卡蓝图里进行关卡的初始化操作。
3、Event Begin Play,Event Tick——所有蓝图里面用到的最多的两个类,Event Begin Play表示蓝图开始执行时的事件,只在蓝图开始执行时运行一次,可通过Event Begin Play做相应蓝图初始化工作;Event Tick蓝图主循环事件,蓝图执行后会不停的去触发Tick事件,可对该事件设定触发间隔时间。
4、其他蓝图——类、接口、宏、插件,说白了就是面向对象的编程方法,基于C++来实现,实际操作起来跟码代码是一样的。UE4有自己的虚幻商城(MarketPlace),需要什么插件、材质、项目,都可以从虚幻商城下载,在使用这些插件和方法的时候,蓝图就比直接手打来的方便快捷多了,比如说你想要实现什么方法,在蓝图的事件图表内右击,就会有相关索引出现,依据自己的意思,输入英文就可以找到对应方法。就像聊天,你告诉蓝图你要什么,它会给你什么,然后你自己把你要到的东西拼接起来,就能实现自己想实现的。
三、UE4结合BlackMagic视频IO卡案例分析
3.1、准备工作
之前的所有概念介绍,目的就是实现应用,庆幸的是UE4商城上有免费的视音频卡采集案例给我们学习虚拟工作室,我就运用下刚学的内容,对这个案例进行分析,让大家更详细的了解它怎么实现的。此次学习测试用到的视频卡是BlackMagic Decklink Quad卡,4路SDI输入,4路SDI输出,1路模拟同步输入,主机位HP Z800工作站,系统WIN10,显卡Nvidia K5200,UE4软件版本是目前最新的4.22.3。UE4商城上下载“Virtual Studio”工程,以及“BlackMagic Design Media Player”视频卡插件,都是免费的,同时我发现“Virtual Stduio”工程中还支持AJA的视频卡,“AJA Media Player”视频卡插件同样也可以从UE4商城免费下载,一个“Virtual Stduio”工程中支持两类视频卡的输入输出,会在后面提及。
3.2、“Virtual Stduio”工程分析
我们从之前学习入门获得的思路上展开学习,项目进入时先看Game Mode,再看Level BluePrint,然后看各类蓝图类,最后再看场景中的应用
3.2.1 Game Mode
在Blueprint-项目设置-游戏模式下,可以看见预加载的Game Mode文件是“GameModeBase.h”,这是个基类的Game Mode,也就是项目没对Game Mode进行修改,使用的默认配置,在此我们就不去深究这个Game Mode基类是做什么的了,主要瞄准项目关键的程序节点。
3.2.2、Level Blueprint
Virtual Studio项目中就一个Level Blueprint,说明只加载一个场景文件,在Blueprint-关卡蓝图-打开关卡蓝图,事件图标中有两个事件:Event Begin Play->Excude Console Command,执行控制台命令“r.SSR.Quality 4”,简单查阅这个命令,就是将UE4渲染效果开到最高;按任意键->On Key Released Event,获取CameraSwitcher这个类的实例(在场景中有对应实例),同时执行该类下On Key Released Event的方法。Level Blueprint目的很明确,初始化关卡配置和实例,等待键盘的输入(键盘可作为Camera信号的切换)。
3.2.3、CameraSwitcher
CameraSwitcher为蓝图类,在Blueprint-关卡蓝图-打开蓝图类中打开,也可直接双击On Key Released Event索引到该类下的方法函数。我们先看CameraSwitcher的事件图表,通过Event BeginPlay事件可看到,在CameraSwitcher类实例化的时候,会执行四步操作:
1、禁用Pawn的输入控制,初始化视频卡中输入的Camera信号,从蓝图的流程中可以看到,流程中禁用了Player Pawn(不能在场景中自由走动),打开了鼠标指针显示(Show Mosue Cusor),同时对每个Camera进行初始化操作,CameraList是一个数组变量,里面存放着具体的Camera对象,Initialize是VirtualSetMediaInput类下面的函数方法,它的主要作用是获取视频输入信号对象下附属的Camera对象,说白了就是获取拍摄场景中虚拟摄像机对象。
Camera信号初始化操作流程如下图
2、设置AJA的视频输出,同样也适用于设置BlackMagic的视频输出,该流程是获取视频输出口的对象,创建视频抓取的方法,等待视频输出。VideoOutputSettings是视频输出变量,EnableOutputByDefault是布尔值变量,控制视频的输入和输出,EnableVideoCapture是Cameraswitcher类下面的方法函数,接收EnableOutputByDefault的值,从字面意思上使能视频输出。
我们不妨再看一下EnableVideoOutput的具体操作方法,双击打开它,根据接收的布尔值进行分支处理,如果是真,就将对应视口上的内容输出给视频输出卡(CaptureActiveSceneViewport),如果是假,就停止输出(StopCapture)。
3、准备视频输入源切换的UI插件,CameraSwitcherUI是一个蓝图插件类,在Content->VirtualSet->Blueprints目录下可打开查看,此UI控件的作用就是切换场景中的视口(Viewport),不同的视口对应不同的外部视频输入源,同时控制视口的视频输出,具体UI控件的内容后面再做探讨。此处创建CameraSwitcherUI后做了四步,将UI控件和场景中的CameraSwitcher对象进行关联(Set CameraSwitcher),创建Camera信号预监(CreateCameraViews),将插件放到视口(AddtoViewport),将插件内的Checkbox关联到输出信号使能(SetIsChecked)。
CreateCameraView事件是CameraSwitcherUI类下面的方法,该事件方法比较复杂,双击打开对应事件,流程上可分为5步:
a.从Camera Switcher这个变量(在之前第3步中已经将CameraSwitcher实例和UI中的这个CameraSwitcher变量做了关联),循环读取Camera输入对象。
b.创建预监的插件,并放到HorizonBox99这个画布下面,Loop出来又两个Camera输入信号就放两个,有三个就放三个。
c.创建一个材质实例,然后将视频信号贴到材质上,视频信号需要实现转换成动态贴图。
d.设定预监窗口下的标签名字,标签名从输入信号的对象名中读取。
e.设定预监窗口的材质
4、选择默认的Camera信号源,Select Camera是CameraSwitcher类下面的事件方法,双击打开它继续探究。
SelectCamera的流程图如图所示,CameraSwitcher类中的GoToCamra、GoToNextCamera方法,最终都会调用SelectCamera,它里面定义了一套逻辑,用来表示如何切换不同视频源。SelectCamera流程上可分为4步:
a.将输入的CameraID设定为NewCamera,并检查输入CameraID是否有效
b.关闭旧的输入信号显示,并打开新的输入信号显示,切换不同的Camera会对应不同的输入信号源。
c.打印一段文字,显示目前切换的CameraID。
d.执行切换Camera操作,主要用到Set View Target With Blend,函数方法里面还能设置切换的方法,此项目中用到的是VTBlend Linear。
3.2.4、Virtual Studio场景
VirtualSetMediaInput、CameraSwitcherUI、CameraViewWedget所有这些Blueprint类和插件都服务于CameraSwitcher类,而CameraSwitcher类和VirtualSetMediaInput类被放入到场景中实例化,并且在Level Blueprint中进行了调用,每个类和插件中也都带有初始化的一些方法,在此不做复述,有兴趣的小伙伴可以自行深入研究,我们继续最后一步分析,看场景。
Virtual Studio场景制作的非常精良且复杂,各种贴图、灯光、桌面、楼梯等,这里面随便拿一些元素进行查看就有很多学问,此次学习我们重在了解流程,先不关注场景中的材质贴图,重点在场景中VirtualSet目录下的内容,CameraSwitcher、VirtualSetMediaInput1、VirtualSetMediaInput2.
1、CameraSwitcher,是CameraSwitcher蓝图类实例化的对象,该类放开了对Camera List、Show UI、Video Output变量的修改,可以在场景中选中CameraSwitcher对象,直接对该对象进行初始化修改,如下图所示。Video Output加载选中的是MediaOutputProxy_01,我们暂时把它当作BlackMagic视频卡的输出代理文件,后面还会相信介绍视频输入输出代理的配置;Camera List,加载了两个元素VirtualSetMediaInput1和VirtualSetMediaInput2,也是场景中的元素,是VirtualSetMediaInput蓝图类的实例化对象,作为两路Camera信号;Show UI是布尔值,表示默认加载CameraSwictherUI(参考CameraSwitcher蓝图类的流程说明)。CameraSwitcher对象是一个全局对象,在任何蓝图类和插件中都能调用,主要拖拽进去就行。
2、VirtualSetMediaInput1、VirtualSetMediaInput2,是VirtualSetMediaInput蓝图类的实例化对象,相面还跟了一个Camera,是cine camera actor类的实例对象,负责提供VirtualSetMediaInput1/VirtualSetMediaInput2的拍摄视口。以VirtualSetMediaInput1为例,如下图所示,它放开了Plate Distance和Camera Name两个变量的修改选项,Plate Distance是设定Camera和输入信号之间的距离,图中显示的是4,及表示距离是400cm(具体位置关系可查看VirtualSetMediaInput类中Construction Script函数),Camera Name就表示摄像机名字,在预监窗口中会使用到;Media Bundle表示输入信号源,默认加载配置文件VideoBundle_01,后面会具体介绍。
3.2.5、视频的输入输出
此次测试使用的BMD Decklink Quad卡,通道上是4入4出,实际上只是一张4通道卡,入出不能同时在一个通道上执行,因此我们此次通道分配上,前两路通道作为输入,第三路通道作为输出。视频输入输出的配置文件在Content->VirtualSet->MediaProfiles->FileMediaProfile,FileMediaProfile是媒体描述文件,入下图所示,输入和输出可通过UE4商城下载的BMD插件来选择Decklink卡的通道,在configuration下可配置视频通道,Video下可配置采样率,输入输出选择是8bit YUV采样。
FileMediaProfile如何去对应场景中的具体对象,我们继续往下。在UE4工程文件Edit->ProjectSettings->Plugins->MediaProfile,可设置场景初始化加载的媒体文件,已经媒体文件中的配置,具体指向的文件对象,如下图,配置中默认加载的是FileMediaProfile,MediaProxySource_01对应Decklink卡的输入通道1,MediaProxySource_02对应Decklink卡的输入通道2,MediaOutputProxy_01对应Decklink卡的输出通道3。此处用到的是“媒体代理文件”的知识点,最终目的是为了在同一场景中适用不同的视频通道卡,比如说我还要用到AJA的视频卡,只需要再新建个媒体描述文件(MediaProfile),在媒体描述文件中指定AJA的输入输出(跟Decklink卡配置类似),场景中调用AJA相关的媒体描述文件,不需要在修改其他配置。当然,如果我们只有BMD的Decklink卡,就不需要媒体描述文件,也不需要用到媒体代理,只需要直接实例化Decklink的输入输出对象即可。
MediaProxySource_01、MediaProxySource_02、MediaOutputProxy_01具体文件路径在Content->VirtualSet->Media目录下,文件创建后是空文件,等待媒体描述文件往指定媒体代理文件中填入信号。在回顾下这三个输入输出文件具体放在场景的哪里?两个输入放入VirtualSetMediaInput1和VirtualSetMediaInput2,但需要依附在“媒体束”文件上,如下图VideoBundle_01和VideoBundle_2,“媒体束”文件相当于一块幕布,视频需要投影到幕布上才能显示,当然这块幕布的功能不止于此,后面再介绍;一路输出放入CameraSwitcher实例对象。
视频输出文件和对象我们都指定好了,接下来要考虑把场景中的什么样的画面给输出,我们需要“虚拟摄像机”拍摄场景中的画面,还需要抓取(Capture)这些画面,然后给输出,具体配置在Window->DeveloperTools->Media Capture,如下图所示,配置在Media Viewport Capture选项下,因为只有一个视口输出,因此我们在视口下加入了两个摄像机对象VirtualSetMediaInput1Camera和VirtualSetMediaInput2Camera(在场景中能直接找到),一个输出对象MediaOutputProxy_01。如果想要测试视频输出状态,直接在Media Captre左上方,点Capture按钮,就能直接抓取“虚拟摄像机”信号并输出,如果需要在场景中使用,则需要在蓝图中调用对应方法,之前已做介绍。
最后编译Play->New Editor Window,两路切换如下,但是选中Enable Video Output选项打开输出时,会报Pixel Error的错误,也就是抓取分辨率跟实际输出的分辨率不匹配导致,网上查了好多没发现有人报这样的问题,没办法,只能自己解决。
直接找到VideoOutput那段蓝图程序,在CameraSwitcher蓝图类->Enable Video Output,有个Capture Active Scene Viewport,该方法表示抓取有效视口输出,但是没有具体分辨率的设置,从函数内带的Capture Option输入引出选项Make MediaCaptureOptions如图,勾选Resize Source Buffer选项,再回到场景,重新编译Play,打开输出,成功实现,但是检查日志一直有丢帧的告警信息,也尝试过锁定输入输出同步,问题依旧,不知道是不是显卡的运算问题。
3.2.6、视频通道抠像
UE4说明文档上还有视频通道抠像的相关设置,此次也做了初步尝试,笔者重新做了一个场景,Decklink输入1选择带绿箱的演播室视频,输入2选择开窗。MediaBundle在实例化对象时,会在对应目录新建MediaBundle1_InnerAssets目录,点进目录并打开MI_MediaBundle1文件,Details面板显示如图,可通过EnableKeyer打开抠像键功能,对此通道内的视频进行抠像设置,具体抠像参数不做复述,跟传统广播电视中的抠像原理一致,另外一张图是笔者测试的抠像显示输出情况,Alpha通道没扣干净,凑合着测试用下。
四、总结
UE4确实在广电应用上提供了一个很好的案例供参考,但是距离更多的应用需求,如AR、VR、4K包装输出等,目前还找不到很好的参考例子,国内外厂家也都在这块继续做深耕探索,之前来我台做过案例暂时的Zero Density,就是运用了UE4,加入自己开发的跟踪和抠像,实现了很好的输出效果,我仅谈一下自己对这块的理解和看法。
1、AR、VR应用——UE4在手机和平板端有ARKit和ARCore两大开发包支持,很方便就能实现AR的输出,但是广电的AR应用又是另外一块,需要结合的是摄像机机器人的位置参数、Zoom和Focus值,比较典型的协议有freed和telemetrics,如何将这些协议放入UE4,将实际摄像机位置和虚拟摄像机进行重叠,把视频信号作为背景,场景信号作为前景,都有值得研究的方向;VR应用则更需要抠像算法上的升级,测试中使用自带的视频通道内抠像,还是遵循着老的一套抠像原理,选取指定颜色进行扣除,存在着扣不干净或者扣太深的情况。VR目前看上去,Zero Density结合UE4的抠像确实做的不错,颠覆了以往的抠像方式。
2、4K包装输入输出——视频通道卡也得做升级,目前暂时只支持HD输入输出,BMD和AJA都有自己的SDK开发包,可以结合实际需求,对SDK开发包进行修改,开放对应的蓝图选项功能,或者等待厂商的发布(UE4商城上更新确实比较慢)。
3、广电的实际应用——离不开的话题就是新闻演播室节目包装的制作,业内很多人会拿Vizrt、Orad跟UE4做比较,我觉得有些人可能过分妖魔化UE4了。首先,我的理解是,UE4就好比一堆高档的食材,新闻演播室的包装就是快餐产品,你拿鲍鱼海参放KFC里面制作,又要让它好吃,又要做的快,这很矛盾,很多人也不会这么做。Vizrt和Orad可能是做“新闻快餐”里面最符合广电人口味的,播控和文稿结合成熟,操作方便,场景制作门槛也不算太高,关键用到的编程不需要太复杂。新闻美编不会去关注这个场景的材质,光影效果,毛发效果,真实感,他们可能最关心的是我怎么把这个模型做出来放到Vizrt里面播出来,然后不要太占用资源,场景能炫一点最好。那么结果就是你让新闻美编去用UE4,其实跟用Vizrt是一样的,至少看上去的做出来的东西一样的。
所以扯了那么多,UE4还能在广电用吗?当然能,它需要的是一些真正愿意去做精品,做专题的人去实现(好的厨师),可能需要一个团队,像游戏开发一样,场景、故事脚本、逻辑设计、程序实现、后期推广等等。