使用 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,我向您展示了滚动是如何混乱的,整个场景变得很奇怪。
拜托,如果有人能找到我遗漏的地方和遗漏的东西,如果你能分享你的想法,我将非常高兴!我正在拔头发,但我找不到我丢失的东西。有人提到改造相机什么的,但我真的不明白如何做这一切,我确实参考了很多资源...
提前致谢!
归根结底,我无法使用我使用的简单欧拉旋转来进行此类旋转。即使尝试以多种方式旋转向上、向右和向前矢量,最终我还是求助于四元数来实现我的目标。现在旋转就像一个魅力!
我已经苦苦挣扎了一段时间,试图实现一个可以在任何轴上自由旋转的相机(即在增加偏航、俯仰和滚动时)。我已经设法根据当前的向前、向右和向上矢量设置相机以正确更改其位置,这些矢量通常不会搞砸(通常我的意思是当我省略滚动时)。简单的说,相机向前移动,但问题是当我尝试旋转相机时,我不知道如何正确设置。
我生成了一个相机用于此 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,我向您展示了滚动是如何混乱的,整个场景变得很奇怪。
拜托,如果有人能找到我遗漏的地方和遗漏的东西,如果你能分享你的想法,我将非常高兴!我正在拔头发,但我找不到我丢失的东西。有人提到改造相机什么的,但我真的不明白如何做这一切,我确实参考了很多资源...
提前致谢!
归根结底,我无法使用我使用的简单欧拉旋转来进行此类旋转。即使尝试以多种方式旋转向上、向右和向前矢量,最终我还是求助于四元数来实现我的目标。现在旋转就像一个魅力!