Why is my FPS Camera rolling? Using euler angles (not quaternions) Implementation in Python

为君一笑 提交于 2019-12-24 10:24:15

问题


I am trying to generate a view matrix that would behave as an FPS camera, but instead I am getting roll. Sharing my python code in case someone can spot what the problem is:

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

Follows a gif of the behavior I am getting:


回答1:


Abstractly, your problem is that rotations induced by pitch and yaw are not closed under composition.

More concretely: Imagine controlling a first-person camera. Look down, then turn to the left and the right. Your view will move in a very different way than if you were to turn while looking straight ahead. Your calculations, however, act like the camera will behave equally.

Each tick, you multiply view from the right with a yaw matrix, then a pitch matrix. This means that after a while your view matrix will be an alternating product of a lot of pitch and yaw matrices. However, pitch and yaw matrices do not commute. What you actually want is to have all the pitch matrices to the left of all the yaw matrices (or to the right, depending on whether you let your view matrix operate from the left or the right, and on whether your matrix represents view-to-global or global-to-view transform).

So a quick fix to this would be to write view = yrot @ view @ xrot. That way, all your y rotations end up to the left of your x rotations, and everything will be fine. Well, at least for a while, but then your view matrix may end up accumulating rounding errors, and the view may become rolled or skewed or worse.

What I recommend is that you don't reuse the view matrix at all. Instead, just store the player's current pitch and yaw, updating it on mouse motion, and then recalculate the view matrix directly from pitch and yaw every time. This way you can also use pitch and yaw in other ways (for example you'll want to clamp pitch to a certain range to prevent your player from doing handstands or somersaults), and you also won't accumulate errors in your matrix.



来源:https://stackoverflow.com/questions/54886220/why-is-my-fps-camera-rolling-using-euler-angles-not-quaternions-implementatio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!