2

自从第一次提出这个问题以来,这个问题发生了很大变化,因为我不明白我对自己所问的内容知之甚少。还有一个问题,关于调整大小,使我无法理解创建和使用帧缓冲区的更大问题。如果您只需要一个帧缓冲区跳转到答案......对于历史,我已经完好无损地保留了原始问题。


新手问题。我有一个正在处理的 GL 项目,并正在尝试使用独特的颜色制定选择策略。大多数讨论/教程都围绕在后台缓冲区中绘制可选实体并在用户单击某处时计算选择进行。我希望选择缓冲区是持久的,因此我可以快速计算任何鼠标移动的命中,并且不会重绘选择缓冲区,除非显示或对象几何形状发生变化。

似乎最好的选择是专用的帧缓冲区对象。这是我的问题。除了对帧缓冲区对象完全陌生之外,我很好奇。我最好是在窗口大小事件上删除和重新创建帧缓冲区对象,还是以最大屏幕分辨率创建一次,然后使用可能只是其中的一小部分。我已经让我的事件正常工作,只为可能是许多调整大小事件的流调用一次帧缓冲区例程,但我担心 GPU 内存碎片或其他问题,可能多次重新创建缓冲区。

此外,帧缓冲区对象(纹理和深度)在仅使用其中一部分时是否会连贯地表现。

想法?我完全离谱吗?

编辑:我已经设置好我的帧缓冲区对象,现在可以在窗口尺寸下工作,我用窗口调整它的大小。我认为我的问题是经典的“过度思考”。虽然确实应该尽可能避免在 GPU 上删除/重新创建对象。只要处理得当,调整大小相对较少。

我发现有效的是在窗口调整大小时设置一个标志并将缓冲区标记为脏,然后在调整缓冲区大小之前等待正常的鼠标事件。正常的鼠标进入或移动表明您已完成将窗口拖动到合适的大小并准备好重新开始工作。缓冲区重新创建一次。此外,由于主帧缓冲区的大小通常会针对管道中的每个窗口大小事件进行调整,因此调整帧缓冲区的大小不会在您的笔记本电脑上烧毁一个洞是有道理的。

危机解除,继续!

4

1 回答 1

3

在问题中提到我过度思考了这个问题。主要原因是问题大于问题。问题是,我不仅不知道如何控制帧缓冲区,我也不知道如何创建一个。有很多选择,但似乎没有一个网络资源专门针对我正在尝试做的事情,所以我很挣扎。如果您还在为如何将选择例程移动到具有持久缓冲区的独特配色方案而苦苦挣扎,或者对帧缓冲区和屏幕外渲染完全束手无策,请继续阅读。

我将 OpenGL 画布定义为一个类,我需要一个“选择缓冲区对象”。我将此添加到班级的私人成员中。

unsigned int sbo;
unsigned int sbo_pixels;
unsigned int sbo_depth;
bool sbo_dirty;
void setSelectionBuffer();

在我的调整大小处理程序和 OpenGL 初始化中,我为选择缓冲区设置了脏标志。

sbo_dirty = true;

在我的鼠标处理程序开始时,我检查脏位,setSelectionBuffer();如果合适的话。

if(sbo_dirty) setSelectionBuffer();

这解决了我最初对缓冲区的多次删除/重新创建的担忧。在调整窗口大小后,直到鼠标指针重新进入客户区,选择缓冲区才会调整大小。现在我只需要弄清楚缓冲区...

void BFX_Canvas::setSelectionBuffer()
{
    if(sbo != 0) // delete current selection buffer if it exists
    {
        glDeleteFramebuffersEXT(1, &sbo);
        glDeleteRenderbuffersEXT(1, &sbo_depth);
        glDeleteRenderbuffersEXT(1, &sbo_pixels);
        sbo = 0;
    }

    // create depth renderbuffer
    glGenRenderbuffersEXT(1, &sbo_depth);
    // bind to new renderbuffer
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, sbo_depth);
    // Set storage for depth component, with width and height of the canvas
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, canvas_width, canvas_height);
    // Set it up for framebuffer attachment
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, sbo_depth);
    // rebind to default renderbuffer
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

    // create pixel renderbuffer
    glGenRenderbuffersEXT(1, &sbo_pixels);
    // bind to new renderbuffer
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, sbo_pixels);
    // Create RGB storage space(you might want RGBA), with width and height of the canvas
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, canvas_width, canvas_height);
    // Set it up for framebuffer attachment
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, sbo_pixels);
    // rebind to default renderbuffer
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

    // create framebuffer object
    glGenFramebuffersEXT(1, &sbo);
    // Bind our new framebuffer
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sbo);
    // Attach our pixel renderbuffer
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, sbo_pixels);
    // Attach our depth renderbuffer
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, sbo_depth);

    // Check that the wheels haven't come off
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
    {
        // something went wrong
        // Output an error to the console
        cout << "Selection buffer creation failed" << endl;
        // restablish a coherent state and return
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        sbo_dirty = false;
        sbo = 0;
        return;
    }

    // rebind back to default framebuffer
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    // cleanup and go home
    sbo_dirty = false;
    Refresh(); // force a screen draw
}

然后在我的渲染函数结束时,我测试了 sbo,如果它似乎准备好了,就绘制它。

if((sbo) && (!sbo_dirty)) // test that sbo exists and is ready
{
    // disable anything that's going to affect color such as...
    glDisable(GL_LIGHTING);
    glDisable(GL_LINE_SMOOTH);
    glDisable(GL_POINT_SMOOTH);
    glDisable(GL_POLYGON_SMOOTH);

    // bind to our selection buffer
    // it inherits current transforms/rotations
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sbo);
    // clear it
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // draw selectables
    // for now i'm just drawing my object
    if (object) object->draw();

    // reenable that stuff from before
    glEnable(GL_POLYGON_SMOOTH);
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_LIGHTING);

    // blit to default framebuffer just to see what's going on
    // delete this bit once selection is setup and working properly.
    glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, sbo);
    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
    glBlitFramebufferEXT(0, 0, canvas_width, canvas_height,
                         0, 0, canvas_width/3, canvas_height/3,
                         GL_COLOR_BUFFER_BIT, GL_LINEAR);

    // We're done here, bind back to default buffer.
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

这给了我这个...

截屏

在这一点上,我相信一切都已准备就绪,可以将可选项目实际绘制到缓冲区,并使用鼠标移动事件来测试命中。而且我有一个屏幕缩略图来显示事情的发展有多糟糕。

我希望这对你有很大的帮助,就像一周前对我一样。:)

于 2011-12-14T17:14:54.763 回答