# 【环绕观察台】

自己写的一个可以进行360度展示角色模型,汽车模型,商品等用途的摄像机控制器。

为了功能精简,尽量减少了一些不必要的控制,比如FOV视野,可以在具体需要用到的时候添加。

  1. 可以拖动左右方向360度旋转。
  2. 可以上下拖动在一定需要的范围内旋转。
  3. 快速拖动还可以在松开手指时进行惯性滑动。

全屏显示

using System;
using UnityEngine;
using UnityEngine.EventSystems;

public class CameraControlScript : MonoBehaviour
{
    /** 主要的摄像机 */
    public Camera mainCamera;

    /** 摄像机直接观察的对象 */
    public GameObject lookTarget;

    /** 控制摄像机水平旋转(绕Y轴旋转) */
    public GameObject cameraRotationH;

    /** 控制摄像机垂直方向旋转(绕Z轴旋转)(范围是0~60度) */
    public GameObject cameraRotationV;

    private Boolean isDownMouse = false;

    private Vector3 downMousePos = Vector3.zero;

    /** 按下时的水平旋转角度 */
    private Quaternion downHRotation = Quaternion.identity;

    /** 按下时的垂直旋转角度 */
    private Quaternion downVRotation = Quaternion.identity;
    
    /** 最后一帧鼠标的位置,用于当前帧的鼠标位置进行相减得出惯性方向和惯性大小 */
    private Vector3 lastFramePosition = Vector3.zero;

    /** 
    * 阻尼,越大停得越快
    * 0~1之间
    */
    private float damping = 0.05f;

    /** 惯性的方向(规格化) */
    private Vector3 velocityDirection = Vector3.zero;

    /** 当前的速度 */
    private float velocity = 0.0f;

    void Update()
    {
        if(cameraRotationH == null){return;}
        if(cameraRotationV == null){return;}
        if(mainCamera == null){return;}
        if(lookTarget == null){return;}

        var isUpMouse = false;
        if(Input.GetMouseButtonDown(0))// 鼠标按下
        {
            var isOnUI = EventSystem.current.IsPointerOverGameObject();
            if(isOnUI) return;
            if(!isDownMouse){
                isDownMouse = true;
                downMousePos = Input.mousePosition;
                downHRotation = cameraRotationH.transform.localRotation;
                downVRotation = cameraRotationV.transform.localRotation;
            }
            
        }else if(Input.GetMouseButtonUp(0))// 鼠标松开
        {
            if(isDownMouse){
                isDownMouse = false;
                isUpMouse = true;
            }
        }

        if(isDownMouse)
        {
            OnMouseMove();
        }else{
            OnVelocityMove();
        }

        // 让摄像机始终指向观察的目标(摄像机的Z轴要指向lookTarget)
        Vector3 pos =  lookTarget.transform.position;
        mainCamera.transform.LookAt(pos);

        if(isUpMouse)
        {
            OnMouseUp();
        }

        // 保存上一次的帧位置
        lastFramePosition = Input.mousePosition;
    }

    /** 根据惯性进行移动摄像机 */
    void OnVelocityMove()
    {
        // 进行减速
        if(velocity > 0){
            float deltaX = velocityDirection.x * velocity;
            Quaternion addAngle = Quaternion.AngleAxis(deltaX * 0.5f,Vector3.up);
            Quaternion newQuaternion = addAngle * cameraRotationH.transform.localRotation;
            
            // 纵向像素差
            float deltaY = velocityDirection.y * velocity;
            Quaternion addAngle2 = Quaternion.AngleAxis(deltaY * -0.2f,Vector3.forward);
            Quaternion newQuaternion2 = addAngle2 * cameraRotationV.transform.localRotation;

            cameraRotationV.transform.localRotation = LimitVRotation(newQuaternion2);
            cameraRotationH.transform.localRotation = newQuaternion;

            velocity = velocity - velocity * damping;
            if(velocity < 0)velocity = 0;
        }
    }

    /** 限制垂直的旋转角度,不能大于60度,不能小于10度 */
    Quaternion LimitVRotation(Quaternion q)
    {
        Quaternion ret = q;
        float angle = q.eulerAngles[2];// Z轴的旋转角度
        if(angle > 180)angle = angle - 360;// 为处理大于180度其实是负数角度的问题
        float max = 60;
        float min = -10;
        if(angle < min){
            ret = Quaternion.AngleAxis(min,Vector3.forward);
        }else if(angle > max){
            ret = Quaternion.AngleAxis(max,Vector3.forward);
        }
        return ret;
    }

    /** 鼠标松开时,进行创建惯性速度 */
    void OnMouseUp()
    {
        var curPos = Input.mousePosition;
        // 上一帧鼠标的位置指向当前帧鼠标的位置
        var vec = curPos - lastFramePosition;
        velocity = vec.magnitude;
        velocityDirection = vec.normalized;
    }

    /** 在屏幕上进行拖动 */
    void OnMouseMove()
    {
        var curPos = Input.mousePosition;
        // 横向像素差
        float deltaX = curPos.x - downMousePos.x;
        Quaternion addAngle = Quaternion.AngleAxis(deltaX * 0.5f,Vector3.up);
        Quaternion newQuaternion = addAngle * downHRotation;

        // 纵向像素差
        float deltaY = curPos.y - downMousePos.y;
        Quaternion addAngle2 = Quaternion.AngleAxis(deltaY * -0.2f,Vector3.forward);
        Quaternion newQuaternion2 = addAngle2 * downVRotation;

        cameraRotationV.transform.localRotation = LimitVRotation(newQuaternion2);
        cameraRotationH.transform.localRotation = newQuaternion;
    }
}

度盘:https://pan.baidu.com/s/1BuVqe1SEPd8QlyIGft48YQ?pwd=66a1 (opens new window)