之前寫過一篇方向向量轉歐拉角的,相對來說歐拉角還是有一些限制,現在研究下方向向量轉四元數公式。
該四元數能夠使方向向量從Z軸(0,0,1)旋轉至(X,Y,Z)。四元數可以理解爲繞某軸(x,y,z)旋轉角度w,記爲(cos(w/2),sin(w/2)x,sin(w/2)y,sin(w/2)z)。
需要注意的是,對於四元數來說,如果對應的四個值都互爲相反數,可以理解爲這兩個四元數對應的旋轉相同。比方說,四元數(a,b,c,d)和四元數(-a,-b,-c,-d)對應的旋轉是相同的。
使用unity函數進行轉換的代碼如下
public Quaternion CalQuaternion(Vector3 dir)
{
Quaternion cal = new Quaternion();
Vector3 euler = Quaternion.LookRotation(dir).eulerAngles;
//歐拉角Y: cosY = z/sqrt(x^2+z^2)
float CosY = dir.z / Mathf.Sqrt(dir.x * dir.x + dir.z * dir.z);
float CosYDiv2 = Mathf.Sqrt((CosY + 1) / 2);
if (dir.x < 0) CosYDiv2 = -CosYDiv2;
float SinYDiv2 = Mathf.Sqrt((1-CosY) / 2);
//歐拉角X: cosX = sqrt((x^2+z^2)/(x^2+y^2+z^2)
float CosX = Mathf.Sqrt((dir.x * dir.x + dir.z * dir.z) / (dir.x * dir.x + dir.y * dir.y + dir.z * dir.z));
if (dir.z < 0) CosX = -CosX;
float CosXDiv2 = Mathf.Sqrt((CosX + 1) / 2);
if (dir.y > 0) CosXDiv2 = -CosXDiv2;
float SinXDiv2 = Mathf.Sqrt((1 - CosX) / 2);
//四元數w = cos(x/2)cos(y/2)
cal.w = CosXDiv2 * CosYDiv2;
//四元數x = sin(x/2)cos(y/2)
cal.x = SinXDiv2 * CosYDiv2;
//四元數y = cos(x/2)sin(y/2)
cal.y = CosXDiv2 * SinYDiv2;
//四元數z = sin(x/2)sin(y/2)
cal.z = -SinXDiv2 * SinYDiv2;
CalCosX = CosX;
CalCosY = CosY;
RightCosX = Mathf.Cos(Mathf.Deg2Rad * (Quaternion.LookRotation(dir).eulerAngles.x));
RightCosY = Mathf.Cos(Mathf.Deg2Rad * (Quaternion.LookRotation(dir).eulerAngles.y));
RightEulers = Quaternion.LookRotation(dir).eulerAngles;
return cal;
}
實際還是使用歐拉角轉四元數的方式進行的換算,旋轉次序還是z,x,y。同時還用到了三角函數轉半三角函數的公式。
需要注意的是,由於之前提到的原因,得到的四元數和unity自帶的Quaternion.LookRotation(dir)可能是相反的,實際代表的是一種旋轉。在計算中需要注意得到的三角函數的正負。