0

我正在编写一个 2D OpenGL 引擎,并且我最近包含了一个帧缓冲区包装类,用于在运行时生成纹理图集。在我在笔记本电脑的集成显卡上对其进行测试之前,它工作得非常好,性能也得到了很大的提升。

显然,在集成显卡上运行时 glCheckFramebufferStatus 返回零。不,它不会返回 GL_FRAMEBUFFER_UNSUPPORTED。它返回零。我真的不认为我的集成显卡不支持帧缓冲区,因为它们不是那么旧。我还尝试延迟帧缓冲区的初始化以在主 GLUT 循环中执行此操作,但它没有解决问题。我也尝试使用 framebufferEXT 而不是 framebuffer,但没有任何改变。如果我忽略该错误,当我尝试绘制帧缓冲区的纹理时它不会绘制任何内容。另外:如果视频卡不支持帧缓冲区并且我绝对需要它们,我应该回退什么?

这是我的帧缓冲区类的代码:

帧缓冲区.hpp:

#pragma once

#include "sprite.hpp"

namespace core
{
    class framebuffer
    {
    public:
        framebuffer();
        virtual ~framebuffer();
        bool initialized();
        void initialize(int width, int height);
        int width();
        int height();
        sprite *getframe();
        void begin();
        void end();

    protected:
        GLubyte *pixels;
        int w, h;
        GLuint id, tex;
        sprite frame;
    };
}

帧缓冲区.cpp:

#include "framebuffer.hpp"
#include <iostream>
#include <cmath>

namespace core
{
    framebuffer::framebuffer()
        : pixels(NULL), w(0), h(0)
    {
        // empty
    }

    framebuffer::~framebuffer()
    {
        glDeleteFramebuffers(1, &id);

        if (pixels)
        {
            // TODO: convert to smart pointer once everything works ok
            delete [] pixels;
            pixels = NULL;
        }
    }

    bool framebuffer::initialized()
    {
        return w != 0 && h != 0;
    }

    void framebuffer::initialize(int width, int height)
    {
        w = width;
        h = height;
        //std::cout << "framebuffer.initialize: w = " << w << "\nh = " << h << std::endl;
    }

    int framebuffer::width()
    {
        return w;
    }

    int framebuffer::height()
    {
        return h;
    }

    sprite *framebuffer::getframe()
    {
        GLuint oldtex;

        glBindFramebuffer(GL_FRAMEBUFFER, id);
        glEnable(GL_TEXTURE_RECTANGLE_ARB);
        glGetIntegerv(GL_TEXTURE_RECTANGLE_ARB, reinterpret_cast<GLint *>(&oldtex)); // store old bound texture
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex); // bind framebuffer texture
        glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // get framebuffer pixels
        frame.fromtexture(tex, GL_RGBA, w, h, GL_RGBA, pixels); // create a sprite object from raw pixels
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldtex); // re-bind the old texture
        glDisable(GL_TEXTURE_RECTANGLE_ARB);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        return &frame;
    }

    void framebuffer::begin() // call this to start drawing to the framebuffer
    {
        if (!pixels)
        {
            GLenum result;

            // initialize the frame buffer if it isn't already

            glGenTextures(1, &tex); // generate the texture that will store the frame

            glEnable(GL_TEXTURE_RECTANGLE_ARB);
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);

            // reserve video memory for the framebuffer image
            pixels = new GLubyte[w * h * 4];
            glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

            glGenFramebuffers(1, &id); // create frame buffer
            glBindFramebuffer(GL_FRAMEBUFFER, id);

            // assign the texture to the framebuffer
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 0);

            result = glCheckFramebufferStatus(GL_FRAMEBUFFER);

            if (result != GL_FRAMEBUFFER_COMPLETE)
            {
                if (result == GL_FRAMEBUFFER_UNSUPPORTED)
                {
                    // todo: handle errors as exceptions and cleanup everything gracefully
                    std::cout << "framebuffer.begin: your video card doesn't seem to support framebuffers" << std::endl;
                    exit(0);
                }

                std::cout << "framebuffer.begin: failed to initialize framebuffer | error " << result << std::endl;
                exit(0);
            }

            glDisable(GL_TEXTURE_RECTANGLE_ARB);
        }

        glBindFramebuffer(GL_FRAMEBUFFER, id); // bind the framebuffer
        glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
        glViewport(0, 0, w, h); // adjust viewport to the fbo's size
        glLoadIdentity(); // reset modelview matrix

        glMatrixMode(GL_PROJECTION);
        glPushMatrix(); // store the non-flipped matrix
        glLoadIdentity();
        glOrtho(0, w, 0, h, -1, 1); // stupid fbo's flipping stuff upside down

        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    void framebuffer::end() // call this to stop drawing to the framebuffer
    {
        glPopAttrib();
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glMatrixMode(GL_PROJECTION);
        glPopMatrix(); // restore old matrix
        glMatrixMode(GL_MODELVIEW);
    }
}
4

2 回答 2

4

来自官方文档:

"如果绑定到目标的帧缓冲区完整,则返回值为GL_FRAMEBUFFER_COMPLETE。否则,返回值确定如下:

...

此外,如果发生错误,则返回零。”

所以你有它,发生了错误。也许 glGetError 有其他信息。

如果不支持帧缓冲区并且您想将其用于渲染到纹理,您可以查看是否支持 pbuffers,否则为 glReadPixels?

于 2013-01-09T14:55:06.823 回答
1

我假设目标显卡可能不支持 GL_TEXTURE_RECTANGLE_ARB。在这种情况下,您可能必须切换到 2 的幂纹理。

于 2013-01-09T15:01:13.513 回答