如果我忽略四元数代数的肮脏细节,我想我理解旋转和平移变换背后的数学。但仍然无法理解我做错了什么。
为什么我的相机一直在转动!? :)
更具体一点,我应该如何根据相机的方向(旋转矩阵)计算相机 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
行为错误但旋转矩阵正确
这就是我得到的:
现在,令人困惑的是,如果我将上述方法更改为:
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 相机一样正确运行,但旋转矩阵似乎不正确。
请问有人能解释一下吗? 提前致谢。
最佳答案
在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/