Objeto Framebuffer com valores de grampos de textura flutuante
Eu verifiquei essa questão semelhante, mas as sugestões não resolveram o meu problema:Baixa precisão e fixação ao escrever em ponto flutuante FBO.
Eu estou renderizando uma imagem flutuante usando um objeto framebuffer como destino de renderização. No entanto, os valores lidos por glReadPixels são fixados entre 0 e 1. Se eu tentar renderizar minha imagem usando valores normalizados nesse intervalo, isso funciona, mas valores fora desse intervalo são limitados a 1 ou 0. Segue algumas partes do código.
Aqui está como eu criei a textura que eu anexei ao 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);
Como eu li depois de pintar:
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0, 0, ResX, ResY, GL_RGB, GL_FLOAT, data);
Eu pintei um triângulo na imagem usando
glColor3f(0.5f, 2.0f, -0.5f);
E os valores de pixel aparecem como(0,5f, 1,0f, 0,0f) no buffer de leitura.
Como posso retornar valores fora desse intervalo?
Segue uma versão simplificada do meu código (eu mantive o buffer de profundidade porque eu o uso no original):
Ps. Eu corrigi o código abaixo com base na resposta. Funciona agora.
#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;
}