使用OpenGL(3.3及以上)+GLFW画一个简单的三角形
在画三角形之前,首先要初始化GLFW和GLAD,以及创建窗口。这里不详细说明。
在OpenGL中,3D坐标转换成2D坐标是由图形渲染管线完成的,可以被分成几个阶段,每一个阶段都有专门的运行程序,称为着色器。OpenGL中的着色器是用GLSL语言编写的。在现代OpenGL中,必须定义至少一个顶点着色器和一个片段着色器,因此要编写、编译和链接着色器。
着色器
顶点着色器
画一个简单的三角形,只需要顶点的位置属性。在关键字in后声明一个三维的位置属性,可以实现这个简单的功能。在main函数中将位置转换成四维变量,输出到gl_Position中,就实现了顶点着色器的位置输出。
1 |
|
片段着色器
在片段着色器中,使用关键字out输出一个颜色变量,颜色为(1.0, 0.5, 0.2, 1.0)。
1 |
|
着色器的编译和链接
为了实现这一功能,编写一个类,用于着色器的编译、链接和使用。
1 | class Shader { |
在构造函数中,读取着色器文件,并使用glCompileShader编译。以顶点着色器为例,编译过程如下:
1 | unsigned int vertexShader; |
编译完成后,将两个着色器链接成程序:
1 | shaderProgram = glCreateProgram(); |
着色器程序的使用
调用glUseProgram函数以激活着色器程序:
1 | void Shader::use() { |
顶点数据的输入、绑定和解析
定义一个数组来存储三角形三个点的坐标数据:
1 | float vertices[] = { |
通过顶点缓冲对象(VBO)管理数据。这里的数据是不变的,因此使用GL_STATIC_DRAW。
1 | unsigned int VBO; |
此外,还需要调用glVertexAttribPointer,告诉OpenGL怎么解析数组中的数据。解析的时候,每次解析3个元素,跳过3个元素。
1 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); |
顶点数组对象
通过绑定VAO,可以将多个VBO集成到顶点数组中,方便多次绘制重复的图形。
1 | unsigned int VAO; |
渲染
使用While循环进行多帧渲染。先激活程序、绑定VAO,然后输入三角形图元,用glDrawArrays生成图形。
1 | shader.use(); |
对三角形的三个顶点分别改为红绿蓝。并解释为什么会出现这样的结果
修改着色器
顶点着色器
为了使三个顶点输出不同的颜色,要在顶点着色器中增加颜色属性。aColor为输入颜色,ourColor为输出颜色。
1 |
|
片段着色器
片段着色器接收来自顶点着色器的输入,转成vec4后输出。
1 |
|
修改数组和解析方式
在数组的每一行添加三个颜色分量数据,表示顶点的颜色:
1 | float vertices[] = { |
解析位置的时候,每次解析3个元素,跳过6个元素;解析颜色的时候,每次解析3个元素,跳过6个元素,开始时跳过3个元素:
1 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); |
渲染结果
原因
在光栅化的阶段,会产生比指定顶点更多的片段。对于没有定义颜色的片段,会根据片段所处的位置,进行颜色的插值。简单来讲,就是根据位置,对已知顶点的颜色进行线性组合。
给上述工作添加一个GUI,里面有一个菜单栏,使得可以选择并改变三角形的颜色。
初始化ImGUI
1 | ImGui::CreateContext(); |
定义一个向量,存储三个顶点的颜色值
1 | std::vector<ImVec4> colors; |
在渲染循环里,设置ImGUI样式,生成三个颜色选择器
1 | ImGui_ImplOpenGL3_NewFrame(); |
根据选择的颜色,改变数组元素的值,达到修改颜色的目的。修改后要重新绑定数据。
1 | for (int i = 0; i < 3; i++) { |
渲染
1 | ImGui::Render(); |
使用EBO(Element Buffer Object)绘制多个三角形
添加三角形和对应的索引
1 | float vertices[] = { |
EBO的创建和绑定
缓冲类型是GL_ELEMENT_ARRAY_BUFFER
1 | unsigned int EBO; |
渲染
渲染时,将glDrawArrays改为glDrawElements,使用EBO中的索引进行渲染。参数分别是图元、顶点数量、索引数据类型和索引偏移量。
1 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); |
绘制其他的图元,除了三角形,还有点、线等
扩充数组
1 | float vertices[] = { |
渲染
使用glDrawArrays进行渲染,传入图元GL_LINES绘制直线,传入图元GL_POINTS绘制点。
1 | glDrawArrays(GL_LINES, 9, 4); |
如下图,新增两条白线和两个白点:
GitHub
https://github.com/Xungerrrr/SYSU-CG/tree/master/GUI%20and%20Draw%20Simple%20Graphics