演示图
你不知道这个东西,请不要看了,请看我的其他文章先了解一下O!
学习目标
掌握着色器程序的执行过程
简单的例子
``
uniform float t; // 时间
uniform mat4 gl_ModelViewMatrix; // 模型视图矩阵
attribute vec4 vel;
const vec4 g = vec4(0.0,-9.8,0.0) // 重力加速度
void main()
{
vec4 position = vel;
position += t*vel + t*t*g;
gl_Position = gl_ModelViewMatrix * position;
}
稍微解释一下:代码的作用是模拟重力加速度,对一个点的位置进行变换.
OpenGL /GLSL 程序接口
先上图
着色器创建流程
C语言,大家应该很熟悉吧! C 语言的编译过程步骤:
1.编译器检查错误
2.将他转换成目标代码(.o文件)
3.将一组目标文件进行链接,最后成为一个可执行文件
在OpenGL 程序中使用GLSL 着色器也是一个相似的过程,要在应用程序中使用顶点或者片段着色器需要按照**顺序**执行下面的步骤:
1.创建着色器对象
2.把着色器代码编译成源代码
3.验证是否着色器是否编译成功
为了把多个着色器对象链接起来,我们需要创建着色器程序
4.创建一个着色器程序
5.把着色器对象链接到这个着色器程序中
6.链接着色器
7.验证着色器链接阶段已经成功完成.
8.使用着色器进行顶点或者片段处理.
函数讲解 (用到的主要是C语法)
GLUint glCreateShader(GLenum type);
作用:创建着色器对象
type 类型值两个: GL_VERTEX_SHADER(顶点做色器) 和 GL_VERTEX_SHADER(片段着色器) 返回一个非零的值,作为着色器的标记
void glShaderSource(GLuint shader,GLsizei count,const GLchar**string,const Glint* length);
作用:创建着色器对象后,需要把着色器的源代码和着色器对象关联
参数1:shader 就是创建着色器成功返回的那个值
参数2:count 包含多个字符串,一般就1个字符串
参数3:字符串数组地址
参数4:,可以为NULL 代表字符串为NULL 结尾的,否则,length就代表具有就有count个元素,每个元素指定了string中对应字符串的长度,如果length数组中的某个元素对应一个正整数,就代表string数组中对应字符串的长度,如果是负整数,对应的字符串就是以NULL 结尾的.
void glCompileShader(GLuint shader)
作用:编译着色器源代码
参数 : shader 着色器标示
glGetShaderiv (GLuint shader, GLenum pname, GLint* params)
作用: 查询编译结果
参数1:shader 着色器标识
参数2:GL_COMPLE_STATUS
参数3:查询结果返回
void glGetShaderInfoLog(GLuint shader,GLsizei bufsize,GLsizei length ,char infoLog);
作用: 获取编译相关日志,调试情况下使用
参数1: shader 着色器对象标识
参数2: bufsize 最大日志长度
参数3: length 如果为NULL 不返回任何日志
参数4:infoLog 保存在缓冲区中
GLuint glCreateProgram()
作用:创建空的着色器程序
返回:非零,如果是0 则创建失败
void AttachShader(GLuint program,GLuint shader);
作用: 把着色器和程序相关联
参数1:program 着色器程序标识
参数2:shader 着色器对象标识
void glDetachShader(GLuint program,Gluint shader);
作用: 把着色器对象从着色器程序中分离出来,以更改着色器的操作。
参数1:program 着色器程序标识
参数2:shader 着色器对象标识
void glLinkProgram()
作用:在着色器对象都连接到着色器程序之后,就要把这些对象连接成一个可执行程序.
void glGetProgramInfoLog(GLuint program,GLsizei bufsize,GLsize length char infoLog)
作用:连接着色器程序也可能出现错误,我们需要进行查询,获取错误日志信息
参数1: program 着色器程序标识
参数2: bufsize 最大日志长度
参数3: length 如果为NULL 不返回任何日志
参数4:infoLog 保存在缓冲区中
void glGetProgramiv (GLuint program, GLenum pname, GLint* params)
作用:查询程序连接后的结果
参数1:program 着色器程序标识
参数2: GL_LINK_STATUS
参数3:params 返回状态
void glUserProgram(GLuint program)
作用: 程序连接成功后,就可以调用这个函数,启动这个顶点或者片段着色器程序了,为了恢复使用固定功能的管线,可以向这个函数传递 0作为参数.
void glDeleteShader(GLuint shader)
作用:删除着色器对象,如果这个着色器对象被多个程序连接,一旦程序不再使用这个对象,那么它便会实际删除
参数: shader 着色器对象标识
void glDeleteProgram(GLuint program)
作用: 删除着色器程序 ,如果这个着色器未在任何渲染环境中使用,它将立即删除。否则,会标记为删除,一旦它没不被使用了,便立即被删除
void GLboolean glIsShader(GLuint shader)
作用: 如果shader 是一个着色器对象名称,则返回GL_TRUE, 否则返回GL_FALSE
void GLboolean glIsProgram(GLuint program)
作用: 如果program 是一个着色器程序,则返回GL_TRUE ,否则返回GL_FALSE
void glValidateProgram(GLuint program)
作用:用于验证一个着色器程序是否可以在当前OpenGL 环境下使用,验证结果查询,使用glGetProgramiv() 传入参数GL_VALIDATE_STATUS 为参数,查询程序验证结果
IOS 代码上一份方便大家理解
导入shader的步骤
第一步. 创建GLuint 类型的shader 标示
第二步. 获取shader 文件所在的路径
第三步 获取文件的内容 并进行NSUTF8StringEncoding 编码
第四步. 根据类型创建shader 着色器对象
第五步. 关联shader着色器源代码
第六步. 编译shader着色器对象源代码
第七步. 检查着色器源代码编译是否成功
第八步. 创建着色器程序
第九步. 将编译好的着色器目标文件链接到程序中去
第十步. 绑定着色器的属性
第十一步. 将着色器和程序分开,并且释放着色器
步骤就是多,最好封装好,不重复敲代码才是王道
``
- (BOOL)loadShaders
{
// 第一步.创建标示
GLuint vertShader, fragShader;
// 第二步.获取文件路径
NSString *vertShaderPathname, *fragShaderPathname;
vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
NSLog(@"编译失败 vertex shader");
return NO;
}
// 创建 编译 片断着色器对象
fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(@"Failed to compile fragment shader");
return NO;
}
// 第八步 创建一个着色器空程序
_program = glCreateProgram();
// 第九步 将顶点着色器链接到程序中
glAttachShader(_program, vertShader);
// 将片断着色器链接到程序中
glAttachShader(_program, fragShader);
//第十步 绑定着色器的属性
glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
if (![self linkProgram:_program]) {
NSLog(@"Failed to link program: %d", _program);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (_program) {
glDeleteProgram(_program);
_program = 0;
}
return NO;
}
// Get uniform locations.
uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix");
// 第十三步 . 分离释放顶点着色器对象 和片段着色器对象
if (vertShader) {
glDetachShader(_program, vertShader);
glDeleteShader(vertShader);
}
if (fragShader) {
glDetachShader(_program, fragShader);
glDeleteShader(fragShader);
}
return YES;
}
-(BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
//第三步 获取文件的内容 并进行NSUTF8StringEncoding 编码
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source) {
NSLog(@"Failed to load vertex shader");
return NO;
}
//第四步 根据类型创建着色器对象
*shader = glCreateShader(type);
//第五步. 获取着色器源代码和着色器关联
glShaderSource(*shader, 1, &source, NULL);
//第六步. 开始编译着色器源代码
glCompileShader(*shader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
NSLog(@"Shader compile log:\n%s", log);
free(log);
}
#endif
//第七步. 查看是着色器源代码否编译成功
GLint status;
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
- (BOOL)linkProgram:(GLuint)prog
{
// 第十一 链接程序
glLinkProgram(prog);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program link log:\n%s", log);
free(log);
}
#endif
// 第十二步 检查着色器程序链接结果
GLint status;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0) {
return NO;
}
代码下载地址
点我下载
参考
OpenGL 编程指南>