赞
踩
在游戏开发过程中,对角色的预览,和某些情况下生成头像是比较常见的需求。有些引擎,可以创建一个额外的场景和相机,然后将需要的内容放置到合适的位置,然后可以获得想要的图像。在UE4中不是这样,没法创建其他的场景,我们需要使用CaptureSceneComponent2D,字面意思看出来这是个场景捕获的组件,它就是用来捕获我们想要的场景内容到2D图像上。
这个组件的使用相当简单,首先我们新建一个第三人称的示例工程,使用以下基本步骤:
对,就是这么简单,这个时候我们已经得到了一张捕获的纹理。那么这个纹理如何使用呢?可以跟普通的贴图一样使用,不过稍微有一点点区别,这个稍后再说。
为了使用刚刚捕获的图像,我们可以建立一个界面来展示它。
2. 运行游戏之后,按F键,发现界面上啥也没有。原来RenderTarget纹理的透明度比较特别(具体是怎样还没有研究),我们回到场景,再次选中SceneCapture2D对象,在Details面板找到Catpture Source
选项,然后选择如下。再次运行我们就可以看到界面中的图像。
从上面的截图可以看出来,角色背后的蓝天及场景中的其他内容都被捕获了。在实际应用中,这些部分一般来说是不需要的。那么如何设置只捕获特定内容呢?
Primitive Render Mode
, 这个就是用来控制绘制内容模式的,它有个叫做Use ShowOnly List
的模式,这个模式就可以指定一些对象,然后只捕获这部分内容。使用这个模式的一个小问题是,如果在编辑器中直接选择这个选项,那么TextureTarget中的预览将会消失。所以我们在编辑器中不修改它的模式,而在蓝图中动态设置。
2. 打开场景蓝图,在F按键之后的代码加上SceneCapture2D的一些设置
结果如下:可以看到场景部分都消失了,不过还有蓝的白的背景在。这部分内容应该是属于透明内容。下一节我们再把它给去除掉。在这里我们使用了Show Only ActorComponents
即只捕获特定的Actor对象,也可以使用Show Only Components
节点来添加指定的组件,可以做到比Actor更细化的控制。后面还会讲到。
Final Color(LDR) in RGB
,这个设置实际上是将Alpha属性给丢了,所以我们首先将这个属性重新设置为第一项:2. 创建一个材质, 命名为 MT_Preview,并打开。
3. 回到界面蓝图,之前图片的Image选择的是RT_Preview,是直接使用的纹理,现在改成MT_Preview,使用新建的材质。
4. 再次运行游戏,按F键可以看到如下画面,背景中的蓝白色已经去除了。
到了这里,我们捕获的内容基本上已经符合了预期:
然而,它还不能正直使用在游戏中,为什么?
目前我们捕获的对象是场景中的玩家对象,玩家对象会移动,一旦移动我们就捕获不到了。这个问题有两个解决方法,
接下来就以第二个方案来简述实际操作。
2. 去除之前场景中添加的那个SceneCapture2D对象,我们使用动态创建的方法来构建Preview Actor。首先在A_Capture_Preview的BeginPlay中设置只捕获自己的本身
3. 然后我们修改一下Level Blueprint,创建这个捕获Actor,CollisionHandlingOverride可以选择AlwaysSpawn,避免因为某些原因创建失败。
4. 运行游戏,按F键,可以看到界面跟之前展示的一样,不同的是:
我们SpawnActor只是为了用于捕获,不希望主摄像机可以看到,那么这里又有两个方法:
我们先来说第二中方案,如何让主摄像机屏蔽或者说过滤掉我们得临时Actor。首先打开ACapturePreview蓝图,选中SkeletalMesh,然后在细节面板上找到Renderring选项卡,点击下面的三角形展开高级选项,如下图:
这里有两个选项,Owner No See(拥有者不可见) Only Owner See(仅拥有者可见) ,利用Owner No See这个选项,再把临时对象的Owner设置成主角Actor,那么主角就看不到这个临时Actor了(对于网络游戏,在客户端创建的临时Actor,其他人本来就看不见,所以也不用担心。)
再次运行游戏,按F之后,已经看不到临时对象了,界面表现则是和之前一样。
这里可能有人要问了,为什么不选择OnlyOwnerSee,然后把Owner设置成自己呢?这里的问题是Owner不能设置成自己,如果要选择OnlyOwnerSee,则必须将模型与SceneCaptureComponent拆成2个Actor来实现,这也是个方法,但是需要管理两个临时对象,具体的实现就大家自行实现吧。
在一定程度上来说,没啥问题,但是如果Actor离主相机太远,引擎会对Actor进行优化,导致捕获的效果非常糟糕,一方面是LOD的原因,一方面未启用LOD的情况下,离的足够用,也会强制优化。
不断的将距离设置的更大之后,可以发现界面上的效果越来越差,直到不能接受。最后一项Actor离主角的距离是40000000。当然你可能不会设置那么远,只要找一个合适的位置让玩家当前看不到他就是可以接受的。如果你发现界面上的效果达不到预期的时候,就要考虑是否因为距离过大导致的。
另外,也是接下来要讲的,使用正交投影来获取2D头像的时候,对距离比透视投影要敏感非常多,距离设置到10000就有明显的区别。
所以推荐的做法是前面说的那种,将临时对象放在离主角比较近的地方,但让主角看不到他。
3D预览使用透视投影,2D头像由于离的非常近,如果继续使用透视投影,很容易出现比例不协调的问题,比如鼻子可能非常大,其他部位特别小,不符合要求。
这个时候就要使用正交投影,继续使用刚刚的ACapturePreview对象,选中SceneCaptureComponent2D组件,找到Projection选项卡,ProjectionType选择Orthographic,选择之后OrthoWidth变得可用,这个选项类似Field,越大则范围越大,越小则范围越小。在这个模式下,相机的远近不会改变捕获的范围,需要修改OrthoWidth才有效果。例如下面的选项,设置为50,可以看到TextureTarget部分的预览。
注意红框中的两个选项,PrimitiveRenderMode在前面有提到,为了方便在未运行时预览TextureTarget,这里不做修改,使用蓝图代码在运行时修改模式为ShowOnlyList
。CaptureEveryFrame
是每帧捕获的意思,可想而知这个选项会带来相当的消耗。对于2D头像来说,是静态的,只需要捕获一帧就可以了,所以这里取消勾选。
2D头像在3D的基础上只是两点不同:
接下来,探讨个稍微复杂点的情况。通过上面的介绍大家基本上明白了,捕获的基本流程:
这个过程中,我们创建了一个RenderTarget,一个材质,一个临时对象。如果我们在游戏中需要同时显示多个动态捕获的头像怎么办?那就得创建N个RenderTarget,N个材质,N个临时对象?下面就来介绍一种全动态RenderTarget+材质的创建方案,对于捕获Actor,如果各个需要的场景对镜头没有区分要求,那其实可以使用同一个,然后动态的修改SkeletonMesh就可以。
ConvertToParameter
, 这个时候可以在左侧ParameterName出修改参数的名称,这个名称记下来,后面动态设置的时候会用到。2. 打开WBP_Head蓝图,新建函数UpdateImgMat
,新增Input参数,类型选择为Material Instance Dynamic, 并命名为 ImgMat
并实现函数,此函数可以让我们使用动态材质来填充图像。
3. 打开Level Blueprint,新建一个函数CreateDynamicHead
,这个函数建在哪里不重要,只要有合适的时机即可
这三个节点,首先创建一个RenderTarget2D ,然后根据MT_Preview来创建一个动态材质示例,第三个节点就是把前面的RenderTarget2D传递给材质的MainTex参数。这就是我们第一步把材质中的纹理提升为参数的目的。实际上动态材质的核心就是上面三个节点,接下来需要做两件事:
界面已经提供了接口,调用一下即可,ACapturePreview也需要提供一个接口来接受RenderTarget数据。
4. 打开ACapturePreview,新建函数SetRenderTarget,新建参数RenderTarget,类型为TextureRenderTarget2D
。
函数内容也很简单
接下来就是稍微改造一下Level Blueprint中的函数CreateDynamicHead
分成四个步骤:
按键F的响应则只需要直接调用该函数
按F运行游戏,发现头像跟之前没有任何的区别。
没有区别就对了,这里只是展示一种动态构建的方法,效果并没有改变。对于界面上多个头像的展示,跟前面的代码结构类似,不同的界面,使用不同的预览对象,自行设置就好。由于大家各自使用的RenderTarget和材质都是动态的,所以不会相互干扰,这是主要目的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。