Lookat矩阵
在三维游戏引擎中,需要摄像机看向某个点,或者需要物体看向某个点,此时需要对物体的变换,以调整到我们需要的姿态。以Unity为例,Unity的坐标系是左手系,朝上的轴是y轴(up,绿色),朝前的轴是z轴(foward,蓝色),朝右的轴是x轴(right,红色)。现在我们想让foward看像某个点,需要对物体进行位姿的变换,那应该怎么做呢?
我们需要提供两个变量,target目标点,up可以理解为世界坐标下的朝上的方向,一般为(0,1,0)
- foward:用target - position并归一化。
- right:用 up 和求得的 foward 叉乘,cross(up,foward)
- up:用求得的 foward 和 求得的 right 叉乘,cross(foward, right)
为了验证正确性,用自己实现的函数和Unity提供的Lookat函数比较。
注意:这里为了方便,认为物体的局部坐标就是世界坐标(物体没有父节点),没有考虑缩放,认为缩放系数都为1.
//物体的位置, 目标点,朝上的方向
Matrix4x4 m_lookat(Vector3 pos,Vector3 target, Vector3 up)
{
Vector3 foward = (target - pos).normalized;
//注意叉乘的顺序,左手系满足左手定理,来判断向量的朝向
Vector3 right = Vector3.Cross(up, foward).normalized;
Vector3 newUp = Vector3.Cross(foward, right).normalized;
Matrix4x4 lookat = Matrix4x4.identity;
//将结果拷贝的新的矩阵上
lookat.SetColumn(0, new Vector4(right.x,right.y, right.z,0));
lookat.SetColumn(1, new Vector4(newUp.x, newUp.y, newUp.z, 0));
lookat.SetColumn(2, new Vector4(foward.x, foward.y, foward.z, 0));
lookat.SetColumn(3, new Vector4(pos.x, pos.y, pos.z, 1));
return lookat;
}
可以获取unity的物体的transofrm的localToWorldMatrix,得到物体的世界矩阵,因为物体没有父节点,所以local和world相等。然后再利用自定义的函数手动计算lookat矩阵,判断是否相等,结果证明相等(在无缩放和父节点的前提下)。