OpenGL ES 3.0 glEnableVertexAttr

作者: 熊皮皮 | 来源:发表于2016-07-06 16:15 被阅读5220次

    本文档讨论glEnableVertexAttribArray的作用及调用位置问题。

    对于OpenGL ES 3.0,可使用至少16个顶点属性,可查询具体实现的支持数量。

    GLint maxVertexAttribs;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
    

    默认情况下,出于性能考虑,所有顶点着色器的属性(Attribute)变量都是关闭的,意味着数据在着色器端是不可见的,哪怕数据已经上传到GPU,由glEnableVertexAttribArray启用指定属性,才可在顶点着色器中访问逐顶点的属性数据。glVertexAttribPointer或VBO只是建立CPU和GPU之间的逻辑连接,从而实现了CPU数据上传至GPU。但是,数据在GPU端是否可见,即,着色器能否读取到数据,由是否启用了对应的属性决定,这就是glEnableVertexAttribArray的功能,允许顶点着色器读取GPU(服务器端)数据。

    那么,glEnableVertexAttribArray应该在glVertexAttribPointer之前还是之后调用?答案是都可以,只要在绘图调用(glDraw*系列函数)前调用即可。

    下面示例代码验证了不用glEnableVertexAttribArray对应属性时绘制内容为清除缓冲区颜色。在取消glEnableVertexAttribArray(0);注释后,得到正常的绘制结果。

    正常情况
    #import <UIKit/UIKit.h>
    #import <OpenGLES/ES3/gl.h>
    
    @interface MyGLView : UIView
    
    @end
    
    @implementation MyGLView
    
    + (Class)layerClass {
        return [CAEAGLLayer class];
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        
        EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
        [EAGLContext setCurrentContext:context];
        
        GLuint renderbuffer;
        glGenRenderbuffers(1, &renderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
        [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.layer];
        
        GLuint framebuffer;
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
        
        NSString *vertexShaderString = @"#version 300 es  \n"
        "layout (location = 0) in vec4 a_position;  \n"
        "void main() {  \n"
        "gl_Position = a_position;  \n"
        "gl_PointSize = 20.0;}";
        NSString *fragmentShaderString = @"#version 300 es  \n"
        "precision lowp float;  \n"
        "out vec4 o_color;  \n"
        "void main() {  \n"
        "o_color = vec4(1.0, 0, 1.0, 1.0);}";
        
        GLint vertexShader = [self compileShaderWithString:vertexShaderString withType:GL_VERTEX_SHADER];
        GLint fragmentShader = [self compileShaderWithString:fragmentShaderString withType:GL_FRAGMENT_SHADER];
        
        GLint program = glCreateProgram();
        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
        glLinkProgram(program);
        GLint linkStatus;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus == GL_FALSE) {
            GLint length;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
            if (length > 0) {
                GLchar *infolog = (GLchar *)malloc(sizeof(GLchar) * length);
                glGetProgramInfoLog(program, length, NULL, infolog);
                fprintf(stderr, "link error = %s", infolog);
                if (infolog) {
                    free(infolog);
                }
            }
        }
        glValidateProgram(program);
        glUseProgram(program);
        
        glClearColor(1.0, 1.0, 1.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        CGRect frame = [UIScreen mainScreen].bounds;
        glViewport(0, 0, frame.size.width * self.layer.contentsScale, frame.size.height * self.layer.contentsScale);
        
        GLfloat vertexs[] = {
            -0.5f,  0.5f, 0.0f,  // Position 0
            -0.5f, -0.5f, 0.0f,  // Position 1
        };
        
        glLineWidth(20);
        
        //glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertexs);
        
        glDrawArrays(GL_LINES, 0, 2/* 1 line = 2 points */);
    
        [context presentRenderbuffer:GL_RENDERBUFFER];
    }
    
    - (GLuint)compileShaderWithString:(NSString *)content withType:(GLenum)type {
        GLuint shader;
        const char *shaderString = content.UTF8String;
        shader = glCreateShader(type);
        glShaderSource(shader, 1, &shaderString, NULL);
        glCompileShader(shader);
        GLint status;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
        if (status == GL_FALSE) {
            GLint length;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
            if (length > 0) {
                GLchar *infolog = (GLchar *)malloc(sizeof(GLchar) * length);
                glGetShaderInfoLog(shader, length, NULL, infolog);
                fprintf(stderr, "%s -> compile error = %s", type == GL_VERTEX_SHADER ? "vertex shader" : "fragment shader", infolog);
                if (infolog) {
                    free(infolog);
                }
            }
        }
        return shader;
    }
    
    @end
    

    相关文章

      网友评论

      本文标题:OpenGL ES 3.0 glEnableVertexAttr

      本文链接:https://www.haomeiwen.com/subject/eupkjttx.html