iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0

今天要繼續說明該Camera 的使用方式,今天要介紹的是 Camera 的移動、拉伸與回到鏡頭的原始位置,今天牽涉到的數學也會比較多一點,但都很容易理解,那就讓我們開始介紹!

Camera 的移動

  1. 首先我們要將先前撰寫的 void Start 進行更改,因為我們現在希望可以隨意地移動Camera,這邊我們要先宣告該 Camera 的視角與原先設定相同,並且取得該追蹤物件的 position 。
void Start() 
   {
        transform.rotation  = Quaternion.identity;
        targetPosition = chickenModel.position;
   }
  1. 接下來我們要使用 Mouse按下左鍵時滑鼠的 dx, dy。我們要注意到滑鼠移動與在環境中是相反的,也就是滑鼠dx向左邊移動則物體position.x則是要向右邊移動,dy 與 position.y 也是有相同的概念,所以差個負號。 targetPosition, targetRotation 皆為 Camera 最後的角度與位置。
if(Input.GetMouseButton(0))
        {
            dx *= moveSpeed;
            dy *= moveSpeed;

            targetPosition -= transform.up * dy + transform.right * dx;
            
        }

請注意到 transform.up 是基於世界坐標系,Vector.up 是基於本地坐標系,transform 的特點就是增加物件旋轉時角度旋轉信息,所以說移動加上旋轉可同時產生。但是Vector 是僅針對單一角度的變化做處理。所以這邊採用如下計算:

targetPosition -= transform.up * dy + transform.right * dx;
  1. 這裡我們到 FixedUpdate 去決定該透過線性插值 Lerp 來實現Camera 位置的方式,使用Vector.Lerp中傳入 position 和 targetPosition 的數值,並且透過宣告的 moveLerp 計算。
void FixedUpdate() {
        rotation = Quaternion.Slerp(rotation, targetRotation, Time.deltaTime * rotateLerp);      // use Slerp to calculate

        position = Vector3.Lerp(position, targetPosition, Time.deltaTime * moveLerp);


        transform.rotation = rotation;                                                     
        transform.position = position - rotation * new Vector3(0, 0, offsetZ);          
    }
  1. 整個程式碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraControl1 : MonoBehaviour
{

   public Transform chickenModel;
   float offsetZ = 2f, offsetY = 1f;
   public Vector3 targetPosition, position;                 // store the position
   private Quaternion rotation, targetRotation;             // store the rotation

   public float rotateSpeed = 32f, rotateLerp = 8f;
    public float moveSpeed = 0.5f, moveLerp = 5f;

   void Start() 
   {
        transform.rotation  = Quaternion.identity;
        targetPosition = chickenModel.position;
   }


    void Update() 
    {
        
        float dx = Input.GetAxis("Mouse X");
        float dy = Input.GetAxis("Mouse Y");

        if(Input.GetMouseButton(0))
        {
            dx *= moveSpeed;
            dy *= moveSpeed;

            targetPosition -= transform.up * dy + transform.right * dx;
            
        }


        if(Input.GetMouseButton(1))
        {
            dx *= rotateSpeed;
            dy *= rotateSpeed;

            if(Mathf.Abs(dx) > 0 || Mathf.Abs(dy) > 0)
            {
                // get the camera eular angle 
                Vector3 currentCameraAngle = transform.rotation.eulerAngles;

                currentCameraAngle.x = Mathf.Repeat(currentCameraAngle.x + 180f, 360f) -180f;      
                currentCameraAngle.y += dx;                       
                currentCameraAngle.x -= dy;                      

                // store camera rotation angle 
                targetRotation.eulerAngles = new Vector3(currentCameraAngle.x  , currentCameraAngle.y , 0);              
            }
        }
        
    }

    void FixedUpdate() {
        rotation = Quaternion.Slerp(rotation, targetRotation, Time.deltaTime * rotateLerp);      // use Slerp to calculate

        position = Vector3.Lerp(position, targetPosition, Time.deltaTime * moveLerp);


        transform.rotation = rotation;                                                     
        transform.position = position - rotation * new Vector3(0, 0, offsetZ);          
    }

}

  1. 接下來到 Unity 中觀察到以滑鼠的左鍵來控制該Camera 的位置

Camera 的遠近控制

  1. 首先若要將鏡頭遠近控制,需要使用到滑鼠中間的滾輪來實現。 首先我們決定該與物件的起始位置。
void Start() 
   {
        transform.rotation  = Quaternion.identity;
        targetPosition = chickenModel.position;
        targetdistance = offsetZ;   // set the first distance of the object 
        
   }
  1. 設定我們想要的速度與之後使用到 Mathf.Lerp 的數值。
public float zoomSpeed = 8f, zoomLerp = 4f;
  1. 接下來在 Update 內部去有效的撰寫滑鼠中間滾輪的滾動數值乘上該 zoomSpeed 想要的距離。請注意到說該滾動與該環境是反方向。
// control the scroll in or out
targetdistance -= Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
  1. 透過 Mathf.Lerp 去計算我們滾動後的數值插值。 使用方式與線性插值與球形插值使用方式相同。這邊請注意到最後要記得去放進我們new Vector3(0, 0, distance) 內部,distance 為 Z軸上的變數變化。
void FixedUpdate() {
        // use Slerp to calculate
        rotation = Quaternion.Slerp(rotation, targetRotation, Time.deltaTime * rotateLerp);      

        position = Vector3.Lerp(position, targetPosition, Time.deltaTime * moveLerp);

        distance = Mathf.Lerp(distance, targetdistance, Time.deltaTime * zoomLerp);


        transform.rotation = rotation;                                                     
        transform.position = position - rotation * new Vector3(0, 0, distance);          
    }
  1. 完整的程式碼結果:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraControl1 : MonoBehaviour
{

    public Transform chickenModel;
    float offsetZ = 2f, offsetY = 1f;
    public Vector3 targetPosition, position;                 // store the position
    private Quaternion rotation, targetRotation;             // store the rotation

    public float distance, targetdistance;

    public float rotateSpeed = 32f, rotateLerp = 8f;
    public float moveSpeed = 0.5f, moveLerp = 5f;
    public float zoomSpeed = 8f, zoomLerp = 4f;


   void Start() 
   {
        transform.rotation  = Quaternion.identity;
        targetPosition = chickenModel.position;
        targetdistance = offsetZ;
        
   }


    void Update() 
    {
        
        float dx = Input.GetAxis("Mouse X");
        float dy = Input.GetAxis("Mouse Y");

        if(Input.GetMouseButton(0))
        {
            dx *= moveSpeed;
            dy *= moveSpeed;

            targetPosition -= transform.up * dy + transform.right * dx;
            
        }


        if(Input.GetMouseButton(1))
        {
            dx *= rotateSpeed;
            dy *= rotateSpeed;

            if(Mathf.Abs(dx) > 0 || Mathf.Abs(dy) > 0)
            {
                // get the camera eular angle 
                Vector3 currentCameraAngle = transform.rotation.eulerAngles;

                currentCameraAngle.x = Mathf.Repeat(currentCameraAngle.x + 180f, 360f) -180f;      
                currentCameraAngle.y += dx;                       
                currentCameraAngle.x -= dy;                      

                // store camera rotation angle 
                targetRotation.eulerAngles = new Vector3(currentCameraAngle.x  , currentCameraAngle.y , 0);              
            }
        }

        // control the scroll in or out
        targetdistance -= Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
        
    }

    void FixedUpdate() {
        rotation = Quaternion.Slerp(rotation, targetRotation, Time.deltaTime * rotateLerp);      // use Slerp to calculate

        position = Vector3.Lerp(position, targetPosition, Time.deltaTime * moveLerp);

        distance = Mathf.Lerp(distance, targetdistance, Time.deltaTime * zoomLerp);


        transform.rotation = rotation;                                                     
        transform.position = position - rotation * new Vector3(0, 0, distance);          
    }


}

  1. 回到 Unity 後執行可以發現到滾輪可以控制場景的遠近。

結論

  1. 今天說明到如何控制 Camera 的移動與拉伸,讓我們可以更全面的以第三人稱視角觀看我們的物件。
  2. 有效的使用該滑鼠移動點擊的方式,並且套用進 Camera 的移動方式。
  3. Slerp, Lerp 線性插值幫助我們平滑的移動到我們想要的視角上。

上一篇
Day13: Unity Camera Control 1
下一篇
Day15: Player Field of View
系列文
Unity 基本功能實作與日常紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言