2010-11-24 22 views
15

Me gustaría renderizar una escena con una textura inicialmente vacía. Para hacerlo, utilizo un Objeto Framebuffer al que adjunto una textura 2d vacía y un buffer de profundidad. Después de la configuración, como para las pruebas, dibujo un cuadrángulo simple en la escena. Cada vértice tiene un color diferente, así que eventualmente espero un cuadrante interpolado por colores en la textura. Luego uso esa textura que contiene el quad y la mapeo en otro quad. Así que, evetually, tengo un quad en mi Framebuffer predeterminado que tiene una textura que contiene un quad de color. Espero que esto no sea demasiado confuso ...OpenGL: Problemas con Renderizar a Textura y Objeto Framebuffer

De todos modos, me falta algo aquí, ya que lo que obtengo no es más que una textura gris. Básicamente seguí las instrucciones this que son bastante sencillas. Sin embargo, no puedo entender lo que me falta aquí. Estaría agradecido si alguien pudiera darme una pista.

Gracias Walter


este es el código que tengo hasta ahora: // crear el objeto memoria intermedia de trama glGenFramebuffers (1, & frameBufferObject);

// create depth buffer 
glGenRenderbuffers(1, &depthAttachment); 

// create empty texture 
int width = 512; 
int height = 512; 
int numberOfChannels = 3; 
GLuint internalFormat = GL_RGB; 
GLuint format = GL_RGB; 

unsigned char* texels = new unsigned char[width * height * numberOfChannels]; 

glGenTextures(1, &texture); 
glBindTexture(GL_TEXTURE_2D, texture); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, texels); 

glGenerateMipmap(GL_TEXTURE_2D); 

delete[] texels; 
texels = NULL; 

// activate & bind empty texture 
glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, texture); 

// attach empty texture to framebuffer object 
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); 

// define render targets (empty texture is at GL_COLOR_ATTACHMENT0) 
glDrawBuffers(1, GL_COLOR_ATTACHMENT0); 

// attach depth buffer 
glBindRenderbuffer(GL_RENDERBUFFER, depthAttachment); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthAttachment); 

// use framebuffer object 
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); 

// draw the colored quad into the initially empty texture 
glDisable(GL_CULL_FACE); 
glDisable(GL_DEPTH_TEST); 

// store attibutes 
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// reset viewport 
glViewport(0, 0, width, height); 

// make background yellow 
glClearColor(1.0f, 1.0f, 0.0f, 1.0f); 

// draw quad into texture attached to frame buffer object 
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 
glBegin(GL_QUADS); 
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glVertex2f(0.0f, 100.0f); // top left 
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); // bottom left 
    glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glVertex2f(100.0f, 0.0f); // bottom right 
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glVertex2f(100.0f, 100.0f); // top right 
glEnd(); 

// restore attributes 
glPopAttrib(); 

glEnable(GL_DEPTH_TEST); 
glEnable(GL_CULL_FACE); 

// use default framebuffer 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

// clear default framebuffer 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// draw the scene 
glMatrixMode(GL_MODELVIEW); 
glPushMatrix(); 
glLoadIdentity(); 

glColor4f(1.0, 1.0, 1.0, 1.0); 

// begin texture mapping 
glEnable(GL_TEXTURE_2D); 
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 

glBegin(GL_QUADS); 
    glNormal3d(0.0f, 0.0f, 1.0f); 
    glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 50.0f, -100.0f); // top left 
    glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, -100.0f);  // bottom left 
    glTexCoord2f(1.0f, 1.0f); glVertex3f(50.0f, 0.0f, -100.0f); // bottom right 
    glTexCoord2f(1.0f, 0.0f); glVertex3f(50.0f, 50.0f, -100.0f); // top right 
glEnd(); 

glDisable(GL_TEXTURE_2D); 

glPopMatrix(); 

// swap buffers (I forgot to mention that I use SDL) 
SDL_GL_SwapBuffers(); 

Resultado esperado:

  • Textura con un quad de color sobre un fondo amarillo
  • que la textura se mapea en otro quad

Resultado real:

  • Una textura gris
  • textura éxito puede ser asignada por el otro quad

EDIT: He echado de menos mencionar el tratamiento de errores. Así es como compruebo los errores. Incluye los casos adicionales sugeridos por Paul S. Gracias por eso.

GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
switch(status) { 
    case GL_FRAMEBUFFER_COMPLETE: 
     return; 
     break; 

case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 
    throw FramebufferIncompleteException("An attachment could not be bound to frame buffer object!"); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 
    throw FramebufferIncompleteException("Attachments are missing! At least one image (texture) must be bound to the frame buffer object!"); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: 
    throw FramebufferIncompleteException("The dimensions of the buffers attached to the currently used frame buffer object do not match!"); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: 
    throw FramebufferIncompleteException("The formats of the currently used frame buffer object are not supported or do not fit together!"); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: 
    throw FramebufferIncompleteException("A Draw buffer is incomplete or undefinied. All draw buffers must specify attachment points that have images attached."); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: 
    throw FramebufferIncompleteException("A Read buffer is incomplete or undefinied. All read buffers must specify attachment points that have images attached."); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: 
    throw FramebufferIncompleteException("All images must have the same number of multisample samples."); 
    break; 

case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS : 
    throw FramebufferIncompleteException("If a layered image is attached to one attachment, then all attachments must be layered attachments. The attached layers do not have to have the same number of layers, nor do the layers have to come from the same kind of texture."); 
    break; 

case GL_FRAMEBUFFER_UNSUPPORTED: 
    throw FramebufferIncompleteException("Attempt to use an unsupported format combinaton!"); 
    break; 

default: 
    throw FramebufferIncompleteException("Unknown error while attempting to create frame buffer object!"); 
    break; 
} 

EDIT 2: Este es el método que utilizo para comprobar si hay errores GL-

checkForGLErrors(string sourceFile, int line) 
    GLenum error = glGetError(); 
    ostringstream o; 

    switch(error) { 
     case GL_NO_ERROR: 
      return; 
      break; 

     case GL_INVALID_ENUM: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Invalid enum!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     case GL_INVALID_VALUE: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Invalid value!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     case GL_INVALID_OPERATION: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Invalid operation!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     case GL_STACK_OVERFLOW: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Stack overflow!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     case GL_STACK_UNDERFLOW: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Stack underflow!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     case GL_OUT_OF_MEMORY: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Out Of memory!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     case GL_TABLE_TOO_LARGE: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Table too large!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 

     default: 
      o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Unknown error!"<<endl; 
      throw GLErrorException(o.str()); 
      break; 
    } 
} 
+0

¿Qué versión de OpenGL utiliza? Las funciones de objeto framebuffer no tienen ningún sufijo de proveedor, por lo que estoy dispuesto a creer en 3.0 - 3.3, pero soy sospechoso. Recuerde que existen grandes diferencias entre la funcionalidad básica de OpenGL 3, GL_ARB_framebuffer_object y GL_EXT_framebuffer_object. ¡No son iguales! Además, llamar simplemente glCheckFramebufferStatus() no es suficiente. Asegúrese de manejar los errores normales de OpenGL también con glGetError() –

+0

Su suposición es correcta. Estoy usando OpenGL 3.1. Debería haber mencionado eso antes. Gracias por la sugerencia glGetError(). Incluí eso en mi código. Agregué el método a las listas de códigos de arriba. Creo que verifico todos los errores posiblemente disparados por OpenGL 3.1, ¿no? Revisé todo el código para detectar errores, pero parece que no hay nada. – Walter

+2

Tengo cada vez más sospechas de que no es la aplicación la que contiene errores, pero puede haber alguna biblioteca o extensión faltante o mal configurada, respectivamente. No estoy seguro si eso es de alguna ayuda, pero este es mi sistema: Windows 7, OpenGL 3.1, NVidia Quadro FX 3700. Estoy usando GLEW 1.5.7, SDL 1.2, GL_EXT_framebuffer_object, GL_EXT_texture3D, GL_ARB_draw_buffers ... Any ideas son apreciadas – Walter

Respuesta

1

espero que lo que está sucediendo, ya sea:

  • estás reproduciendo desde un MIP despoblado nivel de mapa Estás llamando a glGenerateMipmap mucho antes de que hayas renderizado el cuadrángulo coloreado. Solo prueba GL_NEAREST por ahora.
  • Aparecerá un error al crear su objeto framebuffer. Si eso ocurre, tu renderizado caerá en un agujero negro.

Aquí hay un fragmento de código que utilizo para verificar el estado del búfer de cuadros. Utiliza la versión EXT de FBOs y está en Objective-C (de ahí las cadenas @ ""), pero debería ser obvio. Viene después de haber llamado a glBindFramebuffer, glFramebufferTexture2D & glDrawBuffers.

GLenum framebufferStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 

    switch (framebufferStatus) { 
     case GL_FRAMEBUFFER_COMPLETE_EXT: break; 
     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: 
      NSLog(@"Framebuffer Object %d Error: Attachment Point Unconnected", i); 
      break; 
     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: 
      NSLog(@"Framebuffer Object %d Error: Missing Attachment", i); 
      break; 
     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: 
      NSLog(@"Framebuffer Object %d Error: Dimensions do not match", i); 
      break; 
     case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: 
      NSLog(@"Framebuffer Object %d Error: Formats", i); 
      break; 
     case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: 
      NSLog(@"Framebuffer Object %d Error: Draw Buffer", i); 
      break; 
     case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: 
      NSLog(@"Framebuffer Object %d Error: Read Buffer", i); 
      break; 
     case GL_FRAMEBUFFER_UNSUPPORTED_EXT: 
      NSLog(@"Framebuffer Object %d Error: Unsupported Framebuffer Configuration", i); 
      break; 
     default: 
      NSLog(@"Framebuffer Object %d Error: Unkown Framebuffer Object Failure", i); 
      break; 
    } 

El problema es probable que sea el buffer de profundidad, ya que los conductores tienden a ser bastante exigente con esto. Para esta prueba no necesitas profundidad para que puedas eliminar el material del buffer de renderización si está causando problemas.

Otra nota, la textura no necesita estar ligada y activa para renderizarla. Puede posponer ese código hasta que quiera usarlo para representar su imagen final.

+0

Lo siento, me perdí el manejo de errores en el código anterior. Verifico el estado del framebuffer. Sin embargo, pensé que no verifico todos los posibles errores. Olvidé comprobar GL_FRAMEBUFFER_INCOMPLETE_DIMENSION_EXT y GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT que, por supuesto, son muy importantes. Agregué esos dos casos. Lamentablemente, eso no marcó la diferencia ni devuelve un mensaje de error. He agregado mi error al verificar el código anterior. – Walter

+0

Intenté GL_NEAREST en lugar de GL_LINEAR y omití la generación de mipmap. Tampoco funciona – Walter

+0

Ahora tampoco activo y ato las texturas antes de la asignación de textura real. Sigue igual ... – Walter

4

extraño, tanto glDrawBuffers y glFramebufferTexture2D no se parecen a las especificaciones! El primero toma una matriz de GLenum, y no un GLenum (consulte las advertencias: ¡se puede convertir silenciosamente!). ¡Y el segundo solo toma 4 argumentos en las especificaciones!

EDIT:

void glDrawBuffers(GLsizei n, const GLenum * bufs); 
+0

Buena captura.El glFramebufferTexture2D uno se debe a que la versión EXT tiene 5 argumentos, y la versión Core tiene 4. El GL_TEXTURE_2D no es necesario. –

+0

Bueno, es cierto que glFramebufferTexture2D toma solo 4 argumentos. Pero si omito el "GL_TEXTURE_2D", no puedo compilar la aplicación. error C2198: 'PFNGLFRAMEBUFFERTEXTURE2DPROC': muy pocos argumentos para la llamada Supongo que faltan algunos más. Voy a verificar si realmente tengo la última versión de glew.h – Walter

+0

. Estoy un poco confundido sobre la otra afirmación. No es "glDrawBuffers (1, GL_GL_COLOR_ATTACHMENTn)" perfectamente bien? Cita: "El valor de salida del sombreador de fragmentos está escrito en la enésima conexión de color del framebuffer actual. N puede variar desde 0 hasta el valor de GL_MAX_COLOR_ATTACHMENTS". – Walter

5

que resuelve este problema.

Así que aquí está lo que hago. Tal vez hay alguna forma mejor/más inteligente de hacerlo, pero funciona perfectamente bien ahora. No dude en sugerir adaptaciones ...

No enumere el manejo de errores debajo. Puedes encontrar eso más arriba en esta pregunta.


// create frame buffer object 
glGenFramebuffers(1, frameBufferObject); 

// create empty texture 
int width = 512; 
int height = 512; 
int numberOfChannels = 3; 
GLuint internalFormat = GL_RGB8; 
GLuint format = GL_RGB; 

unsigned char* texels = new unsigned char[width * height * numberOfChannels]; 

glGenTextures(1, &texture); 
glBindTexture(GL_TEXTURE_2D, texture); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, texels); 

delete[] texels; 
texels = NULL; 

// draw the colored quad into the initially empty texture 
glDisable(GL_CULL_FACE); 
glDisable(GL_DEPTH_TEST); 

// store attibutes 
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// reset viewport 
glViewport(0, 0, width, height); 

// setup modelview matrix 
glMatrixMode(GL_MODELVIEW); 
glPushMatrix(); 
glLoadIdentity(); 

// setup projection matrix 
glMatrixMode(GL_PROJECTION); 
glPushMatrix(); 
glLoadIdentity(); 

// setup orthogonal projection 
glOrtho(-width/2, width/2, -height/2, height/2, 0, 1000); 

// bind framebuffer object 
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); 

// attach empty texture to framebuffer object 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); 

// check framebuffer status (see above) 

// bind framebuffer object (IMPORTANT! bind before adding color attachments!) 
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); 

// define render targets (empty texture is at GL_COLOR_ATTACHMENT0) 
glDrawBuffers(1, GL_COLOR_ATTACHMENT0); // you can of course have more than only 1 attachment 

// activate & bind empty texture 
// I figured activating and binding must take place AFTER attaching texture as color attachment 
glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, texture); 

// clear color attachments 
glClear(GL_COLOR_BUFFER_BIT); 

// make background yellow 
glClearColor(1.0f, 1.0f, 0.0f, 1.0f); 

// draw quad into texture attached to frame buffer object 
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 
glBegin(GL_QUADS); 
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glVertex2f(0.0f, 100.0f); // top left 
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); // bottom left 
    glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glVertex2f(100.0f, 0.0f); // bottom right 
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glVertex2f(100.0f, 100.0f); // top right 
glEnd(); 

// reset projection matrix 
glMatrixMode(GL_PROJECTION); 
glPopMatrix(); 

// reset modelview matrix 
glMatrixMode(GL_MODELVIEW); 
glPopMatrix(); 

// restore attributes 
glPopAttrib(); 

glEnable(GL_DEPTH_TEST); 
glEnable(GL_CULL_FACE); 

// I guess, now it's OK to create MipMaps 

// draw the scene 
glMatrixMode(GL_MODELVIEW); 
glPushMatrix(); 
glLoadIdentity(); 

glColor4f(1.0, 1.0, 1.0, 1.0); 

// begin texture mapping 
glEnable(GL_TEXTURE_2D); 
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 

    // normal faces "camera" 
    glNormal3d(0.0f, 0.0f, 1.0f); 

    glBegin(GL_QUADS); 
     glNormal3d(0.0f, 0.0f, 1.0f); 
     glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 50.0f, -100.0f); // top left 
     glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, -100.0f);  // bottom left 
     glTexCoord2f(1.0f, 1.0f); glVertex3f(50.0f, 0.0f, -100.0f); // bottom right 
     glTexCoord2f(1.0f, 0.0f); glVertex3f(50.0f, 50.0f, -100.0f); // top right 
    glEnd(); 

glDisable(GL_TEXTURE_2D); 

glPopMatrix(); 

// finish rendering 
glFlush(); 
glFinish(); 

// swap buffers (I forgot to mention that I use SDL) 
SDL_GL_SwapBuffers(); 

// do the clean up! 

Como se ve, que se deshizo del accesorio buffer de profundidad. Pensé que realmente no lo necesitaba para mi tarea. Tan pronto como pude dibujar las cosas, agregué la proyección ortogonal. Sin eso, llegando a una textura de resultados en imágenes bastante incómodas ...

Hope esto es útil para alguien por ahí Walter

+0

Suena como si fuera el archivo adjunto del búfer de profundidad, pero esperaría que proporcionara un error si fuera así. –

+4

debe usar malloc para arreglos grandes, de lo contrario literalmente se acumulará desbordamiento;) –

Cuestiones relacionadas