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];
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.
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.
Related
i am working on OpenGL ES 2.0 for my project,what i m trying to do is just give auto zoom of the texture by giving scale value to model matrix.But the problem is,while zooming the texture the edges of texture not maintain the smooth motion instead the edges move step by step motion...can any one give me the solution....
(void)render:(CADisplayLink*)displayLink {
_currentScale++;
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
GLKMatrix4 aspect = [animations getActualScaleForImage:inputImage.size withPortSize:CGSizeMake(self.frame.size.width, self.frame.size.height)];
aspect = GLKMatrix4Scale(aspect,1 + (_currentScale/3000), 1 + (_currentScale/3000) , 0);
glUniformMatrix4fv(_modelViewUniform, 1, 0, aspect.m);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,_backGroundTxe);
glUniform1i(_textureUniform, 0);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
This is my render function
If I have understood your description, it sounds like you need to adjust your texture filtering.
While _backGroundTxe is still bound during the process where you first create it try adding:
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Alternatively, if you want the texture to look smooth when it zooms out far, you may want to try this instead:
glGenerateMipmaps(GL_TEXTURE_2D);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
This is a nice introduction to OpenGL texture filtering: http://www.learnopengles.com/android-lesson-six-an-introduction-to-texture-filtering/ It's for Android/Java, but it's trivial to translate it to iOS/C++, just omit all the "GLES20."
I have drawing code that first draws the background without a texure, then overlays the texture on top of it. I'm currently using glBindTexture(GL_TEXTURE_2D, 0) in order to un-bind the texture after performing the second lot of drawing.
However, this is generating the following warning when I analyse the GPU performance in Xcode:
When I remove the code to un-bind the texture, the warning disappears, but things aren't drawn correctly. The texture that I'm drawing doesn't have mipmapping enabled, so it's not coming from there.
Drawing Code:
glClear(GL_COLOR_BUFFER_BIT);
{ // Drawing
glViewport(0, 0, frameWidth, frameHeight);
GLuint vertexCount = animBuffer.vertexCounts[animIndex];
glBindBuffer(GL_ARRAY_BUFFER, animBuffer.vertexBuffers[animIndex]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, animBuffer.indexBuffers[animIndex]);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*3));
glVertexAttribPointer(textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*7));
glDrawElements(GL_TRIANGLE_STRIP, vertexCount, GL_UNSIGNED_SHORT, 0);
// glEnable(GL_TEXTURE_2D) (tried this, gives another warning)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(textureUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, textureColorBuffer); // Transparent color buffer to allow texture to be overlayed.
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(float)*3));
glDrawElements(GL_TRIANGLE_STRIP, vertexCount, GL_UNSIGNED_SHORT, 0);
// Unbind texture.... this line is causing the error.
glBindTexture(GL_TEXTURE_2D, 0);
// glDisable(GL_TEXTURE_2D) (tried this, gives another warning)
}
[context presentRenderbuffer:GL_RENDERBUFFER];
Texture Loading Code:
CGImageRef textureImage = image.CGImage;
size_t width = CGImageGetWidth(textureImage);
size_t height = CGImageGetHeight(textureImage);
GLubyte* spriteData = malloc(width*height*4);
CGColorSpaceRef cs = CGImageGetColorSpace(textureImage);
CGContextRef c = CGBitmapContextCreate(spriteData, width, height, 8, width*4, cs, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(cs);
CGContextScaleCTM(c, 1, -1);
CGContextTranslateCTM(c, 0, -CGContextGetClipBoundingBox(c).size.height);
CGContextDrawImage(c, (CGRect){CGPointZero, {width, height}}, textureImage);
CGContextRelease(c);
GLuint glTex;
glGenTextures(1, &glTex);
glBindTexture(GL_TEXTURE_2D, glTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
glBindTexture(GL_TEXTURE_2D, 0);
free(spriteData);
return glTex;
How should I go about un-binding textures in order to remove this warning?
EDIT:
I have tried using glEnable(GL_TEXTURE_2D) & glDisable(GL_TEXTURE_2D) before and after the textured drawing, although this now gives me the following warning:
I think the easiest way to avoid this warning is to keep the texture binded, but just send a uniform to the fragment shader indicating whether to blend the texture or not.
So, before drawing just add:
glUniform1i(drawTexInput, GL_FALSE); // Or GL_TRUE to draw.
And in the fragment shader:
varying lowp vec4 destinationColor;
uniform bool drawTex;
varying lowp vec2 texCoordOut;
uniform sampler2D tex;
void main() {
lowp vec4 result;
if (drawTex) {
lowp vec4 tex2D = texture2D(tex, texCoordOut);
result = tex2D + vec4(1.0 - tex2D.a) * destinationColor; // Alpha blending
} else {
result = destinationColor;
}
gl_FragColor = result;
}
This is driving me nuts! I've not done much with OpenGL before, so any pointers appreciated.
Can anyone tell me any reason why some of my objects appear in my shadow map, and others don't?
I have 2 object I am rendering; southernHemisphere and Frame. Both of these are rendered to the scene and to the shadow map texture. The scene is working perfectly showing all objects, but only southernHemisphere is appearing in the shadow map.
My shadow map texture is bound like this:
- (void)setupShadowmapBuffers {
glGenTextures(1, &_shadowTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _shadowTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenFramebuffers(1, &_shadowFBO);
glGenRenderbuffers(1, &_shadowRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _shadowRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1024, 1024);
glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO);
glBindTexture(GL_TEXTURE_2D, _shadowTexture);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
_shadowRenderBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _shadowTexture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
printf("Error: FrameBufferObject is not complete!\n");
}
}
In my render function, I render to the shadow map texture:
// Render the shadow map
glUseProgram(_shadowProgramHandle);
glUniformMatrix4fv(_shadowProjectionUniform, 1, 0, LSprojection.glMatrix);
glUniformMatrix4fv(_shadowLightMPVUniform, 1, 0, lightsourcemat.glMatrix);
glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO);
glBindRenderbuffer(GL_RENDERBUFFER, _shadowRenderBuffer);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, 1024, 1024);
glUniformMatrix4fv(_shadowModelViewUniform, 1, 0, southernHemispheremat.glMatrix);
[self drawSouthernHemisphere];
glUniformMatrix4fv(_shadowModelViewUniform, 1, 0, framemat.glMatrix);
[self drawFrame];
Then I render to the scene:
// Reset buffers and finally render the scene
glUseProgram(_mainProgramHandle);
glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, msaaRenderBuffer);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, vFrame.size.width, vFrame.size.height);
glUniformMatrix4fv(_modelViewUniform, 1, 0, shadowmat.glMatrix);
[self drawShadow];
glUniformMatrix4fv(_modelViewUniform, 1, 0, southernHemispheremat.glMatrix);
[self drawSouthernHemisphere];
glUniformMatrix4fv(_modelViewUniform, 1, 0, framemat.glMatrix);
[self drawFrame];
My drawing functions look like this:
- (void)drawSouthernHemisphere {
// Southern Hemisphere
glEnable(GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, _globeTexture);
glBindVertexArrayOES(_southernHemisphere);
// Draw outside (textured)
glUniform1f(_useTextureSlot, 1);
glCullFace(GL_BACK);
glDrawElements(GL_TRIANGLES, sizeof(Southern)/sizeof(Southern[0]), GL_UNSIGNED_SHORT, 0);
// Draw inside (coloured)
glCullFace(GL_FRONT);
glUniform1f(_useTextureSlot, 0);
glUniform4f(_runTimeColorSlot, 0, 0, 0, 0);
glDrawElements(GL_TRIANGLES, sizeof(Southern)/sizeof(Southern[0]), GL_UNSIGNED_SHORT, 0);
glBindVertexArrayOES(0);
}
- (void)drawFrame {
// Frame
glEnable(GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, _frameTexture);
glBindVertexArrayOES(_frame);
// Draw outside (textured)
glUniform1f(_useTextureSlot, 1);
glCullFace(GL_BACK);
glDrawElements(GL_LINES, sizeof(Frame)/sizeof(Frame[0]), GL_UNSIGNED_SHORT, 0);
glBindVertexArrayOES(0);
}
Thanks.
EDIT:
I have isolated the issue being down to my vertex arrays - in particular the normals.
I swapped the values in the frame array with the ones in my southernHemisphere array, and bingo - the object appears in both the scene, and the shadow map!
After some adjustment of values, it appears that it will only work if the direction of the normals are the same as the direction of each vector itself.
What baffles me is that in my shadow map shader, I don't even access the normals so why do they have any effect on the rendering at all??
Here is my vertex shader for my shadow map:
attribute vec4 Position;
uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat4 Light;
varying vec4 TexCoord;
void main()
{
TexCoord = Projection * Light * Modelview * Position;
gl_Position = Projection * Light * Modelview * Position;
}
and fragment:
precision mediump float;
varying vec4 TexCoord;
void main()
{
/* Generate shadow map - write fragment depth. */
float value = 10.0 - TexCoord.z;
float v = floor(value);
float f = value - v;
float vn = v * 0.1;
gl_FragColor = vec4(vn, f, 0.0, 1.0);
}
EDIT2:
Here are my set up function for VAOs
// Southern Hemisphere
glGenVertexArraysOES(1, &_southernHemisphere);
glBindVertexArrayOES(_southernHemisphere);
GLuint vb2;
glGenBuffers(1, &vb2);
glBindBuffer(GL_ARRAY_BUFFER, vb2);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(_positionSlot);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(_colorSlot);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Color));
glEnableVertexAttribArray(_normalSlot);
glVertexAttribPointer(_normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(_texCoordSlot);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoord));
GLuint southernBuffer;
glGenBuffers(1, &southernBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,southernBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Southern) * sizeof(Southern[0]), Southern, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
// Frame
glGenVertexArraysOES(1, &_frame);
glBindVertexArrayOES(_frame);
GLuint vb4;
glGenBuffers(1, &vb4);
glBindBuffer(GL_ARRAY_BUFFER, vb4);
glBufferData(GL_ARRAY_BUFFER, sizeof(Frame_Vertices), Frame_Vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(_positionSlot);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(_colorSlot);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Color));
glEnableVertexAttribArray(_normalSlot);
glVertexAttribPointer(_normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(_texCoordSlot);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoord));
GLuint legsBuffer;
glGenBuffers(1, &frameBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,frameBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Frame) * sizeof(Frame[0]), Frame, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
My Arrays all follow the same form of:
const Vertex Vertices[] = {
{{0.0000,-1.5000,0.0000},{0.3843137254902,0.14117647058824,0.082352941176471,1},{0.0000,-1.0000,0.0000},{0.0000,1.0000}},
{{0.0000,-1.4872,0.1958},{0.3843137254902,0.14117647058824,0.082352941176471,1},{0.0000,-0.9914,0.1305},{0.0000,0.9583}},
....
}
which consists of Position, Colour, Normal, Texture Coordinates as you can see from the set up code.
After my shaders are linked, I finish set up with these:
- (void)useMainProgram:(GLfloat[])lightsource {
const GLfloat l_ambient = 0.7;
glUseProgram(_mainProgramHandle);
_positionSlot = glGetAttribLocation(_mainProgramHandle, "Position");
_colorSlot = glGetAttribLocation(_mainProgramHandle, "Color");
_normalSlot = glGetAttribLocation(_mainProgramHandle, "Normal");
_lightingSlot = glGetUniformLocation(_mainProgramHandle, "l1");
_ambientLightingSlot = glGetUniformLocation(_mainProgramHandle, "l_ambient");
_texCoordSlot = glGetAttribLocation(_mainProgramHandle, "TexCoordIn");
_useTextureSlot = glGetUniformLocation(_mainProgramHandle, "use_texture");
_runTimeColorSlot = glGetUniformLocation(_mainProgramHandle, "RunTimeColor");
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
glEnableVertexAttribArray(_normalSlot);
glEnableVertexAttribArray(_texCoordSlot);
_projectionUniform = glGetUniformLocation(_mainProgramHandle, "Projection");
_modelViewUniform = glGetUniformLocation(_mainProgramHandle, "Modelview");
for (int i=0;i<_num_bottles; i++){
_bottlesUniform[i] = glGetUniformLocation(_mainProgramHandle, "Modelview");
}
_textureUniform = glGetUniformLocation(_mainProgramHandle, "Texture");
// Lighting doesn't change, so we set it here.
glUniform3fv(_lightingSlot, 1, lightsource);
glUniform1fv(_ambientLightingSlot, 1, &l_ambient);
}
- (void)useShadowProgram:(GLfloat[])lightsource {
glUseProgram(_shadowProgramHandle);
_shadowPositionSlot = glGetAttribLocation(_shadowProgramHandle, "Position");
_shadowLightMPVUniform = glGetUniformLocation(_shadowProgramHandle, "Light");
_shadowProjectionUniform = glGetUniformLocation(_shadowProgramHandle, "Projection");
_shadowModelViewUniform = glGetUniformLocation(_shadowProgramHandle, "Modelview");
glEnableVertexAttribArray(_shadowPositionSlot);
}
I am trying to render a simple scene into a FBO that is backed by a texture as a color attachment and then draw a quad to the screen using this texture in iOS.
This will help me do some post processing of the final scene. There are a few questions on SO that address similar (but not quite the same) questions and I've tried whatever I could understand. Nothing works.
I have two shader programs. The first one _program simply takes the vertex positions and renders them with a single color. The second one quadProgram takes a texture, the texture coords and the quad Coords. (In the interest of brevity I am omitting the code for these shaders.)
Both shaders work correctly. They independently produce correct results. However, when I try to render the "rendered texture" to the quad instead of using a sample wood texture, I simply get a black screen. Here are the relevant bits of code. I setup everything like so:
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
_program = [self createProgramWithVertexShader:#"Shader" fragShader:#"Shader"];
GLuint GLKVertexAttribPosition = glGetAttribLocation(_program, "position");
quadProgram = [self createProgramWithVertexShader:#"PostShader" fragShader:#"PostShader"];
quadTexCoord = glGetAttribLocation(quadProgram, "a_texcoord");
quadPosition = glGetAttribLocation(quadProgram, "a_position");
diffuseTexture = glGetUniformLocation(quadProgram, "s_diffuse");
glEnable(GL_DEPTH_TEST);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glBindVertexArrayOES(0);
// ============
// ---- for render to texture
width = self.view.bounds.size.width;
height = self.view.bounds.size.height;
// create fbo
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create and attach backing texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
// create and attach depthbuffer
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
// Check if framebuffer was loaded correctly
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"failed to make complete framebuffer object %x", status);
}
// sample texture
NSError *theError;
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"wood_floor_256" ofType:#"jpg"]; // 1
spriteTexture = [GLKTextureLoader textureWithContentsOfFile:filePath options:nil error:&theError]; // 2
}
And then my main loop:
- (void)update
{
// First save the default frame buffer.
static GLint default_frame_buffer = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &default_frame_buffer);
// render to texture
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
glUseProgram(_program);
glDrawArrays(GL_TRIANGLES, 0, 36);
// render to screen
glBindFramebuffer(GL_FRAMEBUFFER, default_frame_buffer);
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(quadProgram);
const float quadPositions[] = { 1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0 };
const float quadTexcoords[] = { 1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0 };
// stop using VBO and other bufs.
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
glBindTexture(GL_TEXTURE_2D, texture);
glActiveTexture(GL_TEXTURE_2D);
// setup buffer offsets
glVertexAttribPointer(quadPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), quadPositions);
glVertexAttribPointer(quadTexCoord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), quadTexcoords);
// ensure the proper arrays are enabled
glEnableVertexAttribArray(quadPosition);
glEnableVertexAttribArray(quadTexCoord);
// draw
glDrawArrays(GL_TRIANGLES, 0, 2*3);
}
I don't even know how to tell if the backing texture contains the rendered screen.
The render to texture part should render into the FBO the following:
If I replace the two lines:
glBindTexture(GL_TEXTURE_2D, texture);
glActiveTexture(GL_TEXTURE_2D);
with
glBindTexture(spriteTexture.target, spriteTexture.name);
glEnable(spriteTexture.target);
I get the following:
Which indicates that the code to render a quad to screen with a texture is correct.
I have no idea how to get the first screen rendered to the quad.
Since the texture you are using is NPOT, it needs a non-default wrap parameter.
Add the following right below the other glTexParameteri call. It should solve the problem:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
I'm trying to create OpenGL ES 1.1 texture and fill is with rendered content.
Preparing a texture:
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
GLuint texFrambuffer;
glGenFramebuffers(1, &texFrambuffer);
glBindFramebuffer(GL_FRAMEBUFFER, texFrambuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"failed to make complete framebuffer object %x", status);
// this message doesn't appear, thus, framebuffer is complete
}
glViewport(0, 0, 32, 32);
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat vertices[] = {
10.0f, 10.0f, 0.0f,
20.0f, 40.0f, 0.0f,
10.0f, 30.0f, 0.0f
};
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &texFrambuffer);
Rendering texture into scene:
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
GLshort texCoord[] = {0, 0, 0, 1, 1, 0, 1, 1};
GLfloat vertices2[] = {0.0, 0.0, 0.0, 31.0f, 31.0f, 0.0f, 31.0f, 31.0f};
glVertexPointer(2, GL_FLOAT, 0, vertices2);
glTexCoordPointer(2, GL_SHORT, 0, texCoord);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
Full source code is available at Bitbucket: https://bitbucket.org/amjaliks/gl2/src/66ee4932e212/GL2/GL2View.m
There other content is rendered correctly. Issue is only with this texture – it renders as a white rectangle.
I have studied a lot of example, but still can't figure out what I doing wrong. What is missing?
Update 1: I have noticed, if I set glClearColor() and call glClear() while texFrambuffer is bound, these changes is saved to my texture. Thus, there is something wrong with glDrawArrays() and/or related things.
Do I need set matrix mode and projection specifically for my texFrambuffer?
Update 2: I have tried also to use glCopyTexImage2D to copy content from "main" framebuffer to a texture.
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glViewport(0, 0, 32, 32);
glClearColor(1.0f, 0.75f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat vertices[] = {
0.0f, 0.0f, 0.0f,
20.0f, 32.0f, 0.0f,
10.0f, 30.0f, 0.0f
};
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 32, 32, 0);
Full source code available at Bitbucket: https://bitbucket.org/amjaliks/gl2/src/b3339661650e/GL2/GL2View.m
The result is the same. Only filled rectangle. It looks like there is definitely issue with my matrices.
Your problem is with matrices. By default projection matrix is identity. Thus giving (-1,-1)-(+1,+1) coordinates for viewport. Most likely you need orthographic projection to (0,0)-(32,32) square.