Skip to content

Commit 3ae74f0

Browse files
committed
Improve 1
1 parent 3f454b4 commit 3ae74f0

23 files changed

+368
-369
lines changed

docs/index.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,44 @@
1-
# 首页
1+
# **首页**
22

3-
## 教程简介
3+
## **教程简介**
44

55
本教程是 Vulkan 的入门教程,将系统讲解 Vulkan 图形与计算 API 的基础知识与实际应用。
66

77
教程将使用 C++ 编写代码,借助 Vulkan-Hpp 封装,充分利用 RAII 等现代 C++ 特性。
88

99
> 注:Vulkan-Hpp 是 Vulkan SDK 的官方组成部分,非第三方库
1010
11-
> 本教程正在重构与完善中,请注意甄别错误!
12-
1311
**教程大致内容如下:**
1412

1513
1. 介绍基础概念
1614
2. 配置开发环境
1715
3. 绘制第一个三角形
18-
4. 实现高级功能
19-
16+
4. 扩展基础功能
2017

2118

22-
## 代码说明
19+
## **代码说明**
2320

24-
教程将使用 C++ 编写代码,使用C++20标准,并使用以下工具链:
21+
教程将使用 C++ 编写代码,采用C++20标准,并使用以下工具链:
2522

2623
- [Vulkan SDK](https://lunarg.com/vulkan-sdk/)
2724
- [GLM](http://glm.g-truc.net/) 线性代数库
2825
- [GLFW](http://www.glfw.org/) 窗口库
2926
- [CMake](https://cmake.org/) 构建系统
3027
- [vcpkg](https://vcpkg.io/) 依赖管理
3128

32-
正如教程名,我会使用 Vulkan SDK 为C++提供的 `vulkan-hpp` 封装,且使用内部的 `raii` 封装,使用更加现代的C++接口。
29+
正如教程名,我会使用 Vulkan SDK 为C++提供的 `vulkan-hpp` 封装,且使用内部的 `raii` 封装,它提供了更现代的C++接口。
3330

3431

35-
虽然 `vulkan-hpp` 提供了模块支持,但是我们还需要使用 `glfw3` 库和 `glm` 库,将他们模块化是比较繁琐的
36-
这超出了本教程的目的,因此不使用C++20的模块功能。
32+
虽然 `vulkan-hpp` 提供了模块支持,但是我们还需要使用 `glfw3` 库和 `glm` 库,将它们模块化是比较繁琐的
33+
这超出了本教程的范围,因此不使用C++20的模块功能。
3734

38-
> C++23 的标准库模块与标准库头文件似乎是冲突的,这很可能导致显著延缓C++社区模块化的进度
35+
> C++23 的标准库模块与标准库头文件似乎是冲突的,这很可能显著延缓C++社区模块化的进度
3936
4037
`CMake` 用于项目构建,实现跨平台的项目,但要求读者了解CMake基础使用。
4138

4239
`Vcpkg` 用于管理第三方库,主要用于安装 `glfw3``glm`,这非常简单。
4340

44-
## 其他说明
41+
## **其他说明**
4542

4643
Vulkan SDK本身由C编写,这带来更好的跨语言能力,可以其他语言调用C接口。
4744

@@ -53,7 +50,7 @@ Vulkan SDK本身由C编写,这带来更好的跨语言能力,可以其他语
5350

5451

5552

56-
## 项目参考资料
53+
## **项目参考资料**
5754

5855
Vulkan-hpp文档 [vulkan-hpp](https://github.com/KhronosGroup/Vulkan-Hpp)
5956

docs/md/0000_intro.md

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
1-
# 项目介绍
1+
# **项目介绍**
22

3-
## Vulkan 技术概览
3+
## **Vulkan 技术概览**
44

5-
### 什么是 Vulkan?
5+
### Vulkan是什么
66

77
Vulkan 是 [Khronos Group](https://www.khronos.org/) 推出的**现代图形与计算 API**。与传统 API (如[OpenGL](https://en.wikipedia.org/wiki/OpenGL)[Direct3D](https://en.wikipedia.org/wiki/Direct3D))相比,它为显卡提供了更好的抽象,使你可以更好的描述应用程序的行为,从而带来更好的性能和减少意外的驱动程序行为。
88

99
### 与传统API的关键差异
1010

1111
| 维度 | OpenGL/D3D11 | Vulkan |
1212
|-----------------|----------------------|----------------------|
13-
| 驱动开销 | 高(隐式状态管理) | 低(显式声明) |
13+
| 驱动开销 | 高(由驱动隐式管理状态) | 低(需开发者显式声明) |
1414
| 线程模型 | 单线程主导 | 原生多线程支持 |
1515
| 着色器编译 | 运行时GLSL编译 | 预编译SPIR-V字节码 |
1616
| 内存管理 | 驱动自动分配 | 开发者控制内存类型 |
1717

1818
这些好处的代价是你必须使用更细致的 API,每个细节都需要由您的应用程序从头开始设置,这意味着您必须在应用程序中执行更多工作以确保正确的行为。
1919

20-
### 什么人适合Vulkan
20+
## **什么人适合Vulkan**
2121

2222
Vulkan 并不适合所有人。它针对的是热衷于高性能计算机图形学并愿意投入一些工作的程序员。
2323

2424
如果您主要对游戏开发感兴趣,那么 OpenGL 或 Direct3D 可能更适合您,因为它们的上手难度相对较低,且在多数场景下仍然能够满足需求。
2525

2626
另一种选择是使用 [Unreal Engine](https://en.wikipedia.org/wiki/Unreal_Engine#Unreal_Engine_4)[Unity](https://en.wikipedia.org/wiki/Unity_(game_engine)) 这样的游戏引擎。这些引擎可以利用 Vulkan 的高性能特性,同时为开发者提供更易用的高级 API,从而在不牺牲太多性能的前提下显著降低开发难度。
2727

28-
## 学习前提
28+
## **学习前提**
2929

3030
### 硬件要求
3131
- 支持 Vulkan 的显卡(NVIDIA/AMD/Intel/Apple Silicon)
3232
- 较新的显卡驱动
3333

3434
### 软件技能
35-
3635
- 熟练的现代 C++ 编程能力(RAII、初始化列表等)
3736
- CMake 和 vcpkg 基础使用经验
3837

@@ -44,20 +43,10 @@ Vulkan 是 [Khronos Group](https://www.khronos.org/) 推出的**现代图形与
4443

4544
强烈推荐先修课程: [GAMES101-现代计算机图形学入门](https://www.bilibili.com/video/BV1X7411F744)
4645

47-
## 绘制三角形
46+
## **绘制三角形**
4847

4948
在编程语言中,常常将打印`Hello World!`作为学习的开始。而图形引擎的学习将从第一个三角形的绘制开始。
5049

51-
### 验证层(Validation Layer)
52-
53-
Vulkan 采用"默认高性能"的设计哲学,其调试系统具有以下关键特性:
54-
55-
1. 默认情况下,错误检查和调试功能非常有限
56-
2. 允许您通过称为验证层的功能启用广泛的检查
57-
3. 可以在开发期间启用它们,然后在发布应用程序时完全禁用
58-
59-
任何人都可以编写自己的验证层,但 LunarG 的 Vulkan SDK 提供了一组标准的验证层,我们将在本教程中使用它。
60-
6150
### 绘制三角形需要什么
6251

6352
绘制一个三角形远比你想象的复杂,初学者很难快速理解各组件的作用。
@@ -69,54 +58,55 @@ Vulkan 采用"默认高性能"的设计哲学,其调试系统具有以下关
6958

7059
1. 首先我们需要创建一个新世界,初始化天空地面和机器人之类的设置。这就是实例 `VkInstance`
7160

72-
2. 我们希望有东西帮我们检查错误,这就是验证层 `Validation Layer`
61+
2. 我们希望有东西在开发时帮我们检查错误,这就是验证层 `Validation Layer`
7362

7463
3. 然后我们需要找一些合适的机器人帮我们画画,也就是物理设备 `VkPhysicalDevice` ,常代指GPU。
7564

7665
4. 这些机器人有的支持画画有的不支持,所以我们需要检查机器人(GPU)的特征。
7766

78-
5. 机器人有很多机械臂,有的机械臂可以画画,有的不仅能画画还能扫地。我们需要选择合适的机械臂去完成任务。一个机械臂对应一个队列`VkQueue`,它表示GPU的功能。一堆支持特定功能的机械臂称为队列族`VkQueueFamily`,比如绘画队列族。
67+
5. 机器人有很多机械臂,有的机械臂可以画画,有的不仅能画画还能扫地。我们需要选择合适的机械臂去完成任务。一个机械臂对应一个队列 `VkQueue` ,它表示GPU的功能。一组支持特定功能的机械臂称为队列族 `VkQueueFamily` ,比如绘画队列族。
7968

8069
6. 机器人(GPU)的型号不一样,但你希望操作的方式都一样,于是设计了统一的接口,这就是逻辑设备 `VkDevice` ,用于抽象物理设备。
8170

82-
7. 你希望通过一个屏幕看画(实时渲染),这个屏幕就是第三方的窗口系统,我们使用`GLFW`
71+
7. 你希望通过一个屏幕看画(实时渲染),这个屏幕就是第三方的窗口系统,我们使用 `GLFW`
8372

84-
8. 我们需要一个工具,将画作扫描进屏幕,这个扫描仪就是窗口表面`VkSurfaceKHR`
73+
8. 我们需要一个工具,将画作扫描进屏幕,这个扫描仪就是窗口表面 `VkSurfaceKHR`
8574

86-
9. 你看画的速度和机器人画画速度不一样,为了提高效率,可以用一个盒子作为缓冲。机器人往盒子里放画,扫描仪从盒子里拿画。这个盒子就是交换链`VkSwapchainKHR`
75+
9. 你看画的速度和机器人画画速度不一样,为了提高效率,可以用一个盒子作为缓冲。机器人往盒子里放画,扫描仪从盒子里拿画。这个盒子就是交换链 `VkSwapchainKHR`
8776

88-
10. 特别的是,这些画画的纸可以重复使用,所以盒子里的纸的总数是固定的。这些纸就是图像`VkImage`,交换链中的图像总数固定。
77+
10. 特别的是,这些画画的纸可以重复使用,所以盒子里的纸的总数是固定的。这些纸就是图像 `VkImage` ,交换链中的图像总数固定。
8978

90-
11. 不同的纸可能有不同的材质和大小,所以我们需要给每个纸写一个标签。这个标签就是图像视图`VkImageView`,描述图像的基本信息。
79+
11. 不同的纸可能有不同的材质和大小,所以我们需要给每个纸写一个标签。这个标签就是图像视图 `VkImageView` ,描述图像的基本信息。
9180

92-
12. 现在机器人终于可以画画了,我们要为他准备一个画架,用来放画纸。这个画架就是帧缓冲`VkFrameBuffer`,一帧代指一副图像。
81+
12. 现在机器人终于可以画画了,我们要为他准备一个画架,用来放画纸。这个画架就是帧缓冲 `VkFrameBuffer` ,一帧代指一副图像。
9382

94-
13. 我们还要为机器人设计一个房子,房子里放着画笔、颜料等工具,还有一台用于清洗(重置)画纸的机器。这个房子就是渲染通道`VkRenderPass`,而画笔和机器等工具就是附件`Attachments`
83+
13. 我们还要为机器人设计一个房子,房子里放着画笔、颜料等工具,还有一台用于清洗(重置)画纸的机器。这个房子就是渲染通道 `VkRenderPass` ,而画笔和机器等工具就是附件 `Attachments`
9584

96-
14. 当画作变得更加复杂,我们可以在一个房子里放多个小房间,每个房间干不同的事情,这些小房间就是子通道`VkSubpass`
85+
14. 当画作变得更加复杂,我们可以在一个房子里放多个小房间,每个房间干不同的事情,这些小房间就是子通道 `VkSubpass`
9786

98-
15. 机器人很笨,只能看着流程图画画,所以你需要在房间中放置一些流程图,可以是一张,也可以是多张。这个流程图就是图形管线`VkPipeline`
87+
15. 机器人很笨,只能看着流程图画画,所以你需要在房间中放置一些流程图,可以是一张,也可以是多张。这个流程图就是图形管线 `VkPipeline`
9988

100-
16. 我们有一份流程图的模版,只需要修改它的部分内容就可以变成新的流程图。其中某几个部分是可编程的,这里就用到了我们熟悉的着色器模块`Shader Model`
89+
16. 我们有一份流程图的模版,只需要修改它的部分内容就可以变成新的流程图。其中某几个部分是可编程的,这里就用到了我们熟悉的着色器模块 `Shader Model`
10190

102-
17. 这些机器人很呆,需要你写信告诉他该画一幅画了,要在哪个房子哪些房间根据哪些流程图画画。这个信就是命令缓冲`VkCommandBuffer`。你需要先写信才能寄信,我们也必须先录制完命令,然后才能提交。
91+
17. 这些机器人很呆,需要你写信告诉他该画一幅画了,要在哪个房子的哪些房间根据哪些流程图画画。这个信就是命令缓冲`VkCommandBuffer`。你需要先写信才能寄信,我们也必须先录制完命令,然后才能提交。
10392

104-
18. 特殊的是,这些信可以重用,所以我们使用一个命令池`VkCommandPool`管理这些资源。
93+
18. 特殊的是,这些信可以重用,所以我们使用一个命令池 `VkCommandPool` 管理这些资源。
10594

106-
19. 事情一多,机器人做起来就乱了。要保证他先画画,画完才能把画拿出去,所以我们用信号量`Semaphore`处理GPU自身的同步。还要保证机器人先完成一张画,我们再寄出新的信,所以我们使用围栏`Fence`处理CPU和GPU之间的同步。
95+
19. 事情一多,机器人做起来就乱了。要保证他先画画,画完才能把画拿出去,所以我们用信号量 `Semaphore` 处理GPU自身的同步。还要保证机器人先完成一张画,我们再寄出新的信,所以我们使用围栏 `Fence` 处理CPU和GPU之间的同步。
10796

108-
20. 显然你写信和机器人画画可以同时进行,所以实际可能有两幅甚至更多的画被同时制作。这些画被称为飞行中的帧`frames in flight`,指代处于流水线不同阶段但都在工作中的帧。
97+
20. 显然你写信和机器人画画可以同时进行,所以实际可能有两幅甚至更多的画被同时制作。这些画被称为飞行中的帧 `frames in flight` ,指代处于流水线不同阶段但都在工作中的帧。
10998

11099
绘制第一个三角形大致就是这些内容,你目前**不需要记住**,在后面的学习中随时可以回顾此内容。
111100

112-
#### 注意
101+
### 注意
113102

114103
上面的描述是**非常简化**的,与各个模块具体的功能并**不完全一致**。 这有助于初学者的理解,但当你学完具体内容,应当去理解他们更加准确的意义。
115104

116-
###
117-
118-
由于大量的初始化工作,仅仅是绘制一个三角形就需要接近800行代码。但在后续的过程中,你会逐渐理解以及这些繁琐步骤的巨大意义。且在完成了第一个三角形后,后续扩展纹理和 3D 模型不再需要那么多重复工作。
105+
## **最后**
119106

107+
由于大量的初始化工作,仅仅是绘制一个三角形就需要约700行代码。
108+
但在后续的过程中,你会逐渐理解以及这些繁琐步骤的巨大意义。
109+
且在完成了第一个三角形后,后续扩展纹理和 3D 模型不再需要那么多重复工作。
120110

121111
---
122112

docs/md/0001_env.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# 开发环境
1+
# **开发环境**
22

3-
## 概述
3+
## **概述**
44
本文将指导你完成Vulkan应用程序开发环境的设置,包括安装必要的工具和库。
55

66
注意,CMake和Vcpkg自身的安装,以及MSVC/Clang等编译器的安装,不是本教程的内容。
77

8-
## Vulkan SDK安装
8+
## **Vulkan SDK安装**
99
Vulkan SDK是开发Vulkan应用程序的核心组件,包含:
1010

1111
- 头文件
@@ -77,7 +77,7 @@ vkcube
7777

7878
![cube](../images/cube_demo_mac.png)
7979

80-
## 依赖库安装
80+
## **依赖库安装**
8181

8282
我们使用Vcpkg作为跨平台包管理器。
8383

@@ -100,8 +100,10 @@ vcpkg install glfw3
100100
vcpkg install glm
101101
```
102102

103-
## 项目初始化
103+
## **项目初始化**
104+
104105
### 目录结构
106+
105107
```
106108
项目根目录/
107109
@@ -121,6 +123,7 @@ vcpkg install glm
121123
5. 链接库。
122124

123125
**参考代码:**
126+
124127
```cmake
125128
# CMakeLists.txt
126129
cmake_minimum_required(VERSION 3.30)
@@ -155,6 +158,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE glfw )
155158
注意,`CMakeLists.txt`代码将在较长时间内不再变动,因此后面几章只给出C++代码。
156159

157160
### 测试代码
161+
158162
添加测试代码,测试三个库是否正常:
159163

160164
```cpp
@@ -200,6 +204,7 @@ int main() {
200204
你无需理解上述C++代码的含义,这只是测试库是否成功导入。
201205

202206
### 构建运行
207+
203208
下面尝试构建和运行程序,在项目根目录执行:
204209

205210
```shell

docs/md/0002_diff.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# 接口介绍
1+
# **接口介绍**
22

3-
## 接口概述
3+
## **接口概述**
44

55
Vulkan提供了两种编程接口风格:
66

@@ -60,8 +60,7 @@ Vulkan-hpp封装与底层C风格接口略有不同,下面将为你粗略展示
6060
- RAII封装位于`vk::raii`
6161

6262
2. **改进特性**
63-
- 枚举值作为类成员而非宏,附带带`e`前缀
64-
- 使用 `Flag` `Bit` 区分特殊的枚举类型。
63+
- 使用 `Flags``Bit``e` 区分特殊的枚举类型。
6564
- 构造函数和资源创建函数直接返回对象
6665
- 提供RAII支持,无需手动清理资源
6766
- 使用异常机制处理错误
@@ -84,7 +83,7 @@ Vulkan-hpp封装与底层C风格接口略有不同,下面将为你粗略展示
8483
}
8584
```
8685

87-
## vk::raii::基本原理
86+
## **vk::raii基本原理**
8887

8988
`vk::raii::` 是 Vulkan-HPP 中提供的 RAII 包装器,用于自动化资源管理。
9089

@@ -121,7 +120,7 @@ someFunction(*semaphore); // 使用 * 运算符获取内部原始引用
121120
```
122121
123122
124-
## 核心差异总结
123+
## **核心差异总结**
125124
126125
| 特性 | C接口 | C++封装 |
127126
|-----------------|-------------------------------|------------------------------|
@@ -134,7 +133,7 @@ someFunction(*semaphore); // 使用 * 运算符获取内部原始引用
134133
135134
> 提示:本教程将主要使用C++ RAII封装,既保持现代C++风格,又简化资源管理。
136135
137-
## 最后
136+
## **代码编辑器**
138137
139138
建议使用一个足够智能的编辑器。
140139
当你不确定某些函数的参数和它的含义时,可以右键函数并跳转到它的定义,从而查看函数参数列表。Visual Studio/VSCode/CLion都能提供此功能。

docs/md/0100_base.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# 基础代码
1+
# **基础代码**
22

3-
## 总体结构
3+
## **总体结构**
44
在上一章中,您已经创建了一个 Vulkan 项目,其中包含所有正确的配置,并使用示例代码进行了测试。
55

6-
在本章中,我们将从以下代码从头开始,请修改`main.cpp`
6+
在本章中,我们将从以下代码开始,请修改`main.cpp`
77

88
```cpp
99
#include <vulkan/vulkan.hpp>
@@ -56,7 +56,7 @@ int main() {
5656
1. **头文件包含**
5757
- `vulkan.hpp`:基础C++封装
5858
- `vulkan_raii.hpp`:资源自动管理封装
59-
- 其他标准库用于异常处理和内存管理
59+
- 其他标准库用于异常处理、内存管理和简化代码
6060

6161
2. **错误处理**
6262
- `vk::SystemError`专门处理Vulkan相关错误
@@ -67,7 +67,7 @@ int main() {
6767
- 将初始化、资源清理、主循环分离,结构清晰。
6868

6969

70-
## 集成 GLFW
70+
## **集成 GLFW**
7171
离屏渲染无需窗口也能完美运行,但我们希望显示一些东西!
7272

7373
### 1. 添加GLFW支持
@@ -117,13 +117,14 @@ private:
117117
// 创建窗口
118118
m_window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
119119
}
120+
...
120121
};
121122
```
122123
123-
`glfwCreateWindow` 前三个参数指定窗口的宽度、高度和标题。
124+
`glfwCreateWindow` 前三个参数指定窗口的宽度、高度和标题。
124125
第四个参数可以指定显示器以及是否全屏,最后一个参数仅与 OpenGL 相关。
125126
126-
> `m_`用于区分是不是成员变量
127+
> `m_` 前缀用于区分是不是成员变量
127128
128129
### 4. 添加主循环
129130
@@ -147,17 +148,7 @@ void cleanup() {
147148
}
148149
```
149150

150-
## 代码结构解析
151-
152-
| 组件 | 功能说明 |
153-
|------|----------|
154-
| `initWindow()` | 初始化GLFW并创建窗口 |
155-
| `initVulkan()` | 后续将初始化Vulkan相关资源 |
156-
| `mainLoop()` | 处理事件和渲染循环 |
157-
| `cleanup()` | 释放所有资源 |
158-
159-
160-
## 尝试运行
151+
## **尝试运行**
161152

162153
现在运行程序,您应该看到一个标题为 Vulkan 的窗口出现,直到应用程序在窗口关闭时终止。
163154

0 commit comments

Comments
 (0)