Draw a straight line using OpenGL ES in iPhone? - iphone

Finally i tried to draw a line using OpenGL ES framework in XCode 4.2 for iPhone simple game app.I studied something about GLKView and GLKViewController to draw a line in iPhone. Here is my sample code that was i tried in my project,
#synthesize context = _context;
#synthesize effect = _effect;
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[EAGLContext setCurrentContext:self.context];
//[self setupGL];
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
NSLog(#"DrawInRect Method");
[EAGLContext setCurrentContext:self.context];
// This method is calling multiple times....
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const GLfloat line[] =
{
-0.5f, -0.5f, //point A
0.5f, -0.5f, //point B
};
glVertexPointer(2, GL_FLOAT, 0, line);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINES, 0, 2);
}
When i run the project only the gray color only appearing in the screen, the line not showing. And also the - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect delegate is calling infinite time. Please guide me where i am doing wrong. Why the line not appearing or drawing? Can you please help? Am trying this 2 days. Thanks in advance.

I'm rather a student of OpenGL ES 2.0 right now myself. I recommend first starting a new project in Xcode with the "OpenGL Game" template Apple provides.
Among other things, the Apple template code will include creation of a GLKBaseEffect, which provides some Shader functionality that seems to be required in order to be able to draw with OpenGL ES 2.0. (Without the GLKBaseEffect, you would need to use GLSL. The template provides an example of both with and without explicit GLSL Shader code.)
The template creates a "setupGL" function, which I modified to look like this:
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
self.effect = [[[GLKBaseEffect alloc] init] autorelease];
// Let's color the line
self.effect.useConstantColor = GL_TRUE;
// Make the line a cyan color
self.effect.constantColor = GLKVector4Make(
0.0f, // Red
1.0f, // Green
1.0f, // Blue
1.0f);// Alpha
}
I was able to get the line to draw by including a few more steps. It all involves sending data over to the GPU to be processed. Here's my glkView:drawInRect function:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Prepare the effect for rendering
[self.effect prepareToDraw];
const GLfloat line[] =
{
-1.0f, -1.5f, //point A
1.5f, -1.0f, //point B
};
// Create an handle for a buffer object array
GLuint bufferObjectNameArray;
// Have OpenGL generate a buffer name and store it in the buffer object array
glGenBuffers(1, &bufferObjectNameArray);
// Bind the buffer object array to the GL_ARRAY_BUFFER target buffer
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray);
// Send the line data over to the target buffer in GPU RAM
glBufferData(
GL_ARRAY_BUFFER, // the target buffer
sizeof(line), // the number of bytes to put into the buffer
line, // a pointer to the data being copied
GL_STATIC_DRAW); // the usage pattern of the data
// Enable vertex data to be fed down the graphics pipeline to be drawn
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Specify how the GPU looks up the data
glVertexAttribPointer(
GLKVertexAttribPosition, // the currently bound buffer holds the data
2, // number of coordinates per vertex
GL_FLOAT, // the data type of each component
GL_FALSE, // can the data be scaled
2*4, // how many bytes per vertex (2 floats per vertex)
NULL); // offset to the first coordinate, in this case 0
glDrawArrays(GL_LINES, 0, 2); // render
}
Btw, I've been going through Learning OpenGL ES for iOS by Erik Buck, which you can buy in "Rough Cut" form through O'Reilly (an early form of the book since it is not going to be fully published until the end of the year). The book has a fair number of typos at this stage and no pictures, but I've still found it quite useful. The source code for the book seems to be very far along, which you can grab at his blog. The author also wrote the excellent book Cocoa Design Patterns.

Related

Asynchronous texture loading and sharegroups in OpenGL ES 2.0 and iOS

I am trying to create a GLKView where I add cubes and draw them. The problem is, each cube is of type NSObject and has its own vertex and texture buffers but I want to draw them in a single context. In order to do this, I followed some WWDC videos and created two contexts, one for rendering and one for texture loading, and I put both into the same sharegroup. Code-wise what I did in this respect, was adding a property called renderContext to my GLKView, which I want all cubes to be drawn in and I also set up a loaderContext property, where I want to load textures. However, nothing is drawn at all, I do not see anything, and sometimes I get a crash and GL ERROR 0x0500. It used to work and model view matrix should be setup correctly and everything. The introduction of the asynchronous loading and the two shared contexts caused the problem...
Here is the code:
This is the GLKView: Container(containing the cubes)
- (void)setupGL {
self.renderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
self.loaderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:self.renderContext.sharegroup];
glGenFramebuffers(1, &defaultFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFrameBuffer);
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.bounds.size.width, self.bounds.size.height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
glEnable(GL_DEPTH_TEST);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
self.opaque = NO;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[EAGLContext setCurrentContext:self.renderContext];
for(Cube *cube in self.cubes){
[cube draw];
}
}
Each individual cube is set up like this:
-(id)init {
self = [super init];
if(self){
self.effect = [[GLKBaseEffect alloc]init];
self.effect.transform.projectionMatrix = GLKMatrix4MakePerspective(45.0f,0.95f, 0.1f, 2.0f);
self.effect.transform.projectionMatrix = GLKMatrix4Translate(self.effect.transform.projectionMatrix, 0, 0.0, 0.0);
self.effect.transform.modelviewMatrix = GLKMatrix4Translate(self.effect.transform.modelviewMatrix,0,0,-1.3);
glGenBuffers(1, &vertexArray);
glBindBuffer(GL_ARRAY_BUFFER, vertexArray);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glVertexAttribPointer(GLKVertexAttribPosition,3,GL_FLOAT,GL_FALSE,0,0);
glGenBuffers(1, &texArray);
glBindBuffer(GL_ARRAY_BUFFER, texArray);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexCoords), TexCoords, GL_STATIC_DRAW);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0,0);
}
return self;
}
And has a draw method:
-(void)draw{
[self.effect prepareToDraw];
self.effect.texture2d0.enabled = YES;
for(int i=0;i<6;i++){
if(i==0)glBindTexture(GL_TEXTURE_2D, frontTexture.name);
if(i==1)glBindTexture(GL_TEXTURE_2D, rightTexture.name);
if(i==2)glBindTexture(GL_TEXTURE_2D, backTexture.name);
if(i==3)glBindTexture(GL_TEXTURE_2D, leftTexture.name);
if(i==4)glBindTexture(GL_TEXTURE_2D, bottomTexture.name);
if(i==5)glBindTexture(GL_TEXTURE_2D, topTexture.name);
glDrawArrays(GL_TRIANGLES, i*6, 6);
}
}
Here is how I try to asynchronously load textures:
Note: The GLKView (container) is the parent of each individual cube, whose loaderContext I retrieve, which is in the renderContext's sharegroup, so textures should be drawn correctly, right ?
-(void)loadTextureForTexture:(GLKTextureInfo*)texN withView:(CubeView *)cV{
__block GLKTextureInfo *texName = texN;
EAGLContext *loaderContext = self.parent.loaderContext;
self.textureLoader = [[GLKTextureLoader alloc]initWithSharegroup:loaderContext.sharegroup];
[EAGLContext setCurrentContext:loaderContext];
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:GLKTextureLoaderOriginBottomLeft];
dispatch_queue_t loaderQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
[self.textureLoader textureWithCGImage:[self imageWithView:cV].CGImage options:options queue:loaderQueue completionHandler:^(GLKTextureInfo *tex, NSError *err){
texName = tex;
if(err)
NSLog(#"%#", err);
else
NSLog(#"no error");
dispatch_async(mainQueue, ^{
[self display];
});
}];
}
It looks like you’re doing more context management than is necessary:
GLKTextureLoader only needs to know which EAGLSharegroup to create its textures in. You don’t have to create an EAGLContext on its behalf, and the one you’re creating in your code already isn’t being passed into any GLKTextureLoader methods.
You should not manually need to manage the current EAGLContext—in fact, the documentation for GLKView specifically mentions that you should not change the current context from inside your drawing methods.
The net result of this is that other than extracting the EAGLSharegroup from your existing context for GLKTextureLoader creation, you should have no new context management code.
Additionally, it looks like the result of loading the texture never makes it out of loadTextureForTexture:withView:. Your texN variable is not passed into the function by reference, so texName is only visible to loadTextureForTexture:withView: and your texture loading completion block. Once loadTextureForTexture:withView: returns and your completion block is invoked, the data is gone. It seems like there should be some kind of CubeView setter that needs to be called with the GLKTextureInfo * you’ve received.
First problem I see in your code is absence of color attachment to the renderbuffer, so you only get depth output which would not draw anything.
glGenRenderbuffers(1, &colorBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, self.bounds.size.width, self.bounds.size.height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT, GL_RENDERBUFFER, colorBuffer);

Basic Drawing of Pixels From Unsigned Short * Using OpenGLES on iOS

For my non-app store app, I've been using the private framework Core Surface to draw directly to the screen of the iPhone. However, this can be rather slow on older devices because it heavily uses the CPU to do its drawing. To fix this, I've decided to try to use OpenGLES to render the pixels to the screen.
Currently (and I have no way of changing this), I have a reference to an unsigned short * variable called BaseAddress, and essential 3rd party code accesses BaseAddress and updates it with the new pixel data.
I've set up a GLKViewController, and implemented the viewDidLoad as follows:
- (void)viewDidLoad {
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
[EAGLContext setCurrentContext:self.context];
GLKView *view = (GLKView *)self.view;
view.context = self.context;
glGenBuffers(1, &screenBuffer);
glBindBuffer(GL_ARRAY_BUFFER, screenBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(BaseAddress), BaseAddress, GL_DYNAMIC_DRAW);
}
where screenBuffer is an instance variable. In the glkView:drawInRect: method I have the following:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glDrawElements(GL_ARRAY_BUFFER, sizeof(BaseAddress)/sizeof(BaseAddress[0]), GL_UNSIGNED_SHORT, BaseAddress);
}
Unfortunately, only a black screen appears when I run the app. If I go back to using Core Surface, the app works fine. So basically, how can I draw the pixels to the screen using OpenGLES?
I think that it might be best to use a texture and for your case I'd try to find some older ES1 template for iOS devices. Basically what you need is a frame buffer and a color buffer made from your UIView layer:
glGenFramebuffers(1, &viewFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
glGenRenderbuffers(1, &viewColorBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, viewColorBuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewColorBuffer);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, & backingHeight);
As for projection matrix I suggest you use glOrthof(.0f, backingWidth, backingHeight, .0f, -1.0f, 1.0f); that will make your GL coordinates same as your view coordinates.
Next on some initialization generate a texture, bind it and give it dimensions of power of 2 (textureWidth = 1; while(textureWidth < backingWidth) textureWidth = textureWidth << 1;) and pass it NULL for data pointer (all in function "glTexImage2D")
Then generate vertex array for a square same as texture, from (0,0) to (textureWidth, textureHeight) and texture coordinates from (0,0) to (1,1)
When you get the data to your pointer and are ready to be pushed to texture use glTexSubImage2D to update it: You can update only a segment of a texture if you get data for it or to update a whole screen use rect (0,0,screenWidth, screenHeight)
Now just draw those 2 triangles with your texture..
Note that there is a limit on texture size: most active iOS devices 1<<11 (2048) iPad3 1<<12
Do not forget to set texture parameters when creating it: glTexParameteri
Do check for retina display and set content scale of CAEAGLLayer to 2 if needed

How we are assigning values to GLFloat to draw a line in iPhone app?

Finally Mr.Chris helped me to draw a line using GLKview and drawInRect: method. It is working fine. But, i need some clarifications,
How we are assigning values to GLFloat?
const GLfloat line[] =
{
-1.0f, -1.5f, //point A : What is -1.0f and -1.5f ? These are x and y or something.
1.5f, -1.0f, //point B : What is 1.5f and -1.0f ? These are x and y or something.
};
Because, i am confusing to set a values here. How it is taking x,y or length? If it is silly question please accept my apologies. Please clarify my doubts on this.
How to set background image for GLKViewController? I have an image to set background but, i don't know where i need to set that?
Sample viewDidLoad code
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"GameDesign03.png"]];
self.context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] autorelease];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[self setupGL];
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self.effect prepareToDraw]; // Prepare the effect for rendering
const GLfloat line[]=
{
-1.0f, -1.5f,
1.5f, -1.0f
};
GLuint bufferObjectNameArray; //Create an handle for a buffer object array
glGenBuffers(1, &bufferObjectNameArray); //Have OpenGL generate a buffer name and store it in the buffer object array
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray); //Bind the buffer object array to the GL_ARRAY_BUFFER target buffer
//Send the line data over to the target buffer in GPU RAM
glBufferData(GL_ARRAY_BUFFER, sizeof(line), line, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition); //Enable vertex data to be fed down the graphics pipeline to be drawn
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 2, NULL); //Specify how the GPU looks up the data
glDrawArrays(GL_LINES, 0, 2); // render
}
Please help on this. Thanks in advance.
So to answer your first question, on this line:
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 2, NULL); //Specify how the GPU looks up the data
you're setting the size argument to 2, which tells OpenGL that there are 2 components per vertex attribute. They are the endpoints of the lines.
And to answer your second question, you need to draw the background image before drawing the lines, as mentioned in my comment above.

Handle multiple meshes in Open GL ES 2.0 (iOS GLKit)?

I've managed to create a single mesh in Open GL ES 2.0 using iOS's GLKit. What I can't figure out is how to create a second mesh that looks identical to the first except with a different position.
I think what would be most helpful would be if someone could simply provide some sample code that draws multiple meshes, as I think I'm going about this entirely wrong. Nonetheless, here's a list of what I've done to try make this work.
I created two C-arrays of vertex information. The first is my template (hardcoded coordinates centered at 0,0,0) and the second is what I'd like displayed (initially empty).
I created two C-arrays of indice information. Same deal as with the vertex information.
I have two global variable ints, vertexCount and indiceCount, both initially 0.
I have a c function, createAt(float x, float y, float z). This function copies my vertex template into my vertex display array and then applies the passed in offsets to each vertex. It also copies indices in and applies an offset so that they point at the new display vertexes.
This doesn't work though. Only one object gets drawn on screen.
Looking through other people's questions and answers, it sounds like maybe I should have multiple vertex buffers? I don't know; I'm horribly confused.
Rendering multiple meshes with the same geometry but different positions or orientations is quite easy with GLKit, thanks to the GLKBaseEffect class. Take a look at the "OpenGL Game" template provided by Xcode, which renders a cube with GLKit and another cube with OpenGL ES 2.0.
Here's a modification of the OpenGL Game sample which adds a new cube above the two spinning ones:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
// Render the object with GLKit
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 36);
// Render another version of the object with GLKit
// First put it in a different place (you would normally
// do this in the update loop):
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -4.0f);
baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _rotation, 0.0f, 1.0f, 0.0f);
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 1.5, -0.0f);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
self.effect.transform.modelviewMatrix = modelViewMatrix;
// Now render it:
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 36);
// Render the object again with ES2
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
The code in-between the "Render another version" and "Render the object again" comments is new. The first thing it needs to do is come up with a new modelview matrix for the additional cube; this is based on the code in update: (not shown). Normally I'd put the code up there but I wanted to keep the sample short.
Next it renders the cube, which is pretty simple with GLKit. Yay GLKit!
I hope this helps. It sounds like you're barking up the wrong tree with additional vertex and index arrays; this is necessary if you want to render different geometries, but you said the same model in different places. That's something GLKit is ideal for.
Since there is only 1 base effect, I take it you would do the matrix calculations in the update, and just assign it to the base effect modelviewmatrix before drawing again?
John Riselvato comments above that he really wishes he could see the update: method contents. I really wished to see this myself as I was having difficulty wrapping my head around putting multiple objects on screen, while using the same GLKBaseEffect object. Here's how I finally did it:
// update method where I create 3 different modelViewMatrices to use with my GLKBaseEffect object later in the draw method
- (void)updateWithDeltaTime:(NSTimeInterval)deltaTime
{
_rotation1 += 120.0 * deltaTime;
_rotation2 += 150.0 * deltaTime;
_rotation3 += 180.0 * deltaTime;
GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, -1.0f, 0.0f, -4.0f);
modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, GLKMathDegreesToRadians(90.0f));
modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, GLKMathDegreesToRadians(_rotation1));
_modelViewMatrix1 = modelViewMatrix;
modelViewMatrix = GLKMatrix4Identity;
modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, 0.0f, 0.0f, -4.0f);
modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, GLKMathDegreesToRadians(90.0f));
modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, GLKMathDegreesToRadians(_rotation2));
_modelViewMatrix2 = modelViewMatrix;
modelViewMatrix = GLKMatrix4Identity;
modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, 1.0f, 0.0f, -4.0f);
modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, GLKMathDegreesToRadians(90.0f));
modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, GLKMathDegreesToRadians(_rotation3));
_modelViewMatrix3 = modelViewMatrix;
}
// draw method where I re-use my GLKBaseEffect object, applying the 3 modelViewMatrices I set in the update: method above
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_effect.transform.modelviewMatrix = _modelViewMatrix1;
[_effect prepareToDraw];
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer1);
glDrawArrays(GL_TRIANGLES, 0, cylinderVertices);
_effect.transform.modelviewMatrix = _modelViewMatrix2;
[_effect prepareToDraw];
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glDrawArrays(GL_TRIANGLES, 0, cylinderVertices);
_effect.transform.modelviewMatrix = _modelViewMatrix3;
[_effect prepareToDraw];
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer3);
glDrawArrays(GL_TRIANGLES, 0, cylinderVertices);
}
// how i initially setup my GLKBaseEffect object and my opengl buffers
- (void)_setupGL
{
[EAGLContext setCurrentContext:_context];
//glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
_effect = [[GLKBaseEffect alloc] init];
[self _createEffect];
[_effect prepareToDraw];
glGenBuffers(1, &_vertexBuffer1);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer1);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glGenBuffers(1, &_vertexBuffer2);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glGenBuffers(1, &_vertexBuffer3);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer3);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)offsetof(Vertex, Position));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)offsetof(Vertex, Texel));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)offsetof(Vertex, Normal));
}
Hope this helps someone.

Why is glClear() so slow with point sprites on iPhone?

I am trying to draw point sprites with OpenGL ES on iPhone. It's possible there could be very many of them (1000) and up to 64 pixels wide (maybe that's my problem right there - is there a limit or could I be using too much memory?)
I am using CADisplayLink to time the frames. What happens is that the first gl drawing function tends to delay or stall when either the point count is too high or when the point size is too big. In my example below, glClear() is the first drawing function, and it can take anywhere from 0.02 seconds to 0.2 seconds to run. If I simply comment out glClear, glDrawArrays becomes the slow function (it runs very fast otherwise).
This example is what I've stripped my code down to in order to isolate the problem. It simply draws a bunch of point sprites, with no texture, all in the same spot. I am using VBOs to store all the sprite data (position, color, size). It may seem like overkill for the example but of course I have intentions to modify this data later.
This is the view's init function (minus the boilerplate gl setup):
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendEquationOES(GL_FUNC_ADD_OES);
glClearColor(0.0, 0.0, 0.0, 0.0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
glEnable(GL_POINT_SPRITE_OES);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
glEnableClientState(GL_COLOR_ARRAY);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_POINT_SMOOTH);
glGenBuffers(1, &vbo); // vbo is an instance variable
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glMatrixMode(GL_PROJECTION);
glOrthof(0.0, [self frame].size.width, 0.0, [self frame].size.height, 1.0f, -1.0f);
glViewport(0, 0, [self frame].size.width, [self frame].size.height);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0f, [self frame].size.height, 0.0f);
glScalef(1.0f, -1.0f, 1.0f);
And this is the rendering function:
- (void)render
{
glClear(GL_COLOR_BUFFER_BIT); // This function runs slowly!
int pointCount = 1000;
// fyi...
// typedef struct {
// CGPoint point;
// CFTimeInterval time;
// GLubyte r, g, b, a;
// GLfloat size;
// } MyPoint;
glBufferData(GL_ARRAY_BUFFER, sizeof(MyPoint)*pointCount, NULL, GL_DYNAMIC_DRAW);
MyPoint * vboBuffer = (MyPoint *)glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
for (int i = 0; i < pointCount; i++) {
vboBuffer[i].a = (GLubyte)0xFF;
vboBuffer[i].r = (GLubyte)0xFF;
vboBuffer[i].g = (GLubyte)0xFF;
vboBuffer[i].b = (GLubyte)0xFF;
vboBuffer[i].size = 64.0;
vboBuffer[i].point = CGPointMake(200.0, 200.0);
}
glUnmapBufferOES(GL_ARRAY_BUFFER);
glPointSizePointerOES(GL_FLOAT, sizeof(MyPoint), (void *)offsetof(MyPoint, size));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyPoint), (void *)offsetof(MyPoint, r));
glVertexPointer(2, GL_FLOAT, sizeof(MyPoint), (void *)offsetof(MyPoint, point));
glDrawArrays(GL_POINTS, 0, pointCount);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Why is the glClear function stalling? It doesn't just delay in random amounts - depending on the point count or size, it tends to randomly delay in the same intevals (eg. 0.015 sec, 0.030 sec, 0.045 sec, etc). Also something strange I noticed is that if I switch to glBlendMode(GL_ZERO, GL_ONE), it runs just fine (although this is will not be the visual effect I'm after). Other glBlendMode values change the speed as well - usually for the better. That makes me think it is not a memory issue because that has nothing to do with the VBO (right?).
I admit I am a bit new at OpenGL and may be misunderstanding basic concepts about VBOs or other things. Any help or guidance is greatly appreciated!
If glClear() is slow you might try drawing a large blank quad that completely covers the viewport area.
Are you using sync (or is it enabled?). The delay you're seeing might be related to the fact that CPU and GPU run in parallel, so measuring time of individual GL calls has no meaning.
If you're using VSync (or the GPU is heavily loaded), there might be some latency in the SwapBuffers call, since some drivers make busy loops to wait for VBlank.
But first consider that you should NOT time individual GL calls, since most GL calls just set some state of the GPU or write to a command buffer, the command execution happens asynchronously.