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

在文件里写着色器代码

2023-08-19 19:16 作者:西村啪啪二  | 我要投稿


我们开始着手写着色器的代码,首先定义一个创建着色器的函数,把它标记为静态,因为我们不希望它渗入到别的C++文件里,在这个函数里写下我们要给OpenGL提供的源代码,这个函数需要的参数就是我们要写的着色器,我们需要把着色器以字符串的模式写好然后传递进来。

这里定义一个CompileShader()函数将字符串形式的着色器代码进行编译,并对错误进行处理。

通过使用glAttachShader将着色器附加到程序,使用glCompileShader编译着色器,以及使用glLinkProgram链接程序,在程序中创建一个或多个可执行文件。当调用glUseProgram时,这些可执行文件成为当前状态的一部分。最后可以通过调用glDeleteProgram来删除程序。当程序不再是任何上下文的当前呈现状态的一部分时,与程序相关联的内存将被删除。

glCreateProgram

我们一般把着色器附加到这个程序上。它还提供了一种方法来检查将用于创建程序的着色器的兼容性(例如,检查顶点着色器和片段着色器之间的兼容性),当着色器不再需要作为程序的一部分时,可以分离着色器。

和缓冲区和纹理对象一样,程序的命名空间可以在一组上下文中共享,只要上下文的服务器端共享相同的地址空间即可。如果程序的命名空间是跨上下文共享的,则任何附加的对象以及与这些附加的对象相关联的数据也会共享。 

当从不同的执行线程访问对象时,应用程序负责提供跨API调用的同步。

如果创建程序对象时出错,该函数返回0。

glCreateShader

shader对象用于维护定义着色器的源代码字符串。

像缓冲区和纹理对象一样,着色器对象的名称空间可以跨一组上下文共享,只要上下文的服务器端共享相同的地址空间。如果名称空间跨上下文共享,则任何附加的对象以及与这些附加的对象相关联的数据也会共享。 

当从不同的执行线程访问对象时,应用程序负责提供跨API调用的同步。

GL_COMPUTE_SHADER仅在GL版本为4.3或更高版本时可用。

如果创建shader对象时出错,此函数返回0。

如果shaderType不是可接受的值,则生成GL_INVALID_ENUM。

glShaderSource

先前存储在着色器对象中的源代码被完全替换。数组中的字符串数量由count指定。如果length为NULL,则假定每个字符串都以NULL结尾。如果length是NULL以外的值,则它指向一个数组,该数组包含string的每个对应元素的字符串长度。length数组中的每个元素可以包含相应字符串的长度(空字符不作为字符串长度的一部分计算)或一个小于0的值,以指示字符串以空字符结束。此时不会扫描或分析源代码字符串;它们只是被复制到指定的着色器对象中。

当调用glShaderSource时,OpenGL复制着色器源代码字符串,因此应用程序可以在函数返回后立即释放其源代码字符串副本。

glCompileShader

该函数将编译我们传递给他的字符串形式的着色器源代码,已存储在Shader指定的shader对象中的源代码字符串。 编译状态将存储为着色器对象状态的一部分。如果着色器编译无误并可供使用,该值将设置为GL_TRUE,否则设置为GL_FALSE。可以通过使用参数Shader和GL_COMPILE_STATUS调用glGetShader来查询。 由于OpenGL着色语言规范中规定的许多原因,着色器的编译可能会失败。无论编译是否成功,都可以通过调用glGetShaderInfoLog从shader对象的信息日志中获取有关编译的信息。

glGetShaderiv

第二个参数:

  •  GL_SHADER_TYPE:返回着色器类型,如果指定的着色器是顶点着色器对象,则params返回GL_VERTEX_SHADER,如果是几何着色器对象,则返回GL_GEOMETRY_SHADER如果是片段着色器对象,则返回GL_FRAGMENT_SHADER。

  • GL_DELETE_STATUS:判断着色器是否被删除,是,params返回GL_TRUE,否则返回GL_FALSE。

  • GL_COMPILE_STATUS:判断编译状态,如果着色器最后一次编译成功,params返回GL_TRUE,否则返回GL_FALSE。

  • GL_INFO_LOG_LENGTH:params返回着色器信息日志中的字符数,包括空终止字符(即存储信息日志所需的字符缓冲区的大小)。如果着色器没有信息日志,则返回值0。

  • GL_SHADER_SOURCE_LENGTH:params返回着色器源码字符串的长度,包括空终止字符。(即存储着色器源码所需的字符缓冲区的大小)。如果不存在源代码,则返回0。

错误:

GL_INVALID_ENUM: pname不是一个可接受的值(只允许上面这些参数)。

GL_INVALID_VALUE: 着色器不是由OpenGL生成的值。

GL_INVALID_OPERATION:shader不是一个着色器对象

_malloca

 _malloca 返回一个void *,该指针能用于存储任何类型的对象,并且只有强制类型转换后才可以正常取值,可以通过等于0或者NULL来初始化。

void*类型的指针可以理解为一个过渡型的指针状态,必须要赋予类型(强制类型转换)才能正常使用,void*可以转化成其他类型,但其他类型不能转化成void*。任何类型的指针都可以直接赋值给void *型指针,无需进行强制类型转换,相当于void *包含了其他类型的指针。

glGetShaderInfoLog


将shader的信息日志储存在InfoLog中,最多可达maxLength个字符,实际返回length字符数(不包括空终止字符)。如果不需要返回字符串的长度,可以把length设置为NULL。这里的maxLength和length一般通过调用glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);获得。

着色器对象的信息日志是OpenGL实现者传达编译过程信息的主要机制。

错误:

如果 shader 参数不是 OpenGL 生成的,那么生成 GL_INVALID_VALUE 错误。

如果 shader 参数不是一个 shader 对象,那么省 GL_INVALID_OPERATION 错误。

如果 maxLength 小于0,那么生成 GL_INVALID_VALUE 错误。

glDeleteShader

该函数释放内存并使shader对象的名称无效。此命令有效地撤消了调用glCreateShader的效果。 如果要删除的着色器对象被附加到程序对象,则它将被标记为删除,但如果在任何渲染的上下文中附加了某个着色器,这个着色器必须先分离,才能被删除,若要确定某个着色器对象是否已标记为删除,可以使用glGetShader(shader, GL_DELETE_STATUS, *params)。

错误:

如果着色器不是由OpenGL生成的值,则生成GL_INVALID_VALUE。

glAttachShader

允许在程序上附加多个相同类型的着色器,也允许将一个着色器附加到多个程序。调用glDetachShader可以将着色器从附加的程序分离。

如果程序或着色器不是由OpenGL生成的值,则生成GL_INVALID_VALUE。 

如果程序不是指定的程序对象,则生成GL_INVALID_OPERATION。 

如果着色器不是指定的着色器对象,则生成GL_INVALID_OPERATION。 

如果着色器已经附加到程序,则生成GL_INVALID_OPERATION。

glDetachShader

如果着色器已通过调用glDeleteShader被标记为删除,且未附加到任何其他程序对象,那么在它被分离后就会被删除。

错误:

如果程序或着色器的值不是由OpenGL生成的,则生成GL_INVALID_VALUE。

 如果程序不是程序对象,则生成GL_INVALID_OPERATION。 

如果shader不是shader对象,则生成GL_INVALID_OPERATION。 

如果着色器未附加到程序,将生成GL_INVALID_OPERATION。


glLinkProgram

根据附加到程序的着色器类型,比如GL_VERTEX_SHADER、GL_GEOMETRY_SHADER和GL_FRAGMENT_SHADER类型的着色器,它们会被用于创建可执行文件。

可以通过调用带参数program和GL_LINK_STATUS的glGetProgram()函数来查询链接操作的状态,如果程序被正确链接并且可以使用,则该值将被设置为GL_TRUE,否则将被设置为GL_FALSE。

成功链接之后,属于程序的uniform变量将被初始化为0,并分配一个位置,该位置可以通过调用glGetUniformLocation来查询,所有未绑定到顶点属性索引的属性变量此时都将绑定一个索引。

glValidateProgram

检查程序中包含的可执行文件是否可以在当前OpenGL状态下执行。验证过程产生的信息将存储在程序的信息日志中。验证信息可以由空字符串组成,或者它可以是包含关于当前程序对象如何与当前OpenGL状态的其余部分交互的信息的字符串。这为OpenGL实现者提供了一种方式来传达关于为什么当前程序是低效的、次优的、无法执行的等等的更多信息。

验证操作的状态将作为程序对象状态的一部分存储。如果验证成功,该值将被设置为GL_TRUE,否则将被设置为GL_FALSE。可以通过调用带参数Program和GL_VALIDATE_STATUS的glGetProgram来查询。如果验证成功,程序在给定的当前状态下执行。否则,程序不会执行。 

该功能通常仅在应用程序开发期间有用。信息日志中存储的信息字符串完全依赖于实现;因此,程序在不同的OpenGL实现下会产生不同的信息字符串。


我们分别以字符串形式写下顶点着色器和片段着色器,着色器是使用一种叫GLSL的语言写的,这里的vec4表示包含4个float分量的向量,position是变量名,着色器只通过输入和输出来进行数据的交流和传递,所以GLSL定义了in和out关键字来专门实现这个目的,GLSL还提供一个额外的layout标识,这可以让顶点着色器从顶点数据中直接接收输入,我们使用location这一元数据指定输入变量,它和CPU上的顶点属性相匹配。

我们可以做一些操作,创建新的文件夹res->shaders,创建一个命名为Basic.shader的文件,将字符串中的代码移到这里

然后写一个函数ParseShader()将两个着色器存到string数组ss中并返回,注意这里函数返回多个值的方法

最后,我们通过指定路径拿到写好的字符串源码,然后创建着色器,用glUseProgram来启动着色器,在程序结束前记得调用glDeleteProgram来删除我们的程序以释放内存。

此时点击本地Windows调试器,将会看到我们着色器开始工作,在窗口中显示一个红色的三角形,并且在输出窗口可以看到我们的调试代码,输出了着色器的字符串源码

glUseProgram

如果程序对象包含一个或多个已成功编译和链接的GL_VERTEX_SHADER类型的着色器对象,则该程序对象将包含在顶点处理器上运行的可执行文件。

如果程序对象包含一个或多个GL_GEOMETRY_SHADER类型的着色器对象,并且这些着色器对象已被成功编译和链接,则该程序对象将包含在几何处理器上运行的可执行文件。

如果程序对象包含一个或多个GL_FRAGMENT_SHADER类型的着色器对象,并且这些着色器对象已被成功编译和链接,则该程序对象将包含可在片段处理器上运行的可执行文件。

当程序对象正在使用时,应用程序可以自由地修改、编译、附加、分离或删除附加的着色器对象。这些操作都不会影响作为当前状态一部分的可执行文件。重新链接当前正在使用的程序对象时,如果链接成功,就会将该程序对象安装为当前渲染状态的一部分(参见glLinkProgram);如果失败,其链接状态将被设置为GL_FALSE,但可执行文件和相关状态会保留为当前状态的一部分,直到后续调用glUseProgram时才将其移除,移除后,在重新链接成功之前,它不会成为当前状态的一部分。

如果program为零,则表示当前渲染状态引用无效的program对象,并且着色器执行的结果是未定义的。但是,这不是错误。 

如果程序不包含GL_FRAGMENT_SHADER类型的着色器对象,可执行文件会安装在顶点处理器上,或者在几何处理器上,但片段着色器执行的结果将是未定义的。

错误:

如果program既不是0也不是OpenGL生成的值,则生成GL_INVALID_VALUE。 

如果程序不是程序对象,则生成GL_INVALID_OPERATION。 

如果程序不能成为当前状态的一部分,则生成GL_INVALID_OPERATION。 

如果转换反馈模式激活,则生成GL_INVALID_OPERATION。

在文件里写着色器代码的评论 (共 条)

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