使用 PyOpenGL 以正确的方式让相机偏航、俯仰和滚动?

Getting a camera to Yaw, Pitch and Roll in a proper manner with PyOpenGL?

我已经苦苦挣扎了一段时间,试图实现一个可以在任何轴上自由旋转的相机(即在增加偏航、俯仰和滚动时)。我已经设法根据当前的向前、向右和向上矢量设置相机以正确更改其位置,这些矢量通常不会搞砸(通常我的意思是当我省略滚动时)。简单的说,相机向前移动,但问题是当我尝试旋转相机时,我不知道如何正确设置。

我生成了一个相机用于此 class:

import math
import numpy


class Camera:
    def __init__(self, position=(0, 0, 0), pitch=0, yaw=0, roll=0):
        self.position = list(position)
        self.yaw = yaw
        self.pitch = pitch
        self.roll = roll
        self.direction = [0.0, 0.0, -1.0]
        self.right = [1.0, 0.0, 0.0]
        self.up = [0.0, 1.0, 0.0]

    # Calculates where each camera vector (front, right, up) is facing given the current pitch, yaw, roll.
    # The derived vectors are the camera's own coordinate system, while the pitch, yaw and roll are world-based so far.
    def cameraVectors(self):
        x = math.sin(math.radians(self.yaw))*math.cos(math.radians(self.pitch))
        y = math.sin(math.radians(self.pitch))
        z = math.cos(math.radians(self.yaw))*math.cos(math.radians(self.pitch))
        self.direction = [x, y, z]

        x = math.sin(math.radians(self.yaw + 90))*math.cos(math.radians(self.roll))
        y = math.sin(math.radians(self.roll))
        z = math.cos(math.radians(self.yaw + 90))*math.cos(math.radians(self.roll))
        self.right = [x, y, z]

        self.up = numpy.cross(self.direction, self.right)

    # Simply increases the rotation when told to. Stuff below function is irrelevant (maybe) as it works alright.
    def cameraRotate(self, rotX, rotY, rotZ):
        self.yaw += rotX
        self.pitch += rotY
        self.roll += rotZ
        self.cameraVectors()

    def cameraMoveF(self, value):
        self.position[0] += value * self.direction[0]
        self.position[1] += value * self.direction[1]
        self.position[2] += value * self.direction[2]
        self.cameraVectors()

    def cameraMoveB(self, value):
        self.position[0] -= value * self.direction[0]
        self.position[1] -= value * self.direction[1]
        self.position[2] -= value * self.direction[2]
        self.cameraVectors()

    def cameraMoveL(self, value):
        self.position[0] += value * self.right[0]
        self.position[1] += value * self.right[1]
        self.position[2] += value * self.right[2]
        self.cameraVectors()

    def cameraMoveR(self, value):
        self.position[0] -= value * self.right[0]
        self.position[1] -= value * self.right[1]
        self.position[2] -= value * self.right[2]
        self.cameraVectors()

    def cameraMoveU(self, value):
        self.position[0] += value * self.up[0]
        self.position[1] += value * self.up[1]
        self.position[2] += value * self.up[2]
        self.cameraVectors()

    def cameraMoveD(self, value):
        self.position[0] -= value * self.up[0]
        self.position[1] -= value * self.up[1]
        self.position[2] -= value * self.up[2]
        self.cameraVectors()

    def getPosition(self):
        return self.position

    def getDirection(self):
        return self.direction

    def getRight(self):
        return self.right

    def getUp(self):
        return self.up

    def getPitch(self):
        return self.pitch

    def getYaw(self):
        return self.yaw

    def getRoll(self):
        return self.roll

我使用我在每一帧创建的 ViewMatrix:

def createViewMatrix(eyePos, eyeForward, eyeUp):
    E = numpy.array(eyePos)
    F = numpy.array(eyeForward)
    U = numpy.array(eyeUp)

    F = F/numpy.linalg.norm(F)

    S = numpy.cross(F, U)
    S = S/numpy.linalg.norm(S)

    Uprim = numpy.cross(S, F)

    mat = numpy.zeros(shape=(4, 4))

    mat[0][0] = S[0]
    mat[1][0] = S[1]
    mat[2][0] = S[2]

    mat[0][1] = Uprim[0]
    mat[1][1] = Uprim[1]
    mat[2][1] = Uprim[2]

    mat[0][2] = -F[0]
    mat[1][2] = -F[1]
    mat[2][2] = -F[2]

    mat[3][0] = -numpy.dot(S, E)
    mat[3][1] = -numpy.dot(Uprim, E)
    mat[3][2] = numpy.dot(F, E)

    mat[0][3] = 0.0
    mat[1][3] = 0.0
    mat[2][3] = 0.0
    mat[3][3] = 1.0

    return mat

变换矩阵、投影和视图矩阵在渲染视图时完美无缺 - 所有对象都正确渲染,但问题是我正在努力设置相机自己的坐标系并使其滚动,俯仰和偏航根据自己的坐标系。我在代码的某处显然是错误的,但我真的不知道问题出在哪里。我放了一个简短的视频,展示了相机如何在不同的相机旋转中渲染物体(例如,当我向下看并向右转时,相机及其目标都根据世界 Y 轴旋转,而不是我想要的相机旋转当我滚动时会发生更多奇怪的事情)。轴表示为旋转以面向相机的正方形。

https://www.youtube.com/watch?v=aBaLkE1cUSo

首先我展示了偏航和俯仰的正常旋转。你可以注意到我的俯仰和偏航越多,旋转就越变成滚动(因为偏航与世界坐标系相关。当相机翻转时也会反转,很明显)。然后我在 0:48 左右显示滚动。在 1:00,我向您展示了滚动是如何混乱的,整个场景变得很奇怪。

拜托,如果有人能找到我遗漏的地方和遗漏的东西,如果你能分享你的想法,我将非常高兴!我正在拔头发,但我找不到我丢失的东西。有人提到改造相机什么的,但我真的不明白如何做这一切,我确实参考了很多资源...

提前致谢!

归根结底,我无法使用我使用的简单欧拉旋转来进行此类旋转。即使尝试以多种方式旋转向上、向右和向前矢量,最终我还是求助于四元数来实现我的目标。现在旋转就像一个魅力!