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