OpenGL环境搭建

OpenGL简介

首先需要明确的是,OpenGL不是什么物理引擎,也不是什么语言,而是一种规范,可以类比成是一个API,而具体的实现需要由开发者自行实现。而这一般也是由显卡的生产商实现的,所以不同平台的OpengL也有所不同。

  • 状态机

OpenGL本身可以看成是一个巨大的状态机,可以通过状态设置函数来改变上下文,和通过状态使用函数来根据当前OpenGL的状态来执行一些操作。

1
2
3
4
5
6
7
8
9
10
// 创建对象
unsigned int objectId = 0;
glGenObject(1, &objectId);
// 绑定对象至上下文
glBindObject(GL_WINDOW_TARGET, objectId);
// 设置当前绑定到 GL_WINDOW_TARGET 的对象的一些选项
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
// 将上下文对象设回默认
glBindObject(GL_WINDOW_TARGET, 0);

这段代码便展示了如何创建一个对象,并将对象绑定至上下文然后进行操作的过程。

窗口创建

由于OpenGL只是一些规范,所以使用OpenGL的上下文以及用于显示渲染结果的窗口都需要我们自行去实现。这里可以使用GLFW库来进行操作。

  • 下载GLFW

可以从官网下载最新的GLFW库,由于完整性所以我们选择下载源码并在本地进行编译。

  • 编译GLFW

这里选择用CMake进行编译,这里也可以从官网下载最新的版本。

下载完成后可以使用CMake的GUI界面进行编译,选择好Source Code和将要存储编译好的目录后,便可以点击Configure进行编译,Generator最好使用VS的编译器,如果使用GCC或者G++可能会出现一些意想不到的错误。
cmake.png
编译完成后可以用VS将Sln文件打开,然后点击Build Solution,这样便可以在build/src/Debug文件夹中看到编译好的glfw3.lib了。

  • 链接

此时我们要做的便是将编译好的glfw3.lib链接到IDE中,这里由于我们选择的IDE是VSCode,所以和LearnOpenGL上的教程略有不同。首先要确保VScode安装了Cmake Tools插件,这可以让你快速创建一个Cmake的C++工程,之后打开CMakeLists.txt,会看到是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required(VERSION 3.0.0)
project(Lesson_0 VERSION 0.1.0 LANGUAGES C CXX)

include(CTest)

enable_testing()

add_executable(Lesson_0 main.cpp)
link_directories(D:/opengl/Libs)
target_link_libraries(Lesson_0 PRIVATE D:/opengl/Libs/glfw3.lib)
include_directories(
D:/opengl/Include
)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

首先通过link_directories()命令来指导cmake找到Lib所在的位置,然后通过target_link_libraries()来将需要倒入的静态库导入。最后还需要将头文件也导入,导入.lib只是相当于导入了.cpp文件,但是还需要.hpp头文件来让C++找到源文件,这里使用的是include_directories()来导入。

这里推荐将LIB文件和Include文件分开存放,这样之后需要导入新的库只要分别将对应的文件放入即可,不需要再进行单独的添加。至此,GLFW的配置便结束了。

  • GLAD

GLFW只是确立了OpenGL上下文以及窗口,但是由于OpenGL只是一个规范,所以具体的实现是显卡厂家自行实现的,所以这就导致函数的位置无法在编译时确定,所以就需要开发者在运行的时候动态搜索函数,并将其保存在一个函数指针里面。

1
2
3
4
5
6
7
// 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 现在函数可以被正常调用了
GLuint buffer;
glGenBuffers(1, &buffer);

这个过程是很繁琐的,但是又有库可以代替我们完成这个工作,其中一个便是GLAD。

  • 配置GLAD

有了配置GLFW的经验,配置GLAD就很简单了,先通过GLAD的在线服务,这很像下载Pytorch一样,将语言设置为C/C++,API选择3.3或以上,这里选择了3.3,然后将Profile选择为Core,并确保勾上了Generate a Loader,然后便可以点击Generate来生成库文件。将生成的glad.zip下载解压后发现里面有一个glad.c文件和include文件,将include文件放入之前的Include里面,然后再将glad.c放入工程,最后别忘了用将glad.c放入add_executable()里面,这样Glad也就配置好了。

编写代码

首先需要导入这两个头文件

1
2
#include<glad/glad.h>
#include<GLFW/glfw3.h>

注意这里glad/glad.h必须要在GLFW/glfw3.h前面,否则会报错

这是创建窗口的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include<glad/glad.h>
#include<GLFW/glfw3.h>

using namespace std;
void framebuffer_size_callback(GLFWwindow* window,int width,int height);
void proccessInput(GLFWwindow*window);
int main(){

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,600,"LearnOpenGL",NULL,NULL);
if(window==NULL){
cout<<"Failed to Create GLFW Window"<<endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
cout<<"Failed to initialize GLAD"<<endl;
return -1;
}
glfwSetFramebufferSizeCallback(window,framebuffer_size_callback);

//渲染循环
while(!glfwWindowShouldClose(window)){
glfwSwapBuffers(window);

proccessInput(window);

//渲染区域
glClearColor(1.f,0.f,0.f,1.f);
glClear(GL_COLOR_BUFFER_BIT);

glfwPollEvents();
}

glfwTerminate();

return 0;
}
void framebuffer_size_callback(GLFWwindow* window,int width,int height){
glViewport(0,0,width,height);
}
void proccessInput(GLFWwindow*window){
if(glfwGetKey(window,GLFW_KEY_ESCAPE)==GLFW_PRESS){
glfwSetWindowShouldClose(window,true);
}
}