《OpenGL编程指南》一2.6 着色器子程序

2.6 着色器子程序

高级技巧
GLSL允许我们在着色器中定义函数,而这些函数的调用过程总是静态的。如果需要动态地选择调用不同的函数,那么可以创建两个不同的着色器,或者使用if语句来进行运行时的选择,如例2.5所示。
例2.5 静态着色器的控制流程

着色器子程序在概念上类似于C语言中的函数指针,它可以实现动态子程序选择过程。在着色器当中,可以预先声明一个可用子程序的集合,然后动态地指定子程序的类型。然后,通过设置一个子程序的uniform变量,从预设的子程序中选择一个并加以执行。

2.6.1 GLSL的子程序设置

当我们需要在着色器中进行子程序的选择时,通常需要三个步骤来设置一个子程序池。
1)通过关键字subroutine来定义子程序的类型:

其中returnType可以是任何类型的函数返回值,而subroutineType是一个合法的子程序名称。由于它相当于函数的原型,因此我们只需要给出参数的类型,不一定给出参数的名称(我们可以将它设想为C语言中的typedef,而subroutineType就是新定义的类型)。
2)使用刚才定义的subroutineType,通过subroutine关键字来定义这个子程序集合的内容,以便稍后进行动态的选择。某个子程序函数的原型定义类似于下面的形式:

3)最后,指定一个子程序uniform变量,其中保存了相当于“函数指针”的子程序选择信息,这可以在应用程序中更改:

将上面的三个步骤整合在一起,我们可以通过例2.6来实现环境光照和漫反射光照方式的动态选择。
例2.6 声明一个子程序集合

子程序并不一定只属于一个子程序类型(例如,例2.6中的LightFunc)。如果定义了多种类型的子程序,那么我们可以设置一个子程序属于多个类型,方法是在定义子函数时把类型添加到列表中,如下所示:

在上面的例子中,func_1可以使用Func_1和Func_2,这是因为两个子程序都指定了Type_1。但是,func_2就只能使用Func_1,而func_3只能使用Func_2。

2.6.2 选择着色器子程序

如果我们已经在着色器中定义了所有子程序类型和函数,那么只需要在链接后的着色器程序中查询一些数值,然后使用这些数值来选择合适的函数即可。
在之前所示的步骤3当中,我们声明了一个子程序的uniform变量,之后就可以获取它的位置并设置它的值。与其他的uniform变量不同的是,子程序的uniform需要使用glGetSubroutineUniformLocation()来获取自身的位置。
GLint glGetSubroutineUniformLocation(GLuint program, GLenum shadertype, const char* name);
返回名为name的子程序uniform的位置,相应的着色阶段通过shadertype来指定。name是一个以NULL结尾的字符串,而shadertype的值必须是GL_VERTEX_SHADER、GL_TESS_CONTROL_SHADER、GL_TESS_EVALUATION_SHADER、GL_GEOMETRY_SHADER或者GL_FRAGMENT_SHADER中的一个。
如果name不是一个激活的子程序uniform,则返回–1。如果program不是一个可用的着色器程序,那么会生成一个GL_INVALID_OPERATION错误。
当取得了子程序uniform数值之后,我们需要判断某个子程序在着色器中的索引号。这一步可以通过调用函数glGetSubroutineIndex()来完成。
GLuint glGetSubroutineIndex(GLuint program, GLenum shadertype, const char* name);
从程序program中返回name所对应的着色器函数的索引,相应的着色阶段通过shadertype来指定。name是一个以NULL结尾的字符串,而shadertype的值必须是GL_VERTEX_SHADER、GL_TESS_CONTROL_SHADER、GL_TESS_EVALUATION_SHADER、GL_GEOMETRY_SHADER或者GL_FRAGMENT_SHADER中的一个。
如果name不是shadertype着色器的一个活动子程序,那么会返回GGL_INVALID_INDEX。
当我们得到了子程序的索引以及uniform的位置之后,可以使用glUniformSubroutinesuiv()来指定在着色器中执行哪一个子程序函数。某个着色阶段中,所有的子程序uniform都必须先经过初始化的过程。
GLuint glUniformSubroutinesuiv(GLenum shadertype, GLsizei count, const GLuint* indices);
设置所有count个着色器子程序uniform使用indices数组中的值,相应的着色阶段通过shadertype来指定。shadertype的值必须是GL_VERTEX_SHADER、GL_TESS_CONTROL_SHADER、GL_TESS_EVALUATION_SHADER、GL_GEOMETRY_SHADER或者GL_FRAGMENT_SHADER中的一个。第i个子程序uniform对应于indices[i]的值。
如果count不等于当前绑定程序的着色阶段shadertype的GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS值,那么会产生一个GL_INVALID_VALUE错误。indices中的所有值都必须小于GL_ACTIVE_SUBROUTINES,否则会产生一个GL_INVALID_VALUE错误。
将上面的步骤组合在一起,可以得到下面的代码段,它演示了例2.6中的顶点着色器的调用过程。

 调用glUseProgram()时会重新设置所有子程序uniform的值,具体的顺序与硬件实现相关。

时间: 2024-10-25 22:54:03

《OpenGL编程指南》一2.6 着色器子程序的相关文章

《OpenGL编程指南(原书第9版)》——2.1 着色器与OpenGL

2.1 着色器与OpenGL 现代OpenGL渲染管线严重依赖着色器来处理传入的数据.如果不使用着色器,那么用OpenGL可以做到的事情可能只有清除窗口内容了,可见着色器对于OpenGL的重要性.在OpenGL 3.0版本以前(含该版本),或者如果你用到了兼容模式(compatibility prof?ile)环境,OpenGL还包含一个固定功能管线(f?ixed-function pipeline),它可以在不使用着色器的情况下处理几何与像素数据.从3.1版本开始,固定功能管线从核心模式中去除

《OpenGL编程指南》一2.1 着色器与OpenGL

2.1 着色器与OpenGL 现代OpenGL渲染管线严重依赖着色器来处理传入的数据.如果不使用着色器,那么用OpenGL可以做到的事情可能只有清除窗口内容了,可见着色器对于OpenGL的重要性.在OpenGL 3.0版本以前(含该版本),或者如果你用到了兼容模式(compatibility profile)环境,OpenGL还包含一个固定功能管线(fixed-function pipeline),它可以在不使用着色器的情况下处理几何与像素数据.从3.1版本开始,固定功能管线从核心模式中去除,因

《OpenGL编程指南(原书第9版)》——2.6 着色器子程序

2.6 着色器子程序 高级技巧GLSL允许我们在着色器中定义函数,而这些函数的调用过程总是静态的.如果需要动态地选择调用不同的函数,那么可以创建两个不同的着色器,或者使用if语句来进行运行时的选择,如例2.5所示.例2.5 静态着色器的控制流程 着色器子程序在概念上类似于C语言中的函数指针,它可以实现动态子程序选择过程.在着色器当中,可以预先声明一个可用子程序的集合,然后动态地指定子程序的类型.然后,通过设置一个子程序的uniform变量,从预设的子程序中选择一个并加以执行.2.6.1 GLSL

《OpenGL编程指南(原书第9版)》——2.3 OpenGL着色语言概述

2.3 OpenGL着色语言概述 本节将会对OpenGL中着色语言的使用进行一个概述.GLSL具备了C++和Java的很多特性,它也被OpenGL所有阶段中使用的着色器所支持,尽管不同类型的着色器也会有一些专属特性.我们首先介绍GLSL的需求.类型,以及其他所有着色阶段所共有的语言特性,然后对每种类型的着色器中的专属特性进行讨论.2.3.1 使用GLSL构建着色器 我们将在这里介绍如何创建一个完整的着色器. 从这里出发 一个着色器程序和一个C程序类似,都是从main()函数开始执行的.每个GLS

《OpenGL编程指南》一2.3 OpenGL着色语言概述

2.3 OpenGL着色语言概述 本节将会对OpenGL中着色语言的使用进行一个概述.GLSL具备了C++和Java的很多特性,它也被OpenGL所有阶段中使用的着色器所支持,尽管不同类型的着色器也会有一些专属特性.我们首先介绍GLSL的需求.类型,以及其他所有着色阶段所共有的语言特性,然后对每种类型的着色器中的专属特性进行讨论. 2.3.1 使用GLSL构建着色器 从这里出发 一个着色器程序和一个C程序类似,都是从main()函数开始执行的.每个GLSL着色器程序一开始都如下所示: 这里的//

《OpenGL编程指南(原书第9版)》——导读

前言 OpenGL图形系统是图形硬件的一种软件接口(GL表示Graphics Library,即图形库).它使得用户可以创建交互式的程序以产生运动的三维对象的颜色图像.通过OpenGL,我们可以使用计算机图形学技术产生逼真的图像,或者通过一些虚构的方式产生虚拟的图像.这本指南将告诉你如何使用OpenGL图形系统进行编程,得到你所期望的视觉效果. 本书的主要内容 本书中包含以下章节: 第1章对OpenGL可以完成的工作进行了概览.它还提供了一个简单的OpenGL程序并解释了一些本质性的编程细节,它

《OpenGL编程指南》一导读

前言 Preface OpenGL图形系统是图形硬件的一种软件接口(GL表示Graphics Library,即图形库).它使得用户可以创建交互式的程序以产生运动的3维对象的颜色图像.通过OpenGL,我们可以使用计算机图形学技术来产生逼真的图像,或者通过一些虚构的方式产生虚拟的图像.这本指南将告诉你如何使用OpenGL图形系统进行编程,得到你所期望的视觉效果. 目 录 第1章 OpenGL概述1.1 什么是OpenGL1.2 初识OpenGL程序 1.3 OpenGL语法1.4 OpenGL渲

《OpenGL编程指南》一2.2 OpenGL的可编程管线

2.2 OpenGL的可编程管线 在第1章已经对OpenGL的渲染管线进行了一个概要的介绍,现在将更加详细地介绍它的每个阶段以及其中所承载的工作.4.3版本的图形管线有4个处理阶段,还有1个通用计算阶段,每个阶段都需要由一个专门的着色器进行控制. 1)顶点着色阶段(vertex shading stage)将接收你在顶点缓存对象中给出的顶点数据,独立处理每个顶点.这个阶段对于所有的OpenGL程序都是必需的,并且必须绑定一个着色器.第3章将对顶点着色的操作进行介绍. 2)细分着色阶段(tesse

《OpenGL编程指南(原书第9版)》——2.2 OpenGL的可编程管线

2.2 OpenGL的可编程管线 第1章已经对OpenGL的渲染管线进行了一个概要的介绍,其中我们简述了着色器自身的运行机制,但是并没有讲解第一个例子当中所用到的简单着色器代码的含义.现在将更加详细地介绍它的每个阶段以及其中所承载的工作.4.5版本的图形管线有4个处理阶段,还有1个通用计算阶段,每个阶段都需要由一个专门的着色器进行控制. 1)顶点着色阶段(vertex shading stage)将接收你在顶点缓存对象中给出的顶点数据,独立处理每个顶点.这个阶段对于所有的OpenGL程序都是唯一