OpenGL ES 2.0 рисует простой треугольник, ничего не показывая

У меня совсем нет идей.

У меня есть Руководство по программированию OpenGL ES 2.0, у меня есть код OpenGL ES 2.0 шаблона Apple, я следил за этой страницей: http://open.gl/drawing

Кажется, я не могу нарисовать простой треугольник, я не уверен, что делаю неправильно.

Примечание. У меня также есть файл GameViewController.xib, который является подклассом GLKView, как и код шаблона Apple.

Мой вершинный шейдер:

attribute vec4 position;

void main()
{
    gl_Position = position;
}

Мой фрагментный шейдер:

void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Мой заголовочный файл GameViewController:

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>

@interface GameViewController : GLKViewController

@end

Мой файл реализации GameViewController:

#import "GameViewController.h"

const GLfloat vertices[] =
{
    0.0f, 0.5f,
    -0.5f, -0.5f,
    0.5f, -0.5f
};

// Class extension to keep data private
@interface GameViewController()
{        
    // vertex buffer object
    GLuint vbo;

    // vertex array object
    GLuint vao;

    // shader program
    GLuint shaderProgram;
}

@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;

@end

@implementation GameViewController

// setup our OpenGL context
-(void)viewDidLoad
{
    [super viewDidLoad];

    [self setupContext];

    // -------------------------------------------------------------
    // create a vertex array object that will hold
    // all the linking between attributes and vertex data
    // -------------------------------------------------------------
    [self createVertexArrayObject];

    [self createVertexBufferObject];

    [self loadShaders];

    [self checkErrors];
}

-(void)checkErrors
{
    GLenum error = glGetError();

    switch (error) {
        case GL_NO_ERROR:
            NSLog(@"No errors");
            break;
        case GL_INVALID_ENUM:
            NSLog(@"An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_VALUE:
            NSLog(@"A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_OPERATION:
            NSLog(@"The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            NSLog(@"The frameBuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_OUT_OF_MEMORY:
            NSLog(@"There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.");
            break;
        case GL_STACK_UNDERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to underflow.");
            break;
        case GL_STACK_OVERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to overflow.");
            break;
        default:
            break;
    }
}

#pragma mark - Setup Context -

-(void)setupContext
{
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    if(!self.context)
    {
        NSLog(@"Failed to create OpenGL ES Context");
    }

    // tell our view the context is an OpenGL context
    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    [EAGLContext setCurrentContext:self.context];

    self.effect = [[GLKBaseEffect alloc] init];

    glEnable(GL_DEPTH_TEST);
}

#pragma mark - Vertex Array Object Methods -

-(void)createVertexArrayObject
{
    glGenVertexArraysOES(1, &vao);
    glBindVertexArrayOES(vao);
}

#pragma mark - Create Vertex Buffer Object Method -

-(void)createVertexBufferObject;
{
    glGenBuffers(1, &vbo); // Generate 1 memory buffer for the VBO

    // Make our VBO the current buffer object to receive data
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // -------------------------------------------------------------
    // Start copying data to our VBO
    //
    // GL_STATIC_DRAW will upload once and drawn many times
    // -------------------------------------------------------------
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

}

#pragma mark - Shader Code -

-(void)loadShaders
{
    // load both vertex shader and fragment shader
    GLuint vertexShader = [self compileVertexShader];
    GLuint fragmentShader = [self compileFragmentShader];

    // create a shader program from the vertex shader and fragment shader
    shaderProgram = [self combineVertexShader:vertexShader AndFragmentShader:fragmentShader];

    // linking vertex data and attributes
    GLint positionAttrib = glGetAttribLocation(shaderProgram, "position");

    glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(positionAttrib);
}

-(GLuint)compileVertexShader
{
    // get the path to the shader file as a C string
    const GLchar *vertexShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"]
                                                                          encoding:NSUTF8StringEncoding
                                                                             error:nil] UTF8String];

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderPath, NULL);
    glCompileShader(vertexShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Vertex shader compiled correctly");
    }
    else
    {
        NSLog(@"Vertex shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(vertexShader, logLength, &logLength, log);
        NSLog(@"Vertex Shader compile log:\n%s", log);
        free(log);
    }

    return vertexShader;
}

-(GLuint)compileFragmentShader
{
    // get the path to the shader as a C string
    const GLchar *fragmentShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"]
                                                                          encoding:NSUTF8StringEncoding
                                                                             error:nil] UTF8String];

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderPath, NULL);
    glCompileShader(fragmentShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Fragment shader compiled correctly");
    }
    else
    {
        NSLog(@"Fragment shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(fragmentShader, logLength, &logLength, log);
        NSLog(@"Fragment Shader compile log:\n%s", log);
        free(log);
    }

    return fragmentShader;
}

-(void)linkProgram:(GLuint)paramShaderProgram
{
    // link shader to program now and become active shader program
    glLinkProgram(paramShaderProgram);

    GLint status;
    // test if the program linked correctly
    glGetProgramiv(paramShaderProgram, GL_LINK_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program linked correctly");
    }
    else
    {
        NSLog(@"Shader program linked failed");
    }
}

-(void)validateProgram:(GLuint)paramShaderProgram
{
    GLint status, logLength;

    glValidateProgram(paramShaderProgram);

    glGetProgramiv(paramShaderProgram, GL_VALIDATE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program validated correctly");
    }
    else
    {
        NSLog(@"Shader program validate failed");
    }

    glGetProgramiv(paramShaderProgram, GL_INFO_LOG_LENGTH, &logLength);

    if(logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(paramShaderProgram, logLength, &logLength, log);
        NSLog(@"Program validate log:\n%s", log);
        free(log);
    }
}

-(GLuint)combineVertexShader:(GLuint)paramVertexShader AndFragmentShader:(GLuint)paramFragmentShader
{
    GLuint newShaderProgram = glCreateProgram();

    glAttachShader(newShaderProgram, paramVertexShader);
    glAttachShader(newShaderProgram, paramFragmentShader);

    [self linkProgram:newShaderProgram];

    [self validateProgram:newShaderProgram];

    // start using shader now, will use the active shader program
    glUseProgram(newShaderProgram);

    return newShaderProgram;
}

#pragma mark - GLKViewController Render Delegate Methods -

-(void)setupViewport
{
    glViewport(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);

    self.effect.transform.projectionMatrix = GLKMatrix4MakeOrtho(-3, 3, -2, 2, 1, -1);
}

-(void)update
{
    [self setupViewport];
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    [self.effect prepareToDraw];

    glDrawArrays(GL_TRIANGLES, 0, 3);
}

#pragma mark - Cleanup Memory -

-(void)tearDownContext
{
    [EAGLContext setCurrentContext:self.context];

    // delete vertex buffer object and vertex array object
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArraysOES(1, &vao);

    // delete shader program
    if(shaderProgram)
    {
        glDeleteProgram(shaderProgram);
        shaderProgram = 0;
    }

    // unset OpenGL context
    if ([EAGLContext currentContext] == self.context)
    {
        [EAGLContext setCurrentContext:nil];
    }

    self.context = nil;
}

-(void)dealloc
{
    [self tearDownContext];
}

-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if([self isViewLoaded] && self.view.window == nil)
    {
        self.view = nil;

        [self tearDownContext];

        if([EAGLContext currentContext] == self.context)
        {
            [EAGLContext setCurrentContext:nil];
        }

        self.context = nil;
    }

    // Dispose of any resources that can be recreated
}

@end

Все, что я вижу, это мой серый фон экрана, для которого я очистил цвет.

Если кто-то может указать, где я ошибся, это было бы здорово.

РЕДАКТИРОВАТЬ

Я решил отложить в сторону свою личную неприязнь к сайту Рэя и просто проглотил этот урок:

http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial

В этом руководстве не используется GLKit, что является дополнительным бонусом, поскольку учащийся пишет свой собственный буфер кадра и буфер рендеринга и представляет их на экране.

Я чувствую, что это ближе к конвейеру OpenGL ES 2.0, чем использование GLKit.

Как предположил Рикардо, использование GLKit требует больше усилий для понимания, чем его ценности на данный момент.

Я также настоятельно рекомендую использовать приведенную выше ссылку на учебник на веб-сайте Рэя, чтобы запустить работающую программу, а не пытаться следовать коду шаблона Apple.

В моем случае код шаблона Apple и книга имели слишком много противоречий, что привело к потере многих часов.

Я также решил это с помощью GLKit для тех, кто все еще заинтересован в использовании метода GLKit.

Решением было сочетание установки моей проекционной матрицы и привязки правильного местоположения атрибута положения вершинного шейдера.

Также хочу отметить одно очень важное замечание:

УБЕДИТЕСЬ, ЧТО КОПИРОВАТЬ НАБОР РЕСУРСОВ ДЛЯ ЦЕЛИ ИМЕЕТ ВЕРШИННЫЙ И ФРАГМЕНТНЫЙ ШЕЙДЕР!

Я был в точке, где треугольник был черного цвета, и я не мог изменить цвет своего треугольника, независимо от того, что я печатал в своем файле фрагментного шейдера. Проблема заключалась в том, что эти файлы шейдеров по умолчанию не копируются в ресурс пакета.

Во всяком случае, мой рабочий обновленный код полностью представлен ниже:

#import "GameViewController.h"

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

// Uniform index.
enum
{
    UNIFORM_MODELVIEWPROJECTION_MATRIX,
    UNIFORM_NORMAL_MATRIX,
    NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];

// Attribute index.
enum
{
    ATTRIB_VERTEX,
    ATTRIB_NORMAL,
    NUM_ATTRIBUTES
};


const GLfloat vertices[] =
{
    0.0f, 0.5f,
    -0.5f, -0.5f,
    0.5f, -0.5f
};

// Class extension to keep data private
@interface GameViewController()
{
    // vertex buffer object
    GLuint vbo;

    // vertex array object
    GLuint vao;

    // shader program
    GLuint shaderProgram;

    GLKMatrix4 modelViewProjectionMatrix;
    GLKMatrix3 normalMatrix;
}

@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;

@end

@implementation GameViewController

// setup our OpenGL context
-(void)viewDidLoad
{
    [super viewDidLoad];

    [self setupContext];

    [self loadShaders];

    // -------------------------------------------------------------
    // create a vertex array object that will hold
    // all the linking between attributes and vertex data
    // -------------------------------------------------------------
    [self createVertexArrayObject];

    [self createVertexBufferObject];

    [self linkAttributes];

    [self checkErrors];
}

-(void)checkErrors
{
    GLenum error = glGetError();

    switch (error) {
        case GL_NO_ERROR:
            NSLog(@"No errors");
            break;
        case GL_INVALID_ENUM:
            NSLog(@"An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_VALUE:
            NSLog(@"A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_OPERATION:
            NSLog(@"The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            NSLog(@"The frameBuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_OUT_OF_MEMORY:
            NSLog(@"There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.");
            break;
        case GL_STACK_UNDERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to underflow.");
            break;
        case GL_STACK_OVERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to overflow.");
            break;
        default:
            break;
    }
}

#pragma mark - Setup Context -

-(void)setupContext
{
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    if(!self.context)
    {
        NSLog(@"Failed to create OpenGL ES Context");
    }

    // tell our view the context is an OpenGL context
    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    [EAGLContext setCurrentContext:self.context];

    self.effect = [[GLKBaseEffect alloc] init];

    //glEnable(GL_DEPTH_TEST);
}

#pragma mark - Vertex Array Object Methods -

-(void)createVertexArrayObject
{
    glGenVertexArraysOES(1, &vao);
    glBindVertexArrayOES(vao);
}

#pragma mark - Create Vertex Buffer Object Method -

-(void)createVertexBufferObject;
{
    glGenBuffers(1, &vbo); // Generate 1 memory buffer for the VBO

    // Make our VBO the current buffer object to receive data
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // -------------------------------------------------------------
    // Start copying data to our VBO
    //
    // GL_STATIC_DRAW will upload once and drawn many times
    // -------------------------------------------------------------
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}

-(void)linkAttributes
{
    /*
    // linking vertex data and attributes
    GLint positionAttrib = glGetAttribLocation(shaderProgram, "position");
    glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(positionAttrib);
    */

    glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(GLKVertexAttribPosition);

    glBindVertexArrayOES(0);
}

#pragma mark - Shader Code -

-(void)loadShaders
{
    shaderProgram = glCreateProgram();

    // load both vertex shader and fragment shader
    GLuint vertexShader = [self compileVertexShader];
    GLuint fragmentShader = [self compileFragmentShader];

    // create a shader program from the vertex shader and fragment shader
    [self combineVertexShader:vertexShader AndFragmentShader:fragmentShader];

    [self linkProgram:shaderProgram];


    // Release vertex and fragment shaders.
    if (vertexShader) {
        glDetachShader(shaderProgram, vertexShader);
        glDeleteShader(vertexShader);
    }
    if (fragmentShader) {
        glDetachShader(shaderProgram, fragmentShader);
        glDeleteShader(fragmentShader);
    }

    //NSLog(@"uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] before = %d", uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX]);

    uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(shaderProgram, "modelViewProjectionMatrix");

    //NSLog(@"uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] after = %d", uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX]);
}

-(GLuint)compileVertexShader
{
    // get the path to the shader file as a C string
    const GLchar *vertexShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"]
                                                                          encoding:NSUTF8StringEncoding
                                                                             error:nil] UTF8String];

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderPath, NULL);
    glCompileShader(vertexShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Vertex shader compiled correctly");
    }
    else
    {
        NSLog(@"Vertex shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(vertexShader, logLength, &logLength, log);
        NSLog(@"Vertex Shader compile log:\n%s", log);
        free(log);
    }

    return vertexShader;
}

-(GLuint)compileFragmentShader
{
    // get the path to the shader as a C string
    const GLchar *fragmentShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"]
                                                                            encoding:NSUTF8StringEncoding
                                                                               error:nil] UTF8String];

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderPath, NULL);
    glCompileShader(fragmentShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Fragment shader compiled correctly");
    }
    else
    {
        NSLog(@"Fragment shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(fragmentShader, logLength, &logLength, log);
        NSLog(@"Fragment Shader compile log:\n%s", log);
        free(log);
    }

    return fragmentShader;
}

-(void)combineVertexShader:(GLuint)paramVertexShader AndFragmentShader:(GLuint)paramFragmentShader
{
    glAttachShader(shaderProgram, paramVertexShader);
    glAttachShader(shaderProgram, paramFragmentShader);

    glBindAttribLocation(shaderProgram, GLKVertexAttribPosition, "position");

    //[self validateProgram:shaderProgram];
}

-(void)linkProgram:(GLuint)paramShaderProgram
{
    // link shader to program now and become active shader program
    glLinkProgram(paramShaderProgram);

    GLint status;
    // test if the program linked correctly
    glGetProgramiv(paramShaderProgram, GL_LINK_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program linked correctly");
    }
    else
    {
        NSLog(@"Shader program linked failed");
    }

    GLint logLength;
    glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(shaderProgram, logLength, &logLength, log);
        NSLog(@"Program link log:\n%s", log);
        free(log);
    }
}

-(void)validateProgram:(GLuint)paramShaderProgram
{
    GLint status, logLength;

    glValidateProgram(paramShaderProgram);

    glGetProgramiv(paramShaderProgram, GL_VALIDATE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program validated correctly");
    }
    else
    {
        NSLog(@"Shader program validate failed");
    }

    glGetProgramiv(paramShaderProgram, GL_INFO_LOG_LENGTH, &logLength);

    if(logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(paramShaderProgram, logLength, &logLength, log);
        NSLog(@"Program validate log:\n%s", log);
        free(log);
    }
}

#pragma mark - GLKViewController Render Delegate Methods -

-(void)setupViewport
{
    //float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);

    //GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0f, -10.0f);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1, 1, -1, 1, 1, -1);
    self.effect.transform.projectionMatrix = projectionMatrix;

    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
    self.effect.transform.modelviewMatrix = modelViewMatrix;

    modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
    normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);

    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, GL_FALSE, modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, normalMatrix.m);
}

-(void)update
{
    [self setupViewport];
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArrayOES(vao);

    [self.effect prepareToDraw];

    glUseProgram(shaderProgram);

    glDrawArrays(GL_TRIANGLES, 0, 3);
}

#pragma mark - Cleanup Memory -

-(void)tearDownContext
{
    [EAGLContext setCurrentContext:self.context];

    // delete vertex buffer object and vertex array object
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArraysOES(1, &vao);

    // delete shader program
    if(shaderProgram)
    {
        glDeleteProgram(shaderProgram);
        shaderProgram = 0;
    }

    // unset OpenGL context
    if ([EAGLContext currentContext] == self.context)
    {
        [EAGLContext setCurrentContext:nil];
    }

    self.context = nil;
}

-(void)dealloc
{
    [self tearDownContext];
}

-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if([self isViewLoaded] && self.view.window == nil)
    {
        self.view = nil;

        [self tearDownContext];

        if([EAGLContext currentContext] == self.context)
        {
            [EAGLContext setCurrentContext:nil];
        }

        self.context = nil;
    }

    // Dispose of any resources that can be recreated
}

@end

Надеюсь, это поможет всем остальным.


person Zhang    schedule 23.12.2012    source источник


Ответы (1)


Забудьте о коде шаблона Apple OpenGL ES 2.0. Если вы новичок, там слишком много всего происходит, чтобы правильно понять, и он смешивает OpenGL ES 1.1 (GLKBaseEffect) и 2.0 (шейдеры).

Вам лучше создать приложение с нуля и узнать плюсы и минусы GLKit и шейдеров.

Этот учебник дает отличное введение в GLKit с использованием функциональности фиксированного конвейера GLKBaseEffect:

И если вы хотите получить более глубокие знания и научиться использовать шейдеры в среде iPhone, я настоятельно рекомендую эту книгу:

В конечном счете, вы захотите объединить GLKView, чтобы обойти весь шаблонный код буфера, и шейдеры, чтобы иметь лучший контроль над вашей программой. OpenGL ES имеет сложную кривую обучения, но как только вы преодолеете первый горб, все станет намного яснее.

person Ricardo RendonCepeda    schedule 23.12.2012
comment
Онлайн-руководство должно занять у вас около 1 часа, в то время как книгу можно читать больше недели (по крайней мере, чтобы добраться до простого 3D-объекта с освещением). - person Ricardo RendonCepeda; 23.12.2012
comment
Я не большой поклонник сайта Рэя, мне не нравится форматирование и цветовая гамма. Тем не менее, для этого сценария я нашел руководство Рэя более близким к книге и конвейеру OpenGL ES 2.0 в том, что мы имеем дело с созданием буфера кадра и буфера рендеринга с помощью этого руководства: raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial - person Zhang; 24.12.2012
comment
Удачи. Начало работы с OpenGL ES разочаровывает, но действительно улучшает ваше понимание компьютерной графики. Как только вы освоитесь с вещами, я настоятельно рекомендую использовать GLKView, а не GLKBaseEffect. Первый обрабатывает все буферы за вас, а второй — слишком ES 1.1. - person Ricardo RendonCepeda; 24.12.2012
comment
Спасибо Рикардо. На самом деле мне удобнее, если я отвечаю за представление буфера кадра и буфера рендеринга (как показано в учебнике Рэя). Один из моих проектов, который я имею в виду, касается внеэкранных буферов, поэтому я очень ценю учебник Рэя за прохождение этого маршрута. - person Zhang; 25.12.2012
comment
Без GLKBaseEffect и фиксированного конвейера функций версии 1.1 как можно нарисовать треугольник, имея в своем распоряжении только шейдеры? - person openfrog; 13.11.2013
comment
Вам потребуется как минимум 3 вершины в вашем VBO и вызов glDrawArrays, а также простая пара шейдеров вершин-фрагментов, подобная тем, которые описаны в моем ответе здесь (stackoverflow.com/questions/ 15513414/). Я бы также рекомендовал вам задать новый вопрос, а не оставлять комментарии здесь :) - person Ricardo RendonCepeda; 13.11.2013