【Unity中的數學】—— 四元數

一、四元數的定義😎

四元數是一種高階復數,是一個四維空間的概念,相對于復數的二維空間。它可以表示為 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz,其中 s s s x x x y y y z z z 都是實數,并且滿足 i 2 = j 2 = k 2 = i j k = ? 1 i^2 = j^2 = k^2 = ijk = -1 i2=j2=k2=ijk=?1 i j = k ij = k ij=k j k = i jk = i jk=i k i = j ki = j ki=j j i = ? k ji = -k ji=?k k j = ? i kj = -i kj=?i i k = ? j ik = -j ik=?j 這些運算規則😜。

四元數的創造源于對復數以及矩陣的某些問題,在很多領域都有廣泛的應用,比如計算機圖形學、機器人學、航空航天等。它可以用來表示向量旋轉或者坐標系轉換,比歐拉角和旋轉矩陣更具優勢👏。例如,在計算機圖形學中,四元數可以避免歐拉角表示旋轉時出現的萬向節死鎖問題,并且計算更加緊湊高效,還能方便地進行球面插值。

二、萬向節死鎖😵

2.1 定義

萬向節死鎖(Gimbal Lock)是機械系統和三維空間旋轉控制中的一種現象,主要發生在使用歐拉角描述三維旋轉時😕。當一個旋轉軸在一定條件下與另一個旋轉軸重合時,系統失去了一個自由度,導致無法獨立控制所有旋轉方向,這種情況就稱為萬向節死鎖。

2.2 原理

歐拉角是用來描述三維空間中剛體旋轉的一種方法,它通過三個角度(通常為偏航角(yaw)、俯仰角(pitch)和滾轉角(roll))來確定剛體的旋轉狀態😃。然而,歐拉角描述旋轉時存在一個問題,就是當中間的旋轉軸轉動 90 度時,第一個旋轉軸和第三個旋轉軸會重合,系統就會損失一個自由度。

舉個例子🤔,假如我們有一個飛機模型,按照 X ? Y ? Z X - Y - Z X?Y?Z 的順序進行旋轉。當飛機繞 Y Y Y 軸旋轉 90 度時, X X X 軸和 Z Z Z 軸的旋轉效果就會相同,此時飛機就無法獨立控制繞 X X X 軸的旋轉了,這就是萬向節死鎖的表現。

2.3 避免方法

根據使用場景調整旋轉順序:用歐拉角描述旋轉時無法完全避免死鎖問題,但可以根據使用場景來減少死鎖出現的概率。比如描述船在海上航行的姿態時,可以把中間的旋轉軸定義為船的左右方向,因為船幾乎很難在這個方向旋轉 90 度(船頭豎直朝上或朝下)🤗。
使用其他描述旋轉的方式:使用四元數、旋轉矩陣等其它方式描述旋轉。四元數可以避免萬向節死鎖現象,并且只需要一個 4 維的四元數就可以執行繞任意過原點的向量的旋轉,方便快捷,在某些實現下比旋轉矩陣效率更高😎。

三、Unity中的四元數🎉

3.1 歐拉角與四元數互相轉換

在 Unity 中,Transform 組件的 rotation 屬性是一個四元數,但為了方便理解,我們通常會使用歐拉角來表示旋轉。下面是歐拉角與四元數互相轉換的方法👇:

3.1.1 歐拉角轉四元數

// 獲得掛在該腳本的對象的歐拉角
Vector3 euler = this.transform.eulerAngles;
Quaternion quater = Quaternion.Euler(euler);
Quaternion quater1 = Quaternion.Euler(0, 0, 0);

這里的 Quaternion.Euler 方法可以將歐拉角轉換為四元數。它的實現原理是根據歐拉角的三個角度,通過一系列的三角函數計算得到四元數的四個分量😃。

3.1.2 四元數轉歐拉角
print(quater.eulerAngles);

通過 eulerAngles 屬性可以將四元數轉換為歐拉角。需要注意的是,四元數到歐拉角的轉換可能不是唯一的,因為一個旋轉可以用多個不同的歐拉角表示😉。

3.2 對比物體間的旋轉角度 Quaternion.Angle

Quaternion.Angle 方法用于計算兩個四元數前方矢量之間的夾角度數,也就是對比物體之間的旋轉角度😃。使用時需要聲明一個公共 Transform 對象,示例代碼如下:

public Transform target;void Update()
{float angle = Quaternion.Angle(transform.rotation, target.rotation);Debug.Log("角度: " + angle);
}

在這個例子中,我們在 Update 函數中不斷計算當前物體和目標物體之間的旋轉角度,并將結果輸出到控制臺。這個方法在很多場景中都很有用,比如游戲中判斷兩個角色的朝向夾角😎。

3.3 直接繞軸旋轉角度 Quaternion.AngleAxis

Quaternion.AngleAxis 方法用于創建一個繞指定軸旋轉指定角度的四元數😜。它的函數原型如下:

public static Quaternion AngleAxis(float angle, Vector3 axis);

參數說明:

angle:旋轉的角度,以度為單位。
axis:旋轉的軸向,一個 Vector3 類型的對象。

返回值是一個 Quaternion 類型的對象,表示旋轉的結果。下面是一些使用示例👇:

3.3.1 繞 Y 軸旋轉游戲對象

public class RotateObject : MonoBehaviour
{public float rotationSpeed = 10f;private void Update(){// 根據旋轉速度和 Y 軸創建旋轉四元數Quaternion rotation = Quaternion.AngleAxis(rotationSpeed * Time.deltaTime, Vector3.up);// 將旋轉應用到游戲對象的旋轉屬性上transform.rotation *= rotation;}
}

在這個示例中,我們創建了一個名為 RotateObject 的腳本,并將其綁定到一個游戲對象上。腳本中定義了一個 rotationSpeed 變量來控制旋轉速度。在 Update 方法中,我們使用 Quaternion.AngleAxis 方法創建了一個繞 Y 軸旋轉的旋轉四元數 rotation,角度為 rotationSpeed 乘以 Time.deltaTime(用于平滑旋轉)。然后,將該旋轉應用到游戲對象的旋轉屬性上,使對象隨時間不斷繞 Y 軸旋轉😎。

3.3.2 繞任意軸旋轉游戲對象

public class RotateObject : MonoBehaviour
{public float rotationSpeed = 10f;public Vector3 rotationAxis = Vector3.up;private void Update(){// 根據旋轉速度和軸向創建旋轉四元數Quaternion rotation = Quaternion.AngleAxis(rotationSpeed * Time.deltaTime, rotationAxis);// 將旋轉應用到游戲對象的旋轉屬性上transform.rotation *= rotation;}
}

這個示例與上面的類似,只是我們可以指定任意的旋轉軸。通過修改 rotationAxis 變量,我們可以讓游戲對象繞不同的軸進行旋轉😃。

3.3.3 連續旋轉游戲對象

public class RotateObject : MonoBehaviour
{public float rotationSpeed1 = 10f;public float rotationSpeed2 = 5f;private void Update(){// 根據旋轉速度和 Y 軸創建旋轉四元數Quaternion rotation1 = Quaternion.AngleAxis(rotationSpeed1 * Time.deltaTime, Vector3.up);// 根據旋轉速度和 X 軸創建旋轉四元數Quaternion rotation2 = Quaternion.AngleAxis(rotationSpeed2 * Time.deltaTime, Vector3.right);// 將兩個旋轉應用到游戲對象的旋轉屬性上transform.rotation *= rotation1 * rotation2;}
}

在這個示例中,我們創建了兩個旋轉四元數 rotation1 和 rotation2,分別繞 Y 軸和 X 軸進行旋轉。然后,將這兩個旋轉應用到游戲對象的旋轉屬性上,使對象同時繞 Y 軸和 X 軸連續旋轉😜。

3.4 其他靜態方法

除了上面介紹的方法,Quaternion 類還有很多其他的靜態方法,如 Dot、Inverse、Lerp、LookRotation、RotateToWards 和 Slerp 等。這些方法的具體使用可以參考官方手冊😃。

四、四元數的計算🧮

4.1 加法

兩個四元數的加法就是將“實部虛部”對應位置做元素求和😃。設兩個四元數 q 1 = s 1 + i x 1 + j y 1 + k z 1 q_1 = s_1 + ix_1 + jy_1 + kz_1 q1?=s1?+ix1?+jy1?+kz1? q 2 = s 2 + i x 2 + j y 2 + k z 2 q_2 = s_2 + ix_2 + jy_2 + kz_2 q2?=s2?+ix2?+jy2?+kz2?,則它們的和為: q 1 + q 2 = ( s 1 + s 2 ) + i ( x 1 + x 2 ) + j ( y 1 + y 2 ) + k ( z 1 + z 2 ) q_1 + q_2 = (s_1 + s_2) + i(x_1 + x_2) + j(y_1 + y_2) + k(z_1 + z_2) q1?+q2?=(s1?+s2?)+i(x1?+x2?)+j(y1?+y2?)+k(z1?+z2?)

四元數的加法滿足交換律、結合律和分配律👏。

4.2 縮放

在系數縮放這一點上,四元數與復數是一致的😃。設四元數 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz,標量為 λ \lambda λ,則它們的乘積為: λ q = λ s + i λ x + j λ y + k λ z \lambda q = \lambda s + i\lambda x + j\lambda y + k\lambda z λq=λs+x+y+z

4.3 乘法

四元數的乘法是所有元素之前都要運算一遍😕。設兩個四元數 q 1 = s 1 + i x 1 + j y 1 + k z 1 q_1 = s_1 + ix_1 + jy_1 + kz_1 q1?=s1?+ix1?+jy1?+kz1? q 2 = s 2 + i x 2 + j y 2 + k z 2 q_2 = s_2 + ix_2 + jy_2 + kz_2 q2?=s2?+ix2?+jy2?+kz2?,則它們的乘積為: q 1 q 2 = ( s 1 s 2 ? x 1 x 2 ? y 1 y 2 ? z 1 z 2 ) + i ( s 1 x 2 + s 2 x 1 + y 1 z 2 ? y 2 z 1 ) + j ( s 1 y 2 + s 2 y 1 + x 2 z 1 ? x 1 z 2 ) + k ( s 1 z 2 + s 2 z 1 + x 1 y 2 ? x 2 y 1 ) q_1q_2 = (s_1s_2 - x_1x_2 - y_1y_2 - z_1z_2) + i(s_1x_2 + s_2x_1 + y_1z_2 - y_2z_1) + j(s_1y_2 + s_2y_1 + x_2z_1 - x_1z_2) + k(s_1z_2 + s_2z_1 + x_1y_2 - x_2y_1) q1?q2?=(s1?s2??x1?x2??y1?y2??z1?z2?)+i(s1?x2?+s2?x1?+y1?z2??y2?z1?)+j(s1?y2?+s2?y1?+x2?z1??x1?z2?)+k(s1?z2?+s2?z1?+x1?y2??x2?y1?)

需要注意的是,四元數與復數的最大的一點不同,復數乘法是有交換律的,而四元數沒有😉。也就是說,一般情況下 q 1 q 2 ≠ q 2 q 1 q_1q_2 \neq q_2q_1 q1?q2?=q2?q1?

4.3.1 旋轉 = 四元數 * 四元數

四元數相乘可以將旋轉效果組合😎。例如, q u a t e r n i o n . e u l e r ( 0 , 0 , 10 ) ? q u a t e r n i o n . e u l e r ( 0 , 0 , 15 ) = = q u a t e r n i o n . e u l e r ( 0 , 0 , 25 ) quaternion.euler(0, 0, 10) * quaternion.euler(0, 0, 15) == quaternion.euler(0, 0, 25) quaternion.euler(0,0,10)?quaternion.euler(0,0,15)==quaternion.euler(0,0,25),這就是四元數相乘的效果。在 Unity 中,我們可以通過四元數相乘來實現物體的復合旋轉。

4.3.2 旋轉向量 = 四元數 * 向量

四元數乘以向量表示將向量按照四元數表示的角度旋轉😃。例如, v e c t o r 3 a = q u a t e r n i o n . e u l e r ( 0 , 0 , 10 ) ? n e w v e c t o r 3 ( 0 , 0 , 30 ) vector3 a = quaternion.euler(0, 0, 10) * new vector3(0, 0, 30) vector3a=quaternion.euler(0,0,10)?newvector3(0,0,30) 表示將(0,0,30)這個向量繞 z 軸為定軸,順時針旋轉 10°。需要注意的是,四元數只能進行 * 運算,不能進行 + - 運算,這是由四元數復雜的內部原理決定的😜。

4.4 其他運算

四元數還有一些其他的運算,如求模、單位化、求共軛、求逆等😃。這些運算在四元數的應用中也非常重要,下面是它們的定義和公式:

4.4.1 求模

四元數 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz 的模定義為: ∣ q ∣ = s 2 + x 2 + y 2 + z 2 |q| = \sqrt{s^2 + x^2 + y^2 + z^2} q=s2+x2+y2+z2 ?

4.4.2 單位化

單位化是將四元數的模變為 1,公式為: N o r m a l i z e ( q ) = q ∣ q ∣ Normalize(q) = \frac{q}{|q|} Normalize(q)=qq?

4.4.3 求共軛

四元數 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz 的共軛定義為: q ? = s ? i x ? j y ? k z q^* = s - ix - jy - kz q?=s?ix?jy?kz

4.4.4 求逆

四元數 q q q 的逆定義為: q ? 1 = q ? ∣ q ∣ 2 q^{-1} = \frac{q^*}{|q|^2} q?1=q2q??

對于單位四元數,分母為 1, q ? 1 = q ? q^{-1} = q^* q?1=q?

五、總結🥳

四元數在 Unity 中是一個非常重要的概念,它可以用來表示物體的旋轉,避免歐拉角表示旋轉時出現的萬向節死鎖問題😎。通過本文的介紹,我們了解了四元數的定義、萬向節死鎖的原理、Unity 中四元數的操作以及四元數的計算方法。希望這些內容對你有所幫助,讓你在使用 Unity 進行開發時能夠更加得心應手👏!

如果你想進一步了解四元數的相關知識,可以參考一些專業的數學書籍或者在線教程。同時,也可以通過實踐來加深對四元數的理解,比如在 Unity 中創建一些簡單的旋轉效果,使用四元數來實現物體的旋轉控制😃。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80652.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80652.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80652.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

macOS 15.4.1 Chrome不能訪問本地網絡

前言 最近使用macmini m4,自帶macOS15系統,對于開發者簡直是一言難盡,Chrome瀏覽器的本地網絡有bug,可以訪問本機,但是不能訪問路由器上的其他機器,路由器提供的頁面也不能訪問,如下是折騰解決…

瀏覽器刷新結束頁面事件,調結束事件的接口(vue)

瀏覽器刷新的時候,正在進行中的事件結束掉,在刷新瀏覽器的時候做一些操作。 如果是調接口,就不能使用axios封裝的接口,需要使用原生的fetch。 找到公共的文件App.vue 使用window.addEventListener(‘beforeunload’, function (e…

TCP/IP 模型每層的封裝格式

TCP/IP 模型是一個四層網絡架構,每一層在數據傳輸時都會對數據進行封裝,添加相應的頭部(和尾部)信息。以下是各層的封裝格式及關鍵字段說明: 1. 應用層(Application Layer) 封裝格式&#xff1a…

【行業深度解析】什么是馬甲包?

在 Android 應用分發和增長運營的實踐中,“馬甲包” 是一個常被提及的策略術語。特別是在 Google Play 平臺上,許多開發者或運營團隊出于營銷、風險分攤或生態布局等原因,會選擇通過發布“馬甲包”來實現多元化的業務拓展。 然而&#xff0c…

谷歌與微軟的AI戰爭:搜索、云服務與生態布局

谷歌與微軟的AI戰爭:搜索、云服務與生態布局 系統化學習人工智能網站(收藏):https://www.captainbed.cn/flu 文章目錄 谷歌與微軟的AI戰爭:搜索、云服務與生態布局摘要引言技術路線對比1. AI基礎設施:算力…

uniapp自定義導航欄搭配插槽

<uni-nav-bar dark :fixed"true" shadow background-color"#007AFF" left-icon"left" left-text"返回" clickLeft"back"><view class"nav-bar-title">{{ navBarTitle }}</view><block v-slo…

無人機飛控算法開發實戰:從零到一構建企業級飛控系統

簡介 無人機飛控算法是實現穩定飛行和精確控制的核心技術,涉及飛行動力學建模、傳感器數據處理、狀態估計和控制策略等多個環節。本實戰指南將系統講解四旋翼無人機飛控算法的開發流程,包括飛行動力學模型建立、傳感器校準與數據融合、主流控制算法實現(PID、ADRC、EKF)以…

p2p虛擬服務器

ZeroTier Central ? 推薦工具&#xff1a;ZeroTier&#xff08;免費、穩定、跨平臺&#xff09; ZeroTier 可以幫你把多臺設備&#xff08;無論是否跨網&#xff09;加入一個虛擬局域網&#xff0c;彼此間可以像在同一個 LAN 中通信&#xff0c;UDP 視頻、文件傳輸、SSH 等都…

MySQL數據庫遷移SQL語句指南

MySQL數據庫遷移SQL語句指南 一、基礎遷移方法 1. 使用mysqldump進行全量遷移 -- 導出源數據庫&#xff08;在命令行執行&#xff09; mysqldump -u [源用戶名] -p[源密碼] --single-transaction --routines --triggers --events --master-data2 [數據庫名] > migration…

畫立方體軟件開發筆記 js three 投影 參數建模 旋轉相機 @tarikjabiri/dxf導出dxf

gitee&#xff1a; njsgcs/njsgcs_3d mainwindow.js:4 Uncaught SyntaxError: The requested module /3dviewport.js does not provide an export named default一定要default嗎 2025-05-10 14-27-58 專門寫了個代碼畫立方體 import{ scene,camera,renderer} from ./3dviewp…

【工具】HandBrake使用指南:功能詳解與視頻轉碼

HandBrake使用指南&#xff1a;功能詳解與視頻轉碼 一、前言 高清視頻在當下日益普及&#xff0c;從影視制作到個人拍攝&#xff0c;從社交媒體發布到遠程教育&#xff0c;如何高效地壓縮、轉換和管理視頻文件的體積與清晰度&#xff0c;成為內容創作者與技術開發者的核心任務…

Docker容器網絡架構深度解析與技術實踐指南——基于Linux內核特性的企業級容器網絡實現

第1章 容器網絡基礎架構 1 Linux網絡命名空間實現原理 1.1內核級隔離機制深度解析 1.1.1進程隔離的底層實現 通過clone()系統調用創建新進程時&#xff0c;設置CLONE_NEWNET標志位將觸發內核執行以下操作&#xff1a; 內核源碼示例&#xff08;linux-6.8.0/kernel/fork.c&a…

SAP 交貨單行項目含稅金額計算報cx_sy_zerodivide處理

業務背景&#xff1a;SAP交貨單只有數量&#xff0c;沒有金額&#xff0c;所以開發報表從訂單的價格按數量計算交貨單的金額。 用戶反饋近期報表出現異常&#xff1a; ****2012/12/12 清風雅雨 規格變更 Chg 修改開始 ** 修改原因:由于余數為0時&#xff0c;可能會報錯溢出。…

【高數上冊筆記01】:從集合映射到區間函數

【參考資料】 同濟大學《高等數學》教材樊順厚老師B站《高等數學精講》系列課程 &#xff08;注&#xff1a;本筆記為個人數學復習資料&#xff0c;旨在通過系統化整理替代厚重教材&#xff0c;便于隨時查閱與鞏固知識要點&#xff09; 僅用于個人數學復習&#xff0c;因為課…

每日算法刷題 Day3 5.11:leetcode數組2道題,用時1h(有點慢)

5.LC 零矩陣(中等) 面試題 01.08. 零矩陣 - 力扣&#xff08;LeetCode&#xff09; 思想: 法一: 利用兩個集合分別儲存要清0的行和列索引 另外兩種原地優化空間的做法暫時不是目前刷題目標&#xff0c;故不考慮 代碼 c: class Solution { public:void setZeroes(vector&l…

【小記】excel vlookup一對多匹配

一個學生報四門課&#xff0c;輸出每個學生課程 應用概述操作預處理數據計數指令 COUNTIFS進行一對多匹配 vlookup 應用概述 應用場景&#xff1a;學生報名考試&#xff0c;需要整理成指定格式&#xff0c;發給考試院。 一個學生最多報考四門 格式實例&#xff1a;準考證號 …

《從零構建大模型》PDF下載(中文版、英文版)

內容簡介 本書是關于如何從零開始構建大模型的指南&#xff0c;由暢銷書作家塞巴斯蒂安? 拉施卡撰寫&#xff0c;通過清晰的文字、圖表和實例&#xff0c;逐步指導讀者創建自己的大模型。在本書中&#xff0c;讀者將學習如何規劃和編寫大模型的各個組成部分、為大模型訓練準備…

基于 Ubuntu 24.04 部署 WebDAV

1. 簡介 WebDAV&#xff08;Web Distributed Authoring and Versioning&#xff09;是一種基于 HTTP 的協議&#xff0c; 允許用戶通過網絡直接編輯和管理服務器上的文件。 本教程介紹如何在 Ubuntu 24.04 上使用 Apache2 搭建 WebDAV 服務&#xff0c;無需域名&#xff0c;…

node.js 實戰——在express 中將input file 美化,并完成裁剪、上傳進度條

美化上傳按鈕 在ejs 頁面 <!DOCTYPE html> <html> <head><meta charset"utf-8"></meta><title><% title %></title><link relstylesheet href/stylesheets/form.css/><!-- 本地 Bootstrap 引入方式 -->…

MySQL為什么選擇B+樹

1.hash表&#xff1a;不支持范圍查詢 2.跳表&#xff1a;索引層增加太快&#xff0c;IO成本增加太快 3.二叉樹、AVL樹、紅黑樹&#xff1a;樹高度增加太快&#xff0c;IO成本增加太快 4.B樹&#xff1a;樹高增加太快&#xff1b;范圍查詢只能走中序遍歷&#xff0c;IO成本很…