【Unity】6.7 向量和Vector3類


分類:Unity、C#、VS2015

創建日期:2016-04-20

一、簡介

在虛擬的游戲世界中,與3D有關的數學知識決定了游戲引擎如何計算和模擬出開發者以及玩家看到的每一幀畫面。學習或者回想一下基礎的3D有關的數學知識,可以幫助開發者對游戲引擎產生更深刻的了解。

二、向量

在數學中向量的定義是:既有大小又有方向的量叫作向量。在空間中,向量可以用一段有方向的線段來表示。

向量在游戲開發過程中的應用十分廣泛,可用於描述具有大小和方向兩個屬性的物理量,例如物體運動的速度、加速度、攝像機觀察方向、剛體受到的力等都是向量,因此向量是物理、動畫、三維圖形的基礎。

1、向量相關概念

·模:向量的長度。

·標准化(Normalizing):保持方向不變,將向量的長度變為1。

·單位向量:長度為1的向量。

·零向量:各分量均為0的向量。

2、向量的運算

(1)加減

向量的加法(減法)為各分量分別相加(相減)。在物理上可以用來計算兩個力的台力,或者幾個速度分量的疊加。

image

(2)數乘

向量與一個標量相乘稱為數乘。數乘可以對向量的長度進行縮放,如果標量大於0,那么向量的方向不變;若標量小於0,則向量的方向會變為反方向。

(3)點乘

兩個向量點相乘得到一個標量,數值等於兩個向量長度相乘后再乘以二者夾角的余弦值。如果兩個向量a,b均為單位向量,那么a.b等於向量b在向量a方向上的投影的長度(也等於向量a在向量b方向的投影)

image

通過兩個向量點乘結果的符號可以快速地判斷兩個向量的夾角情況:

若u·v = 0,則向量u、v相互垂直。

若u·v > 0,則向量u、v夾角小於90°。

若u·v <0,則向量u、v夾角大於90°。

(4)叉乘

兩個向量的叉乘得到一個新的向量,新向量垂直於原來的兩個向量,並旦長度等於原向量長度相乘后再乘夾角的正弦值。

image

可以通過左手擺出上圖所示的手勢來判斷叉乘結果的方向(使用左手是因為Unity里用的是左手坐標系)。假設有向量Result=a×b,將拇指朝向a的方向,食指指向b的方向,則中指指向的方向為叉乘結果的方向。

注意:叉乘不滿足交換律,即a× b≠ b× a。

三、Vector3類

在Unity中,和向量有關的類有Vector2、Vector3、Vector4,分別對應不同維度的向量,其中Vector3的使用最為廣泛。

1、成員變量和方法

Vector3類的常用成員變量和方法如下:

x、y、z:向量的X分量、Y分量、Z分量。

normalized:獲取單位化后的向量(只讀)。

magnitude:獲取向量長度(只讀)。

sqrMagnitude獲取向量長度的平方(只讀)。

Cross():向量叉乘。

Dot():向量點乘。

Project():計算向量在另一向量上的投影。

Angle():返回兩個向量之間的夾角。

Distance():返回兩個向量之間的距離。

運算符:+、-、*、/、==、!=

下面是Vector3類的—些應用示例。

2、示例1(Demo7_1_DistanceTest.unity)

該例子演示了如何計算兩個位置之間的距離。其中other變量綁定的游戲對象的坐標為(50,50,50),腳本綁定的目標對象的坐標為(-2,-3.3,-10)。

在Distance.unity場景中使用了本示例的源文件,運行效果如下:

image

下面是該場景中使用的C#腳本代碼(DistanceTest.cs文件):

using UnityEngine;
using System.Collections;
public class DistanceTest : MonoBehaviour
{
    public Transform other;
    void Start()
    {
        if (other != null)
        {
            var dist = Vector3.Distance(other.position, transform.position);
            print("Distance to other: " + dist);
        }
    }
}

3、示例2(Demo7_2_DirectionMove.unity)

該例子演示如何讓游戲對象沿着指定的方向移動。

DirectionMove.cs的代碼如下:

using UnityEngine;
using System.Collections;
public class DirectionMove : MonoBehaviour
{
    public Vector3 direction = Vector3.forward;//移動方向
    public float speed = 5.0f;//速度

    void Update()
    {
        transform.position += direction * speed * Time.deltaTime;
    }
}

4、示例3(Demo7_3_SqrMagnitude.unity)

該例子演示如何利用Vector3.sqrMagnitude來判斷目標對象的距離是否小於觸發距離,其中other變量的坐標為(-2,-3,-10),該腳本綁定的游戲對象的坐標為(-2,-3.3,-10)。

使用的腳本(SqrMagnitude.cs文件)代碼如下:

using UnityEngine;
using System.Collections;
public class SqrMagnitude : MonoBehaviour
{
    public Transform other;   //目標物體的Transform
    public double closeDistance = 5.0;  // 觸發距離
    void Update()
    {
        if (other)
        {
            var sqrLen = (other.position - transform.position).sqrMagnitude;
            // 使用Vector3.sqrMagnitude比Vector3.magnitude計算速度要快
            if (sqrLen < closeDistance * closeDistance)
            {
                print("目標物體已靠近!");
            }
        }
    }
}

5、示例4(Demo7_4_MoveToTarget.unity)

該例子演示對象從初始點平滑移動到目標點的動畫,其中start變量綁定的對象坐標為(-3,-3,-10),end變量綁定的坐標為(-3,-3,20)。

使用的腳本(MoveToTarget.cs文件)代碼如下:

using UnityEngine;
using System.Collections;
public class MoveToTarget : MonoBehaviour
{
    public Transform start; //初始位置
    public Transform end; //終點位置
    void Update()
    {
        transform.position = Vector3.Lerp(start.position, end.position, Time.time);
    }
}

6、示例5(Demo7_5_SunRiseAndDown.unity)

該例子演示如何利用Slerp插值方法模擬太陽升起和落下的過程。

使用的腳本(SunRiseAndDown.cs文件)代碼如下:

using UnityEngine;
using System.Collections;
public class SunAndRise : MonoBehaviour
{
    public Transform sunrise;//升起位置
    public Transform sunset; //落下位置 
    public float journeyTime = 10.0f; //從升起到落下需要的時間,以秒為單位
    private float startTime; //用於記錄開始的時間

    void Start()
    {
        startTime = Time.time; // 設置開始的時間
    }

    void Update()
    {
        var center = (sunrise.position + sunset.position) * 0.5f;//計算運行軌跡的圓心點
        center -= new Vector3(0, 1, 0);
        var riseRelCenter = sunrise.position - center;//升起位置到圓心的向量
        var setRelCenter = sunset.position - center; //落下位置到圓心的向量
        var fracComplete = (Time.time - startTime) / journeyTime;//計算用於插值的系數
        transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, fracComplete);//Slerp插值
        transform.position += center;
    }
}

下面是該例子的運行效果:

image

四、矩陣

相向量一樣,矩陣也是3D數學中十分重要基礎。

1、矩陣的概念

m× n的矩陣是一個具有m行、n列的矩形數組,行數和列數分別為矩陣的維度。在游戲引擎中使用的矩陣通常為4×4矩陣,因為它可以描述向量的平移、旋轉、縮放等所有的線性變換。

2、矩陣的計算

自己看其他參考資料吧。

3、Matrix4x4類

Unity使用Matrix4x4類來描述4×4矩陣。

更多介紹請參看其他參考資料。

五、奇次坐標

在3D數學中,齊次坐標就是將原本3維的向量(x,y,z)用4維向量(wx,wy,wz,w)來表示。引入齊次坐標的主要有如下目的:

1、可更好地區分向量和點。在三維空間中, (x,y,z)既可以表示點也可以表示分量,不便於區分,如果引入齊次坐標,則可以使用(x,y,z,1)來表示坐標點,使用(x,y,z,0)來表示向量。

2、統—用矩陣乘法表示平移、旋轉、縮放變換。如果使用3×3的矩陣,矩陣乘法只能表示旋轉和縮放變換,無法表示平移變換。而在4D齊次空間中,可以使用4×4的齊次矩陣來統一表示平移、旋轉、縮放變換。

3、當分量w=0時可以用來表示無窮遠的點。

齊次坐標是計算機圖形學中一個非常重要的概念,但是在Unity中很少需要直接和它打交道,在編寫一些shader可能會用到它,平時在腳本中主要還是使用三維向量Vector3。Unity通過便利的接口設計將這一重要概念隱藏在了引擎后面。


免責聲明!

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



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