opengl - 具有 float 纹理钳位值的帧缓冲区对象

标签 opengl framebuffer

我查过这个类似的问题,但建议并没有解决我的问题:Low precision and clamping when writing to floating point FBO .

我正在使用帧缓冲区对象作为渲染目标来渲染 float 图像。但是,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)

如何返回超出此范围的值?

遵循我的代码的简化版本(我保留了深度缓冲区,因为我在原始代码中使用了它):

附言。我根据答案更正了下面的代码。现在可以使用了。

#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;

}

最佳答案

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

关于opengl - 具有 float 纹理钳位值的帧缓冲区对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11211698/

相关文章:

c++ - 显示正交的 OpenGL 投影矩阵

iphone - 在 iPhone 上向屏幕外的 FBO 写入然后读取;在模拟器上有效但在设备上无效?

c++ - Qt:为什么我的图像背景在 LinuxFb 上是绿色的?

java glReadpixels 到 OpenCV mat

android - Framebuffer FBO 渲染到纹理非常慢,在 Android 上使用 OpenGL ES 2.0,为什么?

c++ - 如何在 Windows 中捕获 HDR 帧缓冲区?

c++ - 切割圆的底部

即使使用GL_NEAREST(GL_TEXTURE_2D),OpenGL仍会尝试模糊

macos - OpenGL Driver Monitor 表示纹理正在迅速增加。怎么找漏点?

c++ - 使用 SOILs OGL 函数和 OpenGL 加载纹理