python - 为什么我的 FPS 相机一劳永逸地滚动?

标签 python opengl graphics rotation quaternions

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

为什么我的相机一直在转动!? :)

更具体一点,我应该如何根据相机的方向(旋转矩阵)计算相机 View 矩阵?

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

还有一个CameraNode类,它是Node的一个子类,同样暴露了View和Projection矩阵(投影不是问题,所以我们可以忽略它)。

模型矩阵

为了正确应用变换,我按如下方式乘以矩阵:

PxVxM x v

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

其中 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

请问有人能解释一下吗? 提前致谢。

最佳答案

my last answer对于你的问题,我告诉过你为什么重用你的 View 矩阵不是一个好主意,因为俯仰和偏航不通勤。您现在正在使用四元数,但同样,俯仰和偏航四元数不会交换。只需存储俯仰值和偏航值,然后重新计算 随时随地从俯仰和偏航方向。

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

请注意,在您上一个屏幕截图中,相机旋转矩阵和对象旋转矩阵如何不同:对象旋转和平移矩阵(与模型矩阵一起)描述了从对象坐标世界坐标,而 View 矩阵描述了从世界坐标相机坐标的转换。

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

关于python - 为什么我的 FPS 相机一劳永逸地滚动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55106226/

相关文章:

javascript - 如何使用 JS 获取 div 元素内的值

python - MS SQL 数据库到 SAS

python - 如何根据分类列对 pandas 数据框进行洗牌

c++ - 使用 openGL 缩放和移动 3d 对象

iphone - 如何在 NSMutableArray 中存储 CGGradientRef

c++ - 来自文件错误的 Win32 LoadImage()

python - 使用 RGB 数据将输入数据剪切到 imshow 的有效范围([0..1] 表示 float 或 [0..255] 表示整数)

python - 基本的 openGL、顶点缓冲区和 pyglet

c++ - 文本不会在屏幕上输出 C++/OpenGL

javascript - 在 Canvas 上画出三 Angular 形的 Angular 标记