Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImDrawList callback with custom shader #4174

Closed
marcizhu opened this issue May 25, 2021 · 11 comments
Closed

ImDrawList callback with custom shader #4174

marcizhu opened this issue May 25, 2021 · 11 comments

Comments

@marcizhu
Copy link

Version/Branch of Dear ImGui:

Version: 1.84 WIP (commit 04fd507)
Branch: master

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp
Compiler: AppleClang
Operating System: macOS

My Issue/Question:

I'm trying to implement some custom rendering on top of ImGui. I tried using ImDrawList::AddCallback() to add a callback to a function that only changes the active shader. For some reason, I can't get anything to render there. However, when I remove the line that does the glUseProgram() so that it uses the default shader, then it renders properly. My shader does compile OK and it is indeed the same one the OpenGL3 backend uses, but for some reason I can't get it to work.

With the example I provide, one would expect a window called "FX", with size 1000x600 and a pink rectangle inside it. And this is exactly what I get when I disable my shader and instead rely on the default one, but when I use my shader the window is completely empty.

I know this is probably a dumb mistake by my side, but I've tried everything and I can't get it to work, and it should since the shader source is identical (I literally copied & pasted it). I shouldn't get an empty window with either shader.

Standalone, minimal, complete and verifiable example:

Vertex Shader source
#version 330 core
precision mediump float;
layout (location = 0) in vec2 Position;
layout (location = 1) in vec2 UV;
layout (location = 2) in vec4 Color;

uniform mat4 ProjMtx;
out vec2 Frag_UV;
out vec4 Frag_Color;

void main()
{
    Frag_UV = UV;
    Frag_Color = Color;
    gl_Position = ProjMtx * vec4(Position.xy,0,1);
}
Fragment Shader source
#version 330 core
precision mediump float;

in vec2 Frag_UV;
in vec4 Frag_Color;
layout (location = 0) out vec4 Out_Color;

void main()
{
    Out_Color = Frag_Color;
}
ImGui rendering code
ImGui::Begin("FX", NULL, ImGuiWindowFlags_AlwaysAutoResize);
ImVec2 size(1000.0f, 600.0f);
ImGui::InvisibleButton("canvas", size);
ImVec2 p0 = ImGui::GetItemRectMin();
ImVec2 p1 = ImGui::GetItemRectMax();
ImDrawList* draw_list = ImGui::GetWindowDrawList();

draw_list->PushClipRect(p0, p1);
draw_list->AddCallback([](const ImDrawList*, const ImDrawCmd*)
    {
         ImDrawData* draw_data = ImGui::GetDrawData();
         float L = draw_data->DisplayPos.x;
         float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
         float T = draw_data->DisplayPos.y;
         float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;

         const float ortho_projection[4][4] =
         {
            { 2.0f/(R-L),   0.0f,         0.0f,   0.0f },
            { 0.0f,         2.0f/(T-B),   0.0f,   0.0f },
            { 0.0f,         0.0f,        -1.0f,   0.0f },
            { (R+L)/(L-R),  (T+B)/(B-T),  0.0f,   1.0f },
         };

         glUseProgram(shaderID); // If I remove this line, it works
         glUniformMatrix4fv(glGetUniformLocation(shaderID, "ProjMtx"), 1, GL_FALSE, &ortho_projection[0][0]);
    }, nullptr);

draw_list->AddRectFilled(p0, p1, 0xFFFF00FF);
draw_list->AddCallback(ImDrawCallback_ResetRenderState, nullptr);
draw_list->PopClipRect();

ImGui::End();
@ocornut
Copy link
Owner

ocornut commented May 25, 2021

At this point you’d understand that your question is an OpenGL question and not much of a Dear ImGui question. If they are other OpenGL states you rely on or not rely on you should set them.

You can use glGetError() and shader compilation reports to try to track on what is wrong in your code, perhaps the shaders haven’t been built or linked correctly. OpenGL is a tricky mess in general but I am afraid there’s not much we can do here unfortunately. When you resolve it maybe posting the answer can be useful to others!

@marcizhu
Copy link
Author

If they are other OpenGL states you rely on or not rely on you should set them.

That's the thing, I don't rely on anything that changes the OpenGL state or anything. This is just like a small test program I've built with the code I provided.

I tried running glGetError() after each OpenGL command and all of them return GL_NO_ERROR and I specifically investigated the case that my shader is not compiling/linking properly.

After everything that I've tested I really have no clue on what is wrong. All I do is literally change the active shader for another with the same code...

I was hoping maybe you guys could give me some insight in what could be the issue here. Anyways, if I found out a fix for this, I will let you all know in case it is useful to anyone :)

@ocornut
Copy link
Owner

ocornut commented May 25, 2021 via email

@marcizhu
Copy link
Author

I'm on macOS now and sadly RenderDoc doesn't work on this platform. I will try using it tomorrow on Linux. Thanks for the tip :D

PathogenDavid added a commit to PathogenPlayground/imgui that referenced this issue May 27, 2021
@PathogenDavid
Copy link
Contributor

Your shaders and example code are working for me on Windows:

image

(My square is red because I modified the shader to remove the blue channel just to show it's definitely being used.)

The only code I wrote was the shader compilation since you didn't show that. Here's my full modified example_glfw_opengl3 if you want to compare.

@marcizhu
Copy link
Author

I tried your code (which is exactly the same as far as I can tell) and it doesn't work on macOS. I'm starting to believe that ImGui might do some platform-specific commands on macOS that change the state and thus it doesn't work.

I will try this code on Linux too. I'll keep you guys updated.

image

@PathogenDavid
Copy link
Contributor

Did you check if there's any shader compilation errors printed to the terminal?

One thing that stands out to me is that the default vertex shader used by the OpenGL3 backend does not explicitly specify the locations of the vertex attributes. (Presumably because specifying the location was added in newer versions of GLSL.) I assumed they'd have the same locations, but I wonder if this means the shader compiler is free to arrange them however it pleases. It might be worth comparing the values of g_AttribLocationVtx* and glGetAttribLocation with your shader in the debugger to see if they match.

@marcizhu
Copy link
Author

Did you check if there's any shader compilation errors printed to the terminal?

Yep, there are no errors on the terminal. I runned your code on Linux and it works no problem.

One thing that stands out to me is that the default vertex shader used by the OpenGL3 backend does not explicitly specify the locations of the vertex attributes. [...] I wonder if this means the shader compiler is free to arrange them however it pleases. It might be worth comparing the values of g_AttribLocationVtx* and glGetAttribLocation with your shader in the debugger to see if they match.

Indeed, on macOS I've got 1, 2 and 0 for the position, UV and color locations but my shader expects them to be 0, 1 and 2 respectively. When I change the attribute locations, this is what I get (finally!):

image

Thank you so much! From here it should be easy to fix this :D

@PathogenDavid
Copy link
Contributor

No problem, glad I could help!

Since it sounds like you're targeting OpenGL 3.3 anyway, you might look into increasing the version you pass to ImGui_ImplOpenGL3_Init. If you use == 300 or >= 410, it will user a newer vertex shader with explicit layout.

(I'm not sure why it's == 300. It's been like that since it was introduced in #1941. The 410 check was changed from == to >= for #2329, maybe the same would be appropriate for == 300? Likewise, it's labeled as OpenGL ES, but I think that's only because it was originally introduced to add OpenGL ES support.)

@ocornut ocornut changed the title ImDrawList not working with custom shader ImDrawList callback with custom shader May 27, 2021
@ocornut
Copy link
Owner

ocornut commented May 27, 2021

OSX has specific constraint with OpenGL. The OSX path of example always use 3.2 Core with Forward Compat.

@ocornut ocornut closed this as completed May 27, 2021
@PathogenDavid
Copy link
Contributor

The OSX path of example always use 3.2 Core with Forward Compat.

It uses 3.2 Core, but it uses the GLSL version string #version 150, which unless I'm missing something ends up using vertex_shader_glsl_130 (which does not have attribute locations.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants