OpenGL:使用FBO和视口偏移问题渲染到纹理

时间:2014-02-27 15:12:37

标签: opengl framebuffer fbo

我注意到渲染到纹理时帧缓冲对象(FBO)的意外行为。

如果我们按以下方式设置视口:

glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity() ;

(w和h不需要匹配窗口大小)一切都很好:

因此,我们需要绘制视口的边界矩形:

glBegin(GL_LINE_STRIP);
    glVertex2f(0.0, 0.0);
    glVertex2f(0.0, 1.0);
    glVertex2f(1.0, 1.0);
    glVertex2f(1.0, 0.0);
glEnd();

如果我们在纹理上绘制相同的绘图,然后覆盖整个视口:

glBegin(GL_QUADS);
    glTexCoord2f(0.0, 1.0);
    glVertex2f(0.0, 0.0);
    glTexCoord2f(0.0, 0.0);
    glVertex2f(0.0, 1.0);
    glTexCoord2f(1.0, 0.0);
    glVertex2f(1.0, 1.0);
    glTexCoord2f(1.0, 1.0);
    glVertex2f(1.0, 0.0);
glEnd();

我们得到相同的结果:

但是,如果我们将第一行更改为:

glViewport(x, y, w, h);

其中x和y不等于0 - 执行FBO版本时有一个奇怪的偏移量。偏移完全等于(x,y)但它相对于视口,因此我们得到偏移的结果(2 * x,2 * y)

这是完整的代码演示问题。

void initialize()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}

void resize(int w, int h)
{
    glViewport(50, 50, w-100, h-100);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluOrtho2D(0.0, 1.0, 1.0, 0.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

void paint()
{
    glClear(GL_COLOR_BUFFER_BIT);

    // FBO Drawing
    GLuint fb, texColor;
    glGenFramebuffers(1, &fb);
    glGenTextures(1, &texColor);

    glBindFramebuffer(GL_FRAMEBUFFER, fb);
    glBindTexture(GL_TEXTURE_2D, texColor);
    glTexImage2D(   GL_TEXTURE_2D,
                0,
                GL_RGBA,
                width()-100, height()-100, // Maching size of viewport (size of window - unused area)
                0,
                GL_RGBA,
                GL_UNSIGNED_BYTE,
                NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColor, 0);

    glLineWidth(10.0);
    glColor4f(1.0, 0.0, 0.0, 1.0);
    glBegin(GL_LINE_STRIP);
        glVertex2f(0.0, 0.0);
        glVertex2f(0.0, 1.0);
        glVertex2f(1.0, 1.0);
        glVertex2f(1.0, 0.0);
    glEnd();
    glBegin(GL_LINES);
        glVertex2f(0.0, 0.0);
        glVertex2f(1.0, 1.0);
        glVertex2f(0.0, 1.0);
        glVertex2f(1.0, 0.0);
    glEnd();


    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    glLineWidth(10.0);
    glColor4f(0.0, 1.0, 0.0, 1.0);
    glBegin(GL_LINE_STRIP);
        glVertex2f(0.0, 0.0);
        glVertex2f(0.0, 1.0);
        glVertex2f(1.0, 1.0);
        glVertex2f(1.0, 0.0);
    glEnd();
    glBegin(GL_LINES);
        glVertex2f(0.0, 0.0);
        glVertex2f(1.0, 1.0);
        glVertex2f(0.0, 1.0);
        glVertex2f(1.0, 0.0);
    glEnd();

    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, texColor);
    glColor4f(1.0, 1.0, 1.0, 0.3);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0, 1.0);
        glVertex2f(0.0, 0.0);
        glTexCoord2f(0.0, 0.0);
        glVertex2f(0.0, 1.0);
        glTexCoord2f(1.0, 0.0);
        glVertex2f(1.0, 1.0);
        glTexCoord2f(1.0, 1.0);
        glVertex2f(1.0, 0.0);
    glEnd();

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    glDeleteTextures(1, &texColor);
    glDeleteFramebuffers(1, &fb);

为什么绿色和红色绘图不匹配?

Screenshot

2 个答案:

答案 0 :(得分:3)

你当然得到视口的两倍 - 因为你基本上应用了两次 - 视口在渲染到纹理时也很有效,所以你最终得到纹理中像素(x,y)的对象原点。然后,再次使用视口绘制该纹理,使四边形从窗口坐标中的(x,y)开始,并且纹理中的对象进一步移开 - 两个偏移累积。

在渲染到纹理时,只需将视口设置为从原点开始。

答案 1 :(得分:1)

如果您width() == w函数中的height() == hwh& resize值,则您的纹理(和FBO)大小不同从您的视口大小。明确地说,您的视口为(w-100) * (h-100),而您的纹理为(w-150) * (h-150)