基础
扩展
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"
}
]
}
| 属性 | 值 | 解释 |
|---|---|---|
version | 4 | 指定配置文件的版本。 |
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 可以找到:
- 项目内部的头文件 (
${workspaceFolder}/**)。 - 系统和工具链的头文件 (
compilerPath决定的 MSVC 默认路径和windowsSdkVersion决定的 Windows SDK 路径)。 - 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 | [] | 命令行参数。 如果你的程序需要在启动时接收参数,它们会被放在这个数组中。当前为空,表示没有参数。 |
stopAtEntry | false | 是否在程序入口点暂停。 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 工作流的核心枢纽。它的目标是:
- 自动化 Vcpkg 集成: 通过
cmake.configureArgs自动将 Vcpkg 链接到你的 CMake 项目。 - 统一构建系统: 确保 CMake 始终使用 Visual Studio 2022 作为生成器。
- 强化智能感知: 通过将配置职责完全交给 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 中显示为波浪线。 |