Draw to offscreen renderbuffer in OpenGL ES (iPhone) - iphone

I'm trying to create an offscreen render buffer in OpenGL ES on the iPhone. I've created the buffer like this:
glGenFramebuffersOES(1, &offscreenFramebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, offscreenFramebuffer);
glGenRenderbuffersOES(1, &offscreenRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, offscreenRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, offscreenRenderbuffer);
But I'm confused on how to render the storage. Apple's documentation says to use the EAGLContext renderBufferStorage:fromDrawable: method, but this seems to only work for one render buffer (the main one being displayed). If I use the normal OpenGL function glRenderBufferStorageOES, then I can't seem to get it to display. Here's the code:
// this is in the initialization section:
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGB8_OES, backingWidth, backingHeight);
// and this is when I'm trying to draw to it and display it:
glBindFramebufferOES(GL_FRAMEBUFFER_OES, offscreenFramebuffer);
GLfloat vc[] = {
0.0f, 0.0f, 0.0f,
10.0f, 10.0f, 10.0f,
0.0f, 0.0f, 0.0f,
-10.0f, -10.0f, -10.0f,
};
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vc);
glDrawArrays(GL_LINES, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, offscreenRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
Doing it this way, nothing is displayed on the screen. However, if I switch out the references to "offscreen...Buffer" to the buffers that were created with the renderBufferStorage method, it works fine.
Any suggestions?

Since you can't use presentRenderbuffer with an offscreen FBO, you should associate it with a texture object using glFramebufferTexture2DOES, then render a textured full-screen quad.

#david good idea.. what you need to do is what #prideout said.. create a texture and render to it.. and use the texture on a quad every time. Make sure you draw to the texture only once, as in your case things are persistent.
- (void)setUpTextureBuffer
{
glGenFramebuffersOES(1, &texturebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturebuffer);
// create the texture
glGenTextures(1, &canvastexture);
glBindTexture(GL_TEXTURE_2D, canvastexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, canvastexture, 0);
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if(status != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(#"failed to make complete framebuffer object %x", status);
}
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glClearColor(1.0, 1.0, 1.0, 1.0);
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT);
}
//setTargetToTexture() function
glBindFramebufferOES(GL_FRAMEBUFFER_OES, tbuffer);
glBindTexture(GL_TEXTURE_2D, allbrushes);
glViewport(0, 0, 512, 512);
//reset pointers after finishing drawing to textures
glViewport(0, 0, BWIDTH, BHEIGHT);
glVertexPointer(2, GL_FLOAT, 0, canvas); //canvas vertices
glTexCoordPointer(2, GL_FLOAT, 0, texels);
glBindTexture(GL_TEXTURE_2D, boundtexture); //bind to the texture which is the special render target
glBindFramebufferOES(GL_FRAMEBUFFER_OES, fbuffer); //back to normal framebuffer

You cannot present an normal renderbuffer (created with glRenderbufferStorage), it is always offscreen. presentRenderbuffer: can only be used for renderbuffers that were created using the renderbufferStorage:fromDrawable:. If you checked the return value of that presentRenderbuffer:, you should observe it failing.
What are you trying to do?

Related

iOS openGL ES 1.0, failed to render Texture2D

I use the openGL ES 1.0. After decoding stream data, it is changed to RGBA bits. And then I transfer RGBA bytes to 'renderer' method with parameter.
the renderer method is called by each frame routines. Because RGBA bytes are changed every times.
But it doesn't draw any picture frames. Just the white rectangle and background gray color are displayed. What is the problem?
[initialize]
- (id <ESRenderer>) init
{
if (self = [super init])
{
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context])
{
[self release];
return nil;
}
// Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
glGenFramebuffersOES(1, &defaultFramebuffer);
glGenRenderbuffersOES(1, &colorRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &frameTexture);
glBindTexture(GL_TEXTURE_2D, frameTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, frameTexture, 0);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
}
return self;
}
[Renderer method. It is called by outside per each frames]
static const GLfloat verticesForGL_TRIANGLE_STRIP[] = {
-0.8, 0.8, 0.0, //v1
0.0, 1.0, //UV1
-0.8, -0.8, 0.0, //v2
0.0, 0.0, //UV2
0.8, 0.8, 0.0, //v3
1.0, 1.0, //UV3
0.8, -0.8, 0.0, //v4
1.0, 0.0, //UV4
};
- (void)render:(uint8_t*)data
{
if ([EAGLContext currentContext] != context)
[EAGLContext setCurrentContext:context];
glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.1f, 1.1f, -1.1f, 1.1f, -2.0f, 2.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1280, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, frameTexture);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*5, verticesForGL_TRIANGLE_STRIP);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*5, &verticesForGL_TRIANGLE_STRIP[0]+3);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Seems to me you are attempting to load a non-power-of-two texture. This is not supported on all iOS devices on openGl es 1.0/1.1. You can check if the devices supports such extension
bool npot = strstr(extensions, "GL_APPLE_texture_2D_limited_npot") != 0;
if (! npot)
NSLog("Non power of two textures not supported.");
Also, try loading a power of two square texture and see if that works.
Oh I've solved just now.
I added this line below the glTexImage2D function. (sorry, I'm a beginner about openGL. It seems to make a link frameBuffer with texture.)
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES, GL_TEXTURE_2D, frameTexture, 0);
I use the iPhone5(armv7s). It is enough to decode and resize the 1280x1024 30fps pictures. but rendering need to change from using CPU to GPU.
So, now I can make a better performance. (23fps -> 30fps)
thanks.

how to draw a semi-transparent triangle to back-buffer then render it?

I'm trying to draw a line with semi-transparent color to an offscreen framebuffer, use glCopyTexSubImage2D to copy it into a texture, then draw that texture to onscreen framebuffer.
I tried many configuration but only got an opaque line.
For more information, this is how I setup my OpenGL:
Firstly, I subclass EAGLView, then add an offscreen framebuffer:
glGenFramebuffersOES(1, &offscreenFramebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, offscreenFramebuffer);
glGenRenderbuffersOES(1, &offscreenRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, offscreenRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, kTextureOriginalSize, kTextureOriginalSize);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, offscreenRenderbuffer);
glGenRenderbuffersOES(1, &offscreenDepthBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, offscreenDepthBuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, kTextureOriginalSize, kTextureOriginalSize);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, offscreenDepthBuffer);
// Offscreen framebuffer texture target
glGenTextures(1, &offscreenRenderTexture);
glBindTexture(GL_TEXTURE_2D, offscreenRenderTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
unsigned char * data = (unsigned char *)malloc( kTextureOriginalSize * kTextureOriginalSize * 4 );
memset( data,0xff, kTextureSizeWidth * kTextureSizeHeight * 4 );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureOriginalSize, kTextureOriginalSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, offscreenRenderTexture, 0);
glEnable( GL_TEXTURE_2D);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_BLEND);
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
And copy data from offscreen framebuffer to texture
glBindTexture( GL_TEXTURE_2D, offscreenRenderTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTextureOriginalSize, kTextureOriginalSize);
I used glColor4f to change the alpha of color before drawing.
Thanks for your help!
I found the answer:
First, I need to set alpha to very
small: like 0.1 to see the effect.
Second, glBlendFunc() has effect
only on active framebuffer, so I need
to call glBlendFunc() twice for
both offscreen and onscreen
framebuffer. Or actually, what I do is
disable GL_BLEND when rendering the
texture to onscreen framebuffer.

Draw a line on top of triangles

I created a new iPhone OpenGL Project in Xcode. I filled my background with triangles and gave them a texture, see below:
CGImageRef spriteImage;
CGContextRef spriteContext;
GLubyte *spriteData;
size_t width, height;
// Sets up matrices and transforms for OpenGL ES
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glRotatef(-90,0,0,1);
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
// Clears the view with black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Sets up pointers and enables states needed for using vertex arrays and textures
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
//glColorPointer(4, GL_FLOAT, 0, triangleColors);
//glColor4f(0.0f,1.0f,0.0f,1.0f);
//glEnableClientState(GL_COLOR_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, spriteTexcoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Creates a Core Graphics image from an image file
spriteImage = [UIImage imageNamed:#"Bild.png"].CGImage;
// Get the width and height of the image
width = CGImageGetWidth(spriteImage);
height = CGImageGetHeight(spriteImage);
// Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
// you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
if(spriteImage) {
// Allocated memory needed for the bitmap context
spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
// Uses the bitmap creation function provided by the Core Graphics framework.
spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// After you create the context, you can draw the sprite image to the context.
CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), spriteImage);
// You don't need the context at this point, so you need to release it to avoid memory leaks.
CGContextRelease(spriteContext);
// Use OpenGL ES to generate a name for the texture.
glGenTextures(1, &spriteTexture);
// Bind the texture name.
glBindTexture(GL_TEXTURE_2D, spriteTexture);
// Set the texture parameters to use a minifying filter and a linear filer (weighted average)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specify a 2D texture image, providing the a pointer to the image data in memory
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// Release the image data
free(spriteData);
// Enable use of the texture
glEnable(GL_TEXTURE_2D);
// Set a blending function to use
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Enable blending
glEnable(GL_BLEND);
I have got two questions, bc. I am not so familiar with OpenGL.
I want to write a method, which I give two points as parameters and I want a Line between these two points to be drawn above my triangles (background).
- (void) drawLineFromPoint1:(CGPoint)point1 toPoint2:(CGPoint)point2 {
GLfloat triangle[] = { //Just example points
0.0f, 0.0f,
0.1f, 0.0f,
0.1f, 0.0f,
0.1f, 0.1f
};
GLfloat triangleColors[] = {
0.5f, 0.5f, 0.5f, 1.0f
};
//now draw the triangle
}
Something like that. Now I want to have a 2nd method, which erases this line (and not the background)
My drawing method looks like this:
- (void)drawView
{
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, number_vertices, GL_UNSIGNED_SHORT, indices);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Would be great if you can give e some hints/help,
cheers
The conventional approach would be to redraw everything whenever you move or erase a line.
Well, I got it to work. I just missed to set the Vertex-Pointer in my drawView to my triangles. This here now works:
- (void)drawView
{
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glClear(GL_COLOR_BUFFER_BIT);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLES, number_vertices, GL_UNSIGNED_SHORT, indices);
[self drawLines];
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void) drawLines{
glDisable(GL_TEXTURE_2D);
GLfloat points[4];
for (Dataset *data in buttons) {
CGPoint s = [data screenPosition];
CGPoint p = [data slot];
points[0] = (GLfloat)(768-s.y);
points[1] = (GLfloat)(1024-s.x);
points[2] = (GLfloat)(768-p.y);
points[3] = (GLfloat)(1024-p.x);
glVertexPointer(2, GL_FLOAT, 0, points);
glDrawArrays(GL_LINE_STRIP, 0, 2);
}
glEnable(GL_TEXTURE_2D);
}

OpenGL ES Framebuffer weird mirroring when drawing

I really can't wrap my mind around this:
Previously I couldn't get Framebuffers to work, but I've got it going now. However, there is this incredibly weird mirroring going on with the texture generated from the framebuffer, and I have no idea why. Basically, I will try to draw a texture at 0,0 using GL_TRIANGLE_FAN, and the texture appears as normal (more or less) in the top right corner, but also appears in the bottom left corner, mirrored. If I fill up most or all of my viewport area with the same texture, the result is an ugly z-fighting overlap.
Screenshots will do this more justice.
Original image:
Original http://img301.imageshack.us/img301/1518/testsprite.png
Drawn 80x80 at (0,0)
80x80 http://img407.imageshack.us/img407/8339/screenshot20100106at315.png
Drawn 100x180 at (0,0)
100x180 http://img503.imageshack.us/img503/2584/screenshot20100106at316.png
Drawn 320x480 at (0,0)
320x480 http://img85.imageshack.us/img85/9172/screenshot20100106at317.png
And here is my code:
Set up the view:
//Apply the 2D orthographic perspective.
glViewport(0,0,320,480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, 320, 480, 0, -10000.0f, 100.0f);
//Disable depth testing.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
//Enable vertext and texture coordinate arrays.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glShadeModel(GL_SMOOTH);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glGetError(); // Clear error codes
sprite = [Sprite createSpriteFromImage:#"TestSprite.png"];
[sprite retain];
[self createTextureBuffer];
Create the texture buffer.
- (void) createTextureBuffer
{
// generate texture
glGenTextures(1, &bufferTexture);
glBindTexture(GL_TEXTURE_2D, bufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // check if this is right
// generate FBO
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
// associate texture with FBO
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, bufferTexture, 0);
// clear texture bind
glBindTexture(GL_TEXTURE_2D,0);
// check if it worked (probably worth doing :) )
GLuint status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if (status != GL_FRAMEBUFFER_COMPLETE_OES)
{
printf("FBO didn't work...");
}
}
Run the render loop.
- (void)drawView
{
[self drawToTextureBuffer];
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
//Bind the GLView's buffer.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, 320, 480);
//Clear the graphics context.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Push the matrix so we can keep it as it was previously.
glPushMatrix();
//Rotate to match landscape mode.
glRotatef(90.0, 0, 0, 1);
glTranslatef(0.0f, -320.0f, 0.0f);
//Store the coordinates/dimensions from the rectangle.
float x = 0.0f;
float y = 0.0f;
float w = 480.0f;
float h = 320.0f;
// 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, 1,
1, 1,
0, 1
};
//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);
//Enable 2D textures.
glEnable(GL_TEXTURE_2D);
//Bind this texture.
glBindTexture(GL_TEXTURE_2D, bufferTexture);
//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);
}
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
On the first pass, the render loop will draw the image into the FBO.
- (void)drawToTextureBuffer
{
if (!bufferWasCreated)
{
// render to FBO
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
// set the viewport as the FBO isn't be the same dimension as the screen
glViewport(0, 0, 512, 512);
glPushMatrix();
//Store the coordinates/dimensions from the rectangle.
float x = 0.0f;
float y = 0.0f;
float w = 320.0f;
float h = 480.0f;
// 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, 1,
1, 1,
1, 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);
//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.
glBindTexture(GL_TEXTURE_2D, sprite.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);
}
//Unbind this buffer.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
bufferWasCreated = YES;
}
}
Your texcoords in - (void)drawView seem to be wrong
GLfloat texcoords[] =
{
0, 0,
0, 1,
1, 1,
0, 1 << HERE should be 1, 0
};

OpenGL ES Render to Texture

I have been having trouble finding straightforward code to render a scene to a texture in OpenGL ES (specifically for the iPhone, if that matters). I am interested in knowing the following:
How do you render a scene to a texture in OpenGL ES?
What parameters must you use to create a texture that is capable of being a render target in OpenGL ES?
Are there any implications with applying this rendered texture to other primitives?
This is how I'm doing it.
I define a texture variable (I use Apple's Texture2D class, but you can use an OpenGL texture id if you want), and a frame buffer:
Texture2d * texture;
GLuint textureFrameBuffer;
Then at some point, I create the texture, frame buffer and attach the renderbuffer. This you only need to do it once:
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);
Every time I want to render to the texture, I do:
glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);
...
// GL commands
...
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
About your question 3, that's it, you can use the texture as if it is any other texture.
To render the scene to a texture you must use a framebuffer associated with a texture. Here is a method that i created to simplify it :
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);
}
You can create the frame buffer and the texture easily :
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);
You can later use _framebuffer to render the scene into _texture in your draw method :
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
Now you can do what you want with the texture. If you want to do some post processing (blur, bloom, shadow, etc...) you can !