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

Bug: OpenGL Rendering in Imgui #200

Open
Brohammer5 opened this issue Sep 18, 2023 · 2 comments
Open

Bug: OpenGL Rendering in Imgui #200

Brohammer5 opened this issue Sep 18, 2023 · 2 comments
Labels
question Further information is requested

Comments

@Brohammer5
Copy link

Version

1.86.4

What happened?

I am trying to render an OpenGL scene into an ImGui Window. How would I achieve this as there seems to be no documentation on this repository? I have only seen C++ examples to implement this.

Reproduction

No Documentation

Relevant log output

No response

@Brohammer5 Brohammer5 added the bug Something isn't working label Sep 18, 2023
@SpaiR SpaiR added question Further information is requested and removed bug Something isn't working labels Sep 29, 2023
@blockout22
Copy link

You can render your scene onto ImGui using ImGui.Image(); this requires a Frame Buffer which takes in the texture ID of your Frame Buffer as the first argument

ImGui.image(framebuffer.getTextureId(), regionAvail.x, regionAvail.y, 0, 1, 1, 0);

you can dig around my code below for a better example

https://github.com/blockout22/FusionCoreEditor/blob/686e59f7576694e8c5be2737892bd5d99736c942/src/main/java/fusion/core/editor/Viewport.java#L340

@Displee
Copy link

Displee commented Jan 14, 2024

Here's how I did it for threekt:

package com.displee.imgui.threekt.texture

import org.lwjgl.opengl.GL30.*
import org.lwjgl.opengl.GL32.GL_PROGRAM_POINT_SIZE
import java.nio.ByteBuffer

class ThreeKtTexture {

    var texture_id = -1
    var FBO = -1
    var RBO = -1

    var width = 0
    var height = 0

    fun create_framebuffer(width: Int, height: Int)
    {
        this.width = width
        this.height = height
        // threekt defaults
        glEnable(GL_PROGRAM_POINT_SIZE)
        glEnable(GL_POINT_SPRITE)

        FBO = glGenFramebuffers()
        glBindFramebuffer(GL_FRAMEBUFFER, FBO)

        texture_id = glGenTextures()
        glBindTexture(GL_TEXTURE_2D, texture_id)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
        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, texture_id, 0)

        RBO = glGenRenderbuffers()
        glBindRenderbuffer(GL_RENDERBUFFER, RBO)
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height)
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO)

//        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
//            std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!\n";

        glBindFramebuffer(GL_FRAMEBUFFER, 0)
        glBindTexture(GL_TEXTURE_2D, 0)
        glBindRenderbuffer(GL_RENDERBUFFER, 0)
    }

    // here we bind our framebuffer
    fun bind_framebuffer()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, FBO)
    }

    // here we unbind our framebuffer
    fun unbind_framebuffer()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, 0)
    }

    // and we rescale the buffer, so we're able to resize the window
    fun rescale_framebuffer(width: Int, height: Int)
    {
        this.width = width
        this.height = height
        glBindTexture(GL_TEXTURE_2D, texture_id)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
        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, texture_id, 0)

        glBindRenderbuffer(GL_RENDERBUFFER, RBO)
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height)
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO)
    }

}

Then in your ImGui window:

            ImGui.text("This a demo for ImGui Canvas editor")
            ImGui.sameLine()
            ImGui.text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.")

            if (firstFrame) {
                initThreeKt()
                firstFrame = false
            }

            ImGui.image(threektTexture.texture_id, threektTexture.width.toFloat(), threektTexture.height.toFloat(), 0F, 1F, 1F, 0F)

            controlsEventSource.handleMouseEvents()

            val windowSize = ImGui.getWindowSize()

            ImGui.end()

            threektTexture.bind_framebuffer()
            // threekt clear is called once and while imgui calls it every frame, so we have to call it ourselves
            val bg = Color(Color.skyblue)
            GL32.glClearColor(bg.r, bg.g, bg.b, 1F)
            GL32.glClear(GL32.GL_COLOR_BUFFER_BIT or GL32.GL_DEPTH_BUFFER_BIT)

            onResizeThreeKt(windowSize)

            val dt = clock.getDelta()
            box.rotation.x += 0.5f * dt
            box.rotation.y += 0.5f * dt
            renderer.render(scene, camera)

            threektTexture.unbind_framebuffer()

Init OpenGL/threekt and only resize if needed

    private fun initThreeKt() {
        val imguiWindowSize = ImGui.getWindowSize()
        val windowSize = WindowSize(imguiWindowSize.x.toInt(), imguiWindowSize.y.toInt())
        camera = PerspectiveCamera(75, windowSize.aspect, 0.1, 1000).also {
            it.translateZ(10f)
        }
        controlsEventSource = ImGuiEventSource(windowSize)
        controls = OrbitControls(camera, controlsEventSource)
        renderer = GLRenderer(windowSize)

        threektTexture.create_framebuffer(imguiWindowSize.x.toInt(), imguiWindowSize.y.toInt())
    }

    private fun onResizeThreeKt(windowSize: ImVec2) {
        val width = windowSize.x.toInt()
        val height = windowSize.y.toInt()
        if (width == lastWidth && height == lastHeight) {
            return
        }
        camera.aspect = width.toFloat() / height.toFloat()
        camera.updateProjectionMatrix()
        camera.updateWorldMatrix()

        renderer.setSize(width, height)
        threektTexture.rescale_framebuffer(width, height)

        lastWidth = width
        lastHeight = height
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants