unity Camera控制(上帝视角)

unity Camera控制(上帝视角)

解决问题

  1. 解决移动速度不变带来的操作迟缓;
  2. 实现在摄像机不同角度下,始终针对地面的水平移动(而非视口的上下左右移动);
  3. 实现绕点旋转。

正文

在针对大场景(如智慧城市),需要一种行之有效的Camera控制移动方法。为了提高漫游的效率,Camera的移动速度不应该是不变的。在实际的操作过程中,水平的鸟瞰移动,比视口发上下移动更为快捷。针对某地某建筑绕点旋转比自身旋转观测更具效率。

  1. 动态改变速度

这里引入了射线的,在特定时间用射线和地面或建筑发生碰撞,得到碰撞点,通过计算距离,调整移动速度。

  1. 始终水平地面移动

解决问题要得到一个始终平行于地面的“移动向量”。首先,我们定义Input.GetAxis(“Mouse X”)和Input.GetAxis(“Mouse Y”)为Camera的“移动增量”。unity Camera的x轴是水平地面的,可以用“X移动增量”作为“移动向量的X分量”。y,z两轴是根据图中a角度改变而改变,当控制Camera向前移动时,使用Camera的x欧拉角(如图a角)和Y移动增量,分别用sin和cos计算出“移动向量”的Y、Z分量。这样所构成的向量始终平行于地面。

源代码

using UnityEngine;
using System;
public class CameraControl : MonoBehaviour
{
    enum RayType { Mouse, Camera }
    Transform m_Camera;
    Vector3 m_RayHitPoint;

    void Start()
    {
        m_Camera = this.transform;
        m_RayHitPoint = Vector3.zero;
    }
    void LateUpdate()
    {
        if (Input.GetMouseButtonDown(1))
        {
            RayPoint(RayType.Camera);
        }
        if (Input.GetMouseButton(0))
        {
            Translation(0.05f);
        }
        if (Input.GetMouseButton(1))
        {
            RotatePoint();
        }
        if (Input.GetAxis("Mouse ScrollWheel") < 0)
        {
            RayPoint(RayType.Camera);
            FrontMove(-1);
        }
        if (Input.GetAxis("Mouse ScrollWheel") >0)
        {
            RayPoint(RayType.Camera);
            FrontMove(1);
        }
    }
    Vector3 VecOffet=Vector3.zero;
    /// <summary>
    /// 平移控制
    /// </summary>
    /// <param name="sheep"></param>
    void Translation(float sheep)
    {
        VecOffet =  m_RayHitPoint- m_Camera.position;
    
        float ftCamerDis = Vector3.Distance(m_Camera.position, m_RayHitPoint);
        if (ftCamerDis==0)
        {
            ftCamerDis = 1;
        }
        float moveX = Input.GetAxis("Mouse X");
        float moveY = Input.GetAxis("Mouse Y");
        float tranY = moveY * (float)Math.Sin(Math.Round(m_Camera.localRotation.eulerAngles.x, 2) * Math.PI / 180.0);
        float tranZ = moveY * (float)Math.Cos(Math.Round(m_Camera.localRotation.eulerAngles.x, 2) * Math.PI / 180.0);
        m_Camera.Translate(new Vector3(-moveX, -tranY, -tranZ) * ftCamerDis * sheep, Space.Self);
        m_RayHitPoint = m_Camera.position + VecOffet;
   }
    /// <summary>
    /// 绕点旋转
    /// </summary>
    void RotatePoint()
    {
        Vector3 eulerAngles = m_Camera.eulerAngles;
        float eulerAngles_x = eulerAngles.y;
        float eulerAngles_y = eulerAngles.x;

        float ftCamerDis = Vector3.Distance(transform.position, m_RayHitPoint);
         eulerAngles_x += (Input.GetAxis("Mouse X"));
         eulerAngles_y -= (Input.GetAxis("Mouse Y"));

        if (eulerAngles_y > 80)
        {
             eulerAngles_y = 80;
        }
        else if (eulerAngles_y < 1)
        {
            eulerAngles_y = 1;
        }
        Quaternion quaternion = Quaternion.Euler(eulerAngles_y, eulerAngles_x, (float)0);
        Vector3 vector = ((Vector3)(quaternion * new Vector3((float)0, (float)0, -ftCamerDis))) + m_RayHitPoint;

        m_Camera.rotation = quaternion;
        m_Camera.position = vector;

    }
    /// <summary>
    /// 得到射线碰撞点
    /// </summary>
    void RayPoint(RayType rayType)
    {
        Ray ray;
        switch (rayType)
        {
            case RayType.Mouse:
                 ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                break;
            case RayType.Camera:
                 ray = new Ray(m_Camera.position, m_Camera.forward);
                break;
            default:
                return;
        }
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit))
        {
            m_RayHitPoint = hit.point;
        }
        else
        {
            m_RayHitPoint = transform.forward * 800 + transform.position;//摄像机前方 800 点                                            
        }
    }
    /// <summary>
    /// 键盘控制
    /// </summary>
    void KeyTranslation()
    {
        VecOffet = m_RayHitPoint - m_Camera.position;
        float ftCamerDis = Vector3.Distance(m_Camera.position, m_RayHitPoint);
        float moveX = Input.GetAxis("Horizontal") * Time.deltaTime * 10;
        float moveY = Input.GetAxis("Vertical") * Time.deltaTime * 10;
        if (moveX == 0 && moveY == 0)
        {
            return;
        }
        float tranY = moveY * (float)Math.Sin(Math.Round(m_Camera.localRotation.eulerAngles.x, 2) * Math.PI / 180.0);
        float tranZ = moveY * (float)Math.Cos(Math.Round(m_Camera.localRotation.eulerAngles.x, 2) * Math.PI / 180.0);
        m_Camera.Translate(new Vector3(moveX, tranY, tranZ) * ftCamerDis * 0.1f, Space.Self);
        m_RayHitPoint = m_Camera.position + VecOffet;
    }
    /// <summary>
    /// 向前移动
    /// Direction[方向]
    /// </summary>
    /// <param name="intDirection">填写正反,1向前移动,2向后移动</param>
    void FrontMove(int intDirection)
    {
        float ftCamerDis = Vector3.Distance(m_Camera.position, m_RayHitPoint);
        if (ftCamerDis < 1)
        {
            ftCamerDis = 1;
        }
        m_Camera.Translate(Vector3.forward * ftCamerDis * 0.1f* intDirection);
    }
}

猜你喜欢

转载自blog.csdn.net/dxs1990/article/details/123126483