2009-06-21 26 views
32

Ho riscontrato problemi nel trovare codice semplice per il rendering di una scena in una trama in OpenGL ES (in particolare per iPhone, se questo è importante). Sono interessato a sapere quanto segue:OpenGL ES Render to Texture

  1. Come si esegue il rendering di una scena su una trama in OpenGL ES?
  2. Quali parametri devono essere utilizzati per creare una trama che può essere una destinazione di rendering in OpenGL ES?
  3. Ci sono implicazioni nell'applicare questa trama resa ad altri primitivi?

risposta

43

Ecco come lo sto facendo.

ho definire una variabile di struttura (io uso di classe di Apple Texture2D, ma è possibile utilizzare un ID OpenGL consistenza se volete), e un frame buffer:

Texture2d * texture; 
GLuint textureFrameBuffer; 

Poi ad un certo punto, creo la trama , frame buffer e allegare il renderbuffer. Questo è sufficiente farlo una volta:

texture = [[Texture2D alloc] initWithData:0 
          pixelFormat:kTexture2DPixelFormat_RGB888 
          pixelsWide:32 
          pixelsHigh:32 
          contentSize:CGSizeMake(width, height)]; 

// create framebuffer 
glGenFramebuffersOES(1, &textureFrameBuffer); 
glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer); 

// attach renderbuffer 
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, texture.name, 0); 

// unbind frame buffer 
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 

Ogni volta che voglio rendere alla trama, lo faccio:

glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer); 

... 
// GL commands 
... 

glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 

tua domanda 3, il gioco è fatto, è possibile utilizzare la texture come se è qualsiasi altra trama.

+0

Marco, sai quanta overhead è coinvolta nel mantenere un framebuffer e renderbuffer per ogni texture in cui devi renderizzare? Ho diverse trame di grandi dimensioni in cui la mia app deve attingere e sto collegando in modo diverso a un unico framebuffer "extra" utilizzando glFramebufferTexture2DOES. Sarebbe meglio tenere un framebuffer separato per ciascuno? –

+0

Potresti modificare il tuo codice in modo tale che initWithData: ... la chiamata si adatti senza scorrere? – nornagon

+0

Ok, modificato, sembra migliore ora. –

9

Per rendere la scena a una trama è necessario utilizzare un framebuffer associato a una trama. Ecco un metodo che ho creato per semplificare:

void glGenTextureFromFramebuffer(GLuint *t, GLuint *f, GLsizei w, GLsizei h) 
{ 
    glGenFramebuffers(1, f); 
    glGenTextures(1, t); 

    glBindFramebuffer(GL_FRAMEBUFFER, *f); 

    glBindTexture(GL_TEXTURE_2D, *t); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *t, 0); 

    GLuint depthbuffer; 
    glGenRenderbuffers(1, &depthbuffer);  
    glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer); 

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
    if(status != GL_FRAMEBUFFER_COMPLETE) 
     NSLog(@"Framebuffer status: %x", (int)status); 
} 

È possibile creare il frame buffer e la consistenza facilmente:

GLuint _texture, _framebuffer; 
GLsizei w,h; 
float scale = [UIScreen mainScreen].scale; 
w = self.view.bounds.size.width * scale; 
h = self.view.bounds.size.height * scale; 
glGenTextureFromFramebuffer(&_texture, &_framebuffer, w, h); 

È possibile poi utilizzare _framebuffer per rendere la scena in _texture nel vostro progetto metodo:

glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); 
//draw here the content you want in the texture 
//_texture is now a texture with the drawn content 

//bind the base framebuffer 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 
//or if you use GLKit 
[view bindDrawable]; 
//draw normaly 

Ora puoi fare ciò che vuoi con la trama. Se vuoi fare qualche post processing (sfocatura, fioritura, ombra, ecc ...) puoi farlo!

+0

Ciao, da dove hai preso '_renderToTextureBuffer'? –

+0

_renderToTextureBuffer è _framebuffer lo correggo, sry – Anthony

+0

Cool, questo è quello che stavo pensando. Hai questo in un esempio di lavoro? Proverò ad aggiungere questo al mio codice (di nuovo), ma non sono sicuro di come disegnare nella trama '// disegna qui il contenuto che vuoi nella texture 'Posso farlo con i VBO e' glDrawArrays() ' ? –