从0开始的OpenGL学习(四)-着色器类

本文主要解决两个问题:

1、着色器和应用、着色器之间是如何进行数据传递的?
2、如何封装一个着色器类?

一、开胃小菜GLSL

先来点开胃菜,扯两句GLSL。之前我们就用过GLSL搞了个顶点着色器和片元着色器,也算是对它不陌生了。语法上,它和C语言十分类似,所以使用起来的时候感觉还是很友好的(笔者是学C语言出生的,吼吼)。不说太多关于语法、操作符、数据类型这些废话,学了一门语言之后,所有的语言都会往自己熟悉的方向去用,学一门新语言的时候最讨厌的就是先看语法,烦透了。我们直接从关键点着手!

1、着色器代码的格式:

#version 版本号
in 数据类型 变量名;
in 数据类型 变量名;
out 数据类型 变量名;
uniform 数据类型 变量名;
void main() {
        //处理过程
         输出变量 = 处理结果;
}

in表示从上一个阶段输入的数据,out表示这个阶段需要输出的数据,uniform表示全局的数据(应用里也能读取和写入这个变量,这就是着色器和应用之间互通数据的方法),主函数main中包含了处理过程,将处理结果赋值给输出变量。

2、向量

用的最多的数据类型就是向量,反正到现在为止我们用的是最多的,以后用的也是最多的。已经用过的类型有:vec3,vec4。表示有3个、4个float数据的向量。当然还有vec1,vec2。(vec2可以理解,这个vec1是什么鬼?别问我,我也是新手,别说用过,见都没见过。)这只是包含float类型的向量,还有包含布尔类型的向量bvec1234,包含整型数的向量ivec1234,包含无符号整型数的向量uvec1234,包含双精度浮点型数的向量dvec1234。除了包含的类型不同,操作方式都一样,用到的时候再说。

二、着色器之间的数据互通

说穿了很简单,上一个阶段的输出变量就会成为下一个阶段的输入变量,只要变量名相同就行了。注意,必须要相同变量名,否则接收不到。

从0开始的OpenGL学习(四)-着色器类_第1张图片
顶点着色器和片元着色器数据互通代码

在顶点着色器中定义一个输出的颜色,片元着色器中接收,然后直接将这个颜色赋值给了片元颜色输出量,这样三角形的颜色就成了顶点着色器中定义的暗红色了。

从0开始的OpenGL学习(四)-着色器类_第2张图片
显示效果

三、着色器和应用之间的数据互通

说穿了也很简单,定义成uniform方式的变量就是全局的变量,可以在应用中访问,不过需要一些特殊的访问方式。

从0开始的OpenGL学习(四)-着色器类_第3张图片
使用uniform的着色器代码

(坑提醒:如果申明了一个uniform但是在GLSL中没有使用,编译器会自动将这个变量删除的,这会引起一系列诡谲的BUG,到时候慢慢填吧,哇哈哈)
要使用这个变量,需要两步:

  • 1、获取该变量在着色器程序中的位置(这里是着色器程序,不是片元着色器,是顶点着色器和片元着色器链接进入的那个着色器程序)。
  • 2、通过glUniform4fv函数对其进行赋值。
使用uniform数据的代码

这里的glUniform4f函数调用可以放到glUserProgram之前,在使用着色器程序之前就可以完成对颜色的赋值操作。
运行之后的效果显示了一个绿色三角形:

从0开始的OpenGL学习(四)-着色器类_第4张图片

运行效果

四、封装一个着色器类

直接在源代码中写着色器实在是太麻烦了,不好管理不说,可读性也很差。作为一个上进的好程序员,怎么能不封装一下节省时间呢?
这个类需要什么功能?从文件中读取并且编译是必要的,也要可以设置着色器中变量的功能,使用着色器的功能也不能少,嗯,干脆就弄一个编译链接之后的着色器程序类。

从0开始的OpenGL学习(四)-着色器类_第5张图片
头文件代码

不多解释了,按照我们的思路来编码,代码本身很简单。

其他的实现都很简单,主要是Shader这个构造函数,要完成两个主要步骤:

  • 其一、从文件中读取着色器代码
  • 其二、编译链接这些代码

先实现读取代码的功能:

从0开始的OpenGL学习(四)-着色器类_第6张图片
读取着色器文件

简单地使用C++的STL库来读取文件,保存到流中,再从流中转换到字符串里保存,这样,我们就得到了所需要的代码。

再把代码进行编译:

从0开始的OpenGL学习(四)-着色器类_第7张图片
编译着色器代码的程序

代码很简单,出了添加了一个编译和连接的成功判断,都是我们之前写过的东西,没啥难度。

使用着色器程序以及设置简单数据的功能也没啥好说的,就是单纯的函数调用而已,直接放代码:

从0开始的OpenGL学习(四)-着色器类_第8张图片
使用着色器以及设置简单值

好,功能实现完毕,编译一下,没有问题。Very Good!

等等,这就好了?还没完呢!弄了个东西不弄不就浪费了,我们来改造一下代码。

五、使用着色器类

先创建两个文件,Shader.vs和Shader.fs,分别表示顶点着色器和片元着色器。使用本文第二节中显示为红色的着色器代码。

然后,将冗长的着色器实现代码和加载编译的代码删除掉,用Shader对象来代替:

创建着色器代码

最后,将使用着色器程序的代码删除,调用着色器对象的use函数

使用着色器对象

编译运行,效果和第二节的一样,说明我们的工作是有成效的!

从0开始的OpenGL学习(四)-着色器类_第9张图片
运行结果

总结

嗯,到现在为止,我们的着色器程序算是走上正轨了,手写一遍代码的读者想必也累了,休息一下吧。

下一篇
目录
上一篇

参考资料:

www.learningopengl.com(非常好的学习站点,强烈推荐)

你可能感兴趣的:(从0开始的OpenGL学习(四)-着色器类)