LearnOpenGL环境搭建

2020年2月春节期间我刷完过一遍LearnOpenGL,这是一个很好的入门openGL良心教程,一直没时间记录。最近打游戏荒废了好久,刚好换了电脑,重新装下环境顺便记录下LearnOpenGL的环境搭建。

教程中使用的环境是Visual Studios + CMake + MSVC,我没用过也没安装过Visual Studio。所以我选择的环境是vscode + CMake + MinGW-w64,在linux直接gcc就行了,mac用gcc、clang都可以。这样的好处是在win、linux、mac上都能搭建这套环境。

我的系统是win,因为要打游戏(

  • vscode 就不多说了,用其他编辑器/IDE也行

编译器肯定是必须的,我没用过msvc,只用过gcc,mingw-w64就是win上的gcc。

  • 下载地址:https://www.mingw-w64.org/downloads/

  • 双击打开,选择native windows,x86_64,如果是32位系统则选i686。设置好安装目录

    https://blog-1256556944.file.myqcloud.com/public/mingw-install.png

  • 直接点process安装

    https://blog-1256556944.file.myqcloud.com/public/mingw-install2.png

  • 完成后,安装目录的bin文件夹里就有gcc了

    https://blog-1256556944.file.myqcloud.com/public/mingw-install3.png

  • 最后吧bin目录添加到系统环境变量PATH里:此电脑-属性-高级系统设置-环境变量-PATH-添加D:\app\mingw-w64\bin

c++在编译的时候,需要引用各种头文件,链接这个那个的各种动态库、静态库。项目复杂的时候编译会很麻烦,cmake相当于一个构建系统,用不怎么简洁的语法,描述如何编译目标,帮我们生成makefile文件,自动编译项目。

  • 下载地址:https://cmake.org/download/,选择.msi安装
  • 一路点next,安装路径无所谓,记得加入PATH就行
    https://blog-1256556944.file.myqcloud.com/public/cmake-install.png
  • 完事检查下安装成功
    https://blog-1256556944.file.myqcloud.com/public/cmake-install2.png

需要用到以下库:

  • GLFW - 负责创建OpenGL上下文并显示窗口
  • GLAD - 查找openGL函数指针

在画出出色的效果之前,首先要做的就是创建一个OpenGL上下文(Context)和一个用于显示的窗口。然而,这些操作在每个系统上都是不一样的,OpenGL有目的地从这些操作抽象(Abstract)出去。这意味着我们不得不自己处理创建窗口,定义OpenGL上下文以及处理用户输入。

GLFW就是帮我们在不同平台做这个事情

  • 获取源代码:www.glfw.org/download.html,下载source package
  • 记得看看官方编译指南https://www.glfw.org/docs/latest/compile.html
  • 解压后进入目录
    https://blog-1256556944.file.myqcloud.com/public/GLFW-install.png
  • 在此目录执行cmake -S . -B build -G "MinGW Makefiles" -DBUILD_SHARED_LIBS=ON,其中-S指定源码所在目录,-B指定构建/输出目录,-G指定我们是给MinGW生产makefile,最后一个参数是告诉CMake,我们要动态库
    https://blog-1256556944.file.myqcloud.com/public/GLFW-install2.png
  • 最后,进入build/目录,执行mingw32-make.exe -j4-j4指定我们用4个cpu核心,注意由于我们装的mingw,所以make命令变成了mingw32-make.exe
    https://blog-1256556944.file.myqcloud.com/public/GLFW-install3.png
  • 完事后我们就得到了lib文件
    https://blog-1256556944.file.myqcloud.com/public/GLFW-install4.png
  • GLFW就编译完了,关键目录只有两个
    • 头文件path\to\glfw-3.3.6\include
    • lib文件path\to\glfw-3.3.6\build\src
  • path\to\glfw-3.3.6\build目录执行mingw32-make.exe install(需要管理员权限),文件会被安装到C:/Program Files (x86)/GLFW/
  • 最后手动复制glfw3.dllC:\Windows\System32下,不然运行程序会报找不到dll,其他库类似

OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。

GLAD会帮我们找到函数位置

  • 使用在线服务定制我们需要的源代码:https://glad.dav1d.de/
    https://blog-1256556944.file.myqcloud.com/public/GLAD.png
  • 下载解压后,include目录里是俩头文件,src目录里面就一个glad.c
  • 这个glad.c后面会直接和程序一起参与编译

到这里就可以创建项目了

建立一个名为LearnOpenGL的文件夹作为项目根目录。整个项目结构是这样的:

  • root(LearnOpenGL)
    • CMakeLists.txt - cmake构建文件
    • cmake/modules/ - 存放cmake自动查找库的find文件
    • include/ - 存放头文件
    • src/ - 存放源代码

可以参考:https://github.com/kirito41dd/LearnOpenGL

先给出目录细节再详细说,所有参与文件如下:

  • CMakeLists.txt - cmake构建文件
  • cmake/modules/ - 存放cmake自动查找库的find文件
    • FindGLFW3.cmake - 负责自动查找glfw的头文件路径和lib路径
  • include/ - 存放头文件
    • glad.c - 把安装GLAD时的文件复制过来
    • glad/ - 安装GLAD时的头文件目录,复制过来
      • glad.h
    • KHR/ - 安装GLAD时的头文件目录,复制过来
      • khrplatform.h
  • src/ - 存放源代码
    • start/ - 存放LearnOpenGL教程第一部分源码
      • CMakeLists.txt - 子目录构建文件
      • HelloWindow.cpp - 创建窗口示例程序

根目录下的CMakeLists.txt文件是引导cmake的入口,主要做一些项目设置,和头文件,lib等查找工作,详细如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
cmake_minimum_required(VERSION 2.9) # 指定cmake最小版本

project(learnopengl) # 设置项目名

# 依赖环境
# ------------------------------------------------------------------------------
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
find_package(GLFW3 REQUIRED)
include_directories(${GLFW3_INCLUDE_DIR})
add_library(glad include/glad.c)
# ------------------------------------------------------------------------------

include_directories(./include) # 添加头文件搜索目录

# 子目录
add_subdirectory(src/start) # 子目录也会有CMakeLists.txt文件,环境是相通的

主要来看依赖环境部分:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") 这句是往CMAKE_MODULE_PATH里追加一个目录, 这些目录里存放着各种find文件,命名为Find${LIB}.cmake

find_package(GLFW3 REQUIRED)表示调用FindGLFW3.cmake查找GLFW3的头文件和lib,而且是必须找到,否则构建终止。 如果找到了,会设置GLFW3_XXX等一系列变量

include_directories(${GLFW3_INCLUDE_DIR}),find执行成功才会执行这句,变量GLFW3_INCLUDE_DIR里存放着GLFW头文件的路径,然后添加头文件搜索目录

add_library(glad include/glad.c)声明一个名为glad的lib,后面可以指定链接它,glad.c就会参与编译

看下项目里GLFW的搜索文件cmake/modules/FindGLFW3.cmake,这个文件可以在网上找到很多例子,cmake本身也会预装很多find文件。

 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
set( _glfw3_HEADER_SEARCH_DIRS
"/usr/include"
"/usr/local/include"
"${CMAKE_SOURCE_DIR}/includes"
"C:/Program Files (x86)/glfw/include" 
"C:/Program Files (x86)/GLFW/include") # 注意这里,就是我们安装的目录
set( _glfw3_LIB_SEARCH_DIRS
"/usr/lib"
"/usr/local/lib"
"${CMAKE_SOURCE_DIR}/lib"
"C:/Program Files (x86)/glfw/lib-msvc110"
"C:/Program Files (x86)/GLFW/lib") # 注意这里

# Check environment for root search directory
set( _glfw3_ENV_ROOT $ENV{GLFW3_ROOT} )
if( NOT GLFW3_ROOT AND _glfw3_ENV_ROOT )
	set(GLFW3_ROOT ${_glfw3_ENV_ROOT} )
endif()

# Put user specified location at beginning of search
if( GLFW3_ROOT )
	list( INSERT _glfw3_HEADER_SEARCH_DIRS 0 "${GLFW3_ROOT}/include" )
	list( INSERT _glfw3_LIB_SEARCH_DIRS 0 "${GLFW3_ROOT}/lib" )
endif()

# Search for the header
FIND_PATH(GLFW3_INCLUDE_DIR "GLFW/glfw3.h" # 头文件目录的变量
PATHS ${_glfw3_HEADER_SEARCH_DIRS} )

# Search for the library
FIND_LIBRARY(GLFW3_LIBRARY NAMES glfw3 glfw glfw3dll
PATHS ${_glfw3_LIB_SEARCH_DIRS} )
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLFW3 DEFAULT_MSG
GLFW3_LIBRARY GLFW3_INCLUDE_DIR) # 注意这里


IF(GLFW3_FOUND)
	IF(NOT GLFW3_FIND_QUIETLY)
	MESSAGE(STATUS "Found ASSIMP: ${GLFW3_LIBRARY}")
	ENDIF(NOT GLFW3_FIND_QUIETLY)
ELSE(GLFW3_FOUND)
	IF(GLFW3_FIND_REQUIRED)
	MESSAGE(FATAL_ERROR "Could not find GLFW3")
	ENDIF(GLFW3_FIND_REQUIRED)
ENDIF(GLFW3_FOUND)

这里和LearnOpenGL里教的一样了就,src/start/HelloWindow.cpp

 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 你好,窗口
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>


using namespace std;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);

void processInput(GLFWwindow *window);

int main()
{
    cout << "hellow" << endl;
    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); // Mac OS X 使用

    // 创建一个窗口
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window); // 设置为当前上下文

    // glad
    // GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 设置窗口的维度
    // glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素)。
    glViewport(0, 0, 800, 600);

    // 设置一个回调,当用户改变窗口的大小的时候,视口也应该被调整。
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // 渲染循环 render loop
    while(!glfwWindowShouldClose(window))
    {
        processInput(window); // 处理输入

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清空屏幕所用的颜色
        glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色

        glfwSwapBuffers(window); // 交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲)
        glfwPollEvents(); // 函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)。
    }

    // 释放之前分配的资源
    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    // 如果按下 esc , 窗口在下次循环将会退出
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

最后来写下src/start目录里的CMakeLists.txt,来告诉cmake如何编译上面的cpp文件:

1
2
3
# 你好,窗口
add_executable(HelloWindow HelloWindow.cpp) # 添加可执行程序
target_link_libraries(HelloWindow ${GLFW3_LIBRARY} glad) # 链接lib glfw glad.c

回到项目根目录执行:cmake -S . -B build/ -G"MinGW Makefiles"

进入build目录执行:mingw32-make.exe

编译结束后,在build/src/start/目录里能看到名为HelloWindow.exe的可执行程序,恭喜

https://blog-1256556944.file.myqcloud.com/public/HelloWindow.png

三角形也可以画出来了,具体跟着教程走吧

https://blog-1256556944.file.myqcloud.com/public/HelloTrigger.png

希望你也能通关,终点等你。

(依赖库安装还没写完,待续。。。