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 !
Related
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.
I am working on OpenGL ES 2.0 on iOS and I have this...
A texture (T1) with some image (size 1024x768).
An off screen FBO (FBO1) associated texture T1 so that I can render something into T1.
Another texture (T2) of the same size.
Another FBO (FBO2) associated with T2. (I will render to texture T2 with it).
Now in a loop, I render the content of T1 into FBO2 (so T1 gets transferred to T2) and then render T2 into FBO1 (T2 gets transferred back into T1).
After couple of iterations (just 7-8), the original image which was loaded to T1 gets severely distorted/blurred (as if it did a horizontal blur).
But if I do the same thing with a square image (need not be power of two), the image remains clear.
Here is the code that I use to create the texture..
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
And here is the code I use to create the FBO...
glGenFramebuffers(1, &targetFBO);
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
My shaders are the most basic ones, just renders the texture into gl_FragColor.
Here is my render Objective-C code...
- (void) draw {
GLfloat textureCoordinates[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
GLfloat imageVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
glViewport(0, 0, targetWidth, targetHeight);
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
glUseProgram(program);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(inputTextureLocation, 2);
glDisable(GL_BLEND);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, 0, 0, imageVertices);
glVertexAttribPointer(inputTextureCoordinateLocation, 2, GL_FLOAT, 0, 0, textureCoordinates);
// Clear the screen
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
And my vertex shader...
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
Fragment shader...
varying highp vec2 textureCoordinate;
uniform sampler2D inputTexture;
void main()
{
gl_FragColor = texture2D(inputTexture, textureCoordinate);
}
Original image...
Distorted image ...
How do I avoid blurring on non-square textures?
Edit: The problem is actually with No-Power-of-Two textures. Not just non-square. I am not able to find a solution, so I am going with POT textures.
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.
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);
}
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?