基础

扩展

​ OpenGL的一大特性就是对扩展(Extension)的支持,当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以扩展的方式在驱动中实现。如果一个程序在支持这个扩展的显卡上运行,开发者可以使用这个扩展提供的一些更先进更有效的图形功能。通过这种方式,开发者不必等待一个新的OpenGL规范面世,就可以使用这些新的渲染特性了,只需要简单地检查一下显卡是否支持此扩展。通常,当一个扩展非常流行或者非常有用的时候,它将最终成为未来的OpenGL规范的一部分。

使用扩展的代码大多看上去如下:

if(GL_ARB_extension_name)
{
    // 使用硬件支持的全新的现代特性
}
else
{
    // 不支持此扩展: 用旧的方式去做
}

使用OpenGL3.3时,我们很少需要使用扩展来完成大多数功能,当需要的时候,本教程将提供适当的指示。

状态机

​ OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。

​ 假设当我们想告诉OpenGL去画线段而不是三角形的时候,我们通过改变一些上下文变量来改变OpenGL状态,从而告诉OpenGL如何去绘图。一旦我们改变了OpenGL的状态为绘制线段,下一个绘制命令就会画出线段而不是三角形。

​ 当使用OpenGL的时候,我们会遇到一些状态设置函数(State-changing Function),这类函数将会改变上下文。以及状态使用函数(State-using Function),这类函数会根据当前OpenGL的状态执行一些操作。只要你记住OpenGL本质上是个大状态机,就能更容易理解它的大部分特性。

对象

​ OpenGL库是用C语言写的,同时也支持多种语言的派生,但其内核仍是一个C库。由于C的一些语言结构不易被翻译到其它的高级语言,因此OpenGL开发的时候引入了一些抽象层。“对象(Object)”就是其中一个。

​ 在OpenGL中一个对象是指一些选项的集合,它代表OpenGL状态的一个子集。比如,我们可以用一个对象来代表绘图窗口的设置,之后我们就可以设置它的大小、支持的颜色位数等等。可以把对象看做一个C风格的结构体(Struct):

struct object_name {
    float  option1;
    int    option2;
    char[] name;
};

​ 当我们使用一个对象时,通常看起来像如下一样(把OpenGL上下文看作一个大的结构体):

// OpenGL的状态
struct OpenGL_Context {
    ...
    object* object_Window_Target;
    ...     
};
// 创建对象
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时常见的工作流。我们首先创建一个对象,然后用一个id保存它的引用(实际数据被储存在后台)。然后我们将对象绑定至上下文的目标位置(例子中窗口对象目标的位置被定义成GL_WINDOW_TARGET)。接下来我们设置窗口的选项。最后我们将目标位置的对象id设回0,解绑这个对象。设置的选项将被保存在objectId所引用的对象中,一旦我们重新绑定这个对象到GL_WINDOW_TARGET位置,这些选项就会重新生效。

.vscode配置讲解

c_cpp_properties.json

​ Visual Studio Code (VS Code) 中 C/C++ 扩展使用的配置文件。这个文件专门用于配置 VS Code 的 IntelliSense(智能感知)功能,确保代码编辑器能够正确地识别和理解你的源代码、库和编译器设置,从而提供自动完成、错误波浪线和代码导航等功能。

{
    "version": 4,
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**",
                "${workspaceFolder}/include",
                "E:/vcpkg/vcpkg/installed/x64-windows/include"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "windowsSdkVersion": "10.0.26100.0",
            "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64/cl.exe",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "windows-msvc-x64",
            "configurationProvider": "ms-vscode.cmake-tools"
        }
    ]
}
属性值解释
version4指定配置文件的版本。
configurations[...]包含一个或多个配置对象(如 Win32)。你可以为不同的平台或构建类型(Debug/Release)设置不同的配置。

configurations 数组中的配置对象

​ 您只有一个名为 "Win32" 的配置对象。

属性值解释
name"Win32"配置的名称。用户可以在 VS Code 状态栏中选择此配置。注意,在 64 位系统上,这个名称可能只是历史遗留,实际编译目标由 compilerPath 和 intelliSenseMode 决定。
includePath[...]最重要的部分。 这是一个数组,告诉 IntelliSense 在哪里查找头文件 (.h 或 .hpp):
"${workspaceFolder}/**"递归地查找工作区根目录下所有文件夹中的头文件。
"${workspaceFolder}/include"查找工作区根目录下的 include 文件夹中的头文件。
"E:/vcpkg/vcpkg/installed/x64-windows/include"这是你手动添加的路径。 它指向 Vcpkg 安装的所有 64 位 Windows 库的头文件目录。这是让 IntelliSense 识别 GLFW 等库的关键。
defines[...]预处理器宏定义。这些宏在编译时会被定义:
"_DEBUG"通常用于调试构建。
"UNICODE", "_UNICODE"用于启用 Windows 上的 Unicode 字符集支持。
windowsSdkVersion"10.0.26100.0"指定使用的 Windows SDK 版本。
compilerPath"C:/Program Files (x86)/.../cl.exe"指定 IntelliSense 应该模仿哪个编译器。 这里指向了 Visual Studio 2022 Build Tools 中的 MSVC 编译器 (cl.exe) 的 64 位版本。IntelliSense 会读取此编译器的默认头文件和设置。
cStandard"c17"C 语言标准 (C17)。
cppStandard"c++17"C++ 语言标准 (C++17)。
intelliSenseMode"windows-msvc-x64"指定 IntelliSense 的工作模式。 windows-msvc-x64 表示它将模拟 64 位 Windows 上的 Microsoft Visual C++ 编译器行为。
configurationProvider"ms-vscode.cmake-tools"告诉 C/C++ 扩展,当前的配置信息实际上由另一个扩展(CMake Tools)提供和管理。虽然你在这里手动配置了,但 CMake Tools 扩展可以在其配置步骤中覆盖或补充这些路径。

该配置的目的

这个 c_cpp_properties.json 文件的主要目的是为 VS Code 提供一个 64 位 Windows 环境下的 MSVC 智能感知模型,并确保 IntelliSense 可以找到:

  1. 项目内部的头文件 (${workspaceFolder}/**)。
  2. 系统和工具链的头文件 (compilerPath 决定的 MSVC 默认路径和 windowsSdkVersion 决定的 Windows SDK 路径)。
  3. Vcpkg 安装的第三方库的头文件 (E:/vcpkg/.../include)。

注意: 这个文件 只影响 VS Code 的编辑器功能。它不影响你的实际编译和链接过程。你的 CMakeLists.txt 和 Vcpkg Toolchain 文件 才是决定项目能否成功编译和运行的关键。

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug OpenGL Project",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/Debug/opengl_project.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "console": "integratedTerminal",
            "preLaunchTask": "Build"
        }
    ]
}
属性值解释
version"0.2.0"指定配置文件的版本。
configurations[...]包含一个或多个调试配置对象。

配置对象:Debug OpenGL Project

属性值解释
name"Debug OpenGL Project"配置的显示名称。 你在 VS Code 调试面板中看到的名称。
type"cppvsdbg"要使用的调试器类型。 "cppvsdbg" 对应于 Microsoft Visual Studio 调试器,适用于使用 MSVC (Visual Studio 编译器) 构建的 Windows C++ 程序。
request"launch"请求类型。 指定调试器应该 启动 一个新的程序实例,而不是连接到一个已运行的进程 (attach)。
program"${workspaceFolder}/build/Debug/opengl_project.exe"要启动的可执行文件路径。 这是一个关键设置,它使用**环境变量 ${workspaceFolder}(项目根目录)**来定位你的程序。它假设你的 CMake 构建将 Debug 版本的 .exe 文件放在 build/Debug/ 目录下。
args[]命令行参数。 如果你的程序需要在启动时接收参数,它们会被放在这个数组中。当前为空,表示没有参数。
stopAtEntryfalse是否在程序入口点暂停。 false 表示程序将直接运行到你设置的第一个断点处。如果设置为 true,程序会在 main() 函数开始时立即暂停。
cwd"${workspaceFolder}"工作目录(Current Working Directory)。 程序启动时所处的目录。设置为 ${workspaceFolder} 确保程序可以找到它依赖的任何相对路径文件(例如:着色器文件、纹理、模型等)。
environment[]环境变量。 启动程序时需要设置的特定环境变量,当前为空。
console"integratedTerminal"控制台输出方式。 指定程序的标准输入/输出(如 printf 或 std::cout)将显示在 VS Code 的集成终端中。其他选项包括 externalTerminal(新开一个窗口)等。
preLaunchTask"Build"启动前的任务。 这是一个极其重要的设置。它告诉 VS Code 在启动调试之前,必须先运行一个名为 "Build" 的 Task(任务)。这个任务通常用于执行 CMake 构建,确保调试器运行的是最新的编译结果。

setting.json

{
    "cmake.configureArgs": [
        "-DCMAKE_TOOLCHAIN_FILE=E:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake"
    ],
    "cmake.generator": "Visual Studio 17 2022",
    "cmake.preferredGenerators": [
        "Visual Studio 17 2022"
    ],
    "cmake.buildDirectory": "${workspaceFolder}/build",
    "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
    "C_Cpp.default.compilerPath": "",
    "C_Cpp.default.intelliSenseMode": "windows-msvc-x64"
}

settings.json 配置详解

​ 这个文件主要分为两个部分:针对 CMake Tools 扩展 的配置和针对 C/C++ 扩展 的默认配置。

​ 这个配置文件通常是 VS Code 的 用户或工作区设置文件(settings.json),它主要用于配置 CMake Tools 扩展的行为以及 C/C++ 扩展的一些默认设置。

​ 它将你的 CMake 构建系统与 Vcpkg 完美地结合了起来。

这个文件主要分为两个部分:针对 CMake Tools 扩展 的配置和针对 C/C++ 扩展 的默认配置。

1. CMake Tools 配置(cmake.*)

​ 这些设置直接控制 VS Code 如何调用 CMake 来配置和生成你的项目。

属性值解释
cmake.configureArgs["-DCMAKE_TOOLCHAIN_FILE=..."]配置参数。 这是最重要的部分,它告诉 CMake 在配置项目时,必须使用 Vcpkg 的工具链文件。这确保了 CMake 能够找到你通过 Vcpkg 安装的所有库,如 GLFW。
cmake.generator"Visual Studio 17 2022"默认生成器。 指定 CMake 应该使用哪个构建系统来生成项目文件。这里选择的是 Visual Studio 2022 的生成器,这意味着 CMake 将生成 .sln 和 .vcxproj 文件。
cmake.preferredGenerators["Visual Studio 17 2022"]首选生成器列表。 进一步确定了如果用户没有明确选择,CMake Tools 应该优先使用这个生成器。
cmake.buildDirectory"${workspaceFolder}/build"构建目录。 指定所有 CMake 生成的临时文件和最终可执行文件(如你的 opengl_project.exe)应该放置的位置。这与你的 launch.json 中的路径假设一致。

2. C/C++ 扩展默认配置(C_Cpp.default.*)

​ 这些设置提供了 C/C++ 扩展(负责 IntelliSense)的默认行为,但它们通常会被 c_cpp_properties.json 或 CMake Tools 的推送信息所覆盖。

属性值解释
C_Cpp.default.configurationProvider"ms-vscode.cmake-tools"智能感知配置提供者。 这是最佳实践!它指示 C/C++ 扩展,不要尝试自己去猜头文件路径,而是完全信任 CMake Tools 扩展提供的准确、完整的配置信息。
C_Cpp.default.compilerPath""默认编译器路径。 这是一个空字符串,意味着它将依赖于 configurationProvider(即 CMake Tools)来确定实际的编译器路径。
C_Cpp.default.intelliSenseMode"windows-msvc-x64"默认智能感知模式。 设置为模拟 64 位 Windows 上的 MSVC 编译器行为。这确保了在 CMake Tools 尚未提供配置信息时,IntelliSense 也能有一个合理的默认环境。

这个 settings.json 文件是你的 VS Code C++/CMake 工作流的核心枢纽。它的目标是:

  1. 自动化 Vcpkg 集成: 通过 cmake.configureArgs 自动将 Vcpkg 链接到你的 CMake 项目。
  2. 统一构建系统: 确保 CMake 始终使用 Visual Studio 2022 作为生成器。
  3. 强化智能感知: 通过将配置职责完全交给 CMake Tools 扩展,确保 IntelliSense 的路径(包括所有 GLFW 等 Vcpkg 库的头文件)总是正确且同步的,极大地提高了代码编辑的准确性。

task.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Configure CMake",
            "type": "shell",
            "command": "cmake",
            "args": [
                "-B", "build",
                "-S", ".",
                "-DCMAKE_TOOLCHAIN_FILE=E:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake",
                "-G", "Visual Studio 17 2022",
                "-A", "x64"
            ],
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            },
            "problemMatcher": []
        },
        {
            "label": "Build",
            "type": "shell",
            "command": "cmake",
            "args": ["--build", "build", "--config", "Debug"],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            },
            "problemMatcher": ["$msCompile"]
        }
    ]
}

​ 这个文件定义了你在 VS Code 中可以运行的自定义任务,比如编译、运行脚本或执行外部命令。它主要用于将你的 CMake 构建流程集成到 VS Code 的工作流中,特别是与你之前的 launch.json 文件(其中的 "preLaunchTask": "Build")配合使用。

属性值解释
version"2.0.0"指定配置文件的版本。
tasks[...]包含一个或多个任务定义。

任务一:"Configure CMake"

​ 这个任务负责首次配置你的 CMake 项目,即生成项目文件。

属性值解释
label"Configure CMake"任务名称。 用于在 VS Code 命令面板中识别这个任务。
type"shell"任务类型。 表示它将运行一个外部 shell 命令(在这里是 cmake)。
command"cmake"执行的程序。 假设 cmake 已经在系统的 PATH 中。
args[...]传递给 cmake 的参数。 这些参数定义了你的构建配置:
"-B", "build"-B (Build Directory)。 指定生成的文件放在 build 目录下。
"-S", "."-S (Source Directory)。 指定源代码的根目录是当前目录 (.)。
"-DCMAKE_TOOLCHAIN_FILE=..."Vcpkg 集成。 明确指定 Vcpkg 工具链文件,确保 CMake 找到所有 Vcpkg 依赖项(如 GLFW)。
"-G", "Visual Studio 17 2022"-G (Generator)。 指定使用 Visual Studio 2022 生成器来创建构建系统。
"-A", "x64"-A (Architecture)。 指定目标架构为 x64 (64位)。
group"build"将此任务归类为 构建 任务。
problemMatcher[]问题匹配器。 空数组表示这个任务不负责编译代码,所以不需要匹配编译器错误。

任务二:"Build"

​ 这个任务负责实际编译你的项目。它是你在 launch.json 中用作 preLaunchTask 的任务。

属性值解释
label"Build"任务名称。 这是 launch.json 中引用的名称。
type"shell"任务类型。 运行一个 shell 命令。
command"cmake"执行的程序。 再次使用 cmake。
args["--build", "build", "--config", "Debug"]传递给 cmake 的参数。
"--build", "build"告诉 CMake 运行 build 目录中的生成器(即 Visual Studio)。
"--config", "Debug"指定要构建的配置是 Debug 版本。
group{ "kind": "build", "isDefault": true }默认构建任务。 将此任务设置为默认构建任务,按下 Ctrl+Shift+B (Windows/Linux) 或 Cmd+Shift+B (Mac) 时,就会执行它。
problemMatcher["$msCompile"]问题匹配器。 使用 $msCompile 模式来识别 MSVC 编译器 输出的错误和警告,并在 VS Code 中显示为波浪线。