GLProgram
GLProgram的實現(xiàn)相對簡單哩掺,沒有與其他類產(chǎn)生依賴關(guān)系云芦,主要封裝了著色器與著色器程序的創(chuàng)建关炼、編譯程腹、鏈接、使用和銷毀儒拂。
GPUImage中負責(zé)創(chuàng)建GLProgram的只有GLImageContext寸潦,其他類型需要用到GLProgram的時候,會通過GLImageContext來獲取社痛。
關(guān)于著色器的介紹甸祭,可以參考LearnOpenGL-著色器
下面簡單介紹一下GPUImage的方法:
- 初始化方法,根據(jù)需要傳入頂點著色器和片源著色器的路徑或存放在NSBundle的文件名進行初始化褥影。
- (id)initWithVertexShaderString:(NSString *)vShaderString
fragmentShaderString:(NSString *)fShaderString;
- (id)initWithVertexShaderString:(NSString *)vShaderString
fragmentShaderFilename:(NSString *)fShaderFilename;
- (id)initWithVertexShaderFilename:(NSString *)vShaderFilename
fragmentShaderFilename:(NSString *)fShaderFilename;
初始化的過程包含了頂點著色器和片段著色器的創(chuàng)建池户、編譯,著色器程序的創(chuàng)建并綁定著色器凡怎。
// 其他的初始化方法都會調(diào)用這個初始化方法
- (id)initWithVertexShaderString:(NSString *)vShaderString
fragmentShaderString:(NSString *)fShaderString;
{
if ((self = [super init]))
{
_initialized = NO;
attributes = [[NSMutableArray alloc] init]; // 局部變量列表
uniforms = [[NSMutableArray alloc] init]; // 全局變量列表
program = glCreateProgram(); // 創(chuàng)建Program
// 編譯頂點著色器
if (![self compileShader:&vertShader
type:GL_VERTEX_SHADER
string:vShaderString])
{
NSLog(@"Failed to compile vertex shader");
}
// 編譯片段著色器
if (![self compileShader:&fragShader
type:GL_FRAGMENT_SHADER
string:fShaderString])
{
NSLog(@"Failed to compile fragment shader");
}
// 綁定著色器到著色器程序
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
}
return self;
}
著色器編譯過程校焦,主要包括著色器創(chuàng)建并綁定源代碼、編譯和輸出錯誤日志统倒。
- (BOOL)compileShader:(GLuint *)shader
type:(GLenum)type
string:(NSString *)shaderString
{
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
GLint status;
const GLchar *source;
// 獲取著色器代碼
source =
(GLchar *)[shaderString UTF8String];
if (!source)
{
NSLog(@"Failed to load vertex shader");
return NO;
}
*shader = glCreateShader(type); // 創(chuàng)建指定類型的著色器
glShaderSource(*shader, 1, &source, NULL); // 綁定著色器代碼到著色器
glCompileShader(*shader); // 編譯著色器
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); // 獲取編譯狀態(tài)
// 判斷著色器編譯是否成功寨典,失敗則輸出日志
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);
}
}
// CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
// NSLog(@"Compiled in %f ms", linkTime * 1000.0);
return status == GL_TRUE;
}
- 鏈接著色器程序
- (BOOL)link
{
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
GLint status;
// 鏈接著色器程序
glLinkProgram(program);
// 獲取鏈接狀態(tài)
glGetProgramiv(program, GL_LINK_STATUS, &status);
// 判斷鏈接是否成功,失敗則返回
if (status == GL_FALSE)
return NO;
// 鏈接成功房匆,就可以刪掉相關(guān)的shader耸成,釋放資源
if (vertShader)
{
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader)
{
glDeleteShader(fragShader);
fragShader = 0;
}
// 設(shè)置初始化成功標(biāo)識
self.initialized = YES;
// CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
// NSLog(@"Linked in %f ms", linkTime * 1000.0);
return YES;
}
- 使用著色器程序
- (void)use
{
glUseProgram(program);
}
- 獲取相關(guān)屬性的索引报亩,用于為著色器傳值。
- (void)addAttribute:(NSString *)attributeName
{
// 判斷當(dāng)前的屬性是否已存在
if (![attributes containsObject:attributeName])
{
// 如果不存在先加入屬性數(shù)組井氢,然后綁定該屬性的索引為在屬性數(shù)組中的索引
[attributes addObject:attributeName];
glBindAttribLocation(program,
(GLuint)[attributes indexOfObject:attributeName],
[attributeName UTF8String]);
}
}
// 獲取屬性的索引
- (GLuint)attributeIndex:(NSString *)attributeName
{
return (GLuint)[attributes indexOfObject:attributeName];
}
// 獲取uniform的索引
- (GLuint)uniformIndex:(NSString *)uniformName
{
return glGetUniformLocation(program, [uniformName UTF8String]);
}