Window alpha blend issue when using GLFW_TRANSPARENT_FRAMEBUFFER (OpenGl3) #2764

Closed
opened 2019-08-28 06:18:09 +00:00 by SageMade · 2 comments
SageMade commented 2019-08-28 06:18:09 +00:00 (Migrated from github.com)

Version: 1.73 (cb538fadfe)
Branch: docking

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_opengl3.cpp + imgui_impl_glfw3.cpp
Compiler: Visual Studio 2019 (MSVC)
Operating System: Windows 10 Pro (1809)

My Issue/Question:
When transparent framebuffers are enabled in GLFW (via GLFW_TRANSPARENT_FRAMEBUFFER window hint), imgui backgrounds do not properly alpha blend, and the underlying windows will bleed through the imgui windows, even when the backbuffer transparency is 1.

Expected result:
image

Actual result:
image

Suggested Resolution:
Change line 186 of imgui_impl_opengl3.cpp from:

    ...
    glEnable(GL_BLEND);
    glBlendEquation(GL_FUNC_ADD); // both rgb and alpha func is add
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     ...

to

    ...
    glEnable(GL_BLEND);
    glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); // rgb is add, alpha is max
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    ...

This fixes the issue, but I have not tested the potential side effects of this. In theory additive blending of alpha should work, there is probably something that I'm missing. Looking at the docs, the only way to go from 255 alpha to something lower is if As or sA is < 0). When doing a pixel debug in nsight, things start to make even less sense.

image

If you look at event 50, the alpha actually drops from 255 down to 241

Compare that to what the docs say, we should be getting:

Ar=As sA+Ad dA
sA = GL_ONE = 1
dA = GL_ONE_MINUS_SRC_ALPHA = (1 - 0.941...) = 0.059
Ar =240 * 1 + 255 * 0.059
Ar = 240 + 15
Ar = 255

I have the feeling that this is less of an ImGui issue and more of an issue with how GLFW or OpenGL handle transparent framebuffers (there's also an issue where a=0 does not blend properly with the underlying screen if any of the other channels are non-zero), but I need to do more digging.

As for the visual difference between additive and max, it looks OK to me, but then again I don't have any content underneath it yet:
image

I feel like I may be missing something else here, any suggestions?

Standalone, minimal, complete and verifiable example:

glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
window = glfwCreateWindow(w, h, "", nullptr, nullptr);

...
	
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;

ImGui::StyleColorsDark();

...

ImGui::Begin("Example Bug");
ImGui::ColorEdit4("Easy to see with child controls", &color[0]);
ImGui::End();
Version: 1.73 (cb538fadfe3d24ec2b8c30a97103e44055db811c) Branch: docking **Back-end/Renderer/Compiler/OS** Back-ends: imgui_impl_opengl3.cpp + imgui_impl_glfw3.cpp Compiler: Visual Studio 2019 (MSVC) Operating System: Windows 10 Pro (1809) **My Issue/Question:** When transparent framebuffers are enabled in GLFW (via GLFW_TRANSPARENT_FRAMEBUFFER window hint), imgui backgrounds do not properly alpha blend, and the underlying windows will bleed through the imgui windows, even when the backbuffer transparency is 1. **Expected result:** ![image](https://user-images.githubusercontent.com/6020584/63827546-84cb3080-c931-11e9-9d05-65cea416043c.png) **Actual result:** ![image](https://user-images.githubusercontent.com/6020584/63828047-40d92b00-c933-11e9-85e9-63e0d4207e11.png) **Suggested Resolution:** Change line 186 of [imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/docking/examples/imgui_impl_opengl3.cpp) from: ``` ... glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); // both rgb and alpha func is add glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ... ``` to ``` ... glEnable(GL_BLEND); glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); // rgb is add, alpha is max glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ... ``` This fixes the issue, but I have not tested the potential side effects of this. In theory additive blending of alpha should work, there is probably something that I'm missing. Looking at [the docs](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendEquation.xhtml), the only way to go from 255 alpha to something lower is if As or sA is < 0). When doing a pixel debug in nsight, things start to make even less sense. ![image](https://user-images.githubusercontent.com/6020584/63829643-2190cc80-c938-11e9-8561-2137a65cbf47.png) If you look at event 50, the alpha actually drops from 255 down to 241 Compare that to what the docs say, we should be getting: ``` Ar=As sA+Ad dA sA = GL_ONE = 1 dA = GL_ONE_MINUS_SRC_ALPHA = (1 - 0.941...) = 0.059 Ar =240 * 1 + 255 * 0.059 Ar = 240 + 15 Ar = 255 ``` I have the feeling that this is less of an ImGui issue and more of an issue with how GLFW or OpenGL handle transparent framebuffers (there's also an issue where a=0 does not blend properly with the underlying screen if any of the other channels are non-zero), but I need to do more digging. As for the visual difference between additive and max, it looks OK to me, but then again I don't have any content underneath it yet: ![image](https://user-images.githubusercontent.com/6020584/63829599-032ad100-c938-11e9-9f0a-47d127407b1d.png) I feel like I may be missing something else here, any suggestions? **Standalone, minimal, complete and verifiable example:** ``` glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); window = glfwCreateWindow(w, h, "", nullptr, nullptr); ... ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; ImGui::StyleColorsDark(); ... ImGui::Begin("Example Bug"); ImGui::ColorEdit4("Easy to see with child controls", &color[0]); ImGui::End(); ```
SageMade commented 2019-08-28 06:38:55 +00:00 (Migrated from github.com)

On further messing around, I think it would make more sense to change the blend function instead of equation, so:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

and keep glBlendEquation(GL_ADD)

This appears to have the same effect, and should have minimal impact on the appearance of UI's.

On another note, it looks like there is some more internal work to do to support transparent framebuffers. I may try my hand at a PR later, once I have some of the current issues resolved (biggest one is creating transparent windows and clearing properly for multiple viewports).

On further messing around, I think it would make more sense to change the blend function instead of equation, so: ``` glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); ``` and keep ``` glBlendEquation(GL_ADD)``` This appears to have the same effect, and should have minimal impact on the appearance of UI's. On another note, it looks like there is some more internal work to do to support transparent framebuffers. I may try my hand at a PR later, once I have some of the current issues resolved (biggest one is creating transparent windows and clearing properly for multiple viewports).
ocornut commented 2021-02-18 12:50:52 +00:00 (Migrated from github.com)

Sorry @ShawnM427 for the late answer.

Went through a bunch of backends and examples yesterday.
Fixed this with bda12e5fdd and 6a161b8789 (had seven related issues).

We will still need to work on better Backends and Multi-viewports support, so will keep #2766 open as current change don't fulfill all the ideas suggested by #2766. Will add more details there.

Sorry @ShawnM427 for the late answer. Went through a bunch of backends and examples yesterday. Fixed this with bda12e5fdd829e44e01a25aac015e156f3dad761 and 6a161b878943241ddecbeee4ae27103dbd2d33d0 (had seven related issues). We will still need to work on better Backends and Multi-viewports support, so will keep #2766 open as current change don't fulfill all the ideas suggested by #2766. Will add more details there.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ocornut/imgui#2764
No description provided.