OpenGL从“入门”到“摔门而走”(二)

着色器

着色器(shader)是运行在GPU上的小程序。目前我们主要使用到的着色器有顶点着色器(Vertex Shader)和片段着色器(Fragment Shader),我们使用GLSL(OpenGL Shading Language)编写着色器程序。

GLSL

GLSL是一种类C语言。

  1. 先声明版本
  2. 接着是输入和输出变量(in输入,out输出)
  3. uniform和main函数

每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中
下面就是一个简单的顶点着色器:

#version 330 core
layout(location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

下面会细讲

数据

  • #version 330 core 表示所使用的版本是3.30
  • vec3由三个flaot类型的数组成的向量
  • vec4则是在vec3的基础上加了一个a(透明度)

顶点着色器

#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); // 把输出变量设置为暗红色
}

gl_Position为内置变量表示顶点输出的位置

片段着色器

#version 330 core
out vec4 FragColor;
in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)
void main()
{
FragColor = vertexColor;
}

在顶点着色器中声明了一个vertexColor变量作为vec4输出,并在片段着色器中声明了一个类似的vertexColor。由于它们名字相同且类型相同,片段着色器中的vertexColor就和顶点着色器中的vertexColor链接了。由于我们在顶点着色器中将颜色设置为深红色,最终的片段也是深红色的。

Uniform

很多事情光靠GPU是无法解决的,比如想让颜色随时间变化。这个时候我们就需要CPU的帮助。Uniform就是一种从CPU向GPU中的着色器发送数据的方式

#version 330 core
out vec4 FragColor;
uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量
void main()
{
FragColor = ourColor;
}

在片段着色器中声明了一个uniform类型的vec4的变量,并把片段着色器的输出颜色设置为uniform值的内容。
uniform是全局变量,我们可以在任何着色器中定义它们,而无需通过顶点着色器作为中介。顶点着色器中不需要这个uniform,所以我们不用在那里定义它。

现在我们要给uniform添加数据了

首先,我们用glGetUniformLocation查询uniform ourColor的位置值。

int vertexColorLocation = glGetUniformLocation(shaderProgram, “ourColor”);

如果glGetUniformLocation返回-1就代表没有找到这个位置值。

最后,我们可以通过glUniform4f函数设置uniform值。
(注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的。)

glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, 0.0f, 0.0f, 1.0f);

第一个变量表示有没有找到ourColor所在的位置
后面三个分别是rgba(红,黄,绿,透明度)

我们还可以搞一些好玩的东西

我们可以通过glfwGetTime()获取运行的秒数。然后我们使用sin函数让颜色在0.0到1.0之间改变,最后将结果储存到greenValue里。

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

最后出现的就是颜色逐渐改变的图形(当然这里只有绿色,你也可以自己改一些别的东西)

更多属性

我们可以让一个图形拥有好多颜色。
在三角形那节中定义顶点数据的基础上定义。

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 // 顶部
} ;

这就使每一个点的颜色不同了。

由于现在有更多的数据要发送到顶点着色器,我们有必要去调整一下顶点着色器,使它能够接收颜色值作为一个顶点属性输入。需要注意的是我们用layout标识符来把aColor属性的位置值设置为1。

#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设置为我们从顶点数据那里得到的输入颜色
}

片段着色器

#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}

在这里插入图片描述
(文档中的图)

现在就可以使用glVertexAttribPointer函数更新顶点格式,

// 位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);

前面几个变量已经比较清楚了。由于我们现在一个顶点有两种属性(位置,颜色)所以原来的3 * sizeof(float)变成了6 * sizeof(float)

由于顶点的颜色属性在位置属性的后面,偏移量为3
(void*)(3* sizeof(float))

完整代码

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值