Learn OpenGL笔记: 2025年8月5日

来自: Shaders

着色器是驻留在GPU上的小型程序。这些程序针对图形管线的每个特定部分运行。着色器还是一种非常独立的程序,它们之间不允许相互通信;它们唯一的通信方式是通过它们的输入和输出。

1.GLSL

着色器总是以版本声明开头,随后是输入和输出变量、uniforms(统一变量)以及它的主函数的列表。每个着色器的入口点是它的主函数,我们在其中处理任何输入变量,并将其结果输出到输出变量中。

#version version_number
in type in_variable_name;
in type in_variable_name;

out type out_variable_name;
  
uniform type uniform_name;
  
void main()
{
  // process input(s) and do some weird graphics stuff
  ...
  // output processed stuff to output variable
  out_variable_name = weird_stuff_we_processed;
}

当我们专门讨论顶点着色器时,每个输入变量也被称为顶点属性。顶点属性的最大数量是受硬件限制的,我们允许声明的顶点属性数量有一个最大值。OpenGL保证至少有16个4分量的顶点属性可用,但某些硬件可能会允许更多,你可以通过查询 GL_MAX_VERTEX_ATTRIBS 来获取这个值:

int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

这里通常返回的值最小是16

2.GLSL中的向量数据类型

在GLSL中,向量是一种包含2、3或4个分量的容器,用于存储前面提到的任意基本类型。它们的形式如下(其中n表示分量的数量):
vecn:包含n个float的默认向量。
bvecn:包含n个bool的向量。
ivecn:包含n个int的向量。
uvecn:包含n个uint的向量。
dvecn:包含n个double的向量。
大多数情况下,我们会使用基本的vecn,因为float对于大多数用途来说已经足够了。
向量的分量可以通过vec.x访问,其中x是向量的第一个分量。你可以分别使用.x.y.z.w来访问向量的第一、第二、第三和第四个分量。此外,GLSL还允许你使用rgba(用于颜色)或stpq(用于纹理坐标)来访问相同的分量。

向量数据类型允许一种有趣且灵活的分量选择方式,称为“分量重组"(swizzling)。分量重组允许我们使用如下语法:

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

这段代码的具体含义是:
在GLSL中,向量(vec2/vec3/vec4)支持 [分量重排/复制] 操作,也就是所谓的swizzle。它让你可以通过写.x、.y、.z、.w(或.r、.g、.b、.a)来任意组合已有向量的分量,生成新的向量。下面逐行解释你的代码:
(1) vec2 someVec;
定义了一个二维向量someVec,它有两个分量: someVec.x和someVec.y。
(2) vec4 differentVec = someVec.xyxx;
这里用到了 swizzle:someVec.xyxx
someVec.x → 第1分量
someVec.y → 第2分量
someVec.x → 第3分量
someVec.x → 第4分量
结果是一个四维向量:

differentVec = vec4(someVec.x, someVec.y, someVec.x, someVec.x);

(3) vec3 anotherVec = differentVec.zyw;
differentVec 是 vec4,它有分量 (x, y, z, w)。
在Swizzle中 .zyw 依次取出:
differentVec.z → 第 1 分量
differentVec.y → 第 2 分量
differentVec.w → 第 3 分量
生成一个三维向量:

anotherVec = vec3(differentVec.z, differentVec.y, differentVec.w);

(4) vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
左侧someVec.xxxx:
把someVec.x重复4次,形成vec4(someVec.x, someVec.x, someVec.x, someVec.x)。
右侧anotherVec.yxzy:
anotherVec 分量为 (x, y, z),所以:
第1分量取 anotherVec.y
第2分量取 anotherVec.x
第3分量取 anotherVec.z
第4分量取 anotherVec.y
结果是 vec4(anotherVec.y, anotherVec.x, anotherVec.z, anotherVec.y)。
相加:
GLSL对同维数向量的加法是逐分量相加,最终得到:

otherVec = vec4(
  someVec.x + anotherVec.y,
  someVec.x + anotherVec.x,
  someVec.x + anotherVec.z,
  someVec.x + anotherVec.y
);

3.In和Out
GLSL为此专门定义了in和out关键字。每个着色器都可以使用这些关键字来指定输入和输出,只要一个着色器的输出变量与下一个着色器阶段的输入变量相匹配,数据就会被传递下去。不过,顶点着色器和片段着色器在这方面有所不同。

如果你在片段着色器中没有指定输出颜色,那么这些片段的颜色缓冲区输出将是未定义的(通常意味着OpenGL会将它们渲染为黑色或白色)。因此,如果我们想从一个着色器向另一个着色器传递数据,就需要在发送数据的着色器中声明一个输出变量,并在接收数据的着色器中声明一个类似的输入变量。当两边的类型和名称相同时,OpenGL会将这些变量连接在一起,从而可以在着色器之间传递数据(这在链接程序对象时完成)。

4.统一变量

Uniforms(统一变量)是将数据从CPU上的应用程序传递到GPU上的着色器的另一种方式。

uniforms是全局的。所谓“全局”,意味着每个着色器程序对象中的uniform变量是唯一的,并且可以在着色器程序的任何阶段、任何着色器中被访问。其次,无论你将uniform的值设置为什么,它都会保持这个值,直到它被重置或更新。

这里必须说一下glUniform函数

由于OpenGL本质上是一个C语言库,它没有原生支持函数重载,因此在可以使用不同类型调用函数的地方,OpenGL会为每种需要的类型定义一个新的函数; glUniform 是这一特性的完美示例。该函数需要一个特定的后缀来标识你想要设置的uniform变量的类型。一些可能的后缀包括:
f:函数期望其值为一个float。
i:函数期望其值为一个int。
ui:函数期望其值为一个unsigned int。
3f:函数期望其值为3个float。
fv:函数期望其值为一个float向量/数组。
当你想要配置OpenGL的某个选项时,只需选择与你的数据类型相对应的函数版本即可。在我们的例子中,我们想要分别设置uniform变量的4个float值,因此我们通过glUniform4f传递数据(注意,我们也可以使用fv版本)。

5.添加更多顶点属性

片段插值导致的运行结果:
在这里插入图片描述
我们只提供了3种颜色,但现在结果颜色丰富色彩。这都是片段着色器中一个称为片段插值的结果。在渲染三角形时,光栅化阶段通常会产生比最初指定的顶点更多的片段。光栅化器会根据这些片段在三角形形状上的位置来确定它们的位置。

假设我们有一条线,上面的点是绿色,下面的点是蓝色。如果片段着色器在位于这条线大约70%位置的片段上运行,那么它的结果颜色输入属性将是绿色和蓝色的线性组合;更准确地说:30%的蓝色和70%的绿色。

6.我们自己的着色器类

详细解释一下函数glGetUniformLocation:

glGetUniformLocation 是 OpenGL 中用于 获取 uniform 变量位置的一个非常重要的函数。 在使用OpenGL中的uniform变量(例如:传递变换矩阵、灯光参数、材质等)时,必须先通过这个函数获取它在着色器程序中的“位置”,然后通过对应的glUniform*函数来进行赋值。

函数原型:

GLint glGetUniformLocation(GLuint program, const char* name);

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值