使用浮点纹理的帧缓冲对象会限制数值。

3
我查看了类似的问题,但是那些建议并没有解决我的问题:Low precision and clamping when writing to floating point FBO
我正在使用帧缓存对象作为渲染目标来渲染浮点图像。然而,由glReadPixels读取的值被夹在0和1之间。如果我尝试使用在这个范围内的归一化值来渲染我的图像,它可以工作,但是超出了这个范围的值将被夹在1或0。以下是代码的某些部分。
这是我创建附加到FBO的纹理的方式:
    glGenTextures(1, &color_tex); 
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, color_tex);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
        GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
        GL_NEAREST);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F_ARB, ResX, ResY, 0,
        GL_RGB, GL_FLOAT, NULL);

我画完之后如何读取它:

    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glReadPixels(0, 0, ResX, ResY, GL_RGB, GL_FLOAT, data);

我已经使用画三角形的功能在图像中绘制了一个三角形。
    glColor3f(0.5f, 2.0f, -0.5f);

像素值在读取缓冲区中显示为(0.5f, 1.0f, 0.0f)

如何将其范围外的值返回?

以下是我简化后的代码(保留深度缓冲区,因为它在原始代码中使用):

Ps. 根据答案,我已经更正了下面的代码。 现在可以工作了。

#include <GL/glew.h>
#include <GL/glut.h>

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#define WINDOW_WIDTH                    800
#define WINDOW_HEIGHT                   600

bool initGL(int argc, char *argv[])
{
    // initialize GLUT and glexts
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("FBO");

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed. */
        printf("Error: %s\n", glewGetErrorString(err));
        return 0;
    }

    if (!GLEW_EXT_framebuffer_object)
    {
        printf("Error: no extension GL_EXT_framebuffer_object.");
        return 0;
    }

    if (!GLEW_ARB_color_buffer_float)
    {
        printf("Error: no extension ARB_color_buffer_float.");
        return 0;
    }

    glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);
    glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE);
    glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);

    return 1;
}

void glErrorCheck()
{
    int errCode;
    if ((errCode = glGetError()) != GL_NO_ERROR)
    {
        printf("Failure in OpenGL %d", errCode);
        exit(0);
    }
}

bool renderFBO()
{

    GLenum status;
    GLuint color_tex, depth_rb, fb;

    int ResX, ResY;

    ResY = 4;
    ResX = 4;

    float *data;

    //gen renderbuffer
    glGenRenderbuffers(1, &depth_rb);
    glErrorCheck();
    // initialize depth renderbuffer
    glBindRenderbuffer(GL_RENDERBUFFER, depth_rb);
    glErrorCheck();
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, ResX,
            ResY);

    glErrorCheck();

    // make a texture
    glGenTextures(1, &color_tex);
    // initialize texture that will store the framebuffer image (BGRA type)
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, color_tex);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
            GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
            GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F_ARB, ResX, ResY, 0,
            GL_RGB, GL_FLOAT, NULL);
    glErrorCheck();

    // gen the framebuffer object
    glGenFramebuffers(1, &fb);
    // bind the framebuffer, fb, so operations will now occur on it
    glBindFramebuffer(GL_FRAMEBUFFER, fb);

    // bind this texture to the current framebuffer obj. as color_attachment_0
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_RECTANGLE_ARB, color_tex, 0);
    glErrorCheck();

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
            GL_RENDERBUFFER, depth_rb);
    glErrorCheck();

    //check framebuffer status
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
    {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        {
            printf("Failure in OpenGL Framebuffer %d", status);
            return 0;
        }
    }
    glErrorCheck();

    //render to GL_TEXTURE_2D
    glBindFramebuffer(GL_FRAMEBUFFER, fb);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0, 0, ResX, ResY);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, (float) ResX, 0.0, (float) ResY, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glBegin(GL_TRIANGLES);

    printf("Original color: %f %f %f\n", 0.5f, 2.0f, -0.5f);

    glColor3f(0.5f, 2.0f, -0.5f);

    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f((float) ResX, 0.0f, 0.0f);
    glVertex3f((float) ResX, (float) ResY, 0.0f);

    glEnd();

    // read framebuffer
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glErrorCheck();

    // allocate memory for texture data
    data = new float[ResX * ResY * 3];
    if (data == NULL)
    {
        printf("Out of memory\n");
        return false;
    }

    //glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
    glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);

    glReadPixels(0, 0, ResX, ResY, GL_RGB, GL_FLOAT, data);
    glErrorCheck();

    //print the last pixel of the buffer
    int i = ResX * ResY - 1;
    printf("Buffer color: %f %f %f\n", data[i], data[i + 1], data[i + 2]);

    // Re-enable rendering to the window
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glErrorCheck();

    //deallocate data
    delete[] data;

    //delete buffers
    glDeleteTextures(1, &color_tex);
    glDeleteRenderbuffers(1, &depth_rb);
    glDeleteFramebuffers(1, &fb);
    glErrorCheck();

    return true;
}

int main(int argc, char **argv)
{

    if (!initGL(argc, argv))
    {
        printf("Failure during GLUT/GLEXT initialization.");
        return 0;
    }

    if (!renderFBO())
        printf("Fail!\n");

    printf("End!\n");
    return 0;

}
2个回答

3
在你的initGL()函数中完成一整套glClampColor()操作。
glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);
glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE);
glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);

在我的系统上,我只需要使用 GL_CLAMP_VERTEX_COLOR

成功了!我已经将 GL_CLAMP_READ_COLOR 设置为 false 了。但是,和你一样,我只需要 GL_CLAMP_VERTEX_COLOR。非常感谢! - andrade

1

您必须使用glClampColor来指定您使用glReadPixels读取的颜色是否被夹在范围内。

请注意,这仅适用于颜色的读取。由片段着色器写入的内容始终不会被夹在范围内。


谢谢你的回答,Nicol。我已经尝试使用它了,但是我收到了这个错误:error: ‘glClampColor’ was not declared in this scope。我需要在我的代码中包含一些不同的头文件或库才能使用这个函数吗? - andrade
你是否正在检查ARB_color_buffer_float和/或核心GL版本,并加载相应的函数指针? - genpfault
@andrade:你在使用什麼載入OpenGL函數的工具 - Nicol Bolas
@NicolBolas:我通过使用glew来加载OpenGL函数解决了glClampColor声明的问题。然而,我仍然面临着夹紧结果相同的问题。我在上面的问题中粘贴了我的代码的简化版本。 - andrade
@genpfault,我也使用glew检查了ARB_color_buffer_float,它是存在的。 - andrade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接