views:

512

answers:

1

Using a couple of posts here in StackOverflow, I created what is supposed to be a simple render-to-texture using a framebuffer.

The problem here is that it's not working. Something is broken in the mix, as my final texture is just a white square. I am not getting any gl errors whatsoever. Here is my code.

Declare instance variables.

GLuint texture;
GLuint textureFrameBuffer;

Generate the texture and framebuffer.

 glGetError();

 //Generate the texture that we will draw to (saves us a lot of processor).
 glEnable(GL_TEXTURE_2D);
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

 // Use OpenGL ES to generate a name for the texture.
 // Pass by reference so that our texture variable gets set.
 glGenTextures(1, &texture);

 // Bind the texture name. 
 glBindTexture(GL_TEXTURE_2D, texture);

 // Specify a 2D texture image, providing a pointer to the image data in memory.
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

 //Create a frame buffer to draw to. This will allow us to directly edit the texture.
 GLint oldFBO;
 glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldFBO);
 glGenFramebuffersOES(1, &textureFrameBuffer);
 glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);
 glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, texture, 0);

 glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldFBO);

 GLenum err = glGetError();
 if (err != GL_NO_ERROR)
 {
  NSLog(@"Error on framebuffer init. glError: 0x%04X", err);
 }

Draw a big string into the framebuffer.

glGetError();

GLint oldFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldFBO);

//Bind our frame buffer.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);

//Clear out the texture.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//Draw the letters to the frame buffer. (calls glDrawArrays a bunch of times, binds various textures, etc.) Does everything in 2D.
[self renderDialog:displayString withSprite:displaySprite withName:displaySpriteName];

//Unbind the frame buffer.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldFBO);

GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
 NSLog(@"Error on string creation. glError: 0x%04X", err);
}

Draw it.

 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

 glGetError();

 //Draw the text.
 [EAGLView enable2D];

 //Push the matrix so we can keep it as it was previously.
 glPushMatrix();

 //Store the coordinates/dimensions from the rectangle.
 float x = 0;
 float y = [Globals getPlayableHeight] - dialogRect.size.height;
 float w = [Globals getPlayableWidth];
 float h = dialogRect.size.height;

 // Set up an array of values to use as the sprite vertices.
 GLfloat vertices[] =
 {
  x,  y,
  x,  y+h,
  x+w, y+h,
  x+w, y
 };

 // Set up an array of values for the texture coordinates.
 GLfloat texcoords[] =
 {
  0,   0,
  0,   h / 128,
  w / 512, h / 128,
  w / 512, 0
 };

 //Render the vertices by pointing to the arrays.
 glVertexPointer(2, GL_FLOAT, 0, vertices);
 glTexCoordPointer(2, GL_FLOAT, 0, texcoords);

 // Set the texture parameters to use a linear filter when minifying.
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

 //Allow transparency and blending.
 glEnable(GL_BLEND);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

 //Enable 2D textures.
 glEnable(GL_TEXTURE_2D);

 //Bind this texture.
 [EAGLView bindTexture:texture];

 //Finally draw the arrays.
 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

 //Restore the model view matrix to prevent contamination.
 glPopMatrix();

 GLenum err = glGetError();
 if (err != GL_NO_ERROR)
 {
  NSLog(@"Error on draw. glError: 0x%04X", err);
 }

Any external things I called work just fine in other contexts. Any ideas? I know almost nothing about framebuffers, so any help troubleshooting would be great.

+3  A: 

Texture parameters are set on a per-texture basis. The code you posted appears to be setting GL_TEXTURE_MIN_FILTER before the texture you’re rendering to has been created or bound. If you’re not setting the filter anywhere else, and you haven’t specified texture images for the remaining levels, your texture is likely incomplete, which is why you’re getting white.

For future reference, the absence of GL errors after framebuffer setup does not mean that the framebuffer is usable for rendering. You should also check that the framebuffer is complete by calling glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) and verifying that GL_FRAMEBUFFER_COMPLETE_OES is returned.

Pivot
I'll give that a try. I actually had the completion check before and it was true - I just didn't include it in the code above. If this framebuffer is complete I assume that doesn't necessarily mean everything is going to work, correct? Also, I'm not sure I follow you about GL_TEXTURE_MIN_FILTER - I set it before I call glGenTextures (see the first code block).
Eli
Each texture has its own minification/magnification functions and wrap modes. Calls to glTexParameterf only affect the texture that is currently bound when the function is called. If you want to change the minification function for the texture you’re rendering to, you need to call glTexParameterf after creating and binding the texture.It sounds like framebuffer completeness isn’t relevant for your particular case, but it’s a good thing to keep in mind for more exotic framebuffer object configurations.
Pivot