Skip to main content
 首页 » 编程设计

python之为什么我的 FPS 相机在滚动在 Python 中使用欧拉角(不是四元数)实现

2025年05月04日20powertoolsteam

我正在尝试生成一个像 FPS 相机一样运行的 View 矩阵,但我却开始滚动。分享我的 python 代码以防有人发现问题所在:

import numpy as np 
 
class Camera(): 
    def __init__(self): 
        self.sens = np.array([0.002, 0.002])  # mouse sensitivity (x, y) 
        self.angpos = np.array([0.0, 0.0])  # (pitch, yaw) 
 
    def mouse_move(self, pos, rel): 
        self.angpos = rel[::-1]*self.sens  # mouse relative motion (delta-x, delta-y) 
        ya = self.angpos[1] 
        yrot = np.array([ 
            [ np.cos(ya),  0.0,    np.sin(ya),   0.0], 
            [ 0.0,         1.0,    0.0,          0.0], 
            [-np.sin(ya),  0.0,    np.cos(ya),   0.0], 
            [0.0,          0.0,    0.0,          1.0] 
        ]) 
 
        xa = self.angpos[0] 
        xrot = np.array([ 
            [ 1.0,    0.0,          0.0,          0.0 ], 
            [ 0.0,    np.cos(xa),  -np.sin(xa),   0.0 ], 
            [ 0.0,    np.sin(xa),   np.cos(xa),   0.0 ], 
            [ 0.0,    0.0,          0.0,          1.0 ], 
        ]) 
 
        return yrot @ xrot  # view matrix 
 
 
# this is the callback for mouse movement. `pos` is absolute mouse  
# position in the screen and `rel` is the position relative to previous call 
# def mouseMotionEvent(self, pos, rel): 
#     view = self.cam.mouse_move(pos, rel)  # self.cam is an instance of Camera 
#     self.view = view @ self.view 
#     return True 

遵循我得到的行为的 gif:

请您参考如下方法:

抽象地说,您的问题是由俯仰和偏航引起的旋转在合成下不闭合。

更具体地说:想象一下控制第一人称相机。往下看,然后向左和向右转。您的视线移动方式与您在直视前方时转弯的方式截然不同。然而,您的计算就像相机的行为一样。

每个滴答声,你从右边乘以 view 与偏航矩阵,然后是俯仰矩阵。这意味着一段时间后您的 View 矩阵将是许多俯仰和偏航矩阵的交替产物。但是,俯仰和偏航矩阵不会交换。你真正想要的是让所有的俯仰矩阵都在所有偏航矩阵的左边(或者在右边,这取决于你是让你的 View 矩阵从左边还是右边操作,以及你的矩阵是否代表 view-to -全局或全局到 View 转换)。

因此,快速解决此问题的方法是编写 view = yrot @view @xrot。这样,你所有的 y 旋转结束到你的 x 旋转的左边,一切都会好起来的。好吧,至少有一段时间,但是你的 View 矩阵最终可能会累积舍入误差,并且 View 可能会滚动或倾斜或更糟。

我的建议是您根本不要重用 View 矩阵。相反,只需存储玩家当前的俯仰和偏航,根据鼠标移动对其进行更新,然后每次都直接从俯仰和偏航重新计算 View 矩阵。通过这种方式,您还可以以其他方式使用俯仰和偏航(例如,您需要将俯仰限制在一定范围内以防止玩家倒立或翻筋斗),并且您也不会在矩阵中累积错误。