OpenGL着色器初步,让三角形的颜色随时间变化

前情提要:
OpenGL+VS2022环境配置与变化的背景
开始学习OpenGL:生成第一个三角形
源码地址:OpenGL 着色器初步,颜色变化的三角形

接下来要做的是对三角形着色,着色需要用到着色器,着色器可以理解为是完全工作在硬件上的一个机器,故而需要一个使之运行的指令,这个指令被称为GLSL,即GL Shader Language,着色语言。

为了能够更加直观地理解着色器的方法,接下来以这个三角形作为讲解对象

在这里插入图片描述

其顶点的定义如下

GLfloat 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
};

其中,左侧三列表示其坐标,右侧三列表示其颜色。例如,在 ( 0.5 , − 0.5 , 0 ) (0.5, -0.5, 0) (0.5,0.5,0)位置处,其RGB为 ( 1 , 0 , 0 ) (1,0,0) (1,0,0),即红色,看三角形右下角,的确是红色。

为了实现对这个三角形的着色,则在绘制过程中,必须有一个函数来规定vertices中每个值的含义,这就是上一讲提到的glVertexAttribPointer函数。

由于vertices中有两种属性的值,用来分别表示位置和颜色,故而同样需要用到两种属性

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

其中,第一个属性设置为0号设置,以3个点为单位,每隔6个点设置一次;第二个设置函数为1号设置,同样以3个点为单位,以6个点为周期。

在对这些点进行划分之后,则需要创建一个着色器对象,来进一步确认这些点的含义,这就涉及到了GLSL的应用,再来回顾一下这个三角形

在这里插入图片描述

着色可分为两步,首先是顶点着色,然后根据顶点的颜色,来对顶点之间的其他像素进行着色。故而先做一个顶点着色器的源

#version 330 core
layout (location = 0) in vec3 pIn;
layout (location = 1) in vec3 cIn;
out vec3 cOut;
void main(){gl_Position = vec4(pIn, 1.0);cOut = cIn;
}

其中,#version 330 core表示3.3版本,这一行对某些显卡来说应该可以不写。

layout(location=0)用于声明输入变量的顶点属性位置值是0,对应0号设置,vertices中的位置列;in表示顶点属性输入;vec3为数据类型,表示有三个分量的向量;pIn为声明的输入变量;相应地cIn亦然,变量名为pIncIn主要为了省事儿,分别表示输入位置和输入颜色。

cOutout修饰,表示输出的三维向量。这种规定输入输出的变量格式,对于有点verilog基础的人更易理解。

接下来是主函数,gl_Position用于设置顶点着色器的输出,其类型为4分量的向量,构造方式是在pIn后面加个1。这种操作是为了适应GPU在图形运算中,用以变换的的4x4矩阵。

接下来对顶点之间的其他部分进行着色,即构造片元着色器

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

注意,其输入cOut,实为顶点着色器的输出,二者变量名需要一致。

由于着色器是在GPU中进行编译的,所以接下来要将上面这两段函数加入用某种方法载入传给GPU,方法是用字符串

const GLchar* srcVertexShader = "#version 330 core\n"
"layout (location = 0) in vec3 pIn;\n"
"layout (location = 1) in vec3 cIn;\n"
"out vec3 cOut;\n"
"void main(){\n"
"gl_Position = vec4(pIn, 1.0);\n"
"cOut = cIn;\n"
"}\0";const GLchar* srcFragmentShader = "#version 330 core\n"
"in vec3 cOut;\n"
"out vec4 color;\n"
"void main(){\n"
"color = vec4(cOut, 1.0f);\n"
"}\0";

然后,在main函数中把这两个字符串绑定给着色器,流程分三步

  1. 创建,用glCreateShader
  2. 绑定,用glShaderSource
  3. 编译,用glCompileShader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);     //创建一个着色器对象
glShaderSource(vertexShader, 1, &srcVertexShader, NULL); //绑定着色器
glCompileShader(vertexShader);  //编译
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &srcFragmentShader, NULL);
glCompileShader(fragmentShader);

然后将这两个着色器写入一个图形程序pragram中,

GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);       //释放内存
glDeleteShader(fragmentShader);

最后的最后,将这个program放在主循环中对三角形进行实时绘制

glUseProgram(shaderProgram);//绘制三角形

接下来就可以得到上面那个渐变颜色的三角形了。

接下来,若想让三角形的颜色在时间上渐变,则可使用glUniform,这是一个可以随时传入的变量,首先更改srcVertexShader,注意在传入的时候是以字符串的形式

#version 330 core
layout (location = 0) in vec3 pIn;
layout (location = 1) in vec3 cIn;
uniform float cDelta;
out vec3 cOut;
void main(){
gl_Position = vec4(pIn, 1.0);
cOut = cIn;\n
for (int i = 0; i < 3; i++) {
cOut[i] += cDelta;}
}

其中,cDelta就是一个uniform变量,其cOut将会随着这个值的变化而变化。接下来更改主循环

float cDelta;   //用于存放传入的uniform
while (!glfwWindowShouldClose(win))
{/*前面不用改*/glClear(GL_COLOR_BUFFER_BIT);cDelta = sin(glfwGetTime());  //glfwGetTime()获取当前时间,通过三角函数使之glUseProgram(shaderProgram);int vcLocation = glGetUniformLocation(shaderProgram, "cDelta");glUniform1f(vcLocation, cDelta);    //传入cDeltaglBindVertexArray(VAO);/*后面不用改*/
}

最后得到的结果为

在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部