Windows 下的 OpenGL 开发环境配置(GLFW+GLAD)
Posted 河乐不为
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows 下的 OpenGL 开发环境配置(GLFW+GLAD)相关的知识,希望对你有一定的参考价值。
引言
最近在读 Unity 4.3 的源码,研究到 Unity 集成的物理引擎 PhysX 和 Box2D 部分,接下来还要研究渲染引擎方面的东西,想着直接倒腾一下,自己集成一遍写个小 demo 。当然这都依赖于 OpenGL 这个东西来渲染(因为物理引擎本身都是一些计算,没有可视化的东西,需要借助渲染层将其可视化),这里先搭一个可以在 Windows 下编写 OpenGL 程序的架子,然后再往里面塞物理引擎和 Shader 相关的东西。
OpenGL 基础概念
OpenGL 函数库相关的 API 包括:核心库( gl ),实用库( glu ),辅助库( aux )、实用工具库( glut ),窗口库( glx 、 agl 、 wgl )和扩展函数库等。gl 是核心,glu 是对 gl 的部分封装。glx 、 agl 、wgl 是针对不同窗口系统的函数。扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩展机制开发的函数。
-
gult (OpenGL Utility Toolkit)
是 OpenGL 跨平台的实用工具库,主要用于做窗口界面。大部分函数以 glut 开头,其 API 包括:窗口操作函数,窗口初始化、窗口大小、窗口位置等函数;回调函数:响应刷新消息、键盘消息、鼠标消息、定时器函数等;创建复杂的三维物体;菜单函数;程序运行函数。
对应的开源实现是 freegult
-
glew
glut 或 freeglut 主要是 1.0 的基本函数功能,glew 是使用OpenGL 2.0 之后接口的一个扩展库,能自动识别当前平台支持的全部 OpenGL 高级扩展函数。
在程序中只要引入
glew.h
头文件,便可使用 gl, glu, glext, wgl 和 glx 的全部函数。 -
glfw
是一个跨平台的 OpenGL 应用框架,支持 OpenGL 和 OpenGL ES ,支持窗口创建、读取输入和处理事件等功能。特点:轻量级、开源和跨平台。由于 glut 已经太老了,现在基本都是用 glfw 来替代 glut 。
-
glad
glad 可以说是 glew 的升级版 。
IDE 选择
在 Windows 平台下开发 C++ 程序,可以使用 VS 2017 作为 IDE ,傻瓜式且继承了编译调试等,显然是更加简单的选择。但我还是倾向于折腾一点,也有助于了解底层的一些东西,windows 下开发 C++ 程序我还是更习惯于使用 MinGW-w64
和 CMake
来完成编译,IDE 直接使用比较轻巧的 VS Code 。
这是我之前写的配置过程: Windows下的C++编译工具—— MinGW-w64 和 CMake
资源下载
这里直接使用 glad + glfw 组合的方式
glfw
打开 glfw 官网下载页 ,根据当前使用 MinGW 支持的编译位数选择下载 32 位或 64 位的包,使用 MinGW-w64 的直接下载 64-bit Windows binaries
即可,得到:glfw-3.3.bin.WIN64.zip
glad
glad 有一个在线服务 https://glad.dav1d.de/ ,设置如下:
-
语言(Language)设为
C/C++
; -
API 中 gl 版本指的是 OpenGL 的版本,选择 3.3 以上(因为 3.3 及之后的版本是纯可编程管线,去掉了固定管线),这里我选择最新的 4.6;
-
模式(Profile)设为
Core
;这里有两种选择 :Compatibility 和 Core ,其中 Compatibility 兼容旧版本,包含低版本中的 API ,而 Core 是只包含当前版本必须支持的 API ,不考虑向下兼容旧版本,更为轻巧。
-
确保勾选了
Generate a Loader
,然后点击GENERATE
。
在生成页面中下载 glad.zip
压缩包。
创建工程
-
创建一个空文件夹,并其下创建 include 、lib 和 src 目录
-
将 glad.zip 解压后的文件:
-
include 中的
KHR
和glad
两个文件夹复制到 include 目录; -
src/glad.c
复制到 src 目录。
为了方便起见,还是把 glad.c 编译成静态库:
-
$ gcc .\\src\\glad.c -c -I.\\include\\ $ ar -rc libglad.a glad.o
将
libglad.a
复制到 lib 目录。
-
解压 glfw-3.3.bin.WIN64.zip ,然后将其目录下的文件:
-
include
目录下的GLFW
文件夹复制到 include 目录; -
lib-mingw-w64
目录下的glfw3.dll
和libglfw3dll.a
复制到 lib 目录。
-
-
在 src 目录下创建一个测试脚本
test.cpp
,内容如下:直接从网上抄的一段代码,参考:vscode OpenGL 环境搭建
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> // 设置窗口尺寸 const unsigned int SCR_WIDTH = 400; const unsigned int SCR_HEIGHT = 300; int main() // glfw: 初始化 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ // uncomment this statement to fix compilation on OS X glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif // glfw 创建窗口 GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Test<GLFW+GLAD>", NULL, NULL); if (window == NULL) std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; glfwMakeContextCurrent(window); // glad: load all OpenGL function pointers if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) std::cout << "Failed to initialize GLAD" << std::endl; return -1; // render loop while (!glfwWindowShouldClose(window)) glClearColor(0.0f, 1.f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // glfw: swap buffers and poll IO events (keyspressed/released, mouse moved etc.) glfwSwapBuffers(window); glfwPollEvents(); // glfw: terminate, clearing all previously allocated GLFWresources. glfwTerminate(); return 0;
编译工程
由于工程比较简单,这里有几种方式可以完成工程的编译
-
直接 gcc 命令编译工程:
假如是直接使用
glad.c
进行编译:$ g++ -g -std=c++17 -I ./include -L ./lib src/test.cpp src/glad.c -o main -lglfw3dll
假如使用
libglad.a
进行编译:$ g++ -g -std=c++17 -I ./include -L ./lib src/test.cpp -o main -lglad -lglfw3dll
当然更推荐使用
glfw3.dll
来编译程序:$ g++ -g -std=c++17 -I ./include -L ./lib src/test.cpp -o main -lglad .\\glfw3.dll
-lglfw3dll
使用的是libglfw3dll.a
来进行编译,然而此库文件最终编译出来的 exe 文件也必须依赖 glfw3.dll 才能启动,既然如此,还不如直接使用 glfw3.dll 库文件就好了。 -
手写 makefile ,在工程根目录下创建 makefile 文本文件,内容如下:
CXX := g++ CXX_FLAGS := -g -std=c++17 SRC := src INCLUDE := ./include LIB := ./lib LIBRARIES := -lglad .\\glfw3.dll EXECUTABLE := main all:./$(EXECUTABLE) run: all ./$(EXECUTABLE) $(EXECUTABLE):$(SRC)/*.cpp $(CXX) $(CXX_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES)
在命令行执行
make run
则编译完成后会自动执行可执行程序。 -
创建 CMakeLists.txt ,借助 CMake 来生成 Makefile ,然后再编译工程,内容如下:
cmake_minimum_required(VERSION 3.0) project (TestGladGlfw) # 工程名称 link_directories($PROJECT_SOURCE_DIR/lib) # 库目录, -L set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -g -std=c++17") set(SOURCE_FILES src/test.cpp src/glad.c) add_executable(main $SOURCE_FILES) # 源文件 include_directories($PROJECT_SOURCE_DIR/include) # 头文件目录, -I target_link_libraries(main glfw3)
需要注意的是:原本以为
target_link_libraries
是从只从 MinGW-w64 安装目录中的lib
中去获取库文件的,因为 lib 中明明有libglfw3dll.a
,但编译时且出现cannot find -lglfw3dll
的错误,如下:E:/C++/installs/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lglfw3dll collect2.exe: error: ld returned 1 exit status make[2]: *** [CMakeFiles/main.dir/build.make:104: main.exe] Error 1 make[1]: *** [CMakeFiles/Makefile2:73: CMakeFiles/main.dir/all] Error 2 make: *** [Makefile:84: all] Error 2
而将该库复制到 MinGW-w64 安装目录中的
lib
中去又能正常编译。最后才发现原来link_directories
必须在add_executable
之前,应该该指令对其后续操作生效。假如不使用link_directories
而只使用target_link_libraries
的话,需要使用绝对地址,相对当前工程的地址似乎无效。在 build 目录下生成 Makefile
$ mkdir build $ cd build $ cmake -G"Unix Makefiles" ../ -- The C compiler identification is GNU 8.1.0 -- The CXX compiler identification is GNU 8.1.0 -- Check for working C compiler: E:/C++/installs/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/gcc.exe -- Check for working C compiler: E:/C++/installs/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/gcc.exe -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: E:/C++/installs/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/c++.exe -- Check for working CXX compiler: E:/C++/installs/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/c++.exe -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: E:/C++/projects/TestGladGlfw/build
使用 Makefile 编译当前工程:
$ make Scanning dependencies of target main [ 33%] Building CXX object CMakeFiles/main.dir/src/test.cpp.obj [ 66%] Building C object CMakeFiles/main.dir/src/glad.c.obj [100%] Linking CXX executable main.exe "copy dll files after make" [100%] Built target main
运行结果
上面编译命令执行完成之后,会生成 main.exe
可执行文件,直接在命令行运行或者双击打开:
$ .\\main.exe
可以看到如下结果:
DLL 库 丢失问题
假如 .dll
动态库文件与 .exe
不在同一目录下,常常会出现 无法启动此程序,因为计算机中丢失 xxx.dll 。...
这类的报错,有两个解决方案:
方案一
可以通过 CMakeLists.txt 实现在编译得到目标文件后,将依赖库复制到同级目录下,由于不同平台使用的库文件可能不同,这里只演示 Windows 平台,直接在上述 CMakeLists.txt 末尾加上如下内容:
# 平台区分
if (CMAKE_HOST_WIN32)
set(WINDOWS 1)
elseif(CMAKE_HOST_APPLE)
set(MACOS 1)
elseif(CMAKE_HOST_UNIX)
set(LINUX 1)
endif()
# 复制 dll 到 build 目录
if(WINDOWS)
add_custom_command(TARGET main
POST_BUILD
COMMAND echo "copy dll files after make"
COMMAND $CMAKE_COMMAND -E copy_if_different
"$PROJECT_SOURCE_DIR/lib/glfw3.dll"
$<TARGET_FILE_DIR:main>)
endif()
方案二
参考 Qt5 编译 & 打包依赖dll发布 ,可以使用 EnigmaVirtual Box
工具将所有依赖的 .dll 都打进 .exe 中 。
环境变量更新的坑
编译出来的 .exe
文件在命令行使用 .\\main.exe
可以打开,而直接在资源管理器中双击打开却提示:应用程序无法正常启动(0xc000007b)。请点击 “确定” 关闭程序
。
原本以为是程序编译或者依赖库的问题,后来才发现是环境变量的问题:
我们都知道 Windows 中设置变量有 系统变量
和 用户变量
两种,其中系统变量是针对全部用户起作用的,而用户变量是针对当前用户起作用。而在命令行中输入 PATH
查询的结果其实是系统变量和当前用户变量合并后的结果。
然而,有个坑点,启动命令行的方式也会决定使用变量的不同:
-
以
win+R
快捷键输入cmd
启动的命令行一般会获得最新的 PATH 配置; -
在资源管理器下通过
Shift
+ 鼠标右键,然后选择在此处打开命令窗口
启动的命令行,获取的 PATH 配置是此资源管理器窗口打开时刻的 PATH 配置,假如更细了环境变量后没有重新打开窗口,则此窗口中的 PATH 不会更新。
我之前使用的是 MinGW
,这次改为 MinGW-w64
,因此修改了环境变量的 PATH ,但我没有重启电脑,打开项目文件夹的资源管理器没有关闭重开,因此窗口中的 PATH 还是旧的,而我编译工程是在 VS Code 中进行的(PATH 更新时重启过,使用的是新的 PATH),因此双击启动时的 PATH 配置与 VS Code 中命令行启动时的 PATH 配置不一致,因此导致了结果不同。
解决方案:关闭资源管理器,重新打开资源管理器再双击可执行程序就可以了。
终于知道为什么修改环境变量配置要重启电脑了,其实就是最简单粗暴避开这种隐含规则的方法。
Demo 源码
本工程的源码以提交到 github :/linshuhe/OpenGLWinDemo
参考
以上是关于Windows 下的 OpenGL 开发环境配置(GLFW+GLAD)的主要内容,如果未能解决你的问题,请参考以下文章
Win10 VS2015 OpenGL + freeglut + glew + glm 环境配置