【Unity學習筆記】第十七 Quaternion 中 LookRotation、Lerp、Slerp、RotateTowards等方法辨析與驗證

轉載請注明出處: https://blog.csdn.net/weixin_44013533/article/details/138909256

作者:CSDN@|Ringleader|

目錄

    • Quaternion API 速覽
    • FromToRotation在Transform中的應用
    • LookRotation 中upwards取Vector3.up和 transform.up的區別
    • 旋轉時如何保持Y軸不變,但朝向目標旋轉呢?
    • 不同旋轉方法案例
    • lerp與LerpUnclamped區別
    • Quaternion.Slerp 、Quaternion.RotateTowards區別
    • Lerp、Slerp比較
    • Quaternion * operator
    • 總結

主要參考:

  1. Unity手冊 & Quaternion API
  2. Unity3D - 詳解Quaternion類(二)
  3. 【Unity編程】Unity中關于四元數的API詳解

Quaternion API 速覽

創建旋轉:

  • FromToRotation 創建一個從 fromDirection 旋轉到 toDirection 的旋轉。
  • LookRotation 使用指定的 forward 和 upwards 方向創建旋轉。
  • AngleAxis 創建一個圍繞 axis 旋轉 angle 度的旋轉。
  • Angle 返回兩個旋轉 a 和 b 之間的角度(以度為單位)。(180°以內)

操作旋轉:

  • Lerp 在 a 和 b 之間插入 t,然后對結果進行標準化處理。參數 t 被限制在 [0, 1] 范圍內。
  • Slerp 在四元數 a 與 b 之間按比率 t 進行球形插值。參數 t 限制在范圍 [0, 1] 內。
  • RotateTowards 將旋轉 from 向 to 旋轉。

Transform 類還提供了一些方法可用于處理 Quaternion 旋轉:Transform.Rotate & Transform.RotateAround

FromToRotation在Transform中的應用

Transform中有很多Quaternion的應用,比如獲取對象的xyz軸向量在世界坐標系下的表示,就用到了FromToRotation:

   ///<para>The red axis of the transform in world space.</para>public Vector3 right{get => this.rotation * Vector3.right;set => this.rotation = Quaternion.FromToRotation(Vector3.right, value);}///<para>The green axis of the transform in world space.</para>public Vector3 up{get => this.rotation * Vector3.up;set => this.rotation = Quaternion.FromToRotation(Vector3.up, value);}///<para>Returns a normalized vector representing the blue axis of the transform in world space.public Vector3 forward{get => this.rotation * Vector3.forward;set => this.rotation = Quaternion.LookRotation(value);}

LookRotation 中upwards取Vector3.up和 transform.up的區別

public static Quaternion LookRotation (Vector3 forward, Vector3 upwards= Vector3.up);

因為LookRotation 會使對象Z軸與forward參數向量對齊,X 軸與Vector3.Cross(upwards,forward)這個叉乘結果對齊,Y 軸與 Z 和 X 的叉乘(Vector3.Cross(transform.forward,transform.right) )對齊。(注意unity左手坐標系,叉乘方向)

所以會看到當upwards取世界空間的向上和模型空間的向上是有區別的。

或者說,upwards取模型空間的向上時對象可以繞自身z軸旋轉,對象狀態并不固定。
在這里插入圖片描述

public class LookRotationTest : MonoBehaviour
{public Transform obt_forward;public Transform obt_worldUp;public Transform obt_selfUp;public bool showCrossResult = false;// 驗證叉乘方向用private void Update(){// upwards取世界空間的向上LookForward(obt_worldUp, obt_forward.position - obt_worldUp.position, Vector3.up);// upwards取模型空間的向上LookForward(obt_selfUp,obt_forward.position - obt_selfUp.position, obt_selfUp.up);}private void LookForward(Transform obt, Vector3 forward,Vector3 upwards){obt.rotation = Quaternion.LookRotation(forward, upwards);var position = obt.position;Debug.DrawLine(obt_forward.position, position);Debug.DrawLine(position, position + obt.right * 5, Color.red);Debug.DrawLine(position, position + obt.up * 5, Color.green);Debug.DrawLine(position, position + obt.forward * 5, Color.blue);// 驗證叉乘方向, 叉乘結果與LookFoward結果一致if (showCrossResult){var X_cross = Vector3.Cross(upwards,forward);var Y_cross = Vector3.Cross(obt.forward,obt.right);Debug.DrawLine(position, position + X_cross * 10, Color.cyan);Debug.DrawLine(position, position + Y_cross * 10, Color.yellow);}}
}

旋轉時如何保持Y軸不變,但朝向目標旋轉呢?

使用Vector3.ProjectOnPlane將目標方向投影到xz平面。
在這里插入圖片描述

Lookat, FromToRotation and LookRotation?

不同旋轉方法案例

下面代碼比較了transform.forward 、Transform.LookAt、Quaternion.FromToRotation、LookRotation、Quaternion.RotateTowards、Vector3.ProjectOnPlane等不同方法

public class CompareImmediateAndStep : MonoBehaviour
{public Transform turret;public Transform enemy;private string str;private void Update(){var targetTowards = enemy.position - turret.position;// 立刻跟隨敵人if (Input.GetKey(KeyCode.Alpha1)){turret.forward = targetTowards;str = "使用turret.forward = targetTowards;";}// 上面本質也是使用FromToRotation方法if (Input.GetKey(KeyCode.Alpha2)){turret.rotation = Quaternion.FromToRotation(Vector3.forward, targetTowards);str = "使用turret.rotation = Quaternion.FromToRotation(Vector3.forward, targetTowards);";}if (Input.GetKey(KeyCode.Alpha3)){//當FromToRotation的fromDirection參數是forward軸時,可以用LookRotationturret.rotation = Quaternion.LookRotation(targetTowards);str = "turret.rotation = Quaternion.LookRotation(targetTowards);";}if (Input.GetKey(KeyCode.Alpha4)){turret.LookAt(enemy.transform);str = "turret.LookAt(enemy.transform);";}// 插值方式,加入旋轉速度if (Input.GetKey(KeyCode.Alpha5)){var fromToRotation = Quaternion.LookRotation(targetTowards);turret.rotation = Quaternion.RotateTowards(turret.rotation, fromToRotation, 45 * Time.deltaTime);str = "使用worldUp的Quaternion.RotateTowards";}// 保持對象Y軸朝向不變,將targetTowards進行投影if (Input.GetKey(KeyCode.Alpha6)){var fromToRotation = Quaternion.LookRotation(Vector3.ProjectOnPlane(targetTowards,Vector3.up),Vector3.up);turret.rotation = Quaternion.RotateTowards(turret.rotation, fromToRotation, 45 * Time.deltaTime);str = "保持Y軸朝向不變,將targetTowards進行投影";}DrawAxis(turret);DrawAxis(enemy);}private void DrawAxis(Transform obt){DrawAxis(obt, Color.red, Color.green, Color.blue, 5);}private void DrawAxis(Transform obt, Color xc, Color yc, Color zc, float length){if (obt.gameObject.activeInHierarchy){var position = obt.position;Debug.DrawLine(position, position + obt.right * length, xc);Debug.DrawLine(position, position + obt.up * length, yc);Debug.DrawLine(position, position + obt.forward * length, zc);}}private Rect rect = new Rect(100, 100, 600, 50);private void OnGUI(){DrawLabel(rect, str);}private static void DrawLabel(Rect rect1, String str){var style = new GUIStyle{fontSize = 38,wordWrap = true};GUI.Label(rect1, str, style);}
}

lerp與LerpUnclamped區別

區別就是Unclam不會鉗值,而且取負數時會從to→from旋轉。
在這里插入圖片描述

Vector3: Lerp vs LerpUnclamped

Quaternion.Slerp 、Quaternion.RotateTowards區別

RotateTowards本質也是使用了SlerpUnclamped方法,但其旋轉速度恒定,不會因target變化而改變。

public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta){float num = Quaternion.Angle(from, to);return (double) num == 0.0 ? to : Quaternion.SlerpUnclamped(from, to, Mathf.Min(1f, maxDegreesDelta / num));}

這篇帖子 Use Quaternion.RotateTowards() instead of Quaternion.Slerp() 提到了:

如果旋轉操作的from和to都已知,使用 Quaternion.Slerp() - 例如打開一扇門或箱子蓋。
如果要以恒定角速度轉向某物,則使用 Quaternion.RotateTowards() - 例如,在塔防類游戲中要轉向塔的炮塔。

Lerp、Slerp比較

Quaternion的插值分析及總結
Lerp求得的是四元數在圓上的弦上的等分,而Slerp求得的是四元數載圓上的圓弧的等分
在這里插入圖片描述

進行代碼驗證:

public class SlerpTest : MonoBehaviour
{public Transform obtLerp;public Transform obtSlerp;public Transform towardsObt;public bool towardsNotChanged;private Quaternion currentLookRotation,lastLookRotation;private Quaternion initRotationLerp, initRotationSlerp;public float speed = 0.1f;float total = 0.0f;private void Start(){lastLookRotation = Quaternion.LookRotation(towardsObt.position-obtLerp.position);initRotationLerp = obtLerp.rotation;initRotationSlerp = obtSlerp.rotation;}void Update(){CompareSlerpAndLerp();}private void CompareSlerpAndLerp(){currentLookRotation = Quaternion.LookRotation(towardsObt.position - obtLerp.position);towardsNotChanged = currentLookRotation == lastLookRotation;// 改變朝向時,重置初始位置、重置totalif (!towardsNotChanged){lastLookRotation = currentLookRotation;// 重置執行Lerp、Slerp時的初始旋轉initRotationLerp = obtLerp.rotation;initRotationSlerp = obtSlerp.rotation;total = 0;return;}lastLookRotation = currentLookRotation;total += Time.deltaTime * speed;if (total >= 1.0f)total = 1.0f;obtLerp.rotation = Quaternion.Lerp(initRotationLerp, currentLookRotation, total);obtSlerp.rotation = Quaternion.Slerp(initRotationSlerp, currentLookRotation, total);DrawAxis(obtLerp);DrawAxis(obtSlerp, Color.cyan, Color.magenta, Color.yellow, 10);}private void DrawAxis(Transform obt){DrawAxis(obt, Color.red, Color.green, Color.blue, 5);}private void DrawAxis(Transform obt,Color xc,Color yc,Color zc,float length){if (obt.gameObject.activeInHierarchy){var position = obt.position;Debug.DrawLine(position, position + obt.right * length, xc);Debug.DrawLine(position, position + obt.up * length, yc);Debug.DrawLine(position, position + obt.forward * length, zc);}}private Rect rect = new Rect(100, 100, 600, 50);private void OnGUI(){DrawLabel(rect,"Total:"+total);}private void DrawLabel(Rect rect1, String str){var style = new GUIStyle{fontSize = 38,wordWrap = true};GUI.Label(rect1, str, style);}
}

如下圖,RGB顏色的軸是Lerp方法,青紫黃軸是Slerp方法。可以看到Lerp相對Slerp來說先慢,中間快,最后慢。和上面的弦等分和弧等分理論一致。
請添加圖片描述

Quaternion * operator

在這里插入圖片描述
關于Quaternion 左乘右乘和坐標系的關系看我這篇:【Unity學習筆記】第十六 World space、Parent space和Self space及Quaternion左乘右乘辨析

總結

本文主要辨析Quaternion中Lerp、Slerp、RotateTowards等方法,并進行代碼驗證。至此,對Quaternion核心方法的理解已比較清晰,但其中的數學原理比如四元數、和歐拉角的關系、萬向鎖、逆和共軛等問題還是有待進一步學習。

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

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

相關文章

leetcode題目45

跳躍游戲Ⅱ 中等 給定一個長度為 n 的 0 索引整數數組 nums。初始位置為 nums[0]。 每個元素 nums[i] 表示從索引 i 向前跳轉的最大長度。換句話說&#xff0c;如果你在 nums[i] 處&#xff0c;你可以跳轉到任意 nums[i j] 處: 0 < j < nums[i] i j < n 返回到達 n…

戰網國際服怎么下載 暴雪戰網一鍵下載安裝圖文教程

戰網國際版&#xff0c;或稱為Battle.net全球版&#xff0c;是暴雪娛樂構建的一項跨越國界的綜合游戲交流平臺&#xff0c;它無視地理限制&#xff0c;旨在服務全球每一個角落的游戲愛好者。不同于地區專屬版本&#xff0c;國際版為玩家開啟了一扇無門檻的大門&#xff0c;讓每…

org.springframework.jdbc.BadSqlGrammarException

Cause: java.sql.SQLSyntaxErrorException: Table ‘web.emp’ doesn’t exist 產生原因&#xff1a;web表找不到&#xff0c;所以可能數據庫配置錯誤 spring.datasource.urljdbc:mysql://localhost:3306/web02 更改完成后運行成功

音頻筑基:100字說清哈曼曲線的Why和What

音頻筑基&#xff1a;100字說清哈曼曲線的Why和What 本文為短小精悍的音頻小知識總結&#xff0c;希望有用。 Why 音箱等大型外放設備是沒有哈曼曲線的哈曼曲線是為了解決近耳設備如耳機/助聽器&#xff0c;重放聲音時與聲源實際發聲舉例產生的聽感做衰減匹配也即沒有耳機的重…

免費利器:會議之眼一鍵生成論文功能火爆上線 助你快速起航

會議之眼 快訊 親愛的會議之眼粉絲們&#xff0c;你們是否曾經為了寫論文而徹夜苦思冥想&#xff1f;是否曾經為了找資料而焦頭爛額&#xff1f; 今天小編帶來了一個令人興奮的消息&#xff0c;那就是會議之眼網頁端平臺的全新功能——“一鍵生成論文”已經重磅上線啦&#x…

【計算機畢業設計】springboot房地產銷售管理系統的設計與實現

相比于以前的傳統手工管理方式&#xff0c;智能化的管理方式可以大幅降低房地產公司的運營人員成本&#xff0c;實現了房地產銷售的 標準化、制度化、程序化的管理&#xff0c;有效地防止了房地產銷售的隨意管理&#xff0c;提高了信息的處理速度和精確度&#xff0c;能夠及時、…

STM32-09-IWDG

文章目錄 STM32 IWDG1. IWDG2. IWDG框圖3. IWDG寄存器4. IWDG寄存器操作步驟5. IWDG溢出時間計算6. IWDG配置步驟7. 代碼實現 STM32 IWDG 1. IWDG IWDG Independent watchdog&#xff0c;即獨立看門狗&#xff0c;本質上是一個定時器&#xff0c;這個定時器有一個輸出端&#…

mmdetection訓練(1)voc格式的數據集(自制)

mmdetection訓練&#xff08;1&#xff09;voc格式的數據集&#xff08;自制&#xff09; 提前準備一、voc數據集二、修改配置代碼進行訓練&#xff08;敲黑板&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff09;1.數據集相關內容修改2.自定義配置文件構…

云曦實驗室期中考核題

Web_SINGIN 解題&#xff1a; 點擊打開環境&#xff0c;得 查看源代碼&#xff0c;得 點開下面的超鏈接&#xff0c;得 看到一串base64編碼&#xff0c;解碼得flag 簡簡單單的文件上傳 解題&#xff1a; 點擊打開環境&#xff0c;得 可以看出這是一道文件上傳的題目&#x…

【if條件、for循環、數據框連接、表達矩陣畫箱線圖】

編程能力&#xff0c;就是解決問題的能力&#xff0c;也是變優秀的能力 From 生物技能樹 R語言基礎第七節 文章目錄 1.長腳本管理方式if(F){....}分成多個腳本&#xff0c;每個腳本最后保存Rdata&#xff0c;下一個腳本開頭清空再加載 2.實戰項目的組織方式方法&#xff08;一&…

圓上點云隨機生成(人工制作模擬數據)

1、背景介紹 實際上,很多地物外表形狀滿足一定的幾何形狀結構,如圓形是作為常見一類。那么獲取該類目標的點云數據便是位于一個圓上的點云數據。如下圖所示為兩簇典型的點云,其中一種為理想型,點均位于一個圓上,另外一簇則是近似位于一個圓上,這種更加符合真實情況。有時…

好煩啊,我真的不想寫增刪改查了!

大家好&#xff0c;我是程序員魚皮。 很想吐槽&#xff1a;我真的不想寫增刪改查這種重復代碼了&#xff01; 大學剛做項目的時候&#xff0c;就在寫增刪改查&#xff0c;萬萬沒想到 7 年后&#xff0c;還在和增刪改查打交道。因為增刪改查是任何項目的基礎功能&#xff0c;每…

性能測試工具—jmeter的基礎使用

1.Jmeter三個重要組件 1.1線程組的介紹&#xff1a; 特點&#xff1a; 模擬用戶&#xff0c;支持多用戶操作多個線程組可以串行執行&#xff0c;也可以并行執行 線程組的分類&#xff1a; setup線程組&#xff1a;前置處理&#xff0c;初始化普通線程組&#xff1a;編寫…

springboot+vue+mybatis物業管理系統+PPT+論文+講解+售后

快速發展的社會中&#xff0c;人們的生活水平都在提高&#xff0c;生活節奏也在逐漸加快。為了節省時間和提高工作效率&#xff0c;越來越多的人選擇利用互聯網進行線上打理各種事務&#xff0c;通過線上物業管理系統也就相繼涌現。與此同時&#xff0c;人們開始接受方便的生活…

Swift頁面的跳轉和返回

之前一直使用的OC&#xff0c;現在也有不少人使用Swift&#xff0c;我也嘗試一下&#xff0c;寫一個簡單又基礎的功能&#xff1a;頁面的跳轉和返回。這里將顯示幾個swift文件的代碼。 文件Common.swift的代碼&#xff1a; // // Common.swift // MySwiftProject // // Cre…

怎樣讓貓給啥吃啥?生骨肉凍干拌糧哪有貓咪不吃的!

隨著科學養貓的普及&#xff0c;生骨肉凍干喂養越來越受歡迎&#xff0c;生骨肉凍干喂養對貓的好處很多&#xff0c;它符合貓咪的天性&#xff0c;可以提供全面的營養&#xff0c;保持牙齒和牙齦的健康&#xff0c;還有助于維持健康的消化系統。然而&#xff0c;許多貓主人在選…

考研操作系統-1.計算機系統概述

目錄 操作系統功能 操作系統的發展與分類 操作系統的運行環境 操作系統的體系結構 王道考研操作系統-1.計算機系統概述 操作系統 是指控制和管理整個計算機系統的硬件和軟件資源&#xff0c;合理地組織調度計算機的工作和資源的分配&#xff1b;提供給用戶和軟件方便的接…

PHP類和對象概念及用法

類和對象的關系 可以將類看成為一件模具&#xff0c;倒入不同的材料(屬性和方法)&#xff0c;這些材料用于構建獨特的對象 類的基本組成部分 屬性:類中的變量&#xff0c;用于儲存數據 方法&#xff1a;類中的函數&#xff0c;用于操作和訪問類的屬性 類及其屬性和方法的創建…

GDPU 競賽技能實踐 天碼行空 期末小測

1. 除法&#xff08;原題&#xff09; &#x1f468;?&#x1f3eb; 實驗二&#xff1a;1.簡單枚舉 輸入正整數n&#xff0c;按從小到大的順序輸出所有形如abcde/fghij n的表達式&#xff0c;其中a&#xff5e;j恰好為數字0&#xff5e;9的一個排列&#xff08;可以有前導0&a…

復雜json解析(其中有一個key的value是json格式的字符串)

app上報的參數如下: {"clientId": "8517895440514039afcf6d3e5d7832ae","dua": "SNDOCKCJPH90_GA&VN900042418&BN0&VCXiaomi&MOM2012K11AC&RL1080_2239&CHIDunknown_unknown&LCID&RV&OSAndroid13&…