Unity 點(diǎn)乘和叉乘的原理和使用

Unity當(dāng)中經(jīng)常會(huì)用到向量的運(yùn)算來(lái)計(jì)算目標(biāo)的方位,朝向,角度等相關(guān)數(shù)據(jù),下面咱們來(lái)通過(guò)實(shí)例學(xué)習(xí)下Unity當(dāng)中最常用的點(diǎn)乘和叉乘的使用。

點(diǎn)乘

(又稱(chēng)"點(diǎn)積","數(shù)量積”,"內(nèi)積")(Dot Product, 用*)
定義:a·b=|a|·|b|cos<a,b> 【注:粗體小寫(xiě)字母表示向量,<a,b>表示向量a,b的夾角,取值范圍為[0,180]】
幾何意義:是一條邊向另一條邊的投影乘以另一條邊的長(zhǎng)度.

v1和v2向量的點(diǎn)乘運(yùn)算:相應(yīng)元素的乘積的和:v1( x1, y1,z1) * v2(x2, y2,z2) = x1x2 + y1y2+z1z2;
注意 : 結(jié)果不是一個(gè)向量,而是一個(gè)標(biāo)量。
性質(zhì)1: a
b = |a||b|Cos(θ) ,θ是向量a 和向量 b之間的夾角。
性質(zhì)2: ab = ba 滿足乘法交換律
Unity項(xiàng)目應(yīng)用:
1.根據(jù)點(diǎn)乘計(jì)算兩個(gè)向量的夾角。<a,b>= arccos(a·b / (|a|·|b|))
2.根據(jù)點(diǎn)乘的正負(fù)值,得到夾角大小范圍,>0,則夾角(0,90)<0,則夾角(90,180),可以利用這點(diǎn)判斷一個(gè)多邊形是面向攝像機(jī)還是背向攝像機(jī)。
3.根據(jù)點(diǎn)乘的大小,得到向量的投影長(zhǎng)度,反應(yīng)了向量的長(zhǎng)度關(guān)系。
4.在生產(chǎn)生活中,點(diǎn)積同樣應(yīng)用廣泛。利用點(diǎn)積可判斷一個(gè)多邊形是否面向攝像機(jī)還是背向攝像機(jī)。向量的點(diǎn)積與它們夾角的余弦成正比,因此在聚光燈的效果計(jì)算中,可以根據(jù)點(diǎn)積來(lái)得到光照效果,如果點(diǎn)積越大,說(shuō)明夾角越小,則物理離光照的軸線越近,光照越強(qiáng)。物理中,點(diǎn)積可以用來(lái)計(jì)算合力和功。若b為單位矢量,則點(diǎn)積即為a在方向b的投影,即給出了力在這個(gè)方向上的分解。功即是力和位移的點(diǎn)積。計(jì)算機(jī)圖形學(xué)常用來(lái)進(jìn)行方向性判斷,如兩矢量點(diǎn)積大于0,則它們的方向朝向相近;如果小于0,則方向相反。矢量?jī)?nèi)積是人工智能領(lǐng)域中的神經(jīng)網(wǎng)絡(luò)技術(shù)的數(shù)學(xué)基礎(chǔ)之一,此方法還被用于動(dòng)畫(huà)渲染(Animation-Rendering)。

叉乘

(又稱(chēng)"叉積","向量積","外積")(cross product,用x)
定義:c = a x b,其中a b c均為向量
幾何意義是:得到一個(gè)與這兩個(gè)向量都垂直的向量,這個(gè)向量的模是以兩個(gè)向量為邊的平行四邊形的面積
v1和v2向量的叉乘運(yùn)算:相應(yīng)元素的乘積的和:v1( x1, y1,z1) x v2(x2, y2, z2) = (y1z2 - y2z1)i+(x2z1 - x1z2)j+(x1y2-x2y1)k;
利用三階行列式計(jì)算
|i j k|
|x1 y1 z1|
|x2 y2 z2|
性質(zhì)1:c⊥a,c⊥b,即向量c與向量a,b所在平面垂直
性質(zhì)2:模長(zhǎng)|c| = |a||b| sin<a,b>
性質(zhì)3:(數(shù)學(xué)上)滿足右手法則, a x b = -b x a,所以我們可以使用叉乘的正負(fù)值來(lái)判斷a,b的相對(duì)位置,即b是處于a的順時(shí)針還是逆時(shí)針?lè)较颉?br> 叉乘的右手定則是用來(lái)確定叉乘積的方向的。
右手法則:右手的四指方向指向第一個(gè)矢量,屈向叉乘矢量的夾角方向(兩個(gè)矢量夾角方向取小于180°的方向),那么此時(shí)大拇指方向就是叉乘所得的叉乘矢量的方向.(大拇指應(yīng)與食指成九十度)(注意:Unity當(dāng)中使用左手,因?yàn)閁nity使用的是左手坐標(biāo)系)

數(shù)學(xué)上叉乘的右手法則

Unity當(dāng)中叉乘的左手法則

Unity項(xiàng)目應(yīng)用:
1.根據(jù)叉乘得到a,b向量的相對(duì)位置,和順時(shí)針或逆時(shí)針?lè)轿弧?br> 簡(jiǎn)單的說(shuō): 點(diǎn)乘判斷角度,叉乘判斷方向。
形象的說(shuō): 當(dāng)一個(gè)敵人在你身后的時(shí)候,叉乘可以判斷你是往左轉(zhuǎn)還是往右轉(zhuǎn)更好的轉(zhuǎn)向敵人,點(diǎn)乘得到你當(dāng)前的面朝向的方向和你到敵人的方向的所成的角度大小。
2.得到a,b夾角的正弦值,計(jì)算向量的夾角(0,90),可以配合點(diǎn)乘和Angle方法計(jì)算出含正負(fù)的方向。
3.根據(jù)叉乘大小,得到a,b向量所形成的平行四邊形的面積大小,根據(jù)面積大小得到向量的相對(duì)大小。

下面是代碼

using UnityEngine;  
  
public class VectorExample : MonoBehaviour {  
  
    //點(diǎn)積  
    private void TestDot(Vector3 a, Vector3 b)  
    {  
        // 計(jì)算 a、b 點(diǎn)積結(jié)果  
        float result = Vector3.Dot(a, b);  
  
        // 通過(guò)向量直接獲取兩個(gè)向量的夾角(默認(rèn)為 角度), 此方法范圍 [0 - 180]  
        float angle = Vector3.Angle(a, b);  
  
        // 計(jì)算 a、b 單位向量的點(diǎn)積,得到夾角余弦值,|a.normalized|*|b.normalized|=1;  
        result = Vector3.Dot(a.normalized, b.normalized);  
        // 通過(guò)反余弦函數(shù)獲取 向量 a、b 夾角(默認(rèn)為 弧度)  
        float radians = Mathf.Acos(result);  
        // 將弧度轉(zhuǎn)換為 角度  
        angle = radians * Mathf.Rad2Deg;  
    }  
  
    //叉乘  
    private void TestCross(Vector3 a, Vector3 b)  
    {  
        //計(jì)算向量 a、b 的叉積,結(jié)果為 向量   
        Vector3 c = Vector3.Cross(a, b);  
  
        // 通過(guò)反正弦函數(shù)獲取向量 a、b 夾角(默認(rèn)為弧度)  
        float radians = Mathf.Asin(Vector3.Distance(Vector3.zero, Vector3.Cross(a.normalized, b.normalized)));  
        float angle = radians * Mathf.Rad2Deg;  
  
        // 判斷順時(shí)針、逆時(shí)針?lè)较颍窃?2D 平面內(nèi)的,所以需指定一個(gè)平面,  
        //下面以X、Z軸組成的平面為例 , (Y 軸為縱軸),  
        // 在 X、Z 軸平面上,判斷 b 在 a 的順時(shí)針或者逆時(shí)針?lè)较?  
        if (c.y > 0)  
        {  
            // b 在 a 的順時(shí)針?lè)较? 
        }  
        else if (c.y == 0)  
        {  
            // b 和 a 方向相同(平行)  
        }  
        else  
        {  
            // b 在 a 的逆時(shí)針?lè)较? 
        }  
    }  
  
    // 獲取兩個(gè)向量的夾角  Vector3.Angle 只能返回 [0, 180] 的值  
    // 如真實(shí)情況下向量 a 到 b 的夾角(80 度)則 b 到 a 的夾角是(-80)  
    // 通過(guò) Dot、Cross 結(jié)合獲取到 a 到 b, b 到 a 的不同夾角  
    private void GetAngle(Vector3 a, Vector3 b)  
    {  
        Vector3 c = Vector3.Cross(a, b);  
        float angle = Vector3.Angle(a, b);  
  
        // b 到 a 的夾角  
        float sign = Mathf.Sign(Vector3.Dot(c.normalized, Vector3.Cross(a.normalized, b.normalized)));  
        float signed_angle = angle * sign;  
  
        Debug.Log("b -> a :" + signed_angle);  
  
        // a 到 b 的夾角  
        sign = Mathf.Sign(Vector3.Dot(c.normalized, Vector3.Cross(b.normalized, a.normalized)));  
        signed_angle = angle * sign;  
  
        Debug.Log("a -> b :" + signed_angle);  
    }  
}  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容