Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Updating Only Portion of Rendering Region  (Read 4828 times)

0 Members and 1 Guest are viewing this topic.

JayhawkZombie

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Updating Only Portion of Rendering Region
« on: April 06, 2016, 04:46:09 pm »
Hello, All!

No bugs/major problems to report, but I'm curious as to how I'd accomplish a certain task.

I have a project in which an element on the screen is only rendered in a certain region of the screen, regardless of whether or not the element itself covers more than just that region (anything outside of the region isn't displayed).

It took a while to try to find out how to do this, but it works, and this is the code that I have to do it in the main rendering thread:

        sf::View ElementView;
        sf::FloatRect ElementRect;
        sf::FloatRect Panel;
        for (auto & element : m_elements)
        {              
                ElementRect = sf::FloatRect(element->getPosition().x, element->getPosition().y, element->getSize().x, element->getSize().y);
                Panel = sf::FloatRect(ElementRect.left / m_windowSize.x, ElementRect.top / m_windowSize.y, ElementRect.width / m_windowSize.x, ElementRect.height / m_windowSize.y);
                ElementView.reset(ElementRect);
                ElementView.setViewport(Panel);
                wnd->setView(ElementView);
                element->render(wnd, state);
        }
 
The renderWindow's view is then set back to cover the whole screen (or windowed size) and displayed.

This is an example of what it looks like:(I'm sorry, I don't know to properly use the image tags)


A couple questions I have about this:
  • Is this what the people here would say is a good way to accomplish this clipping that I want?
            - If not, I'd love to hear suggestions! Any and all advice/feedback is appreciated!
  • Is it safe to set the window view to just the view to only render in this element's rendering region, clear it, and then render, then reset the renderWindow's view back to normal after doing this and then displaying?  I seem to have a gap in my understanding of the API.
Any element may, without notice, update itself and need to be rendered again. Currently, the application does not render any object unless it absolutely has to. 
For instance, just sitting there with the mouse just sitting there (no animations or anything) will cause no rendering to be done - it will wait for an event (actually wait by sleeping the event thread).
However, if a single element is updated, then I don't see any reason to wake up my main render thread and waste CPU time by rendering everything over again.
I could very well just be over-complicating this (I have a horrible habit of doing that).

I apologize if this has been asked before, but it seems questions regarding clipping and redrawing aren't the easiest to find/find answers to.  I do know (some) raw OpenGL, but I love the usage of SFML and I really want to avoid jumping down into OpenGL (except shaders,  I love making/playing with shaders).

If my method of clipping isn't right or should be done in a different way, please feel free to say so.  I'm always learning, and I'd rather learn that I was doing it wrong and then learn how to do it right  :)

Thank you!
« Last Edit: April 06, 2016, 04:50:04 pm by JayhawkZombie »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Updating Only Portion of Rendering Region
« Reply #1 on: April 06, 2016, 09:30:11 pm »
Quote
Is this what the people here would say is a good way to accomplish this clipping that I want?

Can't speak for everyone, but this is definitely the simplest way I'm aware of.

Quote
Is it safe to set the window view to just the view to only render in this element's rendering region, clear it, and then render, then reset the renderWindow's view back to normal after doing this and then displaying?  I seem to have a gap in my understanding of the API.

Any element may, without notice, update itself and need to be rendered again. Currently, the application does not render any object unless it absolutely has to. 
For instance, just sitting there with the mouse just sitting there (no animations or anything) will cause no rendering to be done - it will wait for an event (actually wait by sleeping the event thread).
However, if a single element is updated, then I don't see any reason to wake up my main render thread and waste CPU time by rendering everything over again.
I could very well just be over-complicating this (I have a horrible habit of doing that).

It's hard to tell exactly what you mean here and thus whether you're doing anything wrong. So to save time, I'll quote the big red box from the official drawing tutorial:

Quote
This clear/draw/display cycle is the only good way to draw things. Don't try other strategies, such as keeping pixels from the previous frame, "erasing" pixels, or drawing once and calling display multiple times. You'll get strange results due to double-buffering.
Modern graphics hardware and APIs are really made for repeated clear/draw/display cycles where everything is completely refreshed at each iteration of the main loop. Don't be scared to draw 1000 sprites 60 times per second, you're far below the millions of triangles that your computer can handle.

It is completely okay to lower your framerate or even stop rendering entirely if you know you don't need as many frames anymore. But when you do draw a new frame, you absolutely must do the clear/draw/display thing, and every single object that you want to be visible in that frame must go through one of the draw() calls. But it is also completely okay to "cull" or not draw() objects which you know aren't going to be visible anyway. Changing the window's view just to draw() a single object differently is also completely fine, as long as this one object really is unique in some way that prevents it from being drawn alongside all the others.

I think that covers everything you might have been doing wrong or might have been worried about potentially doing wrong.

JayhawkZombie

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Updating Only Portion of Rendering Region
« Reply #2 on: April 08, 2016, 03:27:18 pm »
That definitely addresses it! My apologies for a delayed response.

I was mainly concerned that he method for clipping that I used wasn't ideal.
I'm still not sure how to accomplish clipping that isn't rectangular (like a circular drawing region). It doesn't look like SFML currently has this support, so diving down into raw OpenGL looks to be my best bet there.

Currently I'm just redrawing everything that needs to be seen every time something is updated, but using the above method to clip objects that might be trying to render outside of their defined region.

I've seen that the SFML team was at one point considering clipping masks.  I imagine that feature would be very useful for some. If I do somehow manage to come up with some novel method of clipping using SFML's shapes, I will share it.

Thank you for your feedback and advice.


Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Updating Only Portion of Rendering Region
« Reply #3 on: April 08, 2016, 11:20:02 pm »
I believe it should be possible to achieve arbitrary-shaped clipping without raw OpenGL by drawing to a RenderTexture. I haven't fiddled with RenderTextures in a while so I'm not sure if your clipping mask texture would have to be the clear() color or transparent or something else but there ought to be a way to make that work. Of course whether this approach makes sense depends on how much clipping you're trying to accomplish.

But even if that's not enough, before totally resorting to raw OpenGL you should try sf::Shaders first, since then you only have the GLSL half of OpenGL to worry about.

Mr_Blame

  • Full Member
  • ***
  • Posts: 192
    • View Profile
    • Email
Re: Updating Only Portion of Rendering Region
« Reply #4 on: April 09, 2016, 08:17:32 am »
Updating only part of framebuffer is not very good strategy, for what do you want to use it?

JayhawkZombie

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Updating Only Portion of Rendering Region
« Reply #5 on: April 11, 2016, 03:36:49 pm »
My apologies for such a delayed response.
I was more curious to see if the API would allow me to avoid updating things that weren't changing, more so because the screen locations for the objects won't change, but I now see that's not a good way to go about it. I think my question was quite poorly-worded.  My experience with the nitty-gritty of the OpenGL API isn't extensive enough to know how to utilize it to its fullest extent.I see that simply redrawing everything makes little different to the performance.

I think my main concern was the clipping, which seems to be working as intended, though I've yet to try what Ixrec suggested for irregularly-shaped clipping regions (such as rounded corners). The clipping here just creates a box that my objects won't render outside of (intentional) with hard corners and edges.

I was hoping to reduce CPU usage as much as possible, due to the multi-threaded nature of the application (with all appropriate locks in place, event handling in the thread that created the renderWindow, rendering done solely in one thread, etc). I've since moved everything possible away from the 'render' function for my objects so they do not do any calculations other than what is absolutely necessary.