swiftopengl-esglkit

Having issues with drawing to a frame buffer texture. It draws blank


I am in OpenGL es 2.0 with glKit trying to render to iOS devices.

Basically my goal is to instead of drawing to the main buffer draw to a texture. Then render that texture to the screen. I have been trying to follow another topic on so. Unfortunately they mention something about the power of two (im assuming with regards to resolution) but I don't know how to fix it. Anyway here is my swift interpretation of the code from that topic.

import Foundation
import GLKit
import OpenGLES

class RenderTexture {
    var framebuffer:GLuint = 0
    var tex:GLuint = 0
    var old_fbo:GLint = 0
    
    init(width: GLsizei, height: GLsizei)
    {
        glGetIntegerv(GLenum(GL_FRAMEBUFFER_BINDING), &old_fbo)
        
        glGenFramebuffers(1, &framebuffer)
        glGenTextures(1, &tex)
        
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), framebuffer)
        glBindTexture(GLenum(GL_TEXTURE_2D), tex)
        glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GL_RGBA, GLsizei(width), GLsizei(height), 0, GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), nil)
        glFramebufferTexture2D(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_TEXTURE_2D), tex, 0)
        
        glClearColor(0, 0.1, 0, 1)
        glClear(GLenum(GL_COLOR_BUFFER_BIT))
        
        let status = glCheckFramebufferStatus(GLenum(GL_FRAMEBUFFER))
        if (status != GLenum(GL_FRAMEBUFFER_COMPLETE))
        {
            print("DIDNT GO WELL WITH", width, " " , height)
            print(status)
        }
        
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), GLenum(old_fbo))
    }
    
    func begin()
    {
        glGetIntegerv(GLenum(GL_FRAMEBUFFER_BINDING), &old_fbo)
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), framebuffer)
    }
    
    func end()
    {
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), GLenum(old_fbo))
    }
}

Then as far as rendering I have some things going on.

A code that theoretically renders any texture full screen. This has been tested with two manually loaded pngs (using no buffer changes) and works great.

func drawTriangle(texture: GLuint)
    {
        loadBuffers()
        //glViewport(0, 0, width, height)
        //glClearColor(0, 0.0, 0, 1.0)
        //glClear(GLbitfield(GL_COLOR_BUFFER_BIT) | GLbitfield(GL_DEPTH_BUFFER_BIT))
        
        
        glEnable(GLenum(GL_TEXTURE_2D))
        glActiveTexture(GLenum(GL_TEXTURE0))
        
        glUseProgram(texShader)
        let loc1 = glGetUniformLocation(texShader, "s_texture")
        glUniform1i(loc1, 0)
    
        
        let loc3 = glGetUniformLocation(texShader, "matrix")
        if (loc3 != -1)
        {
            glUniformMatrix4fv(loc3, 1, GLboolean(GL_FALSE), &matrix)
        }
        
        glBindTexture(GLenum(GL_TEXTURE_2D), texture)
        glDrawArrays(GLenum(GL_TRIANGLE_STRIP), 0, 6)
        glDisable(GLenum(GL_TEXTURE_2D))
        
        destroyBuffers()
    }

I also have a function that draws a couple dots on the screen. You dont really need to see the methods but it works. This is how I am going to know that OpenGL is drawing from the buffer texture and NOT a preloaded texture.

Finally here is the gist of the code I am trying to do.

func initialize()
{
      nfbo = RenderTexture(width: width, height: height)
}

fun draw()
{
        glViewport(0, 0, GLsizei(width * 2), GLsizei(height * 2)) //why do I have to multiply for 2 to get it to work????? 
        nfbo.begin()
        drawDots() //Draws the dots
        nfbo.end()
        reset()
        drawTriangle(nfbo.tex)
}

At the end of all this all that is drawn is a blank screen. If there is any more code that would help you figure things out let me know. I tried to trim it to make it less annoying for you.

Note: Considering the whole power of two thing I have tried passing the fbo class 512 x 512 just in case it would make things work being a power of two. Unfortunately it didnt do that.

Another Note: All I am doing is going to be 2D so I dont need depth buffers right?


Solution

  • yesterday I saw exactly the same issue.

    after struggling for hours, I found out why.

    the trick is configuring your texture map with the following:

        glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GL_CLAMP_TO_EDGE);
        glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GL_CLAMP_TO_EDGE);
    

    otherwise, you won't draw anything on the texture map.

    the reason seems to be that while ios supports texture maps that are not power of 2. it requires GL_CLAMP_TO_EDGE. otherwise it won't work.

    it should really report incomplete framebuffer. it took me quite long time to debug this problem!

    here a related discussion:

    Rendering to non-power-of-two texture on iPhone