OpenGL ES GLSL语言和着色器常用API
2020-08-25 本文已影响0人
卡布奇诺_95d2
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。
这里有几个注意点:
- 使用
*.vsh
和*.fsh
是为了区分顶点着色器还是片元着色器,实际项目中,可根据需要自己定义。 - 在这两个文件中,不建议加中文注释,这会导致奇怪的问题,影响开发效率,并且由于在Xcode中并不支持GLSL,所以当中文注释引发问题时,不好排查。
着色器常用API
- 向量的数据类型
类型 | 描述 |
---|---|
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型向量 |
- 矩阵数据类型
类型 | 描述 |
---|---|
mat2,mat2x2 | 两⾏两列 |
mat3,mat3x3 | 三行三列(常用) |
mat4,mat4x4 | 四行四列(常用) |
mat2x3 | 三行两列 |
mat2x4 | 四行两列 |
mat3x2 | 两行三列 |
mat3x4 | 四行三列 |
- 变量存储限定符
限定符 | 描述 |
---|---|
<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
- 创建顶点着色器/片元着色器
/*
GLenum type:创建着⾊器的类型,GL_VERTEX_SHADER 或者GL_FRAGMENT_SHADER
返回值:是指向新着⾊器对象的句柄.可以调用glDeleteShader 删除
*/
GLuint glCreateShader(GLenum type);
- 删除指定着色器
/*
GLuint shader:要删除的着⾊器对象句柄
*/
void glDeleteShader(GLuint shader);
- 指定着色器的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);
- 编译一个着色器
/*
GLuint shader:需要编译的着⾊器对象句柄
*/
void glCompileShader(GLuint shader);
- 查询着色器信息
/*
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 )
- 获取着色器信息日志
/*
GLuint shader:需要获取信息⽇志的着⾊器对象句柄
GLSizei maxLength:保存信息⽇志的缓存区⼤小
GLSizei *length:写⼊的信息⽇志的长度(减去null 终止符); 如果不需要知道⻓度. 这个参数可以为Null
GLChar *infoLog:指向保存信息日志的字符缓存区的指针
*/
void glGetShaderInfolog(GLuint shader , GLSizei maxLength, GLSizei *length , GLChar *infoLog);
- 创建一个程序对象
/*
返回值:返回⼀个执⾏新程序对象的句柄
*/
GLUint glCreateProgram( )
- 删除一个程序对象
/*
GLuint program:指向需要删除的程序对象句柄
*/
void glDeleteProgram( GLuint program )
- 着色器与程序进行附着/连接
/*
GLuint program:指向程序对象的句柄
GLuint shader:指向程序连接的着色器对象的句柄
*/
void glAttachShader( GLuint program , GLuint shader )
- 断开连接
/*
GLuint program:指向程序对象的句柄
*/
void glDetachShader(GLuint program)
- 链接程序
/*
GLuint program:指向程序对象的句柄
*/
void glLinkProgram (GLuint program)
- 链接程序之后,需要检查链接是否成功
/*
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)
- 从程序信息日志中获取信息
/*
GLuint program:指向需要获取信息的程序对象句柄
GLSizei maxLength:存储信息⽇志的缓存区⼤小
GLSizei *length:写⼊的信息⽇志⻓度(减去null 终⽌符),如果不需要知道⻓度,这个参数可以为Null
GLChar *infoLog:指向存储信息日志的字符缓存区的指针
*/
void glGetPorgramInfoLog( GLuint program ,GLSizei maxLength, GLSizei *length , GLChar *infoLog )
- 设置指定程序为活动程序
/*
GLuint program:设置为活动程序的程序对象句柄
*/
void glUseProgram(GLuint program)
着色器程序的编译和链接
- 需要创建两个基本对象才能用着色器进行渲染,它们分别是:着色器对象和程序对象。
- 获取链接后着色器对象的一般过程包含6个步骤:
2.1 创建一个顶点着色器对象和一个片元着色器对象
2.2 将源代码链接到每个着色器对象
2.3 编译着色器对象
2.4 创建一个程序对象
2.5 将编译后的着色器对象连接到程序对象
2.6 链接程序对象