OpenGL-Shader学习之基础知识介绍

Shader与OpenGL

现代OpenGL渲染管线严重依赖着色器(shader)来处理传入的数据。可以这么说,如果不使用shader,用OpenGL可以做到的事情只有清除窗口了。从3.1版本开始,固定管线从core模式中去除,因此我们必须使用shader来完成工作。

OpenGL渲染管线可以被划分为几个阶段,每个阶段会把前一阶段的输出作为输入,每个阶段都是有各自的分工。正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,方能做到加速计算出图的效果。

下图(转自 Learn OpenGL CN),是一个图形渲染管线的每个阶段的抽象展示。

Shader如此重要,学会编写shader也成为很重要的一项技能。我们首先谈一谈编写shader需要的语言。

GLSL与OpenGL

GLSL(OpenGL Shader Language)释义OpenGL着色器语言,它是类C的语言,如果有C或C++语言基础的小伙伴看GLSL代码应该不会陌生,每一阶段的shader都是从main函数开始执行的。大致结构如下代码所示 。类C,这里的 // 是注释符号,多行注释符合同是——/* 和 */ 。此外,着色器的每一行结尾必须有一个分号。

#version 330 core

void main()
{
    //执行代码
}

GLSL语法

变量类型

GLSL语言是一种强类型语言,这就意味着所有变量在使用之前必须先声明,并且给出变量的类型。变量名称的命名规范和C语言相同。表中给出GLSL基本的数据类型

类型描述
floatIEEE32位浮点值
doubleIEEE64位浮点值
int有符号32位整数
uint无符号32位整数
bool布尔值

变量作用域类C++,初始化如下

int i, number = 50;
float fMax, fMin = -10.2;
bool bResult = true;
double dValue = 3.1415926

聚合类型:GLSL的基本类型可以进行合并,从而参与转换的运算。

GLSL的向量和矩阵类型
bvec2包含2个布尔成分的向量
bvec3包含3个布尔成分的向量
bvec4包含4个布尔成分的向量
ivec2包含2个整型成分的向量
ivec3包含3个整型成分的向量
ivec4包含4个整型成分的向量
mat2 或者 mat2x22×2的浮点数矩阵类型
mat3或者mat3x33×3的浮点数矩阵类型
mat4x44×4的浮点矩阵
mat2x32列3行的浮点矩阵(OpenGL的矩阵是列主顺序的)
mat2x42列4行的浮点矩阵
mat3x23列2行的浮点矩阵
mat3x43列4行的浮点矩阵
mat4x24列2行的浮点矩阵
mat4x34列3行的浮点矩阵

表格中mat2x3,第一个值2表示列数,第二值表示行数(体现列优先)。初始化

vec3 vecNormal = vec3(0.0, 2.0, 3.0);

类型之间等价转化和拷贝构造

ivec3 = ivec3(vecNormal);

向量的截断和加长

vec4 Color;
vec3 RGB = vec3(Color);
vec4 White = vec4(RGB , 1.0);

访问和赋值向量中的元素

// 1)通过名称
float r = color.r;
color.r = 1.0f;
// 2)通过下标
float r = color[0];
color[0] = 1.0f;
// 3)搅拌式
vec3 luminance = color.rrr; //基于红色分量设置亮度值
vec4 color2 = color.abgr;   //反转颜色分量
向量分量访问符
向量访问符符号描述
(x, y, z, w)位置相关分量
(r, g, b, a)颜色相关分量
(s, t, p, q)纹理坐标相关分量

矩阵的使用

初始化:可以用向量初始化,或单个值指定,值得注意的是矩阵的初始化遵循列优先原则,所以先填充的是第一列。

mat3 m =mat3 (1.0, 0.0, 0.0,
             0.0, 1.0, 2.0,
             0.0, 0.0, 1.0);

vec3 colum1 = (1.0, 0.0, 0.0);
vec3 colum2 = (1.0, 0.0, 0.0);
vec3 colum3 = (1.0, 0.0, 0.0);
mat3 m = mat3(colum1, colum2, colum3);

mat4 m = mat4(colum1, 1.0,
              colum2, 2.0,
              colum3, 1.0);

      矩阵的访问和赋值

      通过下标形式访问和赋值矩阵的一个向量或者一个元素:

mat4 m = mat4(1.0);
vec4 = m[0]; //矩阵的第一列
float yScale = m[1][1];// 矩阵的第二列,第二行

结构体 类C

struct Particle
{
    float fLifeTime;
    vec3 vecPosition;
    vec3 vecNormal;
}

数组 声明和初始化

float coeff[3];// 等价于float[3] coeff;
int coeff[];   //未定义维度

//定义时候的初始化:
float coeff[3] = float[3](2.3, 1.0, 3.0);

//数组长度可以用默认内建.length()得到n大小;
for(int i = 0; i < coeff.length(); i++)
{
coeff[i] *= 1.0f;
}

存储限制符

GLSL的类型修饰符
修饰符描述
const常量值必须在声明是初始化。它是只读的不可修改的。
attribute表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或则结构体
uniform一致变量。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。
varying顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。
centorid varying在没有多重采样的情况下,与varying是一样的意思。在多重采样时,centorid varying在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。
invariant(不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。
in用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。(相当于C语言的传值),这个是函数参数默认的修饰符
out用在函数的参数中,表示该参数是输出参数,值是会改变的。
inout用在函数的参数,表示这个参数即是输入参数也是输出参数。

GLSL中数据类型也可以通过上述修饰符来指定自己的行为,这些是不同于C或C++的部分,也是shader编程过程中很重要的一部分,单单给出如上表格,很难让初学者理解其发挥的作用,后面的博客 会用具体的例子来体现这些修饰符的作用。

语句

       操作符

       GLSL语言的操作符与C语言相似。如下表(操作符的优先级从高到低排列)

操作符描述
()用于表达式组合,函数调用,构造
[]数组下标,向量或矩阵的选择器
.结构体和向量的成员选择
++ –前缀或后缀的自增自减操作符
+ – !一元操作符,表示正 负 逻辑非
* /乘 除操作符
+ -二元操作符 表示加 减操作
<> <= >= == !=小于,大于,小于等于, 大于等于,等于,不等于 判断符
&& || ^^逻辑与 ,或,  异或
?:条件判断符
= += –= *=  /=赋值操作符
,表示序列

流控制

GLSL的逻辑控制方式用的也是流行的if-else和switch语句。与C不同的,GLSL有一特殊的关键字discard,discard语句只适用于片元着色器中。片元着色器的运行会在discard语句的位置上立即终止。

函数

GLSL支持用户自定义函数,同样也有一些内置函数。

函数声明语法和C类似,只是变量名需要添加访问修饰符:

计算的不变性

GLSL无法保证在不同的着色器中,两个完全相同的计算式会得到完全一样的结果。这一情形与CPU段应用程序进行计算时的问题相同,即不同优化可能会导致结果非常细微的差异。GLSL中有两种方法来确保着色器之间的计算不变性,即invariant或precise关键字。

 

Finally

个人认为 Learn OpenGL 是很好的适合初学者学习的网站,但其中对shader的编写没有深入的介绍;此系列博客整理shader学习中的知识和思考,很少地介绍OpenGL CPU代码编写部分。欢迎一起学习进步。

参考资料:

OpenGL编程指南红宝书。

Learn OpenGL CN https://learnopengl-cn.github.io/

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值