上一篇文章我们已经初步介绍了OpenGL的基本概念,准确来说OpenGL只是一个规范,基于这个规范提供了库去实现图像编程。OpenGL的很多操作都是基于一个窗口,今天我们就来实现创建一个简单的窗口,talk is cheap,show me your code。
工欲善其事, 必先利其器,在正式开发之前还需要搭建一下环境,这里仅仅以个人的环境为例,不同的平台可以去google一下,有很多相关的文章,我自己使用的是Mac,为了方便编辑器使用的是VS Code。
step1:
在正式开始之前需要先安装GLFW,GLFW是一个C语言写的库,符合OpenGLd的标准,使用GLFW可以创建一个OpenGL的context,创建并定义一个窗口的参数以及处理用户的输入,安装后其安装位置要记住,之后需要使用。
brew install glfw
step2:
下载glad,可以去下载页面下载,使用一下配置即可:
然后点击下面的生成按钮并且下载。然后新建一个文件夹将解压后的include和src文件夹复制到新建的文件夹。 这个glad是一个开源库,正如之前我们所提到的OpenGL只是一个标准,具体的实现是有各个显卡厂商完成的, 所以显卡驱动的版本有很多种类,虽然都是基于OpenGL标准,实现的函数和最终的效果是一样的,但是函数的位置在编译期是无法知道的,且需要在运行时检索这些函数,然后将这些函数的位置存储在函数指针中以便之后使用,而这个检索函数的过程又是与操作系统高度相关的,而glad就是用来帮助开发者完成这些繁琐的过程。
step3:
新建CMakeList.txt文件,其内容如下,记得替换GLFW_H和GLFW_LINK的地址,在安装GLFW完成时会提示安装的位置。
cmake_minimum_required(VERSION 3.0.0)
project(HelloGL VERSION 0.1.0)
# 使用 C++ 11 标准
set(CMAKE_CXX_STANDARD 11)
# 添加头文件
set(GLAD_H ${PROJECT_SOURCE_DIR}/include)
set(GLFW_H /usr/local/include)
include_directories(${GLAD_H} ${GLFW_H})
# 添加目标链接
set(GLFW_LINK /usr/local/lib/libglfw.3.dylib)
link_libraries(${GLFW_LINK})
# 执行编译命令
set(SOURCES glad.c main.cpp)
add_executable(HelloGL ${SOURCES})
# 链接系统的 OpenGL 框架
if (APPLE)
target_link_libraries(HelloGL "-framework OpenGL")
endif()
include(CTest)
enable_testing()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
step4:
然后在src目录下新建一个main.cpp,内容如下:
#include
#include
#include
#include
#include
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window);
int main(int argc, const char *argv[])
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// uncomment this statement to fix compilation on OS X
#endif
GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "fail to create window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
然后在主目录下新建一个build目录
mkdir build
然后进入build目录
cd build
使用以下命令
cmake ..
然后使用make编译
make
如果编译成功,会在build目录下生成HelloGL的二进制文件,使用以下命令启动程序
./HelloGL
如果此时出现一个窗口,这就是你绘制的第一个窗口。
经过之前的配置我们已经成功创建了一个窗口了,那么这个窗口是如何被创建的呢,接下来我们通过代码仔细分析这个创建的过程。 step1:
首先我们需要引入需要使用的库,也就是之前提到的glfw和glad
# include
# include
❝其中需要注意的是glad的引入要在GLFW之前,因为GLFW需要使用glad其中的内容
❞
然后需要创建一个主函数,然后在主函数中对glfw进行初始化和各种配置,以便之后使用,其代码如下, 首先需要使用glfwInit函数对glfw进行初始化,然后使用glfwWindowHint对glfw进行配置,glfwWindowHint函数主要有两个参数,第一个参数是需要配置的项,第二个参数是配置给该项的值。 下面代码通过GLFW_CONTEXT_VERSION_MAJOR配置OpenGL的主版本号,GLFW_CONTEXT_VERSION_MINOR是次版本号,GLFW_OPENGL_PROFILE是配置OpenGL的渲染模式,正如上篇文章所提到的,我嘛使用核心渲染模式,最后由于我是苹果平台,所以需要配置GLFW_OPENGL_FORWARD_COMPAT,保证程序正常执行。
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
return 0;
}
step2:
在初始化glfw后我们则需要创建一个窗口,并将其与当前线程绑定,其代码如下:创建一个窗口需要使用glfwCreateWindow函数,其第一个参数是指定窗口的宽度,第二个参数是窗口的高度,第三个参数是窗口的名字,最后两个参数暂时可以不管设置为空即可,然后使用glfwMakeContextCurrent函数将窗口绑定在当前线程。
GLFWwindow *window = glfwCreateWindow(800, 600, "QStackOpenGL", NULL, NULL);
if (window == NULL) {
std::cout<<"Fail to create a glfw window"< glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
step3:
正如之前所提到的,glad将为我们管理一些函数的指针,所以在使用OpenGL的一些函数前,我们需要初始化glad,其代码如下:
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout<<"fail to init glad"< return -1;
}
在正式渲染之前还需要设置一下视口(viewport),其前两个参数是窗口左上角的坐标,后两个参数是窗口的宽度和高度,设置与GLFW的窗口一致即可。
glViewport(0, 0, 800, 600);
step4: 当用户改变窗口大小的时候,窗口的大小也要随之改变,需要先声明一个函数如下:
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
其具体实现如下:
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
glViewport(0, 0, width, height);
}
然后需要注册该函数,每次窗口大小改变时调用该函数,实现如下:
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
step5: 我们不希望窗口出现一下就消失,而是只要我们不取消就一直存在,那么则需要一个循环一直去绘制窗口,其代码如下:
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwWindowShouldClose(window)是用来判断GLFW是否接受到关闭指令,如果没有则是true,glfwSwapBuffers(window)是交换窗口的buffer,其实在渲染过程中是有两块buffer的,一块是屏幕上展示的,另一块是在计算下一桢每一个像素的颜色等,如果使用一个buffer,就会显示出渲染的过程,体验不好,且性能也不好,glfwPollEvents()则是接受一个外界的信号如鼠标和键盘输入等。
step6:
当程序运行结束,我们则要关闭GLFW,代码如下:
glfwTerminate();
这篇文章简要介绍了环境配置以及如何创建一个窗口,更多文章可以关注公众号QStack。