OpenGL: Adding texture to square changes it to a triangle? - ios

I am following along with an exercise in O'Reilly's iOS Game Development Cookbook to draw a square with OpenGL using textures. This follows a previous recipe for creating a square without texture, and that worked fine. However, when I run the code with texture, as below, I see a triangle rather than a square. Also the triangle is not the shape I would expect if only one of the two triangles I am using to draw the square were drawn. Those are right triangles, whereas the triangle that is actually appearing is isosceles.
//Modified with addition of textureCoordinates
typedef struct {
GLKVector3 position;
GLKVector2 textureCoordinates;
} Vertex;
//Modified with addition of second set of braces{} per line
const Vertex SquareVertices[] = {
{{-1, -1, 0}, {0,0}},
{{1, -1, 0}, {1,0}},
{{1, 1, 0}, {1, 1}},
{{-1, 1, 0}, {0, 1}},
};
const GLubyte SquareTriangles[] = {
0, 1, 2,
2, 3, 0
};
#interface ViewController ()
{
GLuint _vertexBuffer;
GLuint _indexBuffer;
GLKBaseEffect *_squareEffect;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
GLKView *view = (GLKView *)self.view;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:view.context];
//Create the vertex array buffer in which opengl will store vertices
//tell opengl to give us a buffer
glGenBuffers(1, &_vertexBuffer);
//make this buffer be the active array buffer
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
//put this data into acive array buffer
//it's as big as square vertices array so we can use the data from that array
//also this data isn't going to change
glBufferData(GL_ARRAY_BUFFER, sizeof(SquareVertices), SquareVertices, GL_STATIC_DRAW);
//now do same for index buffer, which shows which vertices to use to draw triangle
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(SquareTriangles), SquareTriangles, GL_STATIC_DRAW);
//prepare gl effect
_squareEffect = [[GLKBaseEffect alloc] init];
_squareEffect.texture2d0.name = texture.name;
//first set up projection matrix
float aspectRatio = self.view.bounds.size.width/self.view.bounds.size.height;
float fieldOfViewDegrees = 60.0;
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(fieldOfViewDegrees), aspectRatio, 0.1, 10.0);
_squareEffect.transform.projectionMatrix = projectionMatrix;
//next we describe how the square should be positions (6 units from camera)
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -6.0f);
_squareEffect.transform.modelviewMatrix = modelViewMatrix;
//CODE ADDED TO ADD TEXTURE
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"3px-tile" ofType:#"png"];
GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:imagePath options:nil error:&error];
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//tell the effect it should prepare opengl to draw using configured settings
[_squareEffect prepareToDraw];
//opengl alreayd knows the vertex array contains vertex data. we now tell how to use
//tell opengl how the data is laid out for position of each vertex in vertex array
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
//how that open gl knows where to find vertex positions, can draw them
int numberOfVertices = sizeof(SquareTriangles)/sizeof(SquareTriangles[0]);
glDrawElements(GL_TRIANGLES, numberOfVertices, GL_UNSIGNED_BYTE, 0);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, textureCoordinates));
}
#end
Here's what I see:
Here's what I've tried:
Back tracing to original square code - it still works if I change the code back
Changing the location in the code where I add the texture - doesn't change anything, the triangle remains.
Why do I have a triangle and how can I get the square back?

Your first call of glVertexAttribPointer
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
Has a stride of 0. This is may be incorrect, be safe and change it to sizeof(Vertex) (as it is in the second call).
If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.
Your second call of glVertexAttribPointer should be moved in front of your glDrawElements, although this is most likely not a problem right now.
I'm not sure if this solves the problem, but I can't comment yet so I have to submit an answer. Please update the code if you've fixed it.

Related

Smooth changing of line thickness using OpenGL ES

I'm drawing a few lines using OpenGL ES and I need to change their thickness from 1 pixel to 3 pixels smoothly, but glLineWidth doesn't allow to set line thickness between 1.0 and 2.0.
Is it possible?
Here is my code
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
glEnable(GL_DEPTH_TEST);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(thinLines), thinLines, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBindVertexArrayOES(0);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
self.effect.constantColor = GLKVector4Make(lineR, lineG, lineB, 1.0f);
[self.effect prepareToDraw];
glLineWidth(1 + scaleQ);
glDrawArrays(GL_LINES, 0, thinLinesCount*2);
}
OpenGL ES (including 3.0) does not support antialiased lines. From documentation to glLineWidth:
The actual width is determined by rounding the supplied width to the
nearest integer.
So unfortunately you can't "smoothly" change line thickness.

Failing to color line using VBO

I am trying and failing to draw a line with color using glkit / OpenGL Es2. I can draw the line, but it comes out as black.
My current approach is attempting to use a VBO containing both positional and color data.
Set-up:
typedef struct {
float Position[2];
float Color[4];
} LinePoint;
LinePoint line[] =
{
{{0.0, 0.0},{1.0,0.0,0.0,1}},
{{2.0, 3.0},{1.0,0.0,0.0,1}}
};
glGenBuffers(1, &_lineBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _lineBuffer);
glBufferData(GL_ARRAY_BUFFER,sizeof(LinePoint)*2,line,GL_STATIC_DRAW);
In my drawInRect method:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
[EAGLContext setCurrentContext:self.context];
[self.effect prepareToDraw];
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, _lineBuffer);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition,2,GL_FLOAT,GL_FALSE,sizeof(LinePoint),(const GLvoid *) offsetof(LinePoint, Position));
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor,4,GL_FLOAT,GL_FALSE,sizeof(LinePoint),(const GLvoid *) offsetof(LinePoint, Color));
// Set the line width
glLineWidth(50.0);
// Render the line
glDrawArrays(GL_LINE_STRIP, 0, 2);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
}

glDrawElements doesn't show anything

I'm trying to learn OpenGL on iOS. I'm following this tutorial.
http://www.raywenderlich.com/5235/beginning-opengl-es-2-0-with-glkit-part-2
I'm sure I followed the steps carefully, but when I get to the end, only don't see any shapes on the screen.
https://gist.github.com/seanhess/5356598
I do see the background color changing, so OpenGL is working in general. Just the call to glDrawElements doesn't seem to be doing anything.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
He has some demo code, but it's not the same as the code he has you write in the tutorial, and I want to understand why this doesn't work before pasting his in.
Where is the GLKBaseEffect supposed to be drawn? I don't see how we actually used it.
The following seems to be wrong, as all the vertices are the same:
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
};
Even if everything else is correct, your triangle is degenerate as
all is vertices are coincident. When you fix the coordinates, make
sure that the indices reference the vertices in a counter-clockwise
fashion or, even better for your first experiments, call
glDisable(GL_CULL_FACE);
before drawing. You could try to pick your vertices like this:
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{-.9, -.9, 0}, {1, 0, 0, 1}},
{{.9, -.9, 0}, {1, 0, 0, 1}},
{{-.9, .9, 0}, {1, 0, 0, 1}},
{{.9, .9, 0}, {1, 0, 0, 1}},
};
// These are the trianges. Just reference the vertices
const GLubyte Indices[] = {
0, 1, 2,
2, 1, 3
};
Edit
Try to comment away the second part of update:
/*
// Set the projection matrix of the effect. It defines the field of view
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 40., 10.0);
self.effect.transform.projectionMatrix = projectionMatrix;
// Rotate about z axis
// the model view matrix is the transform applied to any geometry that the effect renders
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -6);
_rotation += 90 * self.timeSinceLastUpdate;
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
self.effect.transform.modelviewMatrix = modelViewMatrix;
*/
The matrices you define put your object out of the final image. When you don't see anything on the screen one of the first things you should check are your transformation matrices. In your case, the problem is with the perspective transformation:
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 40., 10.0);
Your translated and rotated object must be located at a distance between the 3rd and 4th parameter of this call in order to be drawn, and actually the 3rd parameter is the distance of the so called near plane, and must be smaller than the 4th parameter, the far plane. A safe bet is usually 1 and 100 for these two parameters.
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0, 100.0);
Edit 2
The following is a working version.
//
// HelloGLKitViewController.m
// OpenGL2Tutorial
//
// Created by Sean Hess on 4/10/13.
// Copyright (c) 2013 Sean Hess. All rights reserved.
//
#import "HelloGLKitViewController.h"
typedef struct {
float Position[3];
float Color[4];
} Vertex;
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{-.9, -.9, 0}, {1, 0, 0, 1}},
{{.9, -.9, 0}, {1, 0, 0, 1}},
{{-.9, .9, 0}, {1, 0, 0, 1}},
{{.9, .9, 0}, {1, 0, 0, 1}},
};
// These are the trianges. Just reference the vertices
const GLubyte Indices[] = {
0, 1, 2,
2, 1, 3
};
#interface HelloGLKitViewController () {
GLuint _vertexBuffer;
GLuint _indexBuffer;
float _rotation;
float _currentRed;
BOOL _increasing;
}
#property (nonatomic, strong) EAGLContext * context;
#property (nonatomic, strong) GLKBaseEffect * effect;
#end
#implementation HelloGLKitViewController
// I think this method just fills the objective-c stuff with the information from my c structs
- (void)setupGL {
[EAGLContext setCurrentContext:self.context];
self.effect = [GLKBaseEffect new];
glGenBuffers(1, &_vertexBuffer); // supposed to be an array of buffers, doing that trick again
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); // when I say "GL_ARRAY_BUFFER" I mean _vertexBuffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
- (void)tearDownGL {
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
self.effect = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) NSLog(#"FAiled to create ES Context");
GLKView * view = (GLKView *)self.view;
view.context = self.context;
// will automatically pause when interrupted
self.pauseOnWillResignActive = YES;
[self setupGL];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
[self tearDownGL];
}
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(_currentRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// have to call after you change any properties in the effect, before drrawing
[self.effect prepareToDraw];
// We don't have to do this again, since we did it above in setupGL
// They're already bound to GL_ARRAY_BUFFER and GL_ELEMENT_ARRAYBUFFER
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
// remember my vertex array contains Vertex(s)
// so we're telling it how to read it
// position is 3 floats, the offset is based on that offsetof function
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) offsetof(Vertex, Position));
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) offsetof(Vertex, Color));
// 1. pretty much always use triangles
// 2. the number of vertices to render. tricky way to do .length on array
// 3. the data type
// 4. seems like should be pointer to indices. We're using VBOs, so it's already set to the GL_ELEMENT_ARRAY_BUFFER. So give it 0.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
- (void)update {
if (_increasing) {
_currentRed += 1.0 * self.timeSinceLastUpdate;
} else {
_currentRed -= 1.0 * self.timeSinceLastUpdate;
}
if (_currentRed >= 1.0) {
_currentRed = 1.0;
_increasing = NO;
}
if (_currentRed <= 0.0) {
_currentRed = 0.0;
_increasing = YES;
}
// Set the projection matrix of the effect. It defines the field of view
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0, 100.0);
self.effect.transform.projectionMatrix = projectionMatrix;
// Rotate about z axis
// the model view matrix is the transform applied to any geometry that the effect renders
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -6);
_rotation += 90 * self.timeSinceLastUpdate;
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
self.effect.transform.modelviewMatrix = modelViewMatrix;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.paused = !self.paused;
NSLog(#"timeSinceLastUpdate: %f", self.timeSinceLastUpdate);
NSLog(#"timeSinceLastDraw: %f", self.timeSinceLastDraw);
NSLog(#"timeSinceFirstResume: %f", self.timeSinceFirstResume);
NSLog(#"timeSinceLastResume: %f", self.timeSinceLastResume);
}
#end

How do I manipulate objects independently of one another in OpenGL ES 2.0?

I am building an iOS game with OpenGL ES 2.0 that contains a scene with around 100 different 'objects' which I need to be able to transform independently of one another. I am new to OpenGL ES. As such, I initially thought I should start with OpenGL ES 1.1, then later migrate the app to 2.0 to take advantage of the enhanced visual effects.
However, just as I was getting comfortable with 1.1, I realized, partly based on Apple's very 2.0-centric Xcode template for OpenGL, that it was going to be more trouble than it's worth to fight moving straight into 2.0, so I bit the bullet.
Now, I'm finding it difficult to grasp the concepts enough to do simple transforms on my vertex array objects independently of one another. I read in the OpenGLES 2.0 docs that the best way to do this would be to use multiple VBOs, one for each vertex array. However, I can't seem to transform one of them without affecting the entire scene.
I started the project with the Apple OpenGL ES template and streamlined it, such that the setupGL method looks like this:
-(void)setupGL
{
// Setup
[EAGLContext setCurrentContext:self.context];
[self loadShaders];
self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f);
glEnable(GL_DEPTH_TEST); // do depth comparisons and update the depth buffer
// Initialize first buffer
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gPyramidVertexData), gPyramidVertexData, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBindVertexArrayOES(0);
// Initialize second buffer
glGenVertexArraysOES(2, &_vertexArray2);
glBindVertexArrayOES(_vertexArray2);
glGenBuffers(2, &_vertexBuffer2);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBindVertexArrayOES(0);
}
I know that's incredibly sloppy code- I basically copy-and-pasted the buffer creation portion to set myself up for experimenting with two different vertextArrays in separate buffers. It appears to have worked, as I can render both buffers in the drawInRect method:
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glBindVertexArrayOES(_vertexArray);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, numberOfVerteces);
glBindVertexArrayOES(_vertexArray2);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, numberOfVerteces2);
}
My problem comes when I try to do transforms on one vertex array without affecting the other one. I tried adding transforms in the above method just before the glDrawArrays calls, without success- I think that may only work with 1.1. It appears my transforms must be done within the update method:
-(void)update
{
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
self.effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation( 0.0f, 0.0f, -4.0f);
baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _sceneRotation, 1.0f, 1.0f, 1.0f);
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, zoomFactor);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _objectRotation, 0.0f, 1.0f, 0.0f);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
}
However, this is where I get really confused-- it's not at all clear how I could modify this method to do transforms to one VBO or the other. It's not even clear that th above code is making any reference to one particular buffer at all.
Eventually I would like to expand my game by moving the code for each game object into an instance of a custom class, which would handle the transforms, etc. But I would like to know if I'm completely misguided in my approach before doing so.
In case this is helpful to anyone having similar issues, I found the answers I was looking for on Ian Terrell's excellent blog, Games by Ian Terrell.
In particular, this tutorial and its accompanying sample code were exactly what I needed to get a grip on this very complicated subject. Hope this helps!
GLKMatrix4 _modelViewProjectionMatrix[5]; // Al inicio
En - (void)update utiliza
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1.0f, 1.0f, -1.0f / aspect, 1.0f / aspect, -10.0f, 10.0f);
for (int i=0; i<5;i++) {
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(i*0.2+ 0.3f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeZRotation(0.0 - _rotation));
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeXRotation(0.0 - _rotation));
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeYRotation(0.20 - _rotation));
_modelViewProjectionMatrix[i] = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
}

Use of VAO around VBO in Open ES iPhone app Causes EXC_BAD_ACCESS When Call to glDrawElements

I'm trying to take my code to the next level. Following some best practices from Apple, I'm trying to implement Vertex Array Objects around my Vertex Buffer Objects (VBO). I setup my VBOs and VAOs like this:
- (void)setupVBOs {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
{
glGenVertexArraysOES(1, &directArrayObject);
glBindVertexArrayOES(directArrayObject);
// GLuint texCoordBuffer;
glGenBuffers(1, &texCoordBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(DirectVertices), DirectVertices, GL_STATIC_DRAW);
glVertexAttribPointer(directPositionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(DirectVertex), (GLvoid*)offsetof(DirectVertex, position));
glEnableVertexAttribArray(directPositionSlot);
glVertexAttribPointer(texCoordSlot, 2, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(DirectVertex), (GLvoid*)offsetof(DirectVertex, texCoord));
glEnableVertexAttribArray(texCoordSlot);
glGenVertexArraysOES(1, &arrayObject);
glBindVertexArrayOES(arrayObject);
// GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glEnableVertexAttribArray(positionSlot);
glVertexAttribPointer(colorSlot, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));
glEnableVertexAttribArray(colorSlot);
// GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
}
which I took from http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=287977 and then use it like this:
- (void) render:(CADisplayLink*)displayLink {
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, backingWidth, backingHeight);
[directProgram use];
glBindVertexArrayOES(directArrayObject);
glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, videoFrameTexture);
// // Update uniform values
glUniform1i(videoFrameUniform, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[program use];
glBindVertexArrayOES(arrayObject);
glDisable(GL_TEXTURE_2D);
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);
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
glBindVertexArrayOES(0);
BOOL success = [context presentRenderbuffer:GL_RENDERBUFFER];
if(!success)
NSLog(#"present failed");
}
The call to glDrawArrays works, and it fills my texture, however, the call to glDrawElements fails with an EXC_BAD_ACCESS. My shader programs (i use two) are wrapped in a GLProgram object that I took from http://iphonedevelopment.blogspot.com/2010/11/opengl-es-20-for-ios-chapter-4.html
Remove glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); from the end of your setup function.
Per the specification for OES_vertex_array_object, a vertex array object encapsulates all state except the array buffer binding1, so there is no element buffer bound at the time that you’re drawing, whereas you presumably wanted indexBuffer to be bound. By leaving indexBuffer bound at the time that you bind away from your vertex array object, you ensure that it’ll be rebound when you return to that vertex array object.
1 If you’re wondering why the array buffer binding isn’t tracked in vertex array objects, this is presumably because the currently-bound array buffer isn’t used directly when reading vertex data from arrays—rather, each vertex attribute has its own buffer binding, which is filled out by its respective gl*Pointer function by looking at the array buffer binding when the function is called.

Resources