【问题标题】:Calculating modelview matrix for 2D camera using Eigen使用 Eigen 计算 2D 相机的模型视图矩阵
【发布时间】:2012-05-26 07:10:20
【问题描述】:

我正在尝试计算我的 2D 相机的模型视图矩阵,但我无法正确计算公式。我使用 Affine3f 变换类,因此矩阵与 OpenGL 兼容。这是我通过反复试验得到的最接近的。这段代码可以旋转和缩放相机,但是如果我同时应用平移和旋转,相机的运动就会变得混乱:相机以旋转的方式移动,这不是我想要的。 (这可能是因为我首先应用旋转矩阵然后平移)

Eigen::Affine3f modelview;
modelview.setIdentity();
modelview.translate(Eigen::Vector3f(camera_offset_x, camera_offset_y, 0.0f));
modelview.scale(Eigen::Vector3f(camera_zoom_x, camera_zoom_y, 0.0f));
modelview.rotate(Eigen::AngleAxisf(camera_angle, Eigen::Vector3f::UnitZ()));
modelview.translate(Eigen::Vector3f(camera_x, camera_y, 0.0f));
[loadmatrix_to_gl]

我想要的是相机将围绕屏幕空间中的偏移位置旋转和缩放 {(0,0) 在这种情况下是屏幕的中间},然后沿着世界空间中的全局 xy 轴定位 {(0,0 ) 也初始在屏幕中间} 到最终位置。我该怎么做?

请注意,我还设置了一个正交投影矩阵,这可能会影响这个问题。

【问题讨论】:

    标签: math opengl matrix camera eigen


    【解决方案1】:

    如果您想要使用 OpenGL 在 XY 平面上渲染的 2D 图像,(1) 围绕点 P 逆时针旋转 a strong>,(2)S 缩放,然后 (3) 平移以使 C 处的像素 (在新缩放和旋转的图像中)位于原点,您将使用此转换:

    1. -P 平移(这会将 P 处的像素移动到原点)
    2. a 旋转
    3. P 翻译(这会将原点移回原来的位置)
    4. S 缩放(如果您之前这样做,您的轮播会搞砸)
    5. -C翻译

    如果我们在原点渲染 2D 图像,您还需要通过沿负 z 轴平移某个值来结束才能看到它。

    通常,您只需使用 OpenGL 基础知识(glTranslatefglScalefglRotatef 等)即可。你会按照我列出的相反顺序来做。既然你想使用glLoadMatrix,你会按照我描述的Eigen的顺序做事。重要的是要记住 OpenGL 需要一个 Column Major 矩阵(但这似乎是 Eigen 的默认值;所以这可能不是问题)。

    【讨论】:

    • 谢谢,现在看来效果更好了。然而,相机并没有按照我预期的方式移动:增加 x 坐标也会影响 y 坐标,因此相机沿着旋转的 xy 轴而不是未旋转的 xy 轴移动。这是我的问题的第二部分,让相机按我的意愿移动。我希望相机仅围绕点旋转和缩放,然后以应用的旋转不会影响此平移的方式将相机移动到其位置。 PS:我将尽可能避免使用固定管道的东西,因此更改为 GL 3.0 + 着色器和更新的着色器会很轻松。
    • @JATothrim 我看了一眼 Eigen 规范。它表示您正在使用的转换应用于矩阵的右侧。我期待它们被应用在左边。由于它们应用在右侧,因此您需要以相反的顺序应用它们。或者,您可以使用“prerotate”和“pretranslate”。
    • 它是如此接近但并不完全。相机现在围绕点旋转和缩放,如果没有旋转,它可以正常平移。旋转会扰乱平移(反之亦然),并且相机不会像我一样移动。旋转 90 度,y 轴在相机运动中变成 x 轴!如何防止这种情况发生?
    • 我想我终于解决了这个移动问题。错误是我将模型视图重置为识别每一帧,即使相对于当前位置移动相机也是如此。因此,从模型视图中提取 X 向量然后朝那个方向平移是行不通的!我现在觉得自己好傻。 C:教训:可以无休止地链接转换而无需返回单位矩阵。
    【解决方案2】:

    JCooper 很好地解释了构建初始矩阵的步骤。

    但是我最终以不同的方式解决了这个问题。当时对我来说几乎没有什么额外的事情和步骤是不明显的。请参阅 JCooper 答案的 cmets。首先是实现所有的矩阵运算都是相对的

    因此如果你想用绝对xy轴来定位或移动相机,你必须首先分解矩阵以提取其在轴不变的情况下的绝对位置。然后通过新旧位置的差异来平移矩阵。

    这是使用 Eigen 执行此操作的方法:

    首先计算 Affine2f 矩阵 cmat 标量行列式 D。使用 Eigen,这是使用 D = cmat.linear().determinant(); 完成的。接下来使用 D.matrev = (RS.array() / (1.0f / determ)).matrix()); 计算当前旋转+缩放矩阵 R 的“反向”矩阵 matrev,其中 RS 为 cmat.matrix().topLeftCorner(2,2) 绝对摄像机位置 P 由 P = invmat * -C 给出,其中 C 为 cmat.matrix().col(2).head<2>()

    现在我们可以沿绝对轴重新定位相机并保持旋转+缩放相同:V = RS * (T - P) 其中 RS 与之前相同,T 是新位置 vec,P 是分解后的位置向量 cmat然后简单翻译成V来移动摄像头:cmat.pretranslate(V)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多