一、OpenGL实现窗口图形的绘制
OpenGL使用特有的API来实现窗口图形的绘制,下面我们先看使用OpenGL创建一个绘制窗口:
OpenGL绘制窗口界面代码如下:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
int main()
{
//glfw的初始化和设置
// -----------------------------------------------------
//调用glfwInit函数来初始化GLFW
glfwInit();
//配置GLFW,第一个参数代表选项的名称,第二个参数接受一个整型,用来设置这个选项的值
//此处设置表示使用的OpenGL版本号3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//glfwWindowHint作为窗口创建的一种提示,可以设置窗口的多种属性,包括透明度等等,感兴趣的可以在glfw文档中查询
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//使用流水线配置模式
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfw窗口创建
// -----------------------------------------------------
//glfwCreateWindow函数需要窗口的宽和高作为它的前两个参数,第三个参数表示这个窗口的名称,最后两个参数我们暂时忽略,它返还一个GLFWwindow对象
GLFWwindow* window = glfwCreateWindow(800, 800, "OpenGL", NULL, NULL);
//创建完窗口,通知GLFW将我们窗口的上下文设置为当前线程的主上下文了
glfwMakeContextCurrent(window);
while (!glfwWindowShouldClose(window))
{
//OpenGL采用双缓冲来渲染窗口
glfwSwapBuffers(window);
//处理按键事件
glfwPollEvents();
}
return 0;
}
glfwWindowHint的更多设置,可以在glfw窗口官方文档中具体了解,执行以上代码可以获得一个OpenGL绘制窗口,如图1-1所示:
图1-1 OpenGL绘制窗口
上面流程我们通过glfwInit()、glfwWindowHint()、glfwCreateWindow()等等就创建了一个窗口对象。
以上只是一个窗口,那么如何使用OpenGL绘制呢?这就需要了解一点背景知识,Khronos组织一直在维护opengl接口,如果Khronos定义了一个glDrawLIne的接口,那么支持OpenGL的GPU设备厂商会让自己的程序员在硬件产品上用图像逻辑去实现这个接口,而当前主流的GPU设备厂商都是支持OpenGL的。
所以是Khronos和GPU设备厂商帮我们实现了具体逻辑,而我们要做的就是遵循这一系列接口的规范,去得到想要的内容,下面可以看下OpenGL和GPU的关系,如图1-2所示:
通过以上,我们可以看出OpenGL的简单流程,首先调用OpenGL的接口,将Attributes、textturedata、uniform等数据输入到vetexshader等着色器中,如果是attributes数据,顶点着色器会处理它,并把结果流转到下一个primitive assembly中实现光栅化,紧接着配合textturedata通过片元着色器进行处理,最终渲染出结果,可以对照着OpenGL渲染管线图进行参考。
OpenGL的常见名词:
OpenGL的渲染实例,代码如下:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
//Shader创建
// -----------------------------------------------------
//GLSL编写的用于顶点着色器的shader
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
//用于片段着色器的shader,rgba格式
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.41f, 0.35f, 0.80f, 1.0f);\n"
"}\n\0";
//顶点数据
float vertices[] = {
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.4f, 0.0f,
-0.4f, -0.5f, 0.0f
};
//索引数据
unsigned int indices[] = {
0, 2, 3,
1, 4, 5
};
int main()
{
//glfw创建
// -----------------------------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 800, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
//glad初始化
// -----------------------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//着色器创建和链接
// -----------------------------------------------------
//顶点着色器创建
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
//片段着色器创建
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
//链接着色器
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
//创建数据对象和绑定数据对象
// -----------------------------------------------------
//顶点数组对象:Vertex Array Object,VAO
//顶点缓冲对象:Vertex Buffer Object,VBO
//索引缓冲对象:Element Buffer Object,EBO或Index Buffer Object,IBO
unsigned int VBO, VAO, EBO;
//unsigned int VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
//绑定VAO数据对象
glBindVertexArray(VAO);
//复制顶点数组到缓冲中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//复制索引数组到缓冲中供OpenGL使用
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//解释顶点数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
//启用顶点属性
glEnableVertexAttribArray(0);
//解绑VAO
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
//按照rgba格式设置窗口背景颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//将当前设置的color写入启用的缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//加载shdaer
glUseProgram(shaderProgram);
//绑定VAO数据对象
glBindVertexArray(VAO);
//获取索引,根据GL_TRIANGLES类型绘制图像
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
return 0;
}
程序执行效果如下:
以上实现的流程,简单的将OpenGL渲染过程进行了介绍,窗口的创建、shader的编写、着色器的创建及链接、VAO、VBO、EBO创建及绘图。