So i was trying to use Dear ImGui to render my game view into a ImGui window.
The problem is, i don't get the image displayed correctly.
Instead i get something like this:
The fact is i would like to see this in my ImGui "Game Rendering" Window.
I'll leave the code i'm using right down here.
Main.cpp:
#include "Engine.h"//it includes all the files the engine uses
//the namespaces of the engine. just to organise the code better
using namespace Engine;
using namespace graphics;
//main function
int main()
{
//create the window object
Window window("Engine", 900, 700, false);
//create a shader object
Shader shader("Res/Shaders/Unlit.shader");
//initialize Dear ImGui
//window.getHandle gets the GLFWwindow* in this case
ImGui_ImplGlfwGL3_Init(window.getHandle(), true);
//the vertices of the triangle
float vertices[] = {
// positions // colors
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top
};
//create a vao,vbo
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//THE PROBLEM IS DOWN HERE//
//create the FBO
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
//create the texture and attach it to the fbo
unsigned int color_Texture;
glGenTextures(1, &color_Texture);
glBindTexture(GL_TEXTURE_2D, color_Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_Texture, 0);
//DEPTH buffer
unsigned int depth_Texture;
glGenTextures(1, &depth_Texture);
glBindTexture(GL_TEXTURE_2D, depth_Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 800, 600, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_Texture, 0);
//create the depth buffer attachment
unsigned int depthBuffer;
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 800, 600);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 0);//return to rendering to the normal fbo
//Here i'm trying to figure out how to render the color_Texture texture to the ImGui window
//Just keep in mind i had no idea what i was doing.. please help
//temporary variables
const int W = 800 / 2;
const int H = 600 / 2;
//main game loop
while (!window.Closed())
{
ImGui_ImplGlfwGL3_NewFrame();
//First problem: i am calling window.Clear() twice
//Here is what window.Clear() does:
//void Window::Clear(float x, float y, float z)const
//{
//clear the color of the window with an alpha value of 1.0f
//glClearColor(x, y, z, 1.0f);
//enable the GL_DEPTH_TEST to be able to see 3D object correctly
//glEnable(GL_DEPTH_TEST);
//clear both the color buffer bit ad the depth buffer bit
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//}
//do i really need to do this?
//because if i don't the texture appears black(just like if i din't call window.Clear() since the clear color is set to white.
window.Clear(0.4f, 0.4f, 0.4f);
//switch to the custom frame buffer object and render there
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//clear again
window.Clear(1.0f, 1.0f, 1.0f);
//Render the triangle(as you saw it's not working)
//use our shader program
shader.Use();
//bind the vao
glBindVertexArray(VAO);
//draw the triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
//switch again to the "Main" fbo to render the texture on the ImGui window
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//set the next window size
ImGui::SetNextWindowSize(ImVec2(W + 10, H + 10),
ImGuiSetCond_FirstUseEver);
//create the imgui window
ImGui::Begin("Game rendering");
{
//the position of the window when it gets created is going to be the mouse position
ImVec2 pos = ImGui::GetCursorScreenPos();
// Ask ImGui to draw it as an image
//Here it is. I have no idea what this method does.
//How does it work?
//is even this the mistake?
ImGui::GetWindowDrawList()->AddImage(
(void *)color_Texture, ImVec2(ImGui::GetItemRectMin().x + pos.x,
ImGui::GetItemRectMin().y + pos.y),
ImVec2(pos.x -10 , pos.y), ImVec2(0, 0), ImVec2(1, 1));
}
//end the imgui window
ImGui::End();
//render all GUI
ImGui::Render();
//swap buffers and check for events
window.Update();
}
//shut down ImGui
ImGui_ImplGlfwGL3_Shutdown();
}
I have no idea why this is happening.
I really hope someone can help me, this is a serious project.
P.S. i know i'm using glDrawArrays()to draw the triangle, but it was just to test this out quickly, without having too many problems.
demo code would be VERY much appreciated
There is demo code under "Widgets > Images". I have now just added additionally comments there as your problem is something many people stumble on.
A) If you are not sure that your texture contents is correct, you can use a GPU debugger such as RenderDoc to inspect that.
B) Inside your application you can call ImGui::ShowMetricsWindow() and use that to browse/debug the draw calls submitted to your application and that will help you understand what is happening.
You passing color_Texture looks right, I think your problem are what you are passing as coordinates:
upper-left corner = ImVec2(ImGui::GetItemRectMin().x + pos. ImGui::GetItemRectMin().y + pos.y),
lower-right corner = ImVec2(pos.x -10 , pos.y)
GetItemRectMin()/Max() gives you the rectangle of the last submitted item, but you are calling that after Begin() without submitting any item. So what it'll give you it undefined there.
The coordinates should be:
upper-left corner = ImGui::GetCursorScreenPos()
lower-right corner = ImGui::GetCursorScreenPos() + YourTextureSize
Note that the low-level ImDrawList imply drawing without interaction nor any feedback, so it won't "notify" the parent window of the size of what you are drawn, so the window will have to be resized manually. If you use ImGui::Image() it will automatically layout from GetCursorScreenPos() and the window size will grow. Or you can use ImGui::Dummy() or InvisibleButton() + ImDrawList::AddImage() as well.
"There is demo code under "Widgets > Images". I have now just added additionally comments there as your problem is something many people stumble on." I'm sorry but i wasn't able to find any "Widgets" folder in this repository.. where is it?
Build and run the examples applications in the examples/ folder, or call ShowTestWindow() in your application to get the example contents in your application.
WE solved it ! thank you!
This is what i got as the first try:
Then i tried to flip the UVs, and i got this:
Which works beatifully, but when i try resizing the window a bit more i get this:
Why is it happening? how can i solve this?
Here is my code:
ImGui::Begin("Scene Window");
ImVec2 pos = ImGui::GetCursorScreenPos();
ImGui::GetWindowDrawList()->AddImage(
(void *)window.getRenderTexture(), ImVec2(ImGui::GetCursorScreenPos()),
ImVec2(ImGui::GetCursorScreenPos().x + window.getWidth()/2, ImGui::GetCursorScreenPos().y + window.getHeight()/2), ImVec2(0, 1), ImVec2(1, 0));
ImGui::End();
Why is it happening?
window.getWidth() returns 800 in this case; / window.getHeight() returns 600 in this case;
Please don't use this github issue tracker as a way to prevent you from thinking your problems through and avoiding to do your homework. This is not a general programming forum.
You can use e.g. GetContentRegionAvail() or GetWindowSize() to query the size available when a window is resized by the user. You might want to use PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)) / PopStyleVar() if you want a window with no spacing between the edge and your image.
I will close this topic now and encourage you to solve further problem by yourself or on another discussion forum.
I apologize for causing you discomfort.
No worry, I just need to protect myself from having to teach or fix everyone's code. There are other communities for that and my focus is on developing dear imgui. I'm trying to improve the comments and examples as we go, the best I can, but cannot hold everyone's hands.
I understand that, i forgot for a moment that you may be working on a lot of other projects, and that you cannot be there for everyone and again i apologize. I really love the intense and costant work that you put in this project, and that's why i also support you on patreon. This is not the first time i use this library, but i'm not that fluent yet. Keep the good work up!
Most helpful comment
I understand that, i forgot for a moment that you may be working on a lot of other projects, and that you cannot be there for everyone and again i apologize. I really love the intense and costant work that you put in this project, and that's why i also support you on patreon. This is not the first time i use this library, but i'm not that fluent yet. Keep the good work up!