LOADING

加载过慢请开启缓存 浏览器默认开启

着色器Shaders

GSGL


着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。

一个典型的着色器有下面的结构:

#version version_number 
in type in_variable_name; 
in type in_variable_name; 
out type out_variable_name; 
uniform type uniform_name; 
void main() 
{ 
    // 处理输入并进行一些图形操作 
    ... 
    // 输出处理过的结果到输出变量 
    out_variable_name = weird_stuff_we_processed; 
}

数据类型


GSGL中有两种容器类型向量Vector和矩阵Matrix,这里先讨论向量类型

向量

GLSL中的向量是一个可以包含有2、3或者4个分量的容器,分量的类型可以是前面默认基础类型的任意一个。它们可以是下面的形式(n代表分量的数量):

类型 含义
vecn 包含n个float分量的默认向量
bvecn 包含n个bool分量的向量
ivecn 包含n个int分量的向量
uvecn 包含n个unsigned int分量的向量
dvecn 包含n个double分量的向量

输入与输出


GSGL 通过定义inout关键字实现每个着色器的输入与输出。只要输出变量与下一个着色器的输入变量相匹配,流水线就会传递下去。

其中,顶点着色器接受的是顶点数据的输入而非任意着色器的输出。我们使用location这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性。layout (location = 0)顶点着色器需要为它的输入提供一个额外的layout标识,这样我们才能把它链接到顶点数据。

同样,片段着色器的输出需要一个vec4的颜色输出变量。

顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0

out vec4 vertexColor; // 为片段着色器指定一个颜色输出

void main()
{
    gl_Position = vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色
}

片段着色器

#version 330 core
out vec4 FragColor;

in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)

void main()
{
    FragColor = vertexColor;
}

Uniform


Uniform类型类似于我们常用的全局变量,但是他的作用范围并不仅仅局限于一个代码文件中。他在整个着色器程序(Program)中是独一无二的,同时可以被着色器程序任意阶段所访问。

要使用Uniform 首先需要在GLSL程序中定义它(==任意着色器均可==)
uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量

这里我们希望在我们的C程序中实时修改它,因此需要在主循环中获取它的索引并更新它。

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);

注意到glUniform这个方法 由于opengl是C编写的 因此没有重载。入参变化后只能通过另一个函数实现
因为OpenGL在其核心是一个C库,所以它不支持类型重载,在函数参数不同的时候就要为其定义新的函数;glUniform是一个典型例子。这个函数有一个特定的后缀,标识设定的uniform的类型。可能的后缀有:

后缀 含义
f 函数需要一个float作为它的值
i 函数需要一个int作为它的值
ui 函数需要一个unsigned int作为它的值
3f 函数需要3个float作为它的值
fv 函数需要一个float向量/数组作为它的值

更多属性!


之前我们的vertices数组仅有顶点属性,在这里我们可以把颜色属性也添加进去

float vertices[] = { 
    // 位置              // 颜色 
    0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f, // 右下 
    -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下 
    0.0f, 0.5f, 0.0f,   0.0f, 0.0f, 1.0f // 顶部 
};

调整了顶点数组后,同时我们要调整顶点着色器的入参,能够接收这样的顶点属性输入

#version 330 core 
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
out vec3 ourColor; // 向片段着色器输出一个颜色 
void main() 
{ 
    gl_Position = vec4(aPos, 1.0); 
    ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色 
}