OpenGL自学笔记(四)(着色器)

如题所述

这一章节没有太多新内容,主要是对之前内容的复述。如果你熟悉shadertoy,那么这一部分可能不需要过多解释。更建议阅读资深人士的教程。

着色器(Shader)是一种运行在GPU上的小程序,为图形渲染管道的特定部分提供支持。从基本意义上讲,着色器是一种将输入转换为输出的程序。着色器非常独立,它们之间不能相互通信,唯一的沟通方式是通过输入和输出。

着色器使用GLSL(类似C语言)编写。除了GLSL,还有HLSL、CG等其他语言。GLSL是为图形计算专门设计的,包含针对向量和矩阵的有用特性。

以下是着色器的基础结构。

在顶点着色器中,每个输入变量被称为顶点属性。可声明的顶点属性数量有限,通常由硬件决定。一般至少有16个(包含4个分量)的顶点属性可用。

GLSL包含C等其他语言的大部分默认基础类型:int、float、double、unit和bool。同时还有两种容器类型:向量(Vector)和矩阵(Matrix)。

GLSL中的向量是一个可以包含最高4个分量的容器,分量类型是基础类型之一。大多数情况下,使用vecn就足够了。一个拥有4个分量的向量可以通过点访问符号进行访问,分别使用.x、.y、.z和.w来获取第1~4个分量。对于颜色,则使用rgba进行访问,同理对纹理坐标则使用stpq访问相同的分量。

重组是向量分量的一种灵活用法,允许使用原来向量的分量任意组合形成一个新的向量。但是不允许从vec2中获取.z元素,即2维向量不能获取第四个分量。也可以把一个向量作为一个参数传给不同的向量构造函数。

着色器是独立的小程序,但也是整体的一部分。因此,每个着色器都有输入和输出,以便进行数据交流和传递。GLSL定义了in和out关键字专门来实现这个目的。每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。但在顶点和片段着色器中会有所不同。

顶点着色器应该接收特殊形式的输入,否则会效率低下。顶点着色器的输入特殊在于它直接从顶点数据中接收输入。为了定义顶点数据该如何管理,使用location这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性。我们已经在前面的教程中看过这个了,layout (location = 0)。顶点着色器需要为它的输入提供一个额外的layout标识,以便将其链接到顶点数据。也可以通过在OpenGL代码中使用glGetAttribLocation查询属性位置值(Location)。

另一个例外是片段着色器,它需要一个vec4颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果你在片段着色器中没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。

因此,如果我们打算从一个着色器向另一个着色器发送数据,我们必须在发送方着色器中声明一个输出,在接收方着色器中声明一个类似的输入。当类型和名字都一样的时候,OpenGL就会把两个变量链接到一起,它们之间就能发送数据了(这是在链接程序对象时完成的)。

uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。其次,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。

我们可以在一个着色器中添加uniform关键字至类型和变量名前来声明一个GLSL的uniform。从此处开始我们就可以在着色器中使用新声明的uniform了。通过uniform设置三角形的颜色:

这里在片段着色器中声明了一个uniform的四维向量作为最终颜色输出。因为uniform是全局变量,可以在任何着色器中定义它们,而无需通过顶点着色器作为中介,所以不用在顶点着色器中定义这个uniform。

如果声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误!

这个uniform现在还是空的;我们还没有给它添加任何数据,所以下面我们就做这件事。我们首先需要找到着色器中uniform属性的索引/位置值。当我们得到uniform的索引/位置值后,我们就可以更新它的值了。这次我们不去给像素传递单独一个颜色,而是让它随着时间改变颜色:

glfwGetTime()获取程序运行秒数,使用sin得到[-1,1]区间的值,最后做一个[0-1]区间的规范化,储存为一个变量。用glGetUniformLocation查询uniform变量的位置值。参数就是着色器程序对象和uniform变量名。如果返回-1,意味着没有找到。最后是通过glUniform4f函数设置uniform变量的值(根据位置值设置变量)第一个参数是位置值,后面就是设置的值了。

查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先激活程序,因为它是在当前激活的着色器程序中设置uniform的。

现在写一个着色器类用来读取硬盘中的着色器文件,编译并链接它们。

这里把所有的着色器类都放在头文件中。第一行的包含是用来防止链接冲突的,once意思是该头文件只被包含一次。着色器类储存了着色器程序的ID。它的构造函数需要顶点和片段着色器源代码的文件路径,这样可以把着色器源码的文本文件储存在硬盘上。use用来激活着色器程序。所有的set…函数能够查询一个uniform的位置值并设置它的值。

这里我创建了一个新的CPP文件用来定义着色器头文件中的声明内容。

构造函数中是处理着色器文件的读取并编译和链接着色器。而检查编译和链接的函数如下。除此之外还有激活程序,自己额外加了个删除的程序。

uniform的setter函数:

创建一个着色器对象,读取文件路径即可。

有可能这一步会出一点问题,不知道具体包含路径。我这里的../表示上级目录,这里是返回到解决方案文件夹了。

其实可以在构造函数中的catch中打印当前输入的路径,就可以知道路径与资源文件夹中路径是否一致。

最后在渲染循环中渲染:
温馨提示:内容为网友见解,仅供参考
无其他回答

OpenGL自学笔记(四)(着色器)
另一个例外是片段着色器,它需要一个vec4颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果你在片段着色器中没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。因此,如果我们打算从一个着色器向另一个着色器发送数据,我们必须在发送方着色器中声明一个输出,在接收方着色器中声...

OpenGL学习笔记(四)高级OpenGL(2)
高级OpenGL学习内容包含多个关键部分:数据导入、高级GLSL、几何着色器、法线可视化、实例化渲染以及绘制模型。下面将对每部分进行简化阐述。数据导入与缓冲:数据从外部导入至OpenGL缓冲,用于顶点分批属性操作。高级GLSL:通过绑定点与Uniform块实现数据管理。在着色器中声明Uniform块,并在第二步中设置绑定点与...

OpenGL 着色器详解
GLSL(OpenGL Shading Language)专用于编写着色器,通过定义main函数的程序片段,指导渲染引擎渲染内容。GLSL语法类似C语言,增加特定关键字修饰变量。基本结构如下:声明GLSL版本、模式、变量,主函数main处理输入输出。输入变量in GLSL允许有限输入变量,硬件决定数量,可通过GL_MAX_VERTEX_ATTRIBS查询上限。输...

LearnOpenGL笔记01_入门_开窗、绘制、着色器、纹理、变换、坐标、相机...
接下来是顶点数据的准备和处理,如顶点数组对象(VAO)、顶点缓冲对象(VBO)和元素缓冲对象(EBO)。glGenBuffers和glVertexAttribPointer函数用于创建和配置这些对象,以支持图形渲染。着色器编程是图形表现的核心,glShaderSource、glCreateProgram和glUseProgram等函数用于编写、编译和激活着色器程序。纹理和变换是O...

glsl的shader(着色器)问题
return是返回值的意思,别告诉我你不知道啥叫返回值 rotate是旋转,是把向量v旋转一个角度a return含义同上 此处length2为函数调用,调用之前定义的函数 snoise是产生噪声的意思,没错 alpha是透明度,*当然是乘以一个数,别告诉我你不知道*的意思 color有alpha,和RGB四个分量,但是这里貌似借用了xyz三...

OpenGL基础-C++| (四)管理3D图形数据
OpenGL 管理3D图形数据的关键在于有效地组织和传输数据,以驱动渲染过程。首先,顶点数据是关键,如立方体的坐标,需要通过顶点缓冲对象(Vertex Buffer Object, VBO)存储并通过顶点着色器处理。创建VAO(Vertex Array Object)有助于组织复杂的场景,让缓冲区管理更加便捷,即使在多个对象渲染时也能保持效率。

openGL-mesa学习总结
让应用程序能够直接与硬件交互,提高3D图形处理性能。Mesa在GLX扩展中使用DRI与X server协调,同时利用DRM进行内存管理和命令发送。TGSI是Mesa中所有驱动程序共享的着色器中间表示,GLSL首先被编译为TGSI,然后根据不同GPU转换为特定指令。这一系列过程展示了OpenGL-mesa学习中的核心概念和技术细节。

opengl 着色器 有什么用
这是可编程管线里的术语 着色器分为 顶点和像素 两种 也叫 vertex shader 和 fragment shader(或pixel shader),就是可编程管线里两种代码的称呼.用shader可以完成你的各种3d模型,图片显示需要.

干货分享 | 基于OpenGL与GPU驱动的实时图形渲染技术
着色器主要可以分为几种类型:顶点着色器、几何着色器、片段着色器、计算着色器。四、着色器的“翻译官”——GLSL语言 GLSL是一种专门用于编写着色器程序的高级着色器语言,它是OpenGL重要的一部分,在GPU上执行,主要用于控制图形渲染的过程。五、总结 1.OpenGL是一种开放的图形API,它为开发人员提供了...

OpenGL学习之旅(3)---Shader编程
在OpenGL中,shader编程是实现图形渲染的关键技术。它允许我们自定义GPU如何处理顶点和片段数据,以实现各种复杂的渲染效果。shader代码通常使用GLSL语言编写,与C++相似,便于编写和理解。为了进行shader编程,建议创建一个名为"Shaders"的文件夹,分别存放顶点着色器(Basic.vert)和片段着色器(Basic.frag)...

相似回答
大家正在搜