《OpenGL编程指南(原书第9版)》——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的位置之后,可以使用glUniformSubrou-tinesuiv()来指定在着色器中执行哪一个子程序函数。某个着色阶段中,所有的子程序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-09-20 17:45:21

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

《OpenGL编程指南》一2.7 独立的着色器对象

2.7 独立的着色器对象 高级技巧在OpenGL 4.1版本之前(不考虑扩展功能),在应用程序中,同一时间只能绑定一个着色器程序.如果你的程序需要使用多个片元着色器来处理来自同一个顶点着色器的几何体变换数据,那么这样会变得很不方便.此时只能将同一个顶点着色器复制多份,并且多次绑定到不同的着色器程序,从而造成了资源的浪费和代码的重复.独立的着色器对象可以将不同程序的着色阶段(例如顶点着色)合并到同一个程序管线中.第一步,我们需要创建用于着色器管线的着色器程序.我们可以调用glProgramPara

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

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

《OpenGL编程指南(原书第9版)》——1.5 第一个程序:深入分析

1.5 第一个程序:深入分析 现在我们来深入探讨一下之前的第一个程序.1.5.1 进入main()函数 为了了解示例程序从一开始是如何运行的,首先了解一下main()函数当中都发生了什么.前面的6行使用GLFW设置和打开了一个渲染用的窗口.这方面的详细介绍可以参见附录A,这里只介绍每一行的执行结果. 第一个函数glfwtInit()负责初始化GLFW库.它会处理向程序输入的命令行参数,并且移除其中与控制GLFW如何操作相关的部分(例如设置窗口的大小).glfwtInit()必须是应用程序调用的第

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

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

《opengl编程指南》第八版 例题都不能编译运行

问题描述 <opengl编程指南>第八版 例题都不能编译运行 所有例题都出现下面这几个错误.好像是库的问题,但不知道那个库,该怎么办 解决方案 1>------ 已启动生成: 项目: Triangles, 配置: Debug Win32 ------ 1>freeglut_static_vs2010_d.lib(freeglut_init.obj) : error LNK2019: 无法解析的外部符号 sscanf,该符号在函数 _glutInit 中被引用 1>freegl

《JavaScript和jQuery实战手册(原书第3版)》---第1章 编写第一个JavaScript程序 1.1 编程简介

本节书摘来自华章出版社<JavaScript和jQuery实战手册(原书第3版)>一书中的第1章,第1.1节,作者David Sawyer McFarland,姚待艳 李占宣 译,更多章节内容可以访问"华章计算机"公众号查看. 第1章 编写第一个JavaScript程序 HTML自身并没有太多智能:它不能做数学运算,不能判断某人是否正确填写了一个表单,而且不能根据Web访问者的交互来做出判断.基本上,HTML让人们阅读文本.观看图片或视频,并且单击链接转向拥有更多文本.图片

《面向对象的思考过程(原书第4版)》一1.3 过程式编程与面向对象编程

本节书摘来自华章出版社<面向对象的思考过程(原书第4版)>一书中的第1章,第1.3节,[美] 马特·魏斯费尔德(Matt Weisfeld) 著黄博文 译更多章节内容可以访问"华章计算机"公众号查看. 1.3 过程式编程与面向对象编程 在我们深入了解面向对象开发的优势之前,先考虑一个更基本的问题:究竟什么是对象?这既是一个复杂的问题,也是一个简单的问题.它复杂是因为学习任何一种软件开发方法论都非易事.它简单是因为人们已经在按对象的方式进行思考.例如,当你看到一个人,你会把他

ROS机器人程序设计(原书第2版).

机器人设计与制作系列 ROS机器人程序设计 (原书第2版) Learning ROS for Robotics Programming,Second Edition 恩里克·费尔南德斯(Enrique Fernández) 路易斯·桑切斯·克雷斯波(Luis Sánchez Crespo) 阿尼尔·马哈塔尼(Anil Mahtani) 亚伦·马丁内斯(Aaron Martinez) 著 刘锦涛 张瑞雷 等译 图书在版编目(CIP)数据 ROS机器人程序设计(原书第2版) / (西)恩里克·费尔南

Java核心技术 卷Ⅰ 基础知识(原书第10版)

Java核心技术系列 Java核心技术 卷Ⅰ 基础知识 (原书第10版) Core Java Volume I-Fundamentals (10th Edition) [美] 凯S.霍斯特曼(Cay S. Horstmann) 著 周立新 陈 波 叶乃文 邝劲筠 杜永萍 译 图书在版编目(CIP)数据 Java核心技术 卷Ⅰ 基础知识(原书第10版) / (美)凯S. 霍斯特曼(Cay S. Horstmann)著:周立新等译. -北京:机械工业出版社,2016.8 (Java核心技术系列) 书

《Java核心技术 卷Ⅱ 高级特性(原书第10版)》一导读

前 言 致读者 本书是按照Java SE 8完全更新后的<Java核心技术 卷Ⅱ 高级特性(原书第10版)>.卷Ⅰ主要介绍了Java语言的一些关键特性:而本卷主要介绍编程人员进行专业软件开发时需要了解的高级主题.因此,与本书卷Ⅰ和之前的版本一样,我们仍将本书定位于用Java技术进行实际项目开发的编程人员. 编写任何一本书籍都难免会有一些错误或不准确的地方.我们非常乐意听到读者的意见.当然,我们更希望对本书问题的报告只听到一次.为此,我们创建了一个FAQ.bug修正以及应急方案的网站http:/