Sean Clark Hess
Sean Clark Hess

Reputation: 16059

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.

Upvotes: 2

Views: 1335

Answers (1)

damix911
damix911

Reputation: 4443

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

Upvotes: 5

Related Questions