0

I have been working on getting screenshot from OpenGL and then also rendering the same on screen. For this purpose i have created two framebuffers. 1 For rendering(ratinaFramebuffer) and 1 for using the apple texture cache drawing(textureFramebuffer). Created both using below code(except variable names).

glGenFramebuffers(1, &ratinaFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, ratinaFramebuffer);

glGenRenderbuffers(1, &ratinaColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, ratinaColorRenderbuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];

glGenRenderbuffers(1, &ratinaDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, ratinaDepthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ratinaDepthRenderbuffer);

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE)
{
    NSLog(@"failed to make complete framebuffer object %x", status);
}

Here is what my render code looks like

glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// Clear content
glBindFramebuffer(GL_FRAMEBUFFER, ratinaFramebuffer);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

glBindFramebuffer(GL_FRAMEBUFFER, textureFramebuffer);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Start drawing
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);

static int nColor = 104;


glClearColor(0, (++nColor & 0xff)/255.0, 55.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);

CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:10];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

CC3GLMatrix *modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(sin(CACurrentMediaTime()), 0, -7)];
_currentRotation += displayLink.duration * 90;
[modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, 0)];
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

// 1
glViewport(0, 0, self.frame.size.width, self.frame.size.height);

glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);

// 2
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));

glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _floorTexture);
glUniform1i(_textureUniform, 0);

// 3
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);

glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);

glActiveTexture(GL_TEXTURE0); // unneccc in practice
glBindTexture(GL_TEXTURE_2D, _fishTexture);
glUniform1i(_textureUniform, 0); // unnecc in practice

glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));

glDrawElements(GL_TRIANGLE_STRIP, sizeof(Indices2)/sizeof(Indices2[0]), GL_UNSIGNED_BYTE, 0);


// Get the image
CGImageRef cgImage = NULL;
UIImage *screenImageimage = nil;
OSStatus res = CreateCGImageFromCVPixelBuffer(renderTarget,&cgImage);
if (res == noErr)
{
    screenImageimage = [UIImage imageWithCGImage:cgImage scale:1.0 orientation:UIImageOrientationUp];

}

At this point, image is perfectly drawn into the texture. But when i try to render it on screen, the same texture, it is not getting drawn :(. It shows the blue color that i have given in clear color but nothing else.

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ratinaFramebuffer);
glBindTexture(GL_TEXTURE_2D, 0);
glClearColor(0, 255/255.0, 255/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);

glViewport(0, 0, self.frame.size.width, self.frame.size.height);


glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, renderTexture);


// Display the buffer
glBindRenderbufferOES(GL_RENDERBUFFER_OES, ratinaColorRenderbuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER_OES];
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • So you bind and draw to the texture frame buffer and get the image from it which seems to work but then you switch to the view bound fame buffer, clear it and present it to the view which seems to then work as expected again. Where do you actually draw the texture to the view bound frame buffer (ratinaFramebuffer)? Simply binding the texture sets the desired texture to the previously set active texture but not draw it anywhere. To draw it you will need the same procedure as drawing any other texture. – Matic Oblak Feb 11 '15 at 17:43
  • thanks for the answer Matic Oblak, i added the below code glVertexPointer(3, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, coordinates); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); and it showed the texture, thank you. But the problem is, it is showing within the box that is animated, not the complete screen, how can i do that, please suggest – Zeeshan Arif Feb 12 '15 at 07:18

2 Answers2

1

When you draw to the separate frame buffer you may attach a texture to it where in the end you may affectively draw to the texture itself. Once this drawing is complete you may then use the texture as you would any other which includes drawing it to your main onscreen buffer.

There are a few points you should check when doing so:

  • Do not forget to rebind the frame buffer when switching
  • You must set the viewport according to the bound frame buffer when switching
  • Possibly you may need to clear the buffer
  • It is possible the texture is drawn only on a part of the buffer for instance drawing a 600x600 screen on an 1024x1024 texture. In this case you need to generate the vertex coordinates in range [0, 600/1024] to draw the correct part of it. This can be checked by comparing the viewport values from the texture bound frame buffer and the texture size.

It is hard to say what you are missing now but the best shot at the moment would be to check the viewport. Beside that you do not need to complicate with the main buffer if you are simply drawing a fullscreen texture. You may disable the matrix and simply use the [-1,1] coordinate system which is the default.

Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
0

Problem is resolved, as i was new to openGL and i was not drawing the screen framebuffer, which i did by using below code in the render on screen call. Just posting if anyone need to look at that at beginer level

GLfloat     coordinates[] = { 0,    1,
                              1,    1,
                              0,    0,
                              1,    0 };

GLfloat     width = self.frame.size.width,
            height =  self.frame.size.height;

GLfloat     vertices[] = {  -width / 2 + point.x,   -height / 2 + point.y,  0.0,
                            width / 2 + point.x,    -height / 2 + point.y,  0.0,
                            -width / 2 + point.x,   height / 2 + point.y,   0.0,
                            width / 2 + point.x,    height / 2 + point.y,   0.0 };

glBindTexture(GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture));

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

Although, this shows the texture but in a small box that is drawn in on the other frame buffer. It does not draw to complete screen although the vertexs and co-ords are of complete screen. Looking into that, will edit this if i found.