【发布时间】:2019-03-11 16:21:46
【问题描述】:
如果我忽略四元数代数的肮脏细节,我想我理解旋转和平移变换背后的数学。但仍然无法理解我做错了什么。
为什么我的相机一劳永逸!? :)
更具体地说,我应该如何根据相机的方向(旋转矩阵)计算相机视图矩阵?
我正在用 Python 编写一个简约的 3d 引擎,其中包含一个场景节点类,用于处理 3d 对象的旋转和平移机制。它具有公开旋转和平移矩阵以及模型矩阵的方法。
还有一个 CameraNode 类,一个 Node 的子类,它也暴露了 View 和 Projection 矩阵(投影不是问题,所以我们可以忽略它)。
模型矩阵
为了正确应用转换,我将矩阵相乘如下:
PxVxM x v
即首先是模型,然后是视图,最后是投影。
其中 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 相机一样正常工作,但旋转矩阵似乎不正确。
请有人能解释一下吗? 提前致谢。
【问题讨论】:
-
在你的最后一个例子中,你只处理音高,如果你在第一个例子中只保留音高,你有同样的结果吗?我不认为你想以你正在做的方式链接你的旋转(俯仰然后偏航)玩ctralie.com/Teaching/COMPSCI290/Materials/EulerAnglesViz。那你可能想看看弧线球
-
@Draykoon,感谢您的评论。如果您的建议是:“而不是将
self.orientation = rot * self.orientation设置在def rotate_in_xx(self, pitch)内部self.orientation = rot * self.orientation内部def rotate_in_yy(self, yaw)”那么我向您脱帽致敬。谢谢,这解决了我的问题:))) -
但是我不完全确定我理解为什么这能解决问题。我相信一旦我添加更多复杂性,这个问题或类似问题最终会再次困扰我,例如添加我现在还没有真正考虑过的子节点。
-
This answer 可能会帮助您理解问题。
-
所以现在你只处理偏航,对吧?你可能想将你的俯仰和偏航存储在 2 个单独的变量上并设置
self.orientation = quat.fromEuler(m_pitch, m_yaw, 0.0f) * m_initialForyardVector你可能不想做一些“* =”因为在下一帧你的新偏航会影响前滚等......跨度>
标签: python opengl graphics rotation quaternions