14
\$\begingroup\$

How do i render my game scene into an imgui window?

I want to get from this:

enter image description here

to this :

enter image description here

\$\endgroup\$

1 Answer 1

17
\$\begingroup\$

First of all we need to create what is called Frame Buffer Object, or FBO for short. I'll leave you a great tutorial on (pretty much everything regarding OpenGL)FBOs right here: https://learnopengl.com/#!Advanced-OpenGL/Framebuffers

Now that we created an FBO, we should have a texture. This texture contains the image of what is rendered on the FBO. At this point all we need to do is to "put" this image inside of a dear ImGui Window. Let's see how to do this:

//this is our main game loop
while (!window.Closed())
{
    //we need to clear the window,
    //This is how the clear method is structured:
    //void Window::Clear(float x, float y, float z, bool enableGLDepth,bool clearImGUIframe)const
    //{
    //  //clear the color of the window with an alpha value of 1.0f
    //  glClearColor(x, y, z, 1.0f);    
    //  if (clearImGUIframe)
    //  {
    //      ImGui_ImplGlfwGL3_NewFrame();
    //  }
    //  if (enableGLDepth)
    //  {
    //      //enable the GL_DEPTH_TEST to be able to see 3D object correctly
    //      glEnable(GL_DEPTH_TEST);
    //      //clear both the color buffer bit and the depth buffer bit
    //      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //  }
    //  else
    //  {
    //      //clear just the color buffer bit
    //      glClear(GL_COLOR_BUFFER_BIT);
    //  }
    //}

    window.Clear(0.5f, 0.5f, 0.5f,true,true);

    //switch to our custom FBO
    //window.bindFBO is the same as writing glBindFramebuffer(GL_FRAMEBUFFER,FBO);
    window.bindFBO();
    
    //we need to call clear twice
    window.Clear(1.0f, 1.0f, 1.0f, true, false);
    //Draw our simple triangle
    shader.Use();
    glBindVertexArray(Tvao);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    //switch to the default FBO
    //again, unbindFBO() is the same as glBindFramebuffer(GL_FRAMEBUFFER,0)
    window.unbindFBO();

    //create our ImGui window
    ImGui::Begin("Scene Window");
    //get the mouse position
    ImVec2 pos = ImGui::GetCursorScreenPos();

    //pass the texture of the FBO
    //window.getRenderTexture() is the texture of the FBO
    //the next parameter is the upper left corner for the uvs to be applied at
    //the third parameter is the lower right corner
    //the last two parameters are the UVs
    //they have to be flipped (normally they would be (0,0);(1,1) 
    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));

    //we are done working with this window
    ImGui::End();
    //swap the buffers and check for events
    window.Update();
}

after all this you should get this result:

enter image description here

Hope this helped someone! I'll also leave the entire code i am using down here:

Main.cpp

#include "Engine.h"

using namespace Engine;
using namespace graphics;

int main()
{
    Window window("Advent3D", 800,600, false);
    Shader shader("Res/Shaders/Unlit.shader");

    //TRIANGLE CREATION//
    float Tvertices[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f,  0.5f, 0.0f};
    
    unsigned int Tvbo, Tvao;
    glGenVertexArrays(1, &Tvao);
    glGenBuffers(1, &Tvbo);
    glBindVertexArray(Tvao);
    glBindBuffer(GL_ARRAY_BUFFER, Tvbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Tvertices), Tvertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);


    while (!window.Closed())
    {
        //we need to clear the window, 
        window.Clear(0.5f, 0.5f, 0.5f,true,true);

        //switch to the custom fbo
        window.bindFBO();
        
        window.Clear(1.0f, 1.0f, 1.0f, true, false);

        shader.Use();
        glBindVertexArray(Tvao);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        //switch to the default fbo
        window.unbindFBO();

        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();

        window.Update();
    }   
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ A gist would be greatly helpful for newcomers. A simple 3D cube in an imgui window. \$\endgroup\$
    – Dilawar
    Nov 20, 2021 at 16:34

You must log in to answer this question.