标签:glob type 对象 table 结果 传递 1.0 目的 如何
着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上说,着色器
只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能互相通信;
着色器之间唯一的沟通只有通过输入和输出;
着色器是用一种叫GLSL(OpenGL Shader Luanguage) 的类C语言写成的。
典型的着色器结构如下
#version version_number in type in_variable_name; in type in_variable_name; out type out_variable_name; uniform type uniform_name; int main() { // 处理输入并进行一些图形操作 ... // 输出处理过的结果到输出变量 out_variable_name = weird_stuff_we_processed; }
特别对于顶点着色器,每个输入变量也叫顶点属性(Vertex Attribute)。我们能声明的顶点属性是有上限的,一般由硬件决定。
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;
GLSL有数据类型可以来指定变量的种类。
数据类型: int、float、double、uin(unsigned int )t、bool;
容器类型: Vector、Matrix;
GLSL中的向量是一个可以包含有1、2、3或者4个分量的容器,分量的类型可以是前面默认基础类型的任意一个。它们可以是下面的形式(n
代表分量的数量):
类型 | 含义 |
vecn | 包含n 个float分量的默认向量 |
bvecn | 包含n 个bool分量的向量 |
ivecn | 包含n 个int分量的向量 |
uvecn | 包含n 个unsigned int分量的向量 |
dvecn | 包含n 个double分量的向量 |
大多数时候我们使用vecn
,因为float足够满足大多数要求了。
我们希望每个着色器都有输入和输出,这样才能进行数据交流和传递。
GLSL定义了in
和out
关键字专门来实现这个目的。每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。
但在顶点和片段着色器中会有点不同。
顶点着色器应该接收的是一种特殊形式的输入,否则就会效率低下。顶点着色器的输入特殊在,它从顶点数据中直接接收输入。
为了定义顶点数据该如何管理,我们使用location
这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性。
我们已经在前面的教程看过这个了,layout (location = 0)
。顶点着色器需要为它的输入提供一个额外的layout
标识,这样我们才能把它链接到顶点数据。
你也可以忽略layout (location = 0)标识符,通过在OpenGL代码中使用glGetAttribLocation查询属性位置值(Location),但是我更喜欢在着色器中设置它们,这样会更容易理解而且节省你(和OpenGL)的工作量。
另一个例外是片段着色器,它需要一个vec4
颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。
如果你在片段着色器没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。
Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。
首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。
第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。
顶点着色器中不需要这个uniform,所以我们不用在那里定义它。
如果你声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误,记住这点!
当我们在着色器中定义了Uniform后,我们还没有给它添加任何数据,所以下面我们就做这件事。
我们首先需要找到着色器中uniform属性的索引/位置值。当我们得到uniform的索引/位置值后,我们就可以更新它的值了。
这次我们不去给像素传递单独一个颜色,而是让它随着时间改变颜色:
float timeValue = glfwGetTime(); float greenValue = (sin(timeValue) / 2.0f) + 0.5f; int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); glUseProgram(shaderProgram); glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
标签:glob type 对象 table 结果 传递 1.0 目的 如何
原文地址:https://www.cnblogs.com/Ziyo/p/9900245.html