版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Forever_wj/article/details/58151706
OpenGL ES的着色器主要有片元着色器和顶点着色器,其使用方法简单的介绍如下:
创建,装载和编译 shader:
- 继续上一篇的基础上,在工程中新建一个类,命名为OpenGLESUtils(继承于NSObject),在.h中声明2个方法:
+ (GLuint)loadShader:(GLenum)type shaderString:(NSString *)shaderString;
+ (GLuint)loadShader:(GLenum)type shaderFilePath:(NSString *)filePath;
- 在OpenGLESUtils.m实现上面的两个方法:
+(GLuint)loadShader:(GLenum)type shaderFilePath:(NSString *)filePath {
NSError *error;
NSString *shaderString = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
if (!shaderString) {
NSLog(@"Error: loading shader file: %@ %@", filePath, error.localizedDescription);
return 0;
} else {
return [self loadShader:type shaderString:shaderString];
}
}
+ (GLuint)loadShader:(GLenum)type shaderString:(NSString *)shaderString {
GLuint shader = glCreateShader(type);
if (shader == 0) {
NSLog(@"Error: failed to create shader.");
return 0;
}
const char *shaderStringUTF8 = [shaderString UTF8String];
glShaderSource(shader, 1, &shaderStringUTF8, NULL);
glCompileShader(shader);
GLint compiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint inforLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &inforLen);
if (inforLen > 1) {
char *infoLog = malloc(sizeof(char)*inforLen);
glGetShaderInfoLog(shader, inforLen, NULL, infoLog);
free(infoLog);
}
glDeleteShader(shader);
return 0;
}
return shader;
}
- OpenGLESUtils中的两个方法用来跟进shader脚本字符串和shader脚本文件创建,具体方法如下:
1、创建/删除 shader:函数 glCreateShader 用来创建 shader,参数 GLenum type 表示我们要处理的 shader 类型,它可以是 GL_VERTEX_SHADER 或 GL_FRAGMENT_SHADER,分别表示顶点 shader 或 片元 shader。它返回一个句柄指向创建好的 shader 对象;
2、装载 shader:函数 glShaderSource 用来给指定 shader 提供 shader 源码。第一个参数是 shader 对象的句柄;第二个参数表示 shader 源码字符串的个数;第三个参数是 shader 源码字符串数组;第四个参数一个 int 数组,表示每个源码字符串应该取用的长度,如果该参数为 NULL,表示假定源码字符串是 \0 结尾的,读取该字符串的内容指定 \0 为止作为源码,如果该参数不是 NULL,则读取每个源码字符串中前 length(与每个字符串对应的 length)长度个字符作为源码;
3、编译 shader:函数 glCompileShader 用来编译指定的 shader 对象,这将编译存储在 shader 对象中的源码。我们可以通过函数 glGetShaderiv 来查询 shader 对象的信息,如本例中查询编译情况,此外还可以查询 GL_DELETE_STATUS,GL_INFO_LOG_STATUS,GL_SHADER_SOURCE_LENGTH 和 GL_SHADER_TYPE。在这里我们查询编译情况,如果返回 0,表示编译出错了,错误信息会写入 info 日志中,我们可以查询该 info 日志,从而获得错误信息。
编写着色脚本:
- 添加顶点着色脚本:在工程中新建一个Empty,命名为VertexShader.glsl,实现内容如下:
attribute vec4 vPosition;
void main(void) {
gl_Position = vPosition;
}
- 添加片元着色脚本:同理实现,代码如下:
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
- 创建 program,装配 shader,链接 program,使用 program:
1、在 OpenGLView.h 的 OpenGLView 类声明中添加两个成员:
GLuint programHandle;
GLuint positionSlot;
2、然后依然在 OpenGLView.m 中的category 中添加成员方法:
- (void)setupProgram {
NSString *vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader" ofType:@"glsl"];
NSString *fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader" ofType:@"glsl"];
GLuint vertexShader = [OpenGLESUtils loadShader:GL_VERTEX_SHADER shaderFilePath:vertexShaderPath];
GLuint fragmentShader =[OpenGLESUtils loadShader:GL_FRAGMENT_SHADER shaderFilePath:fragmentShaderPath];
programHandle = glCreateProgram();
if (!programHandle) {
NSLog(@"Failed to create program.");
return;
}
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glLinkProgram(programHandle);
GLint linked;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linked);
if (!linked) {
GLint infoLen = 0;glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = malloc(sizeof(char) *infoLen);
glGetShaderInfoLog(programHandle, infoLen, NULL, infoLog);
NSLog(@"Error linking program:\n%s\n", infoLog );
free(infoLog);
}
glDeleteProgram(programHandle);
programHandle = 0;
return;
}
glUseProgram(programHandle);
positionSlot = glGetAttribLocation(programHandle, "vPosition");
}
- 使用实例:
在 - (void)layoutSubviews中调用 render 方法之前,插入对 setupProgram 的调用:
- (void)layoutSubviews {
[self setupLayer];
[self setupContext];
[self destoryRenderAndFrameBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self setupProgram];
[self render];
}
// 改写render方法:
- (void)render {
// 设置清屏颜色
glClearColor(0.0, 0.0, 1.0, 1.0);
// 用来指定要用清屏颜色来清除由mask指定的buffer,此处是color buffer
glClear(GL_COLOR_BUFFER_BIT);
// 渲染区域
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
// 通过 glVertexAttribPointer 将三角形顶点数据装载到 OpenGL ES 中并与 vPositon 关联起来
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(positionSlot);
// glDrawArrays 将三角形图元渲染出来
glDrawArrays(GL_TRIANGLES, 0, 3);
[eaglContext presentRenderbuffer:GL_RENDERBUFFER ];
}