natario1 / Egloo

A lightweight Kotlin multiplatform framework for OpenGL ES and EGL management based on object-oriented components, inspired by Google's Grafika.

Home Page:https://natario1.github.io/Egloo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Documentation: How to use the GlFrameBuffer?

kihaki opened this issue · comments

Hey, I am trying to render to a texture using a framebuffer, but I can't seem to make it work, could you help me out here?

So I am setting up a SurfaceView and tried a simple rendering, which works just fine:

        val core = EglCore(flags = EglCore.FLAG_TRY_GLES3)
        val window = EglWindowSurface(core, surface)
        window.makeCurrent()

        val simpleProgram = GlFlatProgram()
        simpleProgram.setColor(Color.GREEN)
        val circle = GlCircle()
        circle.radius = 0.15F
        simpleProgram.draw(circle)

        // Publish
        window.swapBuffers()

But when I am trying to render to a FBO it crashes:

        val core = EglCore(flags = EglCore.FLAG_TRY_GLES3)
        val window = EglWindowSurface(core, surface)
        window.makeCurrent()

        val simpleProgram = GlFlatProgram()
        simpleProgram.setColor(Color.GREEN)
        val circle = GlCircle()
        circle.radius = 0.15F

        val fbTexture = GlTexture()
        val fbo = GlFramebuffer()
        fbo.attach(fbTexture, GLES20.GL_COLOR_ATTACHMENT0)
        fbo.bind()

        simpleProgram.draw(circle)

        // Publish
        window.swapBuffers()

java.lang.RuntimeException: Error during draw start: glError 0x502: invalid operation

Could you help me out with a working sample or a pinpoint in what's wrong? I couldn't glean much more from the docs.

There are many things going on:

  • If you want to render into a framebuffer, you don't need a window, so you can remove it.
  • Instead of creating the window, you should probably make the context current (core.makeCurrent() I think)
  • The GlTexture defaults to target = GL_TEXTURE_EXTERNAL_OES, but this only works with android surfaces, so with windows, not FBOs. You have to use target = GL_TEXTURE_2D and assign a proper width and height.
  • Don't forget to unbind() the FBO after drawing (or you can use fbo.use { /* draw */ } )

A good exercise to learn how to use the lib could be render the circle in the FBO as you're trying to do here, then render the FBO texture into a window (with another draw pass and GlTextureProgram).

Hey, first of all, thanks for you super quick response! I wouldn't have believed that you would answer in just 5 minutes.
I only read it just now but in the meantime I have made some progress on my own:

  • Updated to the latest version (0.5.2)
  • Figured the texture size out, also discovered fbo.use { ... }, which is very handy. Starting to love this library :)

Right now my code looks like this:

        val scene = GlScene()
        val core = EglCore(flags = EglCore.FLAG_TRY_GLES3)
        val window = EglWindowSurface(core, surface /* Surface from a SurfaceView so something becomes visible on screen */)
        window.makeCurrent()

        val simpleProgram = GlFlatProgram()
        simpleProgram.setColor(Color.GREEN)
        val quad = GlRect()

        val textureProgram = GlTextureProgram()
        val fbTexture = GlTexture(GL_TEXTURE0, GL_TEXTURE_2D, 100, 100)
        textureProgram.texture = fbTexture
        val fbo = GlFramebuffer()
        fbo.attach(fbTexture, GLES20.GL_COLOR_ATTACHMENT0)
        fbo.use {
            scene.draw(simpleProgram, quad)
        }
        scene.draw(textureProgram, quad)

        // Publish
        window.swapBuffers()

Which does not crash (so far so good). But the contents of the fbo are not visible on screen (its just black).
Skipping the fbo part will result in the correct image on screen, so I am pretty sure the simpleProgram renders correctly.
Skipping the EglWindowSurface as you mentioned, while not necessary for a fbo, is still required, because I want to render the final output to a surface, right?

I can't quite figure out if either 1) the content of the fbo is not updated or 2) the rendering of the textureProgram is somehow faulty.

Any ideas?

I think it's the same issue of EOS vs. regular textures. In GlTextureProgram constructor, the fragment shader defaults to SIMPLE_FRAGMENT_SHADER (which reads from external, android textures). Since you are using a regular 2D texture, you should replace samplerExternalOES with sampler2D.

Something like SIMPLE_FRAGMENT_SHADER.replace("samplerExternalOES", "sampler2D") might work

This fixes it, it's rendering correctly. Many thanks, this would probably have taken me a lot longer to find out on my own. I would like to write some small samples for your docs which could help out other people when starting out if that is okay for you? :)

This is just a simple example for now but I have it working and can build on it. Once again, thank you, also great work on the library!

Sure, feel free to open a PR :-) there's also a button on each webpage to edit that specific markdown doc.