欢迎光临散文网 会员登陆 & 注册

着色器的处理

2023-08-03 15:31 作者:追逐彗星的尾巴  | 我要投稿

从编写着色器源码,到编译着色器,再到创建着色器程序,这是一个非常繁琐的过程。因此我们需要对整个过程进行简化和封装。

创建着色器

我们首先可以把“创建着色器”这个过程封装为函数CreateShader()。两个参数分别是要创建的着色器的类型和相关的着色器源码。

由于着色器源码很容易出现错误,且一旦出错编译器也无法给出明确的提示,因此我们可以在这里加上错误处理的代码。这需要用到函数glGetShaderiv()glGetShaderInfoLog()

glGetShaderiv用于获取着色器对象的信息。

shader表示要查询的着色器对象的标识符。

pname表示要获取的信息类型:GL_SHADER_TYPE(获取着色器类型),GL_DELETE_STATUS(获取着色器删除状态,返回GL_TRUE表示已删除,GL_FALSE表示未删除),GL_COMPILE_STATUS(获取着色器编译状态,返回GL_TRUE表示编译成功,GL_FALSE表示编译失败),GL_INFO_LOG_LENGTH(获取着色器信息日志的长度),GL_SHADER_SOURCE_LENGTH(获取着色器代码的长度)。

params用于接收查询结果。

glGetShaderInfoLog用于获取着色器对象的编译或链接信息日志。

maxLength指定infoLog缓冲区的最大长度(以字节为单位)。

length用于接收实际写入infoLog缓冲区的字符数。如果不需要返回的字符串长度,可以设置为NULL

infoLog用于接收信息日志的缓冲区,通常是一个字符数组。

下面是错误处理的代码部分:

使用alloca动态分配字符数组message相对简单,也可以使用动态数组vector来代替,这样可以更好地管理内存,避免内存泄漏:

创建着色器程序

创建完着色器后,下一步就是对创建着色器程序进行封装。通过传入相应的着色器源码,来获取最终的着色器程序。

这里比之前创建着色器程序多了一步——使用函数glValidateProgram()。它用于验证一个着色器程序对象的有效性,验证的结果可以通过函数glGetProgramiv()获取。

这只是最基本的实现。严谨一点,就需要在glLinkProgramglValidateProgram后分别进行一次错误处理。当然,这里和上面创建着色器部分的错误处理的方法和步骤以及函数的用法几乎一致。

2

获取着色器源码

为了更好地编写和管理着色器源码,可以把着色器源码全部放在另外一个文件中,避免在代码中出现冗长的字符串。

让我们在项目中添加一个“Shader.glsl”文件,当然文件的命名和后缀都不重要,也可以让它是一个.txt文件,怎样都行。我们把所有的着色器源码都写在这个文件里。为了方便后面读取两个着色器的各自部分的代码,我们为每个着色器添加一个前缀标识符,如下所示:

接下来要做的就是把这个文件读取为两个字符串。我们将定义一个函数,它接收着色器源码文件路径,返回两个字符串。因此我们首先要定义一个存储两个字符串的结构体:

接下来在函数中,我们遍历文件中的每一行。首先检查我们设置的着色器类型标识符。第一个条件语句检查当前行是否包含“#shader”。如果包含,表示这是指定着色器类型的行。第二个条件语句用于确定着色器类型。如果当前行不是指定着色器类型的行,则将该行添加到字符串流数组对象source中。注意,这里让source的下标和枚举的着色器类型相互对应,简化了代码。

当然,这里也只是最基本的实现。我们依然可以添加许多错误处理的代码。譬如可以检查文件是否被正确打开:

另外,使用std::stringstream存储解析结果,可能导致较大的内存消耗。我们也可以换一种方式,使用字符串的加法来解决结果的存储问题:

到此为止,我们已经初步完成了着色器相关步骤的封装。现在我们要在主函数中创建一个着色器程序只需要两行代码:


着色器的处理的评论 (共 条)

分享到微博请遵守国家法律