2010-11-24 33 views
15

Je voudrais rendre une scène à une texture initialement vide. Pour ce faire, j'utilise un objet Framebuffer auquel j'attache une texture 2d vide et un buffer de profondeur. Après la mise en place, comme pour les tests, je dessine un quad simple dans la scène. Chaque sommet a une couleur différente, donc j'attends finalement un quadrilatère interpolé par la couleur dans la texture. J'utilise ensuite cette texture contenant le quad et le mappe sur un autre quad. Donc, objectivement, j'ai un quad dans mon framebuffer par défaut qui a une texture contenant un quad coloré. J'espère que ce n'est pas trop déroutant ...OpenGL: Problème avec Render to Texture et objet Framebuffer

De toute façon, il me manque quelque chose ici, car ce que je reçois n'est rien d'autre qu'une texture grise. J'ai fondamentalement suivi les instructions this qui sont assez simples. Cependant, je n'arrive pas à comprendre ce qui me manque ici. Je serais reconnaissant si quelqu'un pouvait me donner un indice.

Merci Walter


Ceci est le code j'ai à ce jour: // créer l'objet de mémoire tampon de trame 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(); 

Résultat attendu:

  • Texture avec un quad de couleur sur un fond jaune
  • Cette texture est mis en correspondance sur un autre quad

Résultat réel:

  • Une texture grise
  • La texture peut être mis en correspondance avec succès sur l'autre quad

EDIT: Je manqué parler de la gestion des erreurs. C'est comme ça que je vérifie les erreurs. Il comprend les cas supplémentaires suggérés par Paul S. Merci pour ça.

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: Ceci est la méthode que j'utilise pour vérifier les erreurs 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

Quelle version d'OpenGL utilisez-vous? Les fonctions de l'objet framebuffer sont sans aucun suffixe fournisseur, donc je suis enclin à croire 3.0 - 3.3, mais je me méfie. Souvenez-vous qu'il existe des différences majeures entre les fonctionnalités de base d'OpenGL 3, GL_ARB_framebuffer_object et GL_EXT_framebuffer_object. Ils ne sont pas égaux! Aussi, appeler simplement glCheckFramebufferStatus() n'est pas suffisant. Assurez-vous de gérer également les erreurs OpenGL normales avec glGetError() –

+0

Votre hypothèse est correcte. J'utilise OpenGL 3.1. J'aurais dû le mentionner plus tôt. Merci pour l'astuce glGetError(). J'ai inclus cela dans mon code. J'ai ajouté la méthode aux listes de codes ci-dessus. Je pense que je vérifie toutes les erreurs éventuellement lancées par OpenGL 3.1, n'est-ce pas? J'ai vérifié l'ensemble du code pour les erreurs, mais il semble y avoir rien. – Walter

+2

Je suspecte de plus en plus que ce n'est pas l'application qui contient des erreurs, mais il peut y avoir une bibliothèque ou une extension manquante ou mal configurée, respectivement. Je ne suis pas sûr que ce soit de l'aide, mais c'est mon système: Windows 7, OpenGL 3.1, NVidia Quadro FX 3700. J'utilise GLEW 1.5.7, SDL 1.2, GL_EXT_framebuffer_object, GL_EXT_texture3D, GL_ARB_draw_buffers ... Les idées sont appréciées. – Walter

Répondre

1

Je me attends à ce qui se passe soit:

  • Vous rendu d'un mip dépeuplé -map niveau. Vous appelez glGenerateMipmap bien avant que vous ayez rendu le quad coloré. Essayez simplement GL_NEAREST pour le moment.
  • Vous obtenez une erreur lorsque vous créez votre objet framebuffer. Si cela arrive, votre rendu tombera dans un trou noir.

Voici un extrait de code que j'utilise pour vérifier l'état du tampon d'image. Il utilise la version EXT des FBO et est en Objective-C (d'où les @ "" chaînes), mais cela devrait être évident. Il vient après que j'ai appelé 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; 
    } 

Le problème est probablement le tampon de profondeur, car les conducteurs ont tendance à être très pointilleux à ce sujet. Pour ce test, vous n'avez pas besoin de profondeur, vous pouvez donc supprimer le contenu du tampon de rendu si cela cause des problèmes.

Une autre note, la texture n'a pas besoin d'être liée et active pour le rendu. Vous pouvez reporter ce code jusqu'à ce que vous vouliez l'utiliser pour rendre votre image finale.

+0

Désolé, j'ai manqué le traitement des erreurs dans le code ci-dessus. Je vérifie l'état du framebuffer. Cependant, j'ai pensé que je ne vérifie pas toutes les erreurs possibles. J'ai oublié de vérifier pour GL_FRAMEBUFFER_INCOMPLETE_DIMENSION_EXT et GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT qui sont bien sûr très importants. J'ai ajouté ces deux cas. Malheureusement, cela ne fait aucune différence et ne renvoie pas de message d'erreur. J'ai ajouté mon erreur en vérifiant le code ci-dessus. – Walter

+0

J'ai essayé GL_NEAREST au lieu de GL_LINEAR et omis la génération de mipmap. Ne fonctionne pas non plus. – Walter

+0

Maintenant, je n'active et ne lie pas les textures avant le mappage de texture réel. Toujours le même ... – Walter

4

Bizarre, à la fois glDrawBuffers et glFramebufferTexture2D ne ressemble pas aux spécifications! Le premier prend un tableau de GLenum, et pas un GLenum (vérifiez les avertissements: il peut être casté silencieusement!). Et le second ne prend que 4 arguments sur les spécifications!

EDIT:

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

Bonne prise.Le glFramebufferTexture2D est parce que la version EXT a 5 arguments, et la version Core a 4. La GL_TEXTURE_2D n'est pas nécessaire. –

+0

Eh bien, il est vrai que glFramebufferTexture2D ne prend que 4 arguments. Mais si je omets le "GL_TEXTURE_2D", je ne peux pas compiler l'application. erreur C2198: 'PFNGLFRAMEBUFFERTEXTURE2DPROC': trop peu d'arguments pour l'appel Je suppose qu'il y a plus faux/manquant. Je vais vérifier si j'ai réellement la dernière version de glew.h – Walter

+0

Je suis un peu confus au sujet de l'autre déclaration. N'est-ce pas "glDrawBuffers (1, GL_GL_COLOR_ATTACHMENTn)" parfaitement bien? Quote: "La valeur de sortie du fragment shader est écrite dans la nième fixation de couleur du framebuffer actuel, n peut aller de 0 à la valeur de GL_MAX_COLOR_ATTACHMENTS." – Walter

5

Je résolu cette question.

Alors voici ce que je fais. Peut-être qu'il existe une meilleure façon de le faire, mais cela fonctionne parfaitement bien maintenant. N'hésitez pas à suggérer des adaptations ...

Je ne liste pas la gestion des erreurs ci-dessous. Vous pouvez trouver cela plus haut dans cette question.


// 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! 

Comme vous le voyez, je me suis débarrassé de la fixation de tampon de profondeur. Je me suis dit que je n'en avais pas vraiment besoin pour ma tâche. Dès que j'ai pu réellement dessiner des choses, j'ai ajouté la projection orthogonale. Sans cela, le dessin à un résultat de texture dans les images assez maladroits ...

Espérons que cela est utile pour quelqu'un là-bas Walter

+0

On dirait que c'était la pièce jointe du tampon de profondeur, mais je m'attendrais à ce que cela donne une erreur si c'était le cas. –

+4

vous devriez utiliser malloc pour les grands tableaux, sinon vous empilerez littéralement le débordement;) –