EXT_Framebufferobject

Member
Posts: 144
Joined: 2004.07
Post: #1
With 10.4.3 we now have access to the lovely EXT_FBO (EXT_framebuffer_object), which is an extension which finally makes rendering to a texture in GL very easy, fairly fast, and sensible. EXT_FBO is quite a bit more capable then what I'll be demostarting here, but I'll just outline a simple and common technique. You can read more about EXT_FBO here.

Last night I created this simple class that I was able to get working successfully. Hopefully this helps, feel free to use it as you wish:



Code:
#pragma once

#include <glew.h>

using namespace std;

class LVRenderTexture
{
    public:
        LVRenderTexture(int nwidth, int nheight, bool depth);
        ~LVRenderTexture();

        inline bool Valid(void) const { return texureID; }
        inline int Width(void) const { return width; }
        inline int Height(void) const { return height; }
        inline GLuint TexureID(void) const { return texureID; }
        void Use(void);  
        
        void Grab(void);
        void Finish(void);
        void Render(void);
        
    private:
        GLuint texureID, frameBufferID;
        GLuint depthBufferID;
        int width, height;
};


Code:
#include "LVRenderTexture.h"
#include <stdio.h>
#include <assert.h>

void CHECK_FRAMEBUFFER_STATUS(void)                      
{                                                          
    GLenum status;                                          
    status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    
    switch(status)
    {                                        
        case GL_FRAMEBUFFER_COMPLETE_EXT:                      
            break;                                              
        case GL_FRAMEBUFFER_UNSUPPORTED_EXT:                  
            printf("choose different formats\n");                      
            break;  
                                                        
        default:                                              
            printf("programming error; will fail on all hardware\n");  
            assert(0);                                          
    }
}

LVRenderTexture::LVRenderTexture(int nwidth, int nheight, bool depth)
{
    width = nwidth;
    height = nheight;
    
    // generate the frame buffer
    glGenFramebuffersEXT(1, &frameBufferID);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID);
    
    // generate the texture
    glGenTextures(1, &texureID);
    glBindTexture(GL_TEXTURE_2D, texureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texureID, 0);
    
    // generate the depth buffer
    if(depth)
    {
        glGenRenderbuffersEXT(1, &depthBufferID);
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBufferID);
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBufferID);
    }

    CHECK_FRAMEBUFFER_STATUS();

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

LVRenderTexture::~LVRenderTexture()
{
    if(frameBufferID)
        glDeleteFramebuffersEXT(1, &frameBufferID);

    if(texureID)
        glDeleteTextures(1, &texureID);

    if(depthBufferID)
        glDeleteRenderbuffersEXT(1, &depthBufferID);
}

void LVRenderTexture::Grab(void)
{
    if(frameBufferID)
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID);
        
    glViewport(0, 0, width, height);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void LVRenderTexture::Finish(void)
{
    if(frameBufferID)
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        
    // $$ Replace these values with those used in your scene's viewport
    glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}

void LVRenderTexture::Use(void)
{
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texureID);
}


Sample usage:
LVRenderTexture *rt = new LVRenderTexture(128, 128, true);

rt->Grab();
// render whatever you like
rt->Finish();

// now you can use the FBO to draw that to a texture
// just use either rt->Use()
// or glBindTexture(GL_TEXTURE_2D, rt->TextureID());

Notice in LVRenderTexture.cpp you'll have to replace SCREEN_WIDTH and SCREEN_HEIGHT with the appropriate values for your game. Also note that I use glew to avoid a lot of ugly defines and typedefs for EXT_FBO, if someone could help out and post what all I'd have to replace #include glew.h with to get everything working, that'd be great. This code is slightly different then what I created (as it had some engine-specific hooks), but it should still all work.

Otherwise it should now be that easy to render to your own texture. Cheers!
Quote this message in a reply
Member
Posts: 320
Joined: 2003.06
Post: #2
As far as I can tell the stencil buffer still isn't working with FBOs. Something to watch out for if you want to use them. Also not available on some cards so you'll still need PBuffers or something to fall back on.

Great to have it though, much easier to use than PBuffers.

Chopper, iSight Screensavers, DuckDuckDuck: http://majicjungle.com
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #3
Support is limited to CoreImage-capable cards (GeForce FX+, Radeon 9500+). My understanding is that this is an "effort involved" limitation, rather than a technical one, but it mirrors the limitations in the PC drivers, so I guess we can't complain too much Wink
Quote this message in a reply
Member
Posts: 144
Joined: 2004.07
Post: #4
oh geez, I misspelled 'texture' in all that last night. That's really great.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #5
Stencil attachments are not supported yet. We need the EXT_packed_depth_stencil extension, which wasn't quite done in time for 10.4.3.

I encourage everyone to read the FBO spec carefully. I know it is very long, but there are a lot of details to understand...
Quote this message in a reply
Member
Posts: 129
Joined: 2005.02
Post: #6
OSC, you give a very critical look on Apple's OpenGL implementation. Have you played around with the new extensions enough to give your spin? Maybe an updated OpenGL article on your site? Smile
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #7
Thanks! This will likely spur me to use a "real" cube map...
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
I don't think it's worth a whole new article. Obviously this update brings good new feature support, but ARB_draw_buffers and ARB_texture_non_power_of_two are still significantly missing. My impression is that the general bugginess hasn't improved a great deal, and that performance is still very low compared to other platforms.
Quote this message in a reply
Member
Posts: 129
Joined: 2005.02
Post: #9
So... like when are you going to get hired by Apple? Smile
Quote this message in a reply
Member
Posts: 144
Joined: 2004.07
Post: #10
OneSadCookie Wrote:I don't think it's worth a whole new article. Obviously this update brings good new feature support, but ARB_draw_buffers and ARB_texture_non_power_of_two are still significantly missing. My impression is that the general bugginess hasn't improved a great deal, and that performance is still very low compared to other platforms.

I think, until the situation drastically improves, it'd be great if you could every year do at least a little blurb on what's improved, and what hasn't (which it seems like you're doing). This way people don't read something from a year or two ago and sit unsure if that's still true.

Out of everyone on iDG, I can't imagine anyone else giving a better analysis (though I like seeing Alex Eddy (Arekkusu) chime in too)
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #11
There are still a few features missing that are preventing us from claiming full OpenGL 2.0 compliance, and we are working hard on delivering them as soon as possible.

We are also keenly focused on performance improvements, but when comparing with other platforms you should remember that we support multi-head, cross-vendor systems seamlessly, with a composited window manager. I don't think there really is any other platform that you can make a fair comparison to Wink
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #12
I would hope that with all the displays captured and the "single renderer" flag specified, those extra overheads might vanish Wink
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #13
Being new to PBuffers and FBO, what exactly is the difference? I mean, with PBuffers I can render to a texture, too. Is it that FBO offers a depth texture?

EDIT: Having read some of the spec I see that FBO is faster, and more portable. Sounds good!
Quote this message in a reply
Post Reply