相机跟随
学习本节内容你将会学会如何创建一个相机, 并且控制相机跟随Actor移动.
(图片来自互联网)
上图中的运动员在飞奔, 摄像师为了拍出运动员英姿煞爽的身影在追着运动员跑. 因此我们看出相机为了跟随Actor的条件是朝向Actor方向, 并且保持相对禁止(差值运动达到最终条件依旧为相对禁止)。
引擎提供了对应的摄像机Actor,3D虚拟世界中一般为我们内置了一个默认摄像机。我们也可以在世界中创建出多个摄像机(但是同时只会有一个生效,就是拍摄呈现在屏幕上的那个。
摄像机Camera的根组件是XECameraComponent。我们可以像从动画模型Actor中获取它的动画模型根组件从而加载动画文件并播放动画一样。我们使用同样的方法获取到摄像机的根组件。
local comp = pCameraActor:GetRootComponent()
虽然获取不同根组件的方法相同,但是获取到的是完全不同的组件。就像这里,从摄像机Actor获取到的跟组件无法加载动画文件。但是它有另外的用处,它可以控制这个摄像机的拍摄参数。
接下来我们试着控制场景内置的摄像机看向我们想拍摄的模型。
如图为默认相机视角:
我们希望调整镜头,将屏幕上的小人拍摄在屏幕最中间的位置。想象一下,当我们控制摄像机拍向某一个目标的时候,我们往往需要得知两个重要的信息:
- 摄像机所处的位置
- 我们要拍摄的目标位置
就像图中展示的这样,我们依靠这两个位置可以得出若想让摄像机拍摄到目标位置,所需要改变的摄像机的朝向信息。如果目标位置在摄像机前方,我们就要控制摄像机朝前拍摄、如果目标位置在摄像机上方,我们就要控制摄像机朝上拍摄。。。。。。
引擎对于位置的获取,为Actor提供了GetActorLocation()方法。我们可以像这样调用来获取一个Actor在3D虚拟世界中的位置:
local actorPos = actor:GetActorLocation()
像这样,我们得到了一个Actor在3D虚拟世界中的位置。我们也可以相似地获取到摄像机所在的位置(因为摄像机也是一个Actor)。
local cameraPos = camera:GetActorLocation()
GetActorLocation()方法返回了一个XVECTOR3类型的变量,该类型含有3个成员变量x,y,z来使用笛卡尔坐标系描述一个向量。在这里,我们可以把它理解为一个3D世界中的点的位置。
下面,在我们已知了两个点的情况下,很容易地就能得到一个点在另一个点的哪个方向,直接相减就好了:
local dir = actorPos - cameraPos
这样得出的新的XVECTOR3类型的变量所表示的信息,就是从摄像机的位置出发走到目标位置,所需要走的方向和距离,即
摄像机位置 + 变量 = 目标位置
但是我们并不想让摄像机真的走过去(让摄像机和目标重合并不能把目标拍摄到屏幕的正中心),只是希望让摄像机保持距离地旋转过去。所以我们要从这个变量中将方向和距离这两个信息分离。我们可以使用Normalize()函数将其归一化。
local length = dir:Normalize()
像这样调用,该函数会将dir变量的方向保留,将距离剔除并作为返回值返回。此时,我们若想将摄像机移动到目标位置,则需要这样做了:
摄像机位置 + 方向 * 距离 = 目标位置
即从摄像机当前的位置,向某个方向 移动 多少米, 最后会到达目标位置。想象一下用这种方式表达我们向某个地方走过去的话就是这个样子:
for(i = 0; i < 距离; ++i)
摄像机位置 = 摄像机位置 + 方向 * 1;
我们每次往这个方向移动1米,直到移动了N次后,我们会到达目标位置。 而方向 * 1 = 方向,所以当这个用来表示方向和距离类型的变量表示的距离为单位长度时,我们认为它表示的是一个方向(更详细、系统的3D数学知识大家可以自己学习一下,这里只是做一个简单的说明)。
现在,总结一下我们目前所拥有的信息:
- 摄像机位置(通过GetActorLocation()获取到)
- 目标位置 (同上)
- 目标相对摄像机的方向(摄像机需要转向哪里)
我们要做的就很简单了,只要通过引擎提供的接口,将摄像机转向该方向即可。
引擎为摄像机组件提供了SetDirAndUp(vDir, vUp)函数来实现这个功能。它需要的参数是一个让摄像机看向的方向和一个摄像机上方的方向。
为啥需要一个摄像机上方的方向呢?
想象一下,当我们扛着控制摄像机拍向一个物品的时候,我们在保证这个物品在屏幕中间的同时,还可以左右地旋转摄像机: (注意这不是小人在晃动,而是摄像机在晃动)
所以我们需要一个向上的方向来告诉引擎,你希望正着拍摄目标位置,还是旋转着拍摄目标位置。一般,我们不会修改摄像机的上方向,而仅仅修改它的朝向。所以我们可以直接获取到摄像机当前的上方向来传入,直接使用cameraActor的GetActorUpVector()方法即可。
那么现在,万事俱备。我们直接像这样:
--获取相机组件
local comp = camera:GetRootComponent()
--设置朝向和上方向
comp:SetDirAndUp(dir, camera:GetActorUpVector());
即可将目标显示在正中间:
修改前的相机拍摄范围和效果
修改后的相机拍摄范围