SFML community forums

Help => Graphics => Topic started by: Elias Daler on May 10, 2019, 12:01:11 pm

Title: [Solved] How do I combine two view transforms into one view?
Post by: Elias Daler on May 10, 2019, 12:01:11 pm
In my game, I render what game camera sees onto render texture and then I scale this render texture and finally draw it into window (for letterboxing).
So, I have two views for this: one for game camera and one for properly scaling and drawing the texture.

Now, I want to draw something on top of the texture by combining both camera and texture transforms. How can I do this?
Title: Re: How do I combine two view transforms into one view?
Post by: Laurent on May 10, 2019, 12:31:59 pm
I'm not sure what "combining both camera and texture transforms" means, in terms of coordinate system. If you want to draw in window coordinates (like a GUI), then just use the default view for drawing.

And since you talk about combining transforms, have you tried to actually combine those transforms (T = T1 * T2)? What happens then?
Title: Re: How do I combine two view transforms into one view?
Post by: Hapax on May 10, 2019, 01:19:37 pm
Do you want to draw something at the positions that are on the game view but on the main window, effectively "tracking" the point?
If so, is there a reason you can't draw it on the render window using the game view?
Otherwise, you can get the transforms from the views using getTransform() (https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1View.php#a13da786526688bf99dc2cd3e658a3c2a).
If you need to use the other view, you'll probably need to combine the game's transform with the other view's inverse transform and then use the other view to draw.
Title: Re: How do I combine two view transforms into one view?
Post by: Elias Daler on May 10, 2019, 01:42:01 pm
The reason I want to do it are the follows:
1) The "screen" render texture is only 160x144 - internal resolution of the game
2) I want to draw text and other debug stuff on top of game objects properly positioned, but in higher resolution (that's why I don't want to draw on "screen").

As this "screen" gets transformed by window for letterboxing, I can't just use camera's transform to draw this text, I need to combine both "camera" and "screen" transforms.

I've tried to multiplying the transforms, yes, but there are two problems:
1) In docs, it's said that getting transform from sf::View is for internal use only
2) I can't create a view from a transform. I guess I can to it by getting center/size of each View and somehow combining them, but I can't figure out the simple way to do it (the second view has Viewport set which makes the problem trickier).
Title: Re: How do I combine two view transforms into one view?
Post by: Laurent on May 10, 2019, 02:04:55 pm
Quote
1) In docs, it's said that getting transform from sf::View is for internal use only
I can imagine a few use cases for calling this function in user code, just ignore this old comment.

Quote
2) I can't create a view from a transform. I guess I can to it by getting center/size of each View and somehow combining them, but I can't figure out the simple way to do it (the second view has Viewport set which makes the problem trickier).
Indeed, you can't create a view from a transform. You can however pass that transform to the render-states when you draw your objects (if there are not so many, or if your code design allows to do this easily).
Or you can use a vertex shader: upload the matrix as a uniform and apply it to the incoming vertices.

Using the render-states transform would be the easiest solution to quickly test your computed matrix and making sure that it produces the expected results.
Title: Re: How do I combine two view transforms into one view?
Post by: Elias Daler on May 10, 2019, 02:40:13 pm
Yeah, this seems like a nice solution.
However, I can't get it to work.

If I have a view, does this mean that I need to do this, to draw something as if it was drawn with a "view"?

Code: [Select]
sf::RenderStates states;
states.transform = target.getView().getInverseTransform() * view.getTransform();
target.draw(something, states); // here, "target" has default view


However, if I add the second view into equation, I can't get it to work for some reason.

UPD: ah, I get it. View transform doesn't contain Viewport in it! I wonder how I can get it into the equation...
Title: Re: How do I combine two view transforms into one view?
Post by: Laurent on May 10, 2019, 03:42:03 pm
Quote
If I have a view, does this mean that I need to do this, to draw something as if it was drawn with a "view"?
Yes. Note that you can write it in a shorter way, using one of the implicit constructors of sf::RenderState:
target.draw(something, the_transform);

Quote
View transform doesn't contain Viewport in it! I wonder how I can get it into the equation...
Indeed, the viewport is a different thing and is not part of the transform. You can simply give the same viewport to the view that you're using to draw your stuff.
Title: Re: How do I combine two view transforms into one view?
Post by: Elias Daler on May 10, 2019, 04:33:51 pm
Indeed, the viewport is a different thing and is not part of the transform. You can simply give the same viewport to the view that you're using to draw your stuff.
Thanks! That was the missing part of the piece! In total, here's what I did:

target.setView(window.getLetterboxedView());
states.transform *= target.getView().getInverseTransform() * cameraView.getTransform();
 

And here's the result:
(https://i.imgur.com/ZJR8EZb.png)

UPD:
After some thinking, I can just do this, and it works too (because only viewport matters in letterbox view)!

auto view = cameraView;
cameraView.setViewport(window.getLetterboxedView().getViewport());
target.setView(view);
/* draw */