gldrawelements bad access in xcode when used outside of GLKViewController - ios

I'm pretty new to OpenGL ES, but all I'm trying to do is draw indexed vertices using glDrawElements in a Character class. I've gotten this to work before inside of my GLKViewController class, but when I tried creating a Character class which would perform its own rendering, I got nothing but BAD_ACCESS. Here is my Character class:
#import "Character.h"
#interface Character()
{
GLuint _vertexBuffer;
GLuint _indexBuffer;
GLuint _vertexArray;
}
#property(nonatomic, weak) GLKBaseEffect *effect;
#end
typedef struct {
float Position[3];
float Color[4];
} Vertex;
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, 1, 0}, {0, 1, 0, 1}},
{{-1, 1, 0}, {0, 0, 1, 1}},
{{-1, -1, 0}, {0, 0, 0, 1}}
};
const GLushort Indices[] = {
0, 1, 2,
2, 3, 0
};
#implementation Character
- (id)initWithEffect:(GLKBaseEffect *)effect
{
if (self = [super init])
{
self.effect = effect;
[self setupGL];
}
return self;
}
- (void)setupGL
{
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _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);
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));
glBindVertexArrayOES(0);
}
- (void)teardownGL
{
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
}
- (void)render
{
self.effect.transform.modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, self.position.x, self.position.y, self.position.z);
self.effect.transform.modelviewMatrix = GLKMatrix4Rotate(self.effect.transform.modelviewMatrix, self.rotation, 0.0f, 0.0f, 1.0f);
[self.effect prepareToDraw];
glBindVertexArrayOES(_vertexArray);
glDrawElements(GL_TRIANGLES, sizeof(Indices) / sizeof(Indices[0]), GL_UNSIGNED_SHORT, 0);
}
#end
Then in ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView *view = (GLKView *)self.view;
view.context = self.context;
character = [[Character alloc] initWithEffect:self.effect];
character.position = GLKVector3Make(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2, 0.0f);
[self setupGL];
}
rendered using:
- (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);
[character render];
}
I know it isn't something as simple as a miscalculation of byte-size or something because I've been at this for a couple days now.

Hard to say for sure on a quick read, but it looks like the problem is that you don't have a current GL context when you're setting up your VAO in -[Character setupGL].
Creating an EAGLContext object doesn't make it the current context. If the rest of the code in your view controller looks like that from the Xcode "OpenGL Game" template, ViewController doesn't set the current context until its own setupGL method, which you call only after calling into your Character class and its attempts to set up OpenGLĀ ES resources.

Related

How to draw multiple 2D objects in OpenGL ES and move them with touch in iOS?

I'm trying to draw multiple 2D objects and being able to move them with touch in OpenGL ES for iOS. I started a tutorial on drawing a square, but I have no idea how to add touch to move it. I'd like to be able to load multiple objects and move each of them around the screen with touch.
#import "HelloGLKitViewController.h"
typedef struct {
float Position[3];
float Color[4];
} Vertex;
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, 1, 0}, {0, 1, 0, 1}},
{{-1, 1, 0}, {0, 0, 1, 1}},
{{-1, -1, 0}, {0, 0, 0, 1}}
};
const GLubyte Indices[] = {
0, 1, 2,
2, 3, 0
};
GLuint _vertexBuffer;
GLuint _indexBuffer;
#interface HelloGLKitViewController ()
#property (strong, nonatomic) EAGLContext *context;
#property (strong, nonatomic) GLKBaseEffect *effect;
#end
#implementation HelloGLKitViewController
- (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;
[self setupGL];
}
- (void)viewDidUnload
{
[super viewDidUnload];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
[self tearDownGL];
}
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
[self.effect prepareToDraw];
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
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));
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
#pragma mark - GLKViewControllerDelegate
- (void)update {
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 4.0f, 10.0f);
self.effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -6.0f);
self.effect.transform.modelviewMatrix = modelViewMatrix;
}
- (void)setupGL {
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _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;
}
#end
For the code you've posted, you would want to make another GLKBaseEffect, and update the modelviewMatrix properties of each matrix independently based on the touches you received.

Open GL ES object not appearing in shadow map?

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);
}

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);
}

Setting up vertices using pointer not working

im currently working on some OpenGL Basics with OpenGL ES 2.0.
If i setup the vertices as constants in the top the triangle gets drawn; if i try to set them up in a method using a pointer, nothing is drawn.
What am I missing?
#import "CometGLViewController.h"
typedef struct {
float Position[3];
float Color[4];
} Vertex;
//vertices store information for each "point" used to draw a triangle
Vertex* Vertices; // NOT DRAWING
//const Vertex Vertices[] = {
// {{0, 0, 0},{0, 0, 0, 1}},
// {{1, 1, 0}, {1, 0, 0, 1}},
// {{0, 1, 0}, {1, 0, 0, 1}},
//}; // THIS WORKS
//Used to reuse vertices
const GLubyte Indices[] = {
0, 1, 2,
};
... some other stuff
- (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.drawableMultisample = GLKViewDrawableMultisample4X;
[self setupVertices];
[self setupGL];
}
...
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(_curRed, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
[self.effect prepareToDraw];
glBindVertexArrayOES(_vertexArray);
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
...
#pragma mark - OpenGL stuff
- (void)setupGL {
[EAGLContext setCurrentContext:self.context];
glEnable(GL_CULL_FACE);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
// ----- create new buffer, work with "vertexBuffer", glBufferData sends data for opengl usage
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _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);
// ----- Setup vertices attributes
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));
}
- (void)tearDownGL {
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
glDeleteVertexArraysOES(1, &_vertexArray);
self.effect = nil;
}
- (void)setupVertices
{ // test
int points = 3;
Vertices = malloc(sizeof(Vertex) * points);
Vertex v = {{0, 0, 0}, {0, 0, 0, 1}};
Vertices[0] = v;
Vertex v1 = {{1, 1, 0}, {0, 1, 0, 1}};
Vertices[1] = v1;
Vertex v2 = {{0, 1, 1}, {1, 0, 0, 1}};
Vertices[2] = v2;
}
#end
Change
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
to
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * 3, Vertices, GL_STATIC_DRAW);
Your problem is that sizeof(vertices) works differently for pointers than for arrays allocated on the stack.

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

Resources