Unity 以一定角速度轉向動態目標的旋轉方式對比
1.尤拉角旋轉
public void Rotate(Vector3 eulers, [DefaultValue("Space.Self")] Space relativeTo);
就容易想到的就是transform.Rotate方法:
1 RotationObj.transform.Rotate(Vector3.up * Palstance * Time.deltaTime);
其中Palstance代表角速度。
但很快就會發現這個方法有2個很大的缺陷:
①需要利用cross值(叉積)來手動判斷是繞旋轉軸逆時針還是順時針旋轉
如果叉積為正,說明目標體在旋轉體右側,需順時針旋轉;
如果叉積為負,說明目標體在旋轉體左側,需逆時針旋轉
具體判斷如下:
1 var cross = Vector3.Cross(RotationObj.transform.forward, offset).y; 2 if (cross > 0) 3 { 4 //右 5 if (Palstance < 0) 6 { 7 Palstance = -Palstance; 8 } 9 } 10 else if (cross < 0) 11 { 12 //左 13 if (Palstance > 0) 14 { 15 Palstance = -Palstance; 16 } 17 }
其中offset代表目標體與旋轉體座標間的向量。
②難以判斷何時應該停止旋轉,且角速度過大時很容易造成在到達目標向量附近來回鬼畜旋轉
一般的考慮是,當旋轉體的前方向向量transform.forward與offset小於一定閾值時停止旋轉,例如:
1 var angle = Vector3.Angle(RotationObj.transform.forward, offset);2 if (angle < .1f) 3 return ;
但當角速度過快時,很容易錯過[0,0.1]這一角度範圍,但如果把範圍設定過大,有沒辦法精準對齊,於是就造成了在目標向量附近來回鬼畜旋轉的狀況;
當然了,也可以用一種非常生硬的方式來解決:
1 //基於當前角速度一幀內最大的旋轉角度 2 if (angle < Palstance * Time.deltaTime) 3 { 4 RotationObj.transform.forward = offset; 5 }
即設定另一個閾值範圍(並且這個閾值範圍最好和當前角速度正相關,可以計算出基於當前角速度一幀內最大的旋轉角度進行設定),當小於該閾值範圍時直接瞬切,因為本來就是在一幀內的角度運動,所以不會有任何違和感。
也可以考慮將判定範圍與該旋轉閾值設定為同一個。完整旋轉方式如下:
1 //基於當前角速度一幀內最大的旋轉角度 2 if (angle < Palstance * Time.deltaTime) 3 { 4 RotationObj.transform.forward = offset; 5 return; 6 } 7 8 var cross = Vector3.Cross(RotationObj.transform.forward, offset).y; 9 if (cross > 0) 10 { 11 //右 12 if (Palstance < 0) 13 { 14 Palstance = -Palstance; 15 } 16 } 17 else if (cross < 0) 18 { 19 //左 20 if (Palstance > 0) 21 { 22 Palstance = -Palstance; 23 } 24 } 25 RotationObj.transform.Rotate(Vector3.up * Palstance * Time.deltaTime);
上面的方式經過調整後雖然能夠實現準確轉向,但看上去並不簡單直接,那有沒有更簡潔快速的旋轉方式呢。
2.插值旋轉
Lerp(a,b,t);
旋轉朝向實際上可以認為是對transform.forward進行關於角速度的插值變化:
1 RotationObj.transform.forward = Vector3.Lerp(RotationObj.transform.forward, offset, Time.deltaTime * Palstance / angle).normalized;
Time.deltaTime/(angel/Palstance)=Time.deltaTime * Palstance / angle;
利用當前角度與角速度相除計算出當前幀率下的預計旋轉時間,隨後用當前幀率與預計旋轉時間的比值來對兩個向量進行插值。
這種方法非常簡單,但也有一個問題是沒辦法做到勻速旋轉,角色的朝向,當前幀速率和角度可能會隨時發生變化。
3.四元數旋轉
1 Quaternion q = Quaternion.LookRotation(offset); 2 RotationObj.transform.rotation = Quaternion.RotateTowards(RotationObj.transform.rotation, q, Palstance * Time.deltaTime);
四元數類中自帶朝向旋轉的方法,但需要先轉換出目標向量對應的四元數。該方式可以實現勻速率旋轉。