3

我完全没有想法。

我有 OpenGL ES 2.0 编程指南书,我有 Apple 的模板 OpenGL ES 2.0 代码,我关注了这个页面: 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

我所看到的只是我清除颜色的灰色背景屏幕。

如果有人能指出我哪里出错了,那就太好了。

编辑

我决定把我个人对 Ray 网站的厌恶放在一边,硬着头皮完成了这个教程:

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

本教程不使用 GLKit,这是一个额外的好处,因为学习者编写自己的帧缓冲区和渲染缓冲区,并将它们呈现到屏幕上。

我觉得这比使用 GLKit 更接近 OpenGL ES 2.0 管道。

正如里卡多建议的那样,在这个时候,使用 GLKit 比它的价值更容易理解。

我还强烈建议使用上面 Ray 的网站教程链接来运行一个工作程序,而不是尝试遵循 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

希望对其他人有所帮助。

4

1 回答 1

2

忘记 Apple 的 OpenGL ES 2.0 模板代码吧。如果您是初学者,其中有太多内容无法正确理解,它混合了 OpenGL ES 1.1(GLKBaseEffect)和 2.0(着色器)。

您最好从头开始创建应用程序并了解 GLKit 和着色器的优缺点。

本教程很好地介绍了使用 GLKBaseEffect 的固定管道功能的 GLKit:

如果你想要更深入的知识并学习如何在 iPhone 环境中使用着色器,我强烈推荐这本书:

最终,您可能希望结合使用 GLKView 来绕过所有缓冲区样板代码,并使用着色器对您的程序进行最佳控制。OpenGL ES 有一个艰难的学习曲线,但是一旦你克服了第一个障碍,事情就会变得清晰很多。

于 2012-12-23T18:44:48.387 回答