ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.51k stars 10.14k forks source link

Rendering windows one at a time? #6477

Closed what-am-i-doing closed 1 year ago

what-am-i-doing commented 1 year ago

Version/Branch of Dear ImGui:

Version: 1.89.2 Branch: master

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_sdl.cpp + imgui_impl_vulkan.cpp

My Issue/Question:

Is it possible to render just one window at a time?

My engine currently does a little bit of post processing when rendering Dear ImGui in order to blur the scene wherever the scene is occluded by a transparent Dear ImGui window. I do this by doing a UI pass where I render Dear ImGui onto a clear framebuffer, then I use that framebuffer's contents as a mask to determine what regions of the main scene framebuffer to blur. Then I render the framebuffer's contents on top of the (now processed) main scene framebuffer, the result being that transparent Dear ImGui windows appear to blur the scene behind them.

However, because everything in Dear ImGui is rendered in one pass, if one Dear ImGui window is overlapping another, the occluded portions of the rear window are not blurred. I would like them to be blurred, and if I could render one Dear ImGui window at a time then I would basically be able to just cycle through the above described process; render scene, render a window, use it as a mask to blur parts of the scene, then apply the rendered window itself onto the scene (where it will be affected by any subsequent blur passes), move on to the next window, etc.

I can more or less see how I could do this by modifying the ImGui Vulkan backend, so I will most likely end up making a custom backend based on it with the changes I have in mind. But because it would be nicer to just use the built-in backend if possible, I thought I'd first check and see if there is any already-established way of just doing one Dear ImGui window per render pass. It doesn't seem like using the register callback function works for this, because ImGui_ImplVulkan_RenderDrawData runs "inside" a started render pass and I would need each window to have its own pair of render passes (inside the callback function, aka inside RenderDrawData, but render pass begin / end needs to be outside it), but I could be misunderstanding / missing something.

Screenshots/Video

As you can see here the scene behind the windows is blurred - but the window located behind the first one is not.

blur_demo

GamingMinds-DanielC commented 1 year ago

As a general idea:

I have not done anything like this so far, so this approach is untested, but if my understanding of the draw list interface is correct, this is how it should work.

ocornut commented 1 year ago

You can consider each unique ImDrawList to be a window or layer (e.g. GetBackgroundDrawList(), GetForegroundDrawList()) and then rendering each ImDrawList separately.

You would need to provide a custom XXX_RenderDrawData() function indeed. I think you could have a source file which includes imgui_impl_vulkan.cpp so you get access to its data easily, and then add your own RenderDrawData() function. This way you only duplicate this 1 function and not everything else.

what-am-i-doing commented 1 year ago

You can consider each unique ImDrawList to be a window or layer (e.g. GetBackgroundDrawList(), GetForegroundDrawList()) and then rendering each ImDrawList separately.

You would need to provide a custom XXX_RenderDrawData() function indeed. I think you could have a source file which includes imgui_impl_vulkan.cpp so you get access to its data easily, and then add your own RenderDrawData() function. This way you only duplicate this 1 function and not everything else.

Thanks. I'm going to go ahead and close this since it answers my question. Including impl_vulkan is actually a pretty good idea; I had noticed a lot of the functions I would need for an alternate RenderDrawData would require a number of functions contained within it, but for whatever reason it had not occurred to me that I could just put together a quick header to declare them and include that.

Doing the one alternate function is a pretty minor thing, so that's a good solution.

Great library by the way, I appreciate all the work you've put into it.