为什么我的FPS相机一劳永逸?

时间:2019-03-11 16:21:46

标签: python opengl graphics rotation quaternions

如果我忽略四元数代数的肮脏细节,我想我理解旋转和平移变换背后的数学原理。但是仍然无法理解我在做什么。

为什么我的相机一劳永逸!! :)

更具体一点,我应该如何从其方向(旋转矩阵)计算摄像机视图矩阵?

我正在用Python编写一个具有场景Node类的简约3d引擎,该类处理3d对象的旋转和平移机制。它具有公开“旋转”和“平移”矩阵以及“模型”矩阵的方法。

还有一个CameraNode类,它是Node的子类,它也公开了View和Projection矩阵(投影不是问题,因此我们可以忽略它)。

模型矩阵

为了正确应用转换,我将矩阵相乘如下:

PxVxM x v

即首先是模型,然后是视图,最后是投影。

其中M是通过先应用旋转然后进行平移来计算的:

M = TxR

代码如下:

class Node():
    # ...

    def model_mat(self):
        return self.translation_mat() @ self.rotation_mat() @ self.scaling_mat()

    def translation_mat(self):
        translation = np.eye(4, dtype=np.float32)
        translation[:-1, -1] = self.position  # self.position is an ndarray
        return translation

    def rotation_mat(self):
        rotation = np.eye(4, dtype=np.float32)
        rotation[:-1, :-1] = qua.as_rotation_matrix(self.orientation)  # self.orientation is a quaternion object
        return rotation

查看矩阵

我正在根据相机的位置和方向来计算View矩阵,如下所示:

class CameraNode(Node):
    # ...

    def view_mat(self):
        trans = self.translation_mat()
        rot = self.rotation_mat()
        trans[:-1, 3] = -trans[:-1, 3]  # <-- efficient matrix inversion
        rot = rot.T                     # <-- efficient matrix inversion
        self.view = rot @ trans
        return self.view

如果我错了,请纠正我。由于我们只能移动和旋转世界几何图形(与移动/旋转摄影机相反),因此我必须以相反的顺序乘以矩阵,并且还要乘以相反的变换(实际上是每个变换矩阵的逆矩阵)。换句话说,将相机移离物体也可以看作是将物体移离相机。

旋转输入

现在,这是我将键盘输入转换为相机旋转的方法。当我按向右/向左/向上/向下箭头键时,我会以一定的俯仰/偏航角调用以下方法:

def rotate_in_xx(self, pitch):
    rot = qua.from_rotation_vector((pitch, 0.0, 0.0))
    self.orientation *= rot

def rotate_in_yy(self, yaw):
    rot = qua.from_rotation_vector((0.0, yaw, 0.0))
    self.orientation *= rot

行为错误,但旋转矩阵正确

这就是我得到的:

behaves wrong but rot matrix is correct

behaves wrong but rot matrix is correct

现在,令人困惑的是,如果我将上述方法更改为:

class CameraNode(Node):

    def view_mat(self):
        view = np.eye(4)
        trans = self.translation_mat()
        rot = self.rotation_mat()
        trans[:-1, 3] = -trans[:-1, 3]
        # rot = rot.T                     # <-- COMMENTED OUT
        self.view = rot @ trans
        return self.view

    def rotate_in_xx(self, pitch):
        rot = qua.from_rotation_vector((pitch, 0.0, 0.0))
        self.orientation = rot * self.orientation  # <-- CHANGE

我可以使相机像FPS相机一样正常工作,但是旋转矩阵似乎不正确。

behaves well but rot matrix is wrong

enter image description here

请有人能给我一些启示吗? 预先感谢。

1 个答案:

答案 0 :(得分:1)

在您问题的my last answer中,我告诉您了为什么重新使用视图矩阵不是一个好主意,因为俯仰和偏航不会上下班。您现在正在使用四元数,但同样,变桨和偏航四元数不会上下班。只需存储俯仰值和偏航值,然后重新计算 在需要时从俯仰和偏航确定方向。

def rotate_in_xx(self, pitch):
    self.pitch += pitch

def rotate_in_yy(self, yaw):
    self.yaw += yaw

def get_orientation():
    pitch_rotation = qua.from_rotation_vector((self.pitch, 0.0, 0.0))
    yaw_rotation = qua.from_rotation_vector((0.0, self.yaw, 0.0))
    return yaw_rotation * pitch_rotation

关于上一个屏幕快照中相机旋转矩阵和对象旋转矩阵的不同之处的注释:对象旋转和平移矩阵(以及模型矩阵)描述了从对象坐标世界坐标,而视图矩阵描述了从世界坐标相机坐标的转换。

因此,为了使三脚架相对于视口轴对齐显示,视图旋转矩阵必须是模型旋转矩阵的