I have my objects in a world space using right-handed coordinates (x = right, y = up).
When I have to render them using SFML I'm having problems because I can't set up the View matrix in sf::View with a (y = up) matrix and then all is rendered y-flipped.
One solution I'm thinking is flipping the y-axis on every object before rendering it:
ObjectTransformMatrix * MatrixScale(1.0f,-1.0f)
But I think I will have to move the sf::View center to:
y = y - (view_size.y / 2.0)
Why sf::View is y-inverted ? Is my solution correct?
Why sf::View is y-inverted ?
Most graphics packages/libraries have their screen-space coordinate system with origin on the left-top corner, where X goes right and Y goes down. This is just a convention and SFML happens to pick this. Mind you, this isn't left or right-handed; that would depend on the third axes, if any. I'll take that the other coordinate system you're referring to is the conventional mathematical coordinate system.
flipping the y-axis on every object before rendering it
Don't do this! You've a world defined to your convenience. Why change that when you can change the camera (sf::View
) transform which will be implicitly applied to all rendered objects internally. From 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.
Essentially you would be setting the below derived matrix as the camera's transform but through the functions exposed via sf::View
.
Is my solution correct?
Partly right, you've guessed the rest. Flipping the axes is only part of the solution, you should also translate the origin to the right position. What you need is Mm→s where m is the math space and s is the screen space. To find that you need to transform the screen space coordinate system to align with the math coordinate system. Since the scales are the same in both coordinate systems, we can use the values of width W and height H (originally from the screen space) as-is.
We've this:
S--->---- W ---------+ | | v | | | | | | | | | H | | | | | ^ | | | M--->----------------+
When we do S1, −1 i.e. scale X-axis by 1 and Y-axis by −1 (flip Y), we have
^ | S--->---- W ---------+ | | | | | | | | | | | | H | | | | | ^ | | | M--->----------------+
This new system is no longer S since its Y is flipped; lets call it S'. Now we've to translate (move) its origin to reach M. Since we're transforming coordinate systems, and not points, we've to do it with respect to S', the transformed intermediate coordinate system and not S.
We do T0, -H i.e. move H units along negative Y. We will end up with
+-------- W ---------+ | | | | | | | | | | | | H | | | | | ^ | | | O--->----------------+ where both M and S are at O.
We've to concatenate S and T to get the final Mm→s. Since we're transforming coordinate systems, and not points, we've to post-multiply (assuming you're using column-vector convention).
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 |
Say we've a screen that's 5×5 (for simplicity). Transform the point (1, 1) in the world space to screen space:
| 1 0 0 | |1| |1| | 0 −1 5 | |1| = |4| | 0 0 1 | |1| |1|
(1, 4) is the point's coordinates in screen space.
If you're following row-vector convention, you've to transpose the equation, M = AB i.e. MT = BT AT. That would give us
| 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 |