moderngl / moderngl-window

A cross platform utility library for ModernGL making window creation and resource loading simple
MIT License
244 stars 57 forks source link

Imgui + render into FBO #82

Closed jonathangranskog closed 4 years ago

jonathangranskog commented 4 years ago

Hi,

I'm testing the imgui integration and I'm having some issues. I need to render a scene with OpenGL into an FBO and display this as an image next to another image.

I grabbed the example and added an FBO with simple_framebuffer and then I call self.fbo.use() before rendering the cube. When I save the FBO as an image, it looks incorrect. Everything renders normally after commenting out self.fbo.use(). Is there anything else that has to be done for this to work?

Thanks!

from pathlib import Path
import imgui
import moderngl
from pyrr import Matrix44
import moderngl_window as mglw
from moderngl_window import geometry
from PIL import Image
from moderngl_window.integrations.imgui import ModernglWindowRenderer

class WindowEvents(mglw.WindowConfig):
    gl_version = (3, 3)
    title = "imgui Integration"
    resource_dir = (Path(__file__).parent / 'resources').resolve()
    aspect_ratio = None

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        imgui.create_context()
        self.wnd.ctx.error
        self.imgui = ModernglWindowRenderer(self.wnd)

        self.cube = geometry.cube(size=(2, 2, 2))
        self.prog = self.load_program('programs/cube_simple.glsl')
        self.prog['color'].value = (1.0, 1.0, 1.0, 1.0)
        self.prog['m_camera'].write(Matrix44.identity(dtype='f4'))
        self.prog['m_proj'].write(Matrix44.perspective_projection(75, self.wnd.aspect_ratio, 1, 100, dtype='f4'))
        self.fbo = self.wnd.ctx.simple_framebuffer((256, 256), components=3)

    def render(self, time: float, frametime: float):
        rotation = Matrix44.from_eulers((time, time, time), dtype='f4')
        translation = Matrix44.from_translation((0.0, 0.0, -3.5), dtype='f4')
        model = translation * rotation

        self.render_ui()

        self.fbo.use()
        self.ctx.enable(moderngl.DEPTH_TEST | moderngl.CULL_FACE)
        self.prog['m_model'].write(model)
        self.cube.render(self.prog)

        image = Image.frombytes('RGB', (256, 256), self.fbo.read(components=3))
        image.save('test.png')

    def render_ui(self):
        imgui.new_frame()
        if imgui.begin_main_menu_bar():
            if imgui.begin_menu("File", True):

                clicked_quit, selected_quit = imgui.menu_item(
                    "Quit", 'Cmd+Q', False, True
                )

                if clicked_quit:
                    exit(1)

                imgui.end_menu()
            imgui.end_main_menu_bar()

        imgui.show_test_window()

        imgui.begin("Custom window", True)
        imgui.text("Bar")
        imgui.text_colored("Eggs", 0.2, 1., 0.)
        imgui.end()

        imgui.render()
        self.imgui.render(imgui.get_draw_data())

    def resize(self, width: int, height: int):
        self.prog['m_proj'].write(Matrix44.perspective_projection(75, self.wnd.aspect_ratio, 1, 100, dtype='f4'))
        self.imgui.resize(width, height)

    def key_event(self, key, action, modifiers):
        self.imgui.key_event(key, action, modifiers)

    def mouse_position_event(self, x, y, dx, dy):
        self.imgui.mouse_position_event(x, y, dx, dy)

    def mouse_drag_event(self, x, y, dx, dy):
        self.imgui.mouse_drag_event(x, y, dx, dy)

    def mouse_scroll_event(self, x_offset, y_offset):
        self.imgui.mouse_scroll_event(x_offset, y_offset)

    def mouse_press_event(self, x, y, button):
        self.imgui.mouse_press_event(x, y, button)

    def mouse_release_event(self, x: int, y: int, button: int):
        self.imgui.mouse_release_event(x, y, button)

    def unicode_char_entered(self, char):
        self.imgui.unicode_char_entered(char)

if __name__ == '__main__':
    mglw.run_window_config(WindowEvents)
jonathangranskog commented 4 years ago

never mind, I found my issue...

Needed to set it back to use the wnd.fbo and clear the view

einarf commented 4 years ago

Yep. that seems to be it. The fbo will by default set the viewport to match the framebuffer size. It can be modified (among other properties) on the fbo itself.

The imgui overlay should also always be rendered last, but I assume it was moved around when experimenting 😄

jonathangranskog commented 4 years ago

Yeah, I moved stuff around a lot hehe. Spent an hour or two trying to solve this before posting and then I figured it out as soon as I did. :smile:

Thanks for the quick response though! Also, thanks for moderngl and moderngl-window. They are wonderful.

einarf commented 4 years ago

No problem. We do have a discord server linked in the description as well.

Don't hesitate making issues if you bump into something sub-optimal. Even related to documentation.