U3D中攝像機繞屏幕中心點旋轉縮放平移


之前做的都是攝像機繞某個物體旋轉。直接修改的Rotation屬性

然后縮放用的是改攝像機FieldOfView的值

最后發覺效果不僅不盡如人意而且平移后會錯位。在借鑒了一個別人的攝像機代碼后修改成功

按住右鍵旋轉,按住中鍵平移,滾輪縮放

腳本拖放到攝像機上即可

代碼如下

using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FreeCameraController : MonoBehaviour
{
    //攝像機繞屏幕中心旋轉縮放平移腳本
    public float thetaSpeed = 150.0f; //x旋轉速度
    public float phiSpeed = 80.0f; //垂直旋轉速度
    public float moveSpeed = 10.0f; //平移速度
    public float zoomSpeed = 60.0f; //縮放速度

    public float phiBoundMin = 1f;  //最低垂直旋轉角度
    public float phiBoundMax = 89f; //最高垂直旋轉角度
    public bool useMoveBounds = true; //是否綁定移動范圍
    public float moveBounds = 220f; //綁定移動范圍  四周 還有上面
    public float moveLimiyY = 35f; //綁定移動范圍   下方

    //縮放距離限制 最小,最大
    public Vector2 distanceLimit = new Vector2(20f, 600f);

    //旋轉平滑
    public float rotateSmoothing = 0.5f;
    //移動平滑
    public float moveSmoothing = 0.7f;

    //當前距離
    public float distance = 2.0f;

    //攝像機的初始角度
    private Vector2 euler;

    //目標旋轉角度
    public Quaternion targetRot;
    //當前朝向的目標
    private Vector3 targetLookAt;
    //當前攝像機到目標的距離
    public float targetDist;

    //臨時變量
    private Vector3 distanceVec = new Vector3(0, 0, 0);

    //目標對象的變換
    public Transform target;

    //綁定屏幕范圍
    private Rect inputBounds;
    public Rect paramInputBounds = new Rect(0, 0, 1, 1);

    //中心點
    public Vector3 pivotPoint = new Vector3(0, 2, 0);

    //當前選中的對象
    public static BaseModel selectModel;

    //限制鼠標范圍 避免點擊抖動
    private Vector2 limitMouseX = new Vector2(-5, 5);
    private Vector2 limitMouseY = new Vector2(-5, 5);

    //目標位置
    public Vector3 targetPos;

    //日志
    [Logger]
    private IWebLogger logger;

    // 是否能操作
    bool canOper = false;

    //看向目標需要的時間
    float LookAtTime = 1.5f;

    public void Start()
    {
        //獲取當前攝像機的角度
        Vector3 angles = transform.eulerAngles;
        euler.x = angles.y;
        euler.y = angles.x;
        //unity only returns positive euler angles but we need them in -90 to 90
        euler.y = Mathf.Repeat(euler.y + 180f, 360f) - 180f;

        //創建目標物體
        GameObject go = new GameObject("_FreeCameraTarget");
        //設置隱藏並不保存
        go.hideFlags = HideFlags.HideAndDontSave | HideFlags.HideInInspector;

        //設置初始參數
        target = go.transform; //設置目標

        target.position = pivotPoint; //設置中心點為其實目標位置
        targetDist = (transform.position - target.position).magnitude; //獲取相機到中心點的距離

        targetRot = transform.rotation; //設置目標旋轉角度
        targetLookAt = target.position; //設置朝向的目標所在位置

        //開始時攝像機緩慢看向目標
        transform.DOLookAt(targetLookAt, LookAtTime);
        SetOper(pivotPoint, LookAtTime);
    }

    //設置攝像機緩慢看向目標
    public void SetOper(Vector3 targetPos, float lookAtTime)
    {
        canOper = false;
        this.targetPos = targetPos;
        //開啟定時任務
        TimeManager.Instance.AddTask(lookAtTime, false, Oper);
        TimeManager.Instance.AddTask(lookAtTime+0.2f, false, CanOper);
    }

    private void Oper()
    {
        //計算DOLookAt結束后的參數
        target.position = targetPos;
        targetDist = (transform.position - target.position).magnitude;

        targetRot = transform.rotation;
        targetLookAt = target.position;

        //修正DOLookAt的偏差值
        float distanceTemp;
        do
        {
            distanceTemp = distance;
            distance = moveSmoothing * targetDist + (1 - moveSmoothing) * distance;
            //print("Oper.distance --->" + distance);
        } while (distanceTemp != distance); 

    }

    private void CanOper()
    {       
        canOper = true;      
    }

    public void Update()
    {
        if (!canOper)
        {
            return;
        }

        //NOTE: mouse coordinates have a bottom-left origin, camera top-left
        inputBounds.x = GetComponent<Camera>().pixelWidth * paramInputBounds.x;
        inputBounds.y = GetComponent<Camera>().pixelHeight * paramInputBounds.y;
        inputBounds.width = GetComponent<Camera>().pixelWidth * paramInputBounds.width;
        inputBounds.height = GetComponent<Camera>().pixelHeight * paramInputBounds.height;

        //目標存在 且 在屏幕范圍內
        if (target && inputBounds.Contains(Input.mousePosition))
        {
            // 點擊 並獲取點擊物體
            if (Input.GetMouseButtonUp(0))
            {
                // 前端 click() ---> 點擊物體    
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit, 2000))
                {
                    Debug.DrawLine(ray.origin, hit.point, Color.red, 0.5f);
                    //Debug.Log(hit.point);
                    BaseModel baseModel = hit.collider.gameObject.GetComponent<BaseModel>();
                    if (baseModel != null)
                    {
                        selectModel = baseModel;

                        logger.Log("id:" + baseModel.Uuid + " prefabName:" + baseModel.BaseData.PrefabName +
                            " position:" + baseModel.BaseData.Transform.position +
                            " modelType:" + baseModel.modelType);

                        // 觸發點擊事件
                        if (!baseModel.BaseData.IsNoClick)
                        {
                            Sender sender = new Sender();
                            sender.eventName = BaseEvent.click;
                            sender.souce = gameObject;

                            EventCenter.Instance.TriggerEvent(BaseEvent.click, sender, baseModel.Uuid);
                        }

                        return;
                    }
                }
            }

            //獲取鼠標在屏幕的x.y值
            float dx = Input.GetAxis("Mouse X");
            float dy = Input.GetAxis("Mouse Y");

            //鼠標偏移量限制,防止抖動
            if (dx < limitMouseX.x || dx > limitMouseX.y)
            {

                //print("鼠標旋轉位置:" + MousePosition);
                return;
            }

            if (dy < limitMouseY.x || dy > limitMouseY.y)
            {
                //print("鼠標旋轉位置:" + MousePosition);
                return;
            }

            //點擊鼠標右鍵
            bool click1 = Input.GetMouseButton(1);
            //點擊鼠標左鍵
            bool click0 = Input.GetMouseButton(0);

            if (click0)
            {
                //計算移動量
                dx = dx * moveSpeed * 0.005f * targetDist;
                dy = dy * moveSpeed * 0.005f * targetDist;
                targetLookAt -= transform.up * dy + transform.right * dx;

                //使用移動綁定的范圍
                if (useMoveBounds)
                {
                    targetLookAt.x = Mathf.Clamp(targetLookAt.x, -moveBounds, moveBounds);
                    //targetLookAt.y = Mathf.Clamp(targetLookAt.y, -moveBounds, moveBounds);
                    targetLookAt.y = Mathf.Clamp(targetLookAt.y, moveLimiyY, moveBounds);
                    targetLookAt.z = Mathf.Clamp(targetLookAt.z, -moveBounds, moveBounds);
                }
            }

            else if (click1)
            {
                //計算旋轉角度
                dx = dx * thetaSpeed * 0.02f;
                dy = dy * phiSpeed * 0.02f;
                euler.x += dx;
                euler.y -= dy;
                //限制垂直旋轉角度
                euler.y = ClampAngle(euler.y, phiBoundMin, phiBoundMax);
                targetRot = Quaternion.Euler(euler.y, euler.x, 0);
            }

            //當前攝像機到目標的距離 減鼠標滑動距離
            targetDist -= Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
            //限制縮放
            targetDist = Mathf.Clamp(targetDist, distanceLimit.x, distanceLimit.y);
            
        }
    }

    public void FixedUpdate()
    {
        //不可操作的清空下直接return
        if (!canOper)
        {          
            return;
        }

        //計算距離
        distance = moveSmoothing * targetDist + (1 - moveSmoothing) * distance;

        if (Application.platform == RuntimePlatform.WebGLPlayer)
        {
            logger.Error("FixedUpdate.distance --->" + distance);
        }  

        //計算旋轉角度插值
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotateSmoothing);

        //計算距離插值
        target.position = Vector3.Lerp(target.position, targetLookAt, moveSmoothing);

        //設置距離 Z軸
        distanceVec.z = distance;
        //設置相機最終的位置  目標位置 - 相機當前旋轉角度 * 距離Z軸
        transform.position = target.position - transform.rotation * distanceVec;
    }

    /// <summary>
    /// 限制角度
    /// </summary>
    /// <param name="angle"></param>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360f) angle += 360f;
        if (angle > 360f) angle -= 360f;
        return Mathf.Clamp(angle, min, max);
    }


}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM