【OPENGL】第三篇 着色器基础(二)

 


 

在这一小节,主要学习GLSL的基本数据类型以及控制结构。GLSL具有了C++和Java的不少特性,咱们会先了解全部着色阶段共有的特性,再了解各个着色器的专属特性。数组

 


 

一、着色器的基本结构缓存

一个着色器程序和一个C程序相似,都是从main()函数开始执行的。一样支持单行注释//以及多行注释/**/函数

#version 330 core
void main(){
    // add test code
}

 

 二、着色器的数据类型学习

GLSL是一种强类型的语言,全部变量使用前的必须声明。可用字母、数字、以及下划线字符来组成变量名字。可是数字或者下划线字符不能做为变量名的第一个字符,也不能使用连续下划线。ui

全部变量都必须在声明的同时进行初始化。atom

类型透明:基本数据类型(float、double、int、uint、bool)以及聚合类型(所谓聚合类型就是基本类型的合并)spa

类型不透明:采样器(sampler)、图像(Image)、原子计数器(atomic counter)。翻译

 

前面提到的聚合类型,每一个基本类型都有对应的聚合类型,以int为例,有2D向量(vec2)、3D向量(vec3)、4D向量(vec4)以及矩阵(mat二、mat4)等类型。指针

须要注意的是对于矩阵类型好比mat4×3,其中第一个值表示列数,第二个值表示行数。此外,矩阵的指定须要遵循主序的原则。也就是说,传入的数据将先填充列,而后填充行。code

 

向量与矩阵中的元素是能够单独访问和设置的。下面主要说三种比较特殊的份量

(x,y,z,w) 与位置相关的份量

(r,g,b,a)  与颜色相关的份量

(s,t,p,q)  与纹理坐标相关的份量

 

此外,还有数组类型,一个大小为n的数组的元素范围是0到n-1。

float coeff[3];
float[3] coeff;
int indices[];

相似其余语言好比C++/Java。  

数组拥有构造函数 float coeff[3] = float[3](2.38, 3.14, 42.0)

GLSL的数组能够获取数组的长度 length() 该函数返回元素的个数。由于长度值在编译时就是已知的,因此length()方法会返回一个编译时常量。

 

 三、着色器的存储限制符(Storage Qualifiers)

数据类型能够经过一些修饰符来改变本身的行为。GLSL中一共定义了4种全局范围内的修饰符。

一、const 将一个变量定义为只读形式,能够理解为常量的意思

二、in 设置为着色器阶段的输入变量

三、out 设置为着色器阶段的输出变量

四、uniform 表示惟一,对全部几何图元的值都是一致的,除非应用程序对它执行了更新,不然着色器是并不会影响它的值的变化的。

五、buffer 设置应用程序共享的愉快可读写的内存

六、shared  只能用于用于计算着色器当中,它能够创建本地工做组内共享的内存。

 

四、逻辑语句

与其余语言相似GLSL提供了大量的操做符以及控制语句执行流程的逻辑操做

包括算术运算符、操做符、ifels、while、for、break、continue、return等,

这里有个特殊的关键字 discard 它只能用于片元着色器中,用于丢弃当前的片元、终止着色器的运行,不过这也得取决于具体的硬件实现。

 

另外函数的声明以及定义和C/C++相似,而且使用函数以前必须先声明,不然会产生错误。可是,须要特别注意的是,GLSL中没有指针或者引用的概念,

所以,GLSL提供了参数限制符,来代表其参数时候能够修改或者拷贝到函数等等,类型以下:

一、in 将数据拷贝到函数中(默认)

二、const in 将只读数据拷贝到函数中

三、out 从函数中获取数值

四、inout 将数据拷贝到函数中,而且返回函数中修改的数据

 


 

以上大概了解了GLSL的数据类型以及语句,下面是一些零散的知识点,先看看,之后用到时再从新回顾。


 

一、计算的不变性

GLSL没法保证在不一样的着色器中,两个彻底相同的计算公式会获得彻底同样的结果。所以GLSL提供了invariant和precise关键字来保持着色器之间的计算不变性。

关于这个知识点,暂时没法理解,之后再回顾。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

二、着色器的预处理器(跳过)

三、数据块接口(Interface Blocks)

着色器与应用程序之间,或者着色器阶段之间共享的变量能够组织为变量块的形式,而且有的时候必须采用这种形式

例如 uniform块、in块、out块、buffer块等等。

写法有点类型结构体的写法:

下面以uniform为例
uniform b{   vec4 v1;   bool v2; };
一个uniform块中只能够包含透明类型的变量,并且uniform块必须在全局做用域内声明。

注意:着色器中的数据类型有两种:不透明以及透明的。上文有说起。

四、从应用程序中访问uniform块

uniform变量是着色器与应用程序之间共享数据的桥梁,所以若是着色器中的uniform变量是定义在命名的uniform块中,那么就有必要找到不一样变量的偏移值。

五、Buffer块

GLSL中的buffer块,或者对于应用程序而言,就是着色器的存储缓存对象(shader storage buffe object)

与uniform块相似,可是buffer块更为强大。若是不须要写入缓存,那么能够直接使用uniform块,而且硬件设备自己可能也没有足够的资源空间来支持buffer块,

可是uniform块一般是足够的。

六、in/out块


 

 

关于着色器的编译

 

OpenGL着色器程序的编写与C语言等基于编译器的语言很是相似。

咱们使用编译器来解析程序,检查是否存在错误,而后将它翻译为目标代码obj。而后,在链接过程当中将一系列目标文件合并,并产生最终的可执行程序。

在程序中使用GLSL着色器的过程与之相似,只不过编译器和链接器都是OpenGL API的一部分而已。

 

常规步骤:

对于每个着色器对象:

  一、建立一个着色器对象

  二、将着色器源代码编译为对象

  三、验证着色器的编译是否成功

将后须要将多个着色器对象连接为一个着色器程序,包括:

  一、建立一个着色器程序

  二、将着色器对象关联到着色器程序

  三、链接着色器程序。

  四、判断着色器的链接过程是否成功完成

  五、使用着色器来处理顶点和片元

相关OpenGL函数

  一、建立着色器对象  glCreateShader(GLenum type)

     type必须是  GL_VERTEX_SHADER、GL_FFRAGMENT_SHADER、

              GL_TESS_CONTROL_SHADER、GL_TESS_EVALUATION_SHADER、GL_GEOMETRY_SHADER

     中的一个。

  二、将着色器的源代码关联到这个对象上。  glShaderSource(...)

  三、编译着色器对象的源代码       glCompileShader()

  四、将着色器对象shader关联到着色器程序program中    glAttachShader()

and so on...


 

 

不知不觉明天就是11月份了。一份小记拖了将近2个月,我也是醉了。

最近发现了DOOM3源码,如获至宝。之后有时间会研究下约翰卡马克大神的这个引擎。

 

10月31日

广州

相关文章
相关标签/搜索