【unity】关于unity3D摄像机视角移动的几种方式详解

目录

一、前言

二、Transform基础

1、几种坐标系

2、position和localPosition属性

3、rotation属性

三、摄像机的平移

1、键盘控制平移

2、鼠标控制平移

3、整合 

四、摄像机的旋转

1、绕自身旋转

2、绕目标物体旋转

3、整合 

五、优化功能

1、调整速率

2、切换目标物体

3、设置常用摄像机观察点


一、前言

        在做虚拟仿真或数字孪生等项目中,常常会遇到需要自由移动视角的场景。最近在用unity制作一个有关3D打印机的数字孪生项目时遇到了这种情况,本文将结合unity和blender的视角移动功能,介绍一个类似这两个软件的视角移动的方法。

二、Transform基础

        Unity3D中的Transform组件是每个GameObject对象都有的组件,它控制着对象的位置、旋转和缩放。 在介绍视角移动前,本文将先介绍transform的position、rotation两个属性和unity中的坐标系。

1、几种坐标系

        在unity中常见的有两种坐标系,分别是全局坐标(World Space)和局部坐标(Local Space),在unity场景窗口(Scene)中可以切换这两种坐标系,如图所示:

        全局坐标:也称为世界坐标,表示物体在场景中的绝对位置和方向。全局坐标是相对于场景的原点(0,0,0)而言的。

        局部坐标:也称为相对坐标,表示物体相对于其父物体的位置和方向。局部坐标是相对于父物体的原点(0,0,0)而言的。

2、position和localPosition属性

        position和localPosition都是三维向量(Vector3),前者用于描述物体在场景中的绝对位置,即相对于世界原点的位置;后者描述物体相对于其父级对象的位置,以父物体为原点。

        在没有设置父物体时,Transform.position和Transform.localPosition的值相同,都等于物体的全局坐标。

        当物体P被设为物体Q的子物体时,物体P的Transform.localPosition表示与父物体Q的相对位置,当只改变父物体Q的Transform.position时,子物体P将跟随父物体Q移动,因此子物体P的Transform.position随物体Q改变,然而子物体P相对于父物体Q的相对位置不变,所以子物体P的Transform.localPosition保持不变。

        值得一提的是,在unity的检查器(Inspector)面板的Transform组件中,所显示的position为localPosition,对于无父物体的物体而言,其代表全局(世界)坐标,对于有父物体的物体而言,则表示两者的相对位置。

3、rotation属性

        和描述位置的属性一样,描述旋转的属性也分为rotation和localRotation。它是一个四元数(Quaternion)。rotation与localRotation的关系和position与localPosition一样,这里就不多做赘述。不过值得注意的一点是,在unity中文文档中提到:

        “请勿尝试编辑/修改 rotation。”

        “要旋转 Transform,请使用 Transform.Rotate,它将使用欧拉角。”

三、摄像机的平移

        在unity场景窗口中我们可以按住鼠标滚轮进行平移,而在blender中我们可以按住左Shift+鼠标滚轮平移视角,除此之外,在unity中也可以通过键盘上下左右键控制视角移动。而在项目中,我们将尝试控制摄像机平移模仿上述效果。

1、键盘控制平移

        键盘控制平移的代码非常简单,不过在此之前应该在unity的项目设置(Project Setting)中设置好输入管理器(Input Manager)。如下图所示:

        在脚本分别调用Input.GetAxis("Vertical")和Input.GetAxis("Horizontal")将返回一个float值,由于类型设置为“Key or Mouse Button”,则返回-1、0、1三个值。

        当按下键盘W或者↑键时Input.GetAxis("Vertical")将返回1,按下S或者↓键时将返回-1,不按任何键将返回0;同理当按下D或→键时Input.GetAxis("Horizontal")将返回1,按下A或者←键时将返回-1,不按则返回0。

        根据这个属性可得到控制平移的代码:

float moveZ = Input.GetAxis("Vertical") * moveSpeedWithKeyBoard * Time.deltaTime;
float moveX = Input.GetAxis("Horizontal") * moveSpeedWithKeyBoard * Time.deltaTime;
transform.position += transform.forward *  moveZ + transform.right * moveX;
2、鼠标控制平移

        我将用按下滚轮拖动鼠标的方式控制摄像机上下左右平移,滚动滚轮控制前后平移。

        首先是前后移动,确保你的输入管理器(Input Manager)设置如图所示:

        通过调用Input.GetAxis("Mouse ScrollWheel")获取前后移动的值,同样这个函数将返回一个float值,滚轮向前滚为正,向后为负。代码如下:

float MouseScroll = Input.GetAxis("Mouse ScrollWheel") * moveSpeedWithScroll * Time.deltaTime;
transform.position += transform.forward * MouseScroll;

       

        然后是上下左右移动 ,当鼠标滚轮按下时获取鼠标在xy轴移动的值:

if (Input.GetMouseButton(2))
{
    float moveX = -Input.GetAxis("Mouse X") * moveSpeedWithMouse * Time.deltaTime;
    float moveY = -Input.GetAxis("Mouse Y") * moveSpeedWithMouse * Time.deltaTime;

    transform.position += transform.right * moveX + transform.up * moveY;
}
3、整合 

        综合上述,不难发现这几段代码的相似之处:接收来自鼠标或键盘的输入并算出摄像机在forward、right、up三个方向上的移动值,再乘以对应的方向向量并加到相机的位置上,因此可以整合成以下函数:

/// <summary>
/// 相机移动
/// </summary>
public void Move()
{

    float moveX = 0;
    float moveY = 0;
    float moveZ = 0;

    // 接收键盘输入
    moveZ = Input.GetAxis("Vertical") * moveSpeedWithKeyBoard * Time.deltaTime;
    moveX = Input.GetAxis("Horizontal") * moveSpeedWithKeyBoard * Time.deltaTime;

    // 接收滚轮输入
    moveZ = Input.GetAxis("Mouse ScrollWheel") * moveSpeedWithScroll * Time.deltaTime;

    // 接收鼠标输入
    if (Input.GetMouseButton(2))
    {
        moveX = -Input.GetAxis("Mouse X") * moveSpeedWithMouse * Time.deltaTime;
        moveY = -Input.GetAxis("Mouse Y") * moveSpeedWithMouse * Time.deltaTime;
    }

    // 控制移动
    transform.position += transform.forward * moveZ + transform.right * moveX + transform.up * moveY;

}

四、摄像机的旋转

         常见的摄像机旋转有两种,即摄像机自身旋转和摄像机绕目标物体旋转。在unity的场景窗口中按住鼠标滚轮为绕自身旋转,按住左Alt+鼠标左键时绕选中物体旋转。下面我们将尝试做出上述效果。

1、绕自身旋转

        绕自身旋转的思路很简单,只需要获取鼠标输入并更改摄像机自身的旋转。代码如下:

if (Input.GetMouseButton(0))
{
    float rotateX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
    float rotateY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;

    Vector3 eulerAngles = transform.eulerAngles;

    eulerAngles.y += rotateX;
    eulerAngles.x -= rotateY;

    transform.eulerAngles = eulerAngles;
}
2、绕目标物体旋转

        绕目标物体转动较为复杂,需要同时改变position和rotation的值。首先确定目标物体,再改变position值,这个过程和上文的鼠标控制平移一样,接下来需要改变rotation的值确保摄像机始终面向目标物体,只需调用transform.LookAt()函数即可。

        当然使用上述方法可以粗略实现围绕旋转,但是依旧有个小问题,就是摄像机会在旋转的过程中逐渐远离目标物体,原因是我们每次改变position的值都将增加一点二者之间的距离(根据三角形的斜边大于直角边的原理),而后面的步骤没有抵消掉这个距离变化。

        所有在以上步骤之后还应矫正一下距离,将摄像机的位置在目标物体的方向上移动至距离不变的位置,最终的代码如下:

if (Input.GetMouseButton(1))
{
    float rotateX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
    float rotateY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;

    float distance = Vector3.Distance(target.transform.position, transform.position);

    transform.position += transform.right * -rotateX + transform.up * -rotateY;

    transform.LookAt(target.transform);

    transform.position = target.transform.position + -transform.forward * distance;
}
3、整合 

        同样的,我们将以上两段代码整合封装成函数,可以得到以下代码:

/// <summary>
/// 相机旋转
/// </summary>
public void Rotate()
{
    //接收输入
    float rotateX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
    float rotateY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;

    // 绕自身旋转
    if (Input.GetMouseButton(0))
    {
        Vector3 eulerAngles = transform.eulerAngles;

        eulerAngles.y += rotateX;
        eulerAngles.x -= rotateY;

        transform.eulerAngles = eulerAngles;
    }


    // 绕喷头旋转
    if (Input.GetMouseButton(1))
    {
        float distance = Vector3.Distance(target.transform.position, transform.position);

        transform.position += transform.right * -rotateX + transform.up * -rotateY;

        transform.LookAt(target.transform);

        transform.position = target.transform.position + -transform.forward * distance;
    }
}

五、优化功能

1、调整速率

        上述方法中,移动的速率是不变的,这样可能会导致当摄像机离物体很远时会显得移动很慢,离物体很近时会显得太快,可以写一个函数,根据距离目标物体的远近自动调整速率或许可以获得更好的手感。 

2、切换目标物体

        上述方法中没有提到目标物体的切换与选择,可以添加一个功能,通过鼠标点击选中游戏中的对象作为目标物体围绕旋转,切换目标只需选择其他对象即可。

3、设置常用摄像机观察点

        在实际项目中,可设置几个常用的摄像机机位,用户可通过快捷键快速切换到该位置观察。例如在3D打印机的仿真中,可以在打印机窗口前设置一个观察点来模拟实际中用户观察3D打印机的视角。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>