引言

最近在读 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-w64CMake 来完成编译,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 中的 KHRglad 两个文件夹复制到 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.dlllibglfw3dll.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 XglfwWindowHint(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 pointersif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// render loopwhile (!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

参考

  • cmake 添加头文件目录,链接动态、静态库

  • 如何将DLL文件复制到与使用CMake的可执行文件相同的文件夹中?

Windows 下的 OpenGL 开发环境配置(GLFW+GLAD)相关推荐

  1. 一、C++基础入门之 Windows下C/C++开发环境配置

    Windows 下 C/C++开发环境的配置:(51开源时代) 我的系统是Windows的,所以在这里我以Windows为例,我使用的是微软提供的VS2013(Microsoft Visual Stu ...

  2. windows下的WSL开发环境配置以及相关工具、插件

    最近在自己的X1上捣鼓Django框架的编程,windows环境使用起来确实让人痛苦,因此决定还是在Linux系统下进行Django框架的编程,跟朋友交流了一下,最终敲定了以下方案并把中间使用的一些插 ...

  3. OpenGL 开发环境配置(Windows) - Visual Studio 2017 + GLFW + GLAD 详细图文教程

    OpenGL 开发环境配置(Windows) - Visual Studio 2017 + GLFW + GLAD 详细图文教程 大部分 OpenGL 是直接面向设备商的,如果开发者需要使用 Open ...

  4. 【VSCode】【msys2】VS Code + msys2配置Windows下C/C++开发环境

    [VSCode][msys2]VS Code + msys2配置Windows下C/C++开发环境 一.Msys2配置 1. 下载msys2, 网址:https://www.msys2.org/ 2. ...

  5. Windows下安装Objective-C开发环境

    Windows下安装Objective-C开发环境 1.首先用GNUstep在windows下模拟object c开发环境. 官方网址:http://www.gnustep.org/ 百度云下载: 链 ...

  6. Windows下搭建ESP-IDF开发环境,适合ESP32/S2/C3/S3系列模组二次开发

    前言 本教程适用于以下两种用户: ①无Linux环境搭建经验或搭建Linux开发环境不成功: ②使用安信可windows一体化环境IDE V1.5开发环境搭建不成功: 本教程提供了windows下搭建 ...

  7. Windows 下使用GNU开发环境[转]

    Windows 下使用GNU开发环境http://www.hebl.name/zh/archives/gnuwin32-dev.html 2005-4-22 GNU/Linux, 軟件技術 GNU/U ...

  8. Windows下Ionic Android开发环境搭建

    转自 http://www.itwap.net/ArticleContent.aspx?id=26 来源: itwap.net 作者: 词略 时间: 2015-4-2 16:57:28 (一)Ioni ...

  9. 乐鑫Esp32学习之旅② 巧用eclipes编辑器,官方教程在Windows下搭建esp32开发环境,打印 “Hello World”。

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. 爬坑学习新旅程,虚拟机搭建esp32开发环境,打印 " ...

最新文章

  1. 第一次CM--CosH.2
  2. boost::python::detail::copy_ctor_mutates_rhs相关的测试程序
  3. 用积木做了个无人机。
  4. shell脚本触发java程序支持传参补跑 +crontab定时器_02
  5. shell脚本的简单学习
  6. redis学习-列表(list)常用命令
  7. 现代科技概论_现代科技概论课程:力与运动1
  8. oracle删除的数据没有commit,在Oracle中误删除数据后并commit后的数据恢复办法
  9. iOS通过点坐标获取js对应元素
  10. java实训致谢_Java教学实习报告(最终版).doc
  11. idea插件JRebel激活
  12. 讲课大师 把微信消息同步转发到企业微信中
  13. 一步教你轻松实现--Word方括号打勾☑
  14. TCP通信协议基本操作
  15. php新年计划,New Year’s Resolution |给20出头的你19条最赞的新年计划
  16. 天啦噜,项目上使用InputStream,我被坑了一把!
  17. ​邦基科技上交所上市:市值42亿 王由成家族色彩浓厚
  18. [渝粤教育] 四川大学 模拟电子技术基础(Ⅰ) 参考 资料
  19. ECharts之饼状图
  20. elasticsearch8.2集群部署

热门文章

  1. FOHEART·X动捕+“虎牙直播”,3分钟搞定虚拟人物直播!
  2. 打造顶级坚固的“钛金”进程防火墙(转)
  3. Java多线程基础-9:代码案例之阻塞队列
  4. google scholar按照 引用量进行排序 harzing Publish or Perish
  5. [机缘参悟-47]:鬼谷子-第十一决篇-决策者,中庸也,利益合理化分配也
  6. 中国摩托车国内外进出口数据和分析2018-2020
  7. python闹钟界面源码_Python编程练习:简单的闹钟提醒
  8. 计算机科学与技术的院校特色,应用型本科院校计算机科学与技术专业特色化建设研究...
  9. 喷雾破碎模型整理(更新中)
  10. Geometric Search