SFML::View 倒y轴是标准的吗?如何解决它?

Is SFML::View inverted-y axis standard? How to workaround it?

我的对象在世界中 space 使用右手坐标(x = 右,y = 上)。

当我必须使用 SFML 渲染它们时,我遇到了问题,因为我无法在 sf::View 中使用 (y = up) 矩阵设置视图矩阵,然后所有内容都呈现为 y 翻转.

我想的一个解决方案是在渲染之前翻转每个对象的 y 轴:

ObjectTransformMatrix * MatrixScale(1.0f,-1.0f)

但我想我必须将 sf::View 中心移动到:

y = y - (view_size.y / 2.0)

为什么 sf::View 是倒置的?我的解决方案正确吗?

Why sf::View is y-inverted ?

大多数图形 packages/libraries 的屏幕-space 坐标系的原点在左上角,X 向右,Y 向下。这只是一个惯例,SFML 恰好选择了它。请注意,这不是左撇子或右撇子;这将取决于第三轴,如果有的话。我将您所指的另一个坐标系视为传统的数学坐标系。

flipping the y-axis on every object before rendering it

不要这样做!你有一个为你方便而定义的世界。当您可以更改将在内部隐式应用于所有渲染对象的相机 (sf::View) 变换时,为什么要更改它。来自 the documentation:

sf::View defines a camera in the 2D scene.

This is a very powerful concept: you can scroll, rotate or zoom the entire scene without altering the way that your drawable objects are drawn. [...] To apply a view, you have to assign it to the render target. Then, every objects drawn in this render target will be affected by the view until you use another view.

本质上,您会将下面的派生矩阵设置为相机的变换,但要通过 sf::View.

公开的函数

Is my solution correct?

部分正确,其余部分您已经猜对了。翻转轴只是解决方案的一部分,您还应该将原点平移到正确的位置。你需要的是 Mm→s 其中 m 是数学 space 和 s是屏幕space。发现需要变换屏幕space坐标系,使其与数学坐标系对齐。由于两个坐标系中的比例相同,我们可以按原样使用宽度 W 和高度 H 的值(最初来自屏幕space)。

我们有这个:

              S--->---- W ---------+
              |                    |
              v                    |
              |                    |
              |                    |
              |                    |
              |
              |                    H
              |
              |                    |
              |                    |
              ^                    |
              |                    |
              M--->----------------+

当我们执行 S1, −1 时,即 X 轴缩放 1,Y 轴缩放 −1(翻转 Y),我们有

              ^
              |
              S--->---- W ---------+
              |                    |
              |                    |
              |                    |
              |                    |
              |                    |
              |
              |                    H
              |
              |                    |
              |                    |
              ^                    |
              |                    |
              M--->----------------+

这个新系统不再是S,因为它的Y被翻转了;让我们称之为S'。现在我们必须平移(移动)它的原点以到达 M。由于我们正在变换坐标系,而不是点,我们必须相对于 S'、变换后的中间坐标系而不是 S 来做。

我们做 T0, -​​H 即沿着负 Y 移动 H 个单位。我们最终会得到

              +-------- W ---------+
              |                    |
              |                    |
              |                    |
              |                    |
              |                    |
              |
              |                    H
              |
              |                    |
              |                    |
              ^                    |
              |                    |
              O--->----------------+

where both M and S are at O.

我们必须连接 S 和 T 以获得最终的 Mm→s。由于我们正在变换坐标系,而不是点,我们必须 post-multiply(假设您使用的是列向量约定)。

Mm→s = S1, −1 T0, -H

| 1  0  0 | | 1  0  0 |   | 1  0  0 |
| 0 −1  0 | | 0  1 −H | = | 0 −1  H |
| 0  0  1 | | 0  0  1 |   | 0  0  1 |

假设我们有一个 5×5 的屏幕(为简单起见)。将世界space中的点(1, 1)变换到屏幕space:

| 1  0  0 | |1|   |1|
| 0 −1  5 | |1| = |4|
| 0  0  1 | |1|   |1|

(1, 4) 是点在屏幕中的坐标 space.

如果您遵循行向量约定,则必须转置方程 M = AB 即 MT = BTAT。那会给我们

| 1  0  0 | | 1  0  0 |   | 1  0  0 |
| 0  1  0 | | 0 −1  0 | = | 0 −1  0 |
| 0 −H  1 | | 0  0  1 |   | 0  H  1 |

我刚刚把window高度反了过来。我想就是这样。

sf::View view = window.getDefaultView();
view.setSize(WINDOW_WIDTH, -WINDOW_HEIGHT); 
window.setView(view);

我发现最好的方法就是在渲染精灵之前和之后翻转 y 位置坐标到 window:

void draw(window)
{
    pos = sprite.getPos();
    sprite.setPos(pos.x, pos.y * -1);
    window.draw(sprite);
    sprite.setPos(pos.x, pos.y * -1);
}