首页 > 系统 > iOS > 正文

iOS之OpenGL ES【2】:渲染管线和着色器

2019-11-06 09:54:00
字体:
来源:转载
供稿:网友

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 ];}

参考文章:http://blog.csdn.net/kesalin/article/details/8223649


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表