近日开发的一些功能,需要开发独立于Unity的一些旋转算法,其中就需要一个Unity中四元数的LookRotation方法的平替。
矩阵的知识不用很快就忘记了,而今天有幸找到了一篇讲述OpenGL中的LookAt方法的文章,并记录在此基础上开发平替版LookRotation的思路,文章路径:Breakdown of the LookAt function in OpenGL | Geert Arien。
文章中的LookAt源码,获得的其实是视图矩阵的逆矩阵,为的是能够将视图内的坐标转换到世界坐标。而我们的诉求,其实就是当某个实体朝向一个给定的方向向量时,能够获取到该实体的旋转矩阵,有了旋转矩阵再获取四元数也就是一个公式的事情了。
所以,文章中讲述的线性变换内容并不是我们重点关注的,需要关注的是旋转部分。
旋转部分,因旋转矩阵与矩阵的逆矩阵的数值是一致的,所以依据方向向量、给定的向上的向量,就可以以此求出:
- 旋转后的z轴向量(即给定的方向向量)
- z轴向量与给定的向上的向量,叉乘可以求出旋转后的x轴向量
- 通过前面得到的旋转后的x、z轴向量,叉乘得出y轴向量
需要说明的是,此处的计算会因左手坐标系与右手坐标系的不同而有细节上的差别,一定要根据自身诉求选择计算公式。文章里是以右手坐标系进行计算的,而我们的需求则是在左手坐标系下,所以向量的求解会有很大不同。我的开发工作就是因为在旋转矩阵、左手坐标系这里犯了糊涂,导致在这里兜兜转转很久。
下面就贴个源码:
// 创建基于左手坐标系的,朝向目标的旋转矩阵
public static Matrix3x3 CreateLookAt(ref Vector3 forward, ref Vector3 up)
{
Vector3 zaxis = Vector3.Normalize(forward);
Vector3 xaxis = Vector3.Normalize(Vector3.Cross(up, zaxis));
Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
return new Matrix3x3(
xaxis.X, xaxis.Y, xaxis.Z,
yaxis.X, yaxis.Y, yaxis.Z,
zaxis.X, zaxis.Y, zaxis.Z
);
}