iOS技术文章

OpenGL ES 3.0 UniformBlock使用示例

2016-07-07  本文已影响359人  熊皮皮

本文档参考自OpenGL Shading Language Cookbook,执行结果如下图所示。

模糊圆

顶点着色器代码:

#version 300 es

layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec3 VertexTexCoord;

uniform mat4 ProjectionMatrix;

out vec3 TexCoord;

void main() {
    TexCoord = VertexTexCoord;
    gl_Position = ProjectionMatrix * VertexPosition;
}

片段着色器代码:

#version 300 es
precision mediump float;

in vec3 TexCoord;
layout (location = 0) out vec4 FragColor;

uniform BlobSetting {
    vec4 InnerColor;
    vec4 OuterColor;
    float RadiusInner;
    float RadiusOuter;
};

void main() {
    float dx = TexCoord.x - 0.5;
    float dy = TexCoord.y - 0.5;
    float dist = sqrt(dx*dx + dy*dy);
    FragColor = mix(
                    InnerColor,
                    OuterColor,
                    smoothstep(RadiusInner, RadiusOuter, dist));
}

smoothstep(edge1, edge2, x),前两个参数表示下、上沿,最后一个参数表示权重。函数基于权重x计算并返回两个边沿值之间的插值数据,函数图示如下。

smoothstep函数图

mix函数使用smoothstep()提供的权重混合内、外部颜色。

客户端代码:

#import <OpenGLES/ES3/gl.h>

@interface MyGLView : UIView

@end

typedef struct
{
    GLfloat   m[4][4];
} ESMatrix;

void
esMatrixLoadIdentity ( ESMatrix *result )
{
    memset ( result, 0x0, sizeof ( ESMatrix ) );
    result->m[0][0] = 1.0f;
    result->m[1][1] = 1.0f;
    result->m[2][2] = 1.0f;
    result->m[3][3] = 1.0f;
}

void
esMatrixMultiply ( ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB )
{
    ESMatrix    tmp;
    int         i;
    
    for ( i = 0; i < 4; i++ )
    {
        tmp.m[i][0] =  ( srcA->m[i][0] * srcB->m[0][0] ) +
        ( srcA->m[i][1] * srcB->m[1][0] ) +
        ( srcA->m[i][2] * srcB->m[2][0] ) +
        ( srcA->m[i][3] * srcB->m[3][0] ) ;
        
        tmp.m[i][1] =  ( srcA->m[i][0] * srcB->m[0][1] ) +
        ( srcA->m[i][1] * srcB->m[1][1] ) +
        ( srcA->m[i][2] * srcB->m[2][1] ) +
        ( srcA->m[i][3] * srcB->m[3][1] ) ;
        
        tmp.m[i][2] =  ( srcA->m[i][0] * srcB->m[0][2] ) +
        ( srcA->m[i][1] * srcB->m[1][2] ) +
        ( srcA->m[i][2] * srcB->m[2][2] ) +
        ( srcA->m[i][3] * srcB->m[3][2] ) ;
        
        tmp.m[i][3] =  ( srcA->m[i][0] * srcB->m[0][3] ) +
        ( srcA->m[i][1] * srcB->m[1][3] ) +
        ( srcA->m[i][2] * srcB->m[2][3] ) +
        ( srcA->m[i][3] * srcB->m[3][3] ) ;
    }
    
    memcpy ( result, &tmp, sizeof ( ESMatrix ) );
}


void
esOrtho ( ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ )
{
    float       deltaX = right - left;
    float       deltaY = top - bottom;
    float       deltaZ = farZ - nearZ;
    ESMatrix    ortho;
    
    if ( ( deltaX == 0.0f ) || ( deltaY == 0.0f ) || ( deltaZ == 0.0f ) )
    {
        return;
    }
    
    esMatrixLoadIdentity ( &ortho );
    ortho.m[0][0] = 2.0f / deltaX;
    ortho.m[3][0] = - ( right + left ) / deltaX;
    ortho.m[1][1] = 2.0f / deltaY;
    ortho.m[3][1] = - ( top + bottom ) / deltaY;
    ortho.m[2][2] = -2.0f / deltaZ;
    ortho.m[3][2] = - ( nearZ + farZ ) / deltaZ;
    
    esMatrixMultiply ( result, &ortho, result );
}

@implementation MyGLView

+ (Class)layerClass {
    return [CAEAGLLayer class];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.layer.contentsScale = [UIScreen mainScreen].scale;

    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 *fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"Fragment.shader" ofType:nil];
    NSString *fragmentShaderString = [NSString stringWithContentsOfFile:fragmentShaderPath encoding:NSUTF8StringEncoding error:nil];
    
    NSString *vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"Vertex.shader" ofType:nil];
    NSString *vertexShaderString = [NSString stringWithContentsOfFile:vertexShaderPath encoding:NSUTF8StringEncoding error:nil];
    
    GLint vertexShader = [self compileShaderWithString:vertexShaderString withType:GL_VERTEX_SHADER];
    GLint fragmentShader = [self compileShaderWithString:fragmentShaderString withType:GL_FRAGMENT_SHADER];
    
    GLuint 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 = malloc(sizeof(GLchar) * length);
            glGetProgramInfoLog(program, length, NULL, infolog);
            fprintf(stderr, "link error = %s", infolog);
            if (infolog) {
                free(infolog);
            }
        }
    }
    glUseProgram(program);
#if DEBUG
    glValidateProgram(program);
#endif
    
    glClearColor(0, 0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    CGSize size = self.frame.size;
    GLfloat scale = [UIScreen mainScreen].scale;
    glViewport(0, 0, size.width * scale, size.height * scale);
//    glViewport(size.width/2, size.height/2, size.width * scale / 10, size.height * scale  / 10);
    
    //glGetUniformBlockIndex获取统一变量块的索引
    //GLuint blockIndex = glGetUniformBlockIndex(programHandle, "BlobSettings");
    
    //Allocate space for the buffer to contain the data for the uniform block. We get the size of the block using glGetActiveUniformBlockiv.
    //lGetActiveUniformBlockiv(programHandle, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
    //GLubyte * blockBuffer= (GLubyte *) malloc(blockSize);
    
    GLuint blobSettingHandler = glGetUniformBlockIndex(program, "BlobSetting");
    GLint blockSize;
    glGetActiveUniformBlockiv(program, blobSettingHandler, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
    GLubyte * blockBuffer= (GLubyte *) malloc(blockSize);
    //Query for the offset of each variable within the block. To do so, we  rst  nd the index of each variable within the block.
        // Query for the offsets of each block variable
    const GLchar *names[] = { "InnerColor", "OuterColor", "RadiusInner", "RadiusOuter" };
    GLuint indices[4];
    glGetUniformIndices(program, 4, names, indices);
    GLint offset[4];
    glGetActiveUniformsiv(program, 4, indices,
                          GL_UNIFORM_OFFSET, offset);
    
    //Place the data into the buffer at the appropriate offsets.
    GLfloat outerColor[] = {0.0f, 0.0f, 0.0f, 0.0f};
    GLfloat innerColor[] = {1.0f, 1.0f, 0.75f, 1.0f};
    GLfloat innerRadius = 0.25f, outerRadius = 0.45f;
    memcpy(blockBuffer + offset[0], innerColor,
           4 * sizeof(GLfloat));
    memcpy(blockBuffer + offset[1], outerColor,
           4 * sizeof(GLfloat));
    memcpy(blockBuffer + offset[2], &innerRadius,
           sizeof(GLfloat));
    memcpy(blockBuffer + offset[3], &outerRadius,
           sizeof(GLfloat));
    
    //Create the OpenGL buffer object and copy the data into it.
    GLuint uboHandle;
    glGenBuffers( 1, &uboHandle );
    glBindBuffer( GL_UNIFORM_BUFFER, uboHandle );
    glBufferData( GL_UNIFORM_BUFFER, blockSize, blockBuffer,
                 GL_DYNAMIC_DRAW );
    
    // 6. Bind the buffer object to the uniform block.
    glBindBufferBase( GL_UNIFORM_BUFFER, blobSettingHandler, uboHandle );
    
    ESMatrix orth;
    esMatrixLoadIdentity(&orth);
    GLfloat aspect = size.width / size.height;
    esOrtho(&orth, -aspect, aspect, -1.0, 1.0, -1.0, 1.0);
    
    GLint projection_matrix_index = glGetUniformLocation(program, "ProjectionMatrix");
    glUniformMatrix4fv(projection_matrix_index, 1, GL_FALSE, &orth.m[0][0]);


    /*
     vertex:
     0 -- 3
     |    |
     1 -- 2
     texcoord:
     0 -- 3
     |    |
     1 -- 2
     */
    GLfloat vertex[] = {
    // position, texcoord
        -1, 1,      0, 1, // 0
        -1, -1,      0, 0, // 1
        1, -1,      1, 0, // 2
        1, 1,      1, 1, // 3
    };
    
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertex);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), &vertex[2]);
    
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
    [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 = 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
上一篇下一篇

猜你喜欢

热点阅读