我使用右手坐标(x =右,y =上)将我的物体放在世界空间中。
当我必须使用SFML渲染它们时我遇到了问题,因为我无法在sf :: View中使用(y = up)矩阵设置View矩阵,然后全部渲染为y-翻转。
我想到的一个解决方案是在渲染之前在每个对象上翻转y轴:
ObjectTransformMatrix * MatrixScale(1.0f,-1.0f)
但我认为我必须将sf :: View中心移至:
y = y - (view_size.y / 2.0)
为什么sf :: View是y-inverted?我的解决方案是否正确
答案 0 :(得分:5)
为什么sf :: View是y-inverted?
大多数图形包/库的屏幕空间坐标系都是左上角的原点,其中X向右,Y向下。这只是一个惯例,SFML恰好选择了这个。请注意,这不是左手或右手;这将取决于第三轴,如果有的话。我会认为你所指的另一个坐标系是传统的数学坐标系。
在渲染之前在每个对象上翻转y轴
不要这样做!你的世界是为了方便而定义的。当您可以更改相机(sf::View
)变换时,为什么要更改它,该变换将在内部隐式应用于所有渲染对象。来自the documentation:
sf :: View定义2D场景中的摄像头。
这是一个非常强大的概念:您可以滚动,旋转或缩放整个场景,而无需改变绘制可绘制对象的方式。 [...] 要应用视图,您必须将其分配给渲染目标。然后,在此渲染目标中绘制的每个对象都将受到视图的影响,直到您使用另一个视图。
基本上你会将下面派生的矩阵设置为相机的变换,但是通过sf::View
曝光的功能。
我的解决方案是否正确?
部分正确,你已经猜到了其余部分。翻转轴只是解决方案的一部分,您还应将原点转换到正确的位置。你需要的是M m→s ,其中 m 是数学空间, s 是屏幕空间。要找到您需要转换屏幕空间坐标系以与数学坐标系对齐。由于两个坐标系中的比例相同,我们可以按原样使用宽度W和高度H(最初来自屏幕空间)的值。
我们有这个:
S--->---- W ---------+ | | v | | | | | | | | | H | | | | | ^ | | | M--->----------------+
当我们做S 1,-1 ,即将X轴缩放1并且将Y轴缩放-1(翻转Y)时,我们有
^ | S--->---- W ---------+ | | | | | | | | | | | | H | | | | | ^ | | | M--->----------------+
这个新系统不再是S,因为Y被翻转了;我们称之为S'。现在我们要将它的原点转换(移动)到达M.因为我们要改变坐标系而不是点,我们要对S'进行转换,转换的中间坐标系而不是S.
我们做T 0,-H ,即沿负Y移动H单位。我们最终将
+-------- W ---------+ | | | | | | | | | | | | H | | | | | ^ | | | O--->----------------+ where both M and S are at O.
我们要连接S和T以获得最终的M m→s 。由于我们正在变换坐标系,而不是点,我们要进行后乘(假设您使用的是列向量约定)。
M m→s = S 1,-1 T 0,-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(为简单起见)。将世界空间中的点(1,1)转换为屏幕空间:
| 1 0 0 | |1| |1| | 0 −1 5 | |1| = |4| | 0 0 1 | |1| |1|
(1,4)是屏幕空间中的点坐标。
如果您遵循行向量约定,则必须转换等式,M = AB,即M T = B T A T < / SUP>。这会给我们
| 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 |
答案 1 :(得分:2)
我只是颠倒了窗户高度。我想就是这样。
sf::View view = window.getDefaultView();
view.setSize(WINDOW_WIDTH, -WINDOW_HEIGHT);
window.setView(view);
答案 2 :(得分:0)
我发现最好的方法就是简单地在向窗口渲染精灵之前和之后翻转y位置坐标:
void draw(window)
{
pos = sprite.getPos();
sprite.setPos(pos.x, pos.y * -1);
window.draw(sprite);
sprite.setPos(pos.x, pos.y * -1);
}