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);
}
我的对象在世界中 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);
}