Objeto framebuffer con textura flotante sujeta valores
He comprobado esta pregunta similar, pero las sugerencias no resolvieron mi problema:Baja precisión y sujeción al escribir en coma flotante FBO.
Estoy renderizando una imagen flotante utilizando un objeto framebuffer como objetivo de renderizado. Sin embargo, los valores leídos por glReadPixels se fijan entre 0 y 1. Si intento renderizar mi imagen utilizando valores normalizados en este rango, funciona, pero los valores fuera de este rango se fijan en 1 o 0. Sigue algunas partes del código.
Así es como creé la textura que adjunté al 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);
Cómo lo leí después de pintar:
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0, 0, ResX, ResY, GL_RGB, GL_FLOAT, data);
He pintado un triángulo en la imagen usando
glColor3f(0.5f, 2.0f, -0.5f);
Y los valores de píxel aparecen como(0.5f, 1.0f, 0.0f) en el buffer de lectura.
¿Cómo puedo devolver valores fuera de este rango?
Sigue una versión simplificada de mi código (conservé el búfer de profundidad porque lo uso en el original):
PD. Corrigí el código abajo basado en la respuesta. Ahora funciona.
#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;
}