OpenGL ES GLSL语言和着色器常用API

EGL(Embedded Graphics Library)

  • OpenGL ES命令需要渲染上下文绘制表面才能完成图形图像的绘制。
  • 渲染上下文:存储OpenGL ES状态,是一个状态机。
  • 绘制表面:用于绘制图元的表面,需要指定渲染的缓冲区,如颜色缓冲区、深度缓冲区和模板缓冲区。
  • OpenGL ES API并没有提供如何创建渲染上下文或者上下文如何连接到原生窗口系统。EGL是Khronos渲染API是和原生窗口系统之间的接口。
  • 唯一支持OpenGL ES却不支持EGL的平台是iOS,Apple提供自己的EGL API,称为EAGL
  • 因为每个窗口系统都有不同的定义,所以EGL提供基本的不透明类型-EGLDisplay,这个类型封装了所有系统相关内容,用于和原生窗口系统连接。

EGL的主要功能

  • 和本地窗口系统(native windowing system)通讯
  • 查询可用配置
  • 创建OpenGL ES可用的“绘制表面(drawing surface)”
  • 同步不同类别API之间的渲染,比如在OpenGL ES和OpenVG之间同步,或者在OpenGL和本地窗口的绘图命令之间同步
  • 管理“渲染资源”,比如纹理映射(redering map)

GLSL

Xcode中不支持GLSL语言对顶点/片元着色器的编译和连接,因此需要在项目中创建两个空的文件,分别命名为shader.vsh和shaderv.fsh。
这里有几个注意点:

  1. 使用*.vsh*.fsh是为了区分顶点着色器还是片元着色器,实际项目中,可根据需要自己定义。
  2. 在这两个文件中,不建议加中文注释,这会导致奇怪的问题,影响开发效率,并且由于在Xcode中并不支持GLSL,所以当中文注释引发问题时,不好排查。

着色器常用API

  1. 向量的数据类型
类型 描述
vec2,vec3,vec4 2分量、3分量、4分量浮点向量(常用)
ivec2,ivec3,ivec4 2分量、3分量、4分量整型向量
uvec2,uvec3,uvec4 2分量、3分量、4分量无符号整型向量
bvec2,bvec3,bvec4 2分量、3分量、4分量bool型向量
  1. 矩阵数据类型
类型 描述
mat2,mat2x2 两⾏两列
mat3,mat3x3 三行三列(常用)
mat4,mat4x4 四行四列(常用)
mat2x3 三行两列
mat2x4 四行两列
mat3x2 两行三列
mat3x4 四行三列
  1. 变量存储限定符
限定符 描述
<none> 只是普通的本地变量,外部不可见,且外部不可访问
const 一个编译常量,对一个函数来说为只读的参数
in/varying 一个从以前阶段传递过来的变量
in/varying centroid 一个从以前阶段传递过来的变量,使用质心插值
out/attribute 传递到下一个处理阶段或者在一个函数中指定一个返回值
out/attribute centroid 传递到下一个处理阶段,质心插值
uniform 一个从客户端代码传递过来的变量,在顶点之间不做改变

一般我们用到varying、attribute、uniform。

  • varying 修饰符:当一个变量需要从顶点着色器将数据传递到片元着色器时,就需要用它来做修饰符。注意,在两个着色器传递的变量必须一模一样(如纹理坐标变量)
  • attribute修饰符:由该修饰符修饰的变量,只能从客户端传递到顶点着色器,并且只能在顶点着色器中使用。它可以用来修改顶点、纹理、颜色、法线等。
  • uniform修饰符:使用该修饰符修饰的变量,在顶点着色器和片元着色器一般将它作为常量,可以用来传递视图模型矩阵、投影矩阵、投影视图矩阵等。

OpenGL ES错误处理

如果不正确使用OpenGL ES命令,应用程序会产生一个错误编码,且会被记录。可以用glGetError进行查询,一旦查询到错误,当前的错误代码就会被复位为GL_NO_ERROR。

GLenum glGetError(void)
错误代码 描述
GL_NO_ERROR 从上⼀次调⽤glGetError 以来没有生成任何错误
GL_INVALID_ENUM GLenum 参数超出范围,忽略生成错误命令
GL_INVALID_VALUE 数值型参数超出范围,忽略生成错误命令
GL_INVALID_OPERATION 特定命令在当前OpenGL ES 状态⽆法执⾏
GL_OUT_OF_MEMORY 内存不足时执⾏该命令,如果遇到这个错误,除⾮当前错误代码,否则OpenGL ES 管线的状态被认为未定义

自定义着色器API

  1. 创建顶点着色器/片元着色器
/*
GLenum type:创建着⾊器的类型,GL_VERTEX_SHADER 或者GL_FRAGMENT_SHADER
返回值:是指向新着⾊器对象的句柄.可以调用glDeleteShader 删除
*/
GLuint glCreateShader(GLenum type);
  1. 删除指定着色器
/*
GLuint shader:要删除的着⾊器对象句柄
*/
void glDeleteShader(GLuint shader);
  1. 指定着色器的source
/*
GLuint shader:指向着⾊器对象的句柄
GLSizei count:着⾊器源字符串的数量,着⾊器可以由多个源字符串组成,但是每个着⾊器只有⼀个main函数
const GLChar * const *string:指向保存数量的count 的着⾊器源字符串的数组指针
const GLint *length:指向保存每个着⾊器字符串⼤小且元素数量为count 的整数数组指针
*/
void glShaderSource(GLuint shader , GLSizei count ,const GLChar * const *string, const GLint *length);
  1. 编译一个着色器
/*
GLuint shader:需要编译的着⾊器对象句柄
*/
void glCompileShader(GLuint shader);
  1. 查询着色器信息
/*
GLuint shader:需要编译的着⾊器对象句柄
GLenum pname:获取的信息参数,可以为
    GL_COMPILE_STATUS
    GL_DELETE_STATUS
    GL_INFO_LOG_LENGTH
    GL_SHADER_SOURCE_LENGTH
    GL_SHADER_TYPE
GLint *params:指向查询结果的整数存储位置的指针
*/
void glGetShaderiv(GLuint shader , GLenum pname , GLint *params )
  1. 获取着色器信息日志
/*
GLuint shader:需要获取信息⽇志的着⾊器对象句柄
GLSizei maxLength:保存信息⽇志的缓存区⼤小
GLSizei *length:写⼊的信息⽇志的长度(减去null 终止符); 如果不需要知道⻓度. 这个参数可以为Null
GLChar *infoLog:指向保存信息日志的字符缓存区的指针
*/
void glGetShaderInfolog(GLuint shader , GLSizei maxLength, GLSizei *length , GLChar *infoLog);
  1. 创建一个程序对象
/*
返回值:返回⼀个执⾏新程序对象的句柄
*/
GLUint glCreateProgram( )
  1. 删除一个程序对象
/*
GLuint program:指向需要删除的程序对象句柄
*/
void glDeleteProgram( GLuint program )
  1. 着色器与程序进行附着/连接
/*
GLuint program:指向程序对象的句柄
GLuint shader:指向程序连接的着色器对象的句柄
*/
void glAttachShader( GLuint program , GLuint shader )
  1. 断开连接
/*
GLuint program:指向程序对象的句柄
*/
void glDetachShader(GLuint program)
  1. 链接程序
/*
GLuint program:指向程序对象的句柄
*/
void glLinkProgram (GLuint program) 
  1. 链接程序之后,需要检查链接是否成功
/*
GLuint program:指向程序对象的句柄
GLenum pname:获取信息的参数,可以是
    GL_ACTIVE_ATTRIBUTES
    GL_ACTIVE_ATTRIBUTES_MAX_LENGTH
    GL_ACTIVE_UNIFORM_BLOCK
    GL_ACTIVE_UNIFORM_BLOCK_MAX_LENGTH
    GL_ACTIVE_UNIFROMS
    GL_ACTIVE_UNIFORM_MAX_LENGTH
    GL_ATTACHED_SHADERS
    GL_DELETE_STATUS
    GL_INFO_LOG_LENGTH
    GL_LINK_STATUS
    GL_PROGRAM_BINARY_RETRIEVABLE_HINT
    GL_TRANSFORM_FEEDBACK_BUFFER_MODE
    GL_TRANSFORM_FEEDBACK_VARYINGS
    GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH
    GL_VALIDATE_STATUS
GLint* params:指向查询结果整数存储位置的指针
*/
void glGetProgramiv (GLuint program, GLenum pname, GLint* params)
  1. 从程序信息日志中获取信息
/*
GLuint program:指向需要获取信息的程序对象句柄
GLSizei maxLength:存储信息⽇志的缓存区⼤小
GLSizei *length:写⼊的信息⽇志⻓度(减去null 终⽌符),如果不需要知道⻓度,这个参数可以为Null
GLChar *infoLog:指向存储信息日志的字符缓存区的指针
*/
void glGetPorgramInfoLog( GLuint program ,GLSizei maxLength, GLSizei *length , GLChar *infoLog )
  1. 设置指定程序为活动程序
/*
GLuint program:设置为活动程序的程序对象句柄
*/
void glUseProgram(GLuint program)

着色器程序的编译和链接

  1. 需要创建两个基本对象才能用着色器进行渲染,它们分别是:着色器对象和程序对象。
  2. 获取链接后着色器对象的一般过程包含6个步骤:
    2.1 创建一个顶点着色器对象和一个片元着色器对象
    2.2 将源代码链接到每个着色器对象
    2.3 编译着色器对象
    2.4 创建一个程序对象
    2.5 将编译后的着色器对象连接到程序对象
    2.6 链接程序对象
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335