GPUImage源码解读之GLProgram
简述
GLProgram是GPUImage中代表openGL ES 中的program,具有glprogram功能。其实是作者对OpenGL ES program的面向对象封装
初始化
- (id)initWithVertexShaderString:(NSString *)vShaderString fragmentShaderString:(NSString *)fShaderString; - (id)initWithVertexShaderString:(NSString *)vShaderString fragmentShaderFilename:(NSString *)fShaderFilename; - (id)initWithVertexShaderFilename:(NSString *)vShaderFilename fragmentShaderFilename:(NSString *)fShaderFilename;
program
program = glCreateProgram();
shader
c语言编译流程:预编译、编译、汇编、链接
glsl的编译过程类似c语言,主要有glCompileShader、glAttachShader、glLinkProgram三步
创建shader
分别根据两个Shader String来创建两个Shader。但是要注意区别的是,两个Shader的type对应的GLEnum是不一样的。
创建并且compile shader的过程包括几步:
- 创建OpenGL ES Shader:VertexShader的type是GL_VERTEX_SHADER;而FragmentShader是GL_FRAGMENT_SHADER。
shader = glCreateShader(type);
- 加载Source String:
source = (GLchar *)[shaderString UTF8String]; glShaderSource(*shader, 1, &source, NULL);
- 编译Shader:
glCompileShader(*shader);
- 检查Shader的状态;如果创建失败,则获取log:
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { GLint logLength; glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength); if (logLength > 0) { GLchar *log = (GLchar *)malloc(logLength); glGetShaderInfoLog(*shader, logLength, &logLength, log); if (shader == &vertShader) { self.vertexShaderLog = [NSString stringWithFormat:@"%s", log]; } else { self.fragmentShaderLog = [NSString stringWithFormat:@"%s", log]; } free(log); } }
- 将生成的两个Shader Attach到Program上:
glAttachShader(program, vertShader); glAttachShader(program, fragShader);
- link program并且检查program的状态,如果link失败,则获取log;如果link成功,则表示GLProgram的初始化完毕:
glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &status); if (status == GL_FALSE) return NO; if (vertShader) { glDeleteShader(vertShader); vertShader = 0; } if (fragShader) { glDeleteShader(fragShader); fragShader = 0; } self.initialized = YES;
- use
glUseProgram(program);
Attribute的管理
简介
attribute变量是只能在vertex shader中使用的变量。它不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)
在application中,一般用函数glBindAttribLocation()来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。
在GPUImage中,作者通过一个attributes数组来管理attribute变量。
- (void)addAttribute:(NSString *)attributeName { if (![attributes containsObject:attributeName]) { [attributes addObject:attributeName]; glBindAttribLocation(program, (GLuint)[attributes indexOfObject:attributeName], [attributeName UTF8String]); } } // END:addattribute // START:indexmethods - (GLuint)attributeIndex:(NSString *)attributeName { return (GLuint)[attributes indexOfObject:attributeName]; }
如上述函数所示,每当加入一个attribute时,会先判断在数组中有没有这个变量,如果没有的话,就加到数组中,并且绑定到shader中。变量获取的位置也就是在数组中的位置
uniform的管理
简介
uniform变量 外部程序传递给shader的变量.
函数glUniform**()函数赋值的.shader 中是只读变量,不能被 shader 修改.
在GPUImage中,作者同样通过一个uniforms数组来管理attribute变量。(然而并没有用到