Skip to content

Commit c784b6f

Browse files
committed
Improve 3
1 parent 3994080 commit c784b6f

File tree

10 files changed

+106
-102
lines changed

10 files changed

+106
-102
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
备用站点:<https://vulkan.mysvac.com>
3535

36-
> 注意:文档代码已经完善,部分文字描述正在改善中
36+
> 如有错误,请提交Issue或PR
3737
3838
### 教程简介
3939

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Vulkan SDK本身由C编写,这带来更好的跨语言能力,可以其他语
4747

4848
- 基于Vulkano封装的Rust教程 [Vulkan-tutorial-rs](https://github.com/bwasty/vulkan-tutorial-rs)
4949

50-
50+
> 如果你发现了文档的错误,请点击右上角前往Github仓库,提交 Issue 或 PR 。
5151
5252
## **项目参考资料**
5353

docs/md/0400_texture.md

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# 纹理
1+
# **纹理**
22

3-
## 前言
3+
## **前言**
44

55
我们将从这一节开始使用纹理映射让图像看起来更加有趣,这也是为后面的3D模型章节打基础。
66

@@ -11,32 +11,33 @@
1111
3. 创建图像采样器
1212
4. 添加组合图像采样器描述符,以从纹理获取颜色
1313

14-
为了让着色器读取纹理,我们需要一个目标图像\(有Dsc标志的VkImage\),就像我们之前的最终顶点缓冲。
15-
16-
我们直接已经使用过交换链创建的图像对象`vk::Image`,现在我们需要创建自己的图像对象。
14+
为了让着色器读取纹理,我们需要一个着色器可读图像\(有ShaderRead标志的VkImage\)
15+
我们之前已经使用过交换链创建的图像对象`vk::Image`,现在我们需要创建自己的图像对象。
1716

1817
要让着色器读取,资源位于显存,CPU无法直接写入,我们需要通过缓冲\(VkBuffer\)或暂存图像\(有Src的VkImage\)中转数据。
1918

20-
我们可以使用暂存图像,但使用缓冲时的性能往往不低于暂存图像,在某些硬件上更快
19+
使用暂存缓冲的性能往往不低于暂时图像,所以本教程使用第一种方式
2120

22-
我们首先创建此缓冲区并用像素值填充,然后创建一个图像将像素复制到其中。这和之前的顶点缓冲过程基本一致。
21+
我们先创建此缓冲区并用像素值填充,然后创建一个图像将像素复制到其中。这和之前的顶点缓冲过程基本一致。
2322

2423
不过我们还需要注意一些事情,图像可以有不同的布局,这些布局会影响图像在内存中的组织方式。
25-
由于显卡的工作模式,按行存储图像资源未必带来最佳性能表现,我们我们需要为图像指定合适的布局方式
24+
由于显卡的工作模式差异,按行存储图像资源未必带来最佳性能表现,我们需要为图像指定合适的布局方式
2625

27-
实际上我们在创建渲染通道时已经接触过了一些布局,它们都在`vk::ImageLayout`枚举类型中
26+
实际上我们在创建渲染通道时已经接触过了一些布局:
2827

29-
| 布局类型 | 含义 |
30-
|--------------|----------------|
28+
| `vk::ImageLayout` | 含义 |
29+
|-----------------------|----------------|
3130
| `ePresentSrcKHR` | 优化呈现 |
3231
| `eColorAttachmentOptimal` | 优化色彩的修改 |
3332
| `eTransferSrcOptimal` | 资源传输时作为源优化 |
3433
| `eTransferDstOptimal` | 资源传输时作为目标优化 |
3534
| `eShaderReadOnlyOptimal` | 优化着色器采样 |
3635

37-
一种常见的修改图像布局的方式是使用管线屏障(pipeline barrier),在本章节我们会向你展示。
36+
一种常见的修改图像布局的方式是使用管线屏障(pipeline barrier),我们会在本章节中向你展示。
37+
38+
> 另一种常见的方式是交给渲染通道处理,就像我们的颜色附件一样。
3839
39-
## 图像库
40+
## **图像库**
4041

4142
Vulkan不含内置的图像/模型加载工具,你需要使用第三方库,或者自己写一个程序加载简单的图像数据。
4243

@@ -61,7 +62,7 @@ find_package(Stb REQUIRED)
6162
target_include_directories(${PROJECT_NAME} PRIVATE ${Stb_INCLUDE_DIR})
6263
```
6364

64-
## 加载图像
65+
## **加载图像**
6566

6667
现在在程序中添加头文件从而导入库:
6768

@@ -94,7 +95,7 @@ void createTextureImage() {
9495
现在在项目根目录创建一个新文件夹 `textures` 用于存放图像资源,文件夹与 `shaders` 平级。
9596
本教程将使用 [CC0 licensed image](https://pixabay.com/en/statue-sculpture-fig-historically-1275469/),你可以使用自己喜欢的图像。
9697

97-
我们已经将此图像修改成了 512*512 像素,并改名为 `texture.jpg`,你可以直接点击下方的图像并保存:
98+
原教程已经将此图像修改成了 512*512 像素,并改名为 `texture.jpg`,你可以直接点击下方的图像并保存:
9899

99100
![texture.jpg](../images/texture.jpg)
100101

@@ -115,10 +116,9 @@ void createTextureImage() {
115116
我们使用 `STBI_rgb_alpha` 让他强制加载4通道,缺少的通道会自动补齐。
116117
一个像素一个通道是1Byte,可以轻松算出图片的总大小。
117118

118-
## 暂存缓冲
119+
## **暂存缓冲**
119120

120-
我们需要创建一个主机可见缓冲用于暂存数据,就像创建顶点缓冲时的那样。
121-
`createTextureImage` 函数中添加两个临时变量:
121+
我们需要创建一个主机可见缓冲用于暂存数据,请在 `createTextureImage` **函数中**添加两个临时变量:
122122

123123
```cpp
124124
vk::raii::DeviceMemory stagingBufferMemory{ nullptr };
@@ -152,10 +152,10 @@ stagingBufferMemory.unmapMemory();
152152
stbi_image_free(pixels);
153153
```
154154

155-
## 纹理图像
155+
## **纹理图像**
156156

157157
我们还要让着色器能够访问缓冲中的像素值,最好的方式是使用 Vulkan 的图像对象。
158-
图像对象允许我们更简单且快速地使用2D坐标检索对应位置的颜色
158+
图像对象允许我们简单且快速地使用2D坐标检索对应位置的颜色
159159
图像对象中的像素们被称为纹素(texels),我们后面会使用此名称。
160160

161161
现在添加两个新的类成员,放在`m_swapChain`的上方:
@@ -183,7 +183,7 @@ imageInfo.arrayLayers = 1;
183183
我们使用 `imageType` 指定图像类型,可以是1D、2D和3D图像,它们在Vulkan中有不同的坐标系统。
184184
一维图像是一个数组,二维常用于存放纹理,三维图形则常用于存放立体元素(voxel volumes)。
185185

186-
`extent`自动指定了图像每个轴包含的纹素数,所以深度是1
186+
`extent`自动指定了图像每个轴包含的纹素数,所以 `depth` 是1
187187
我们暂时不使用mipmapping,所以`mipLevels`设为了1。
188188
我们只有一副图像,所以`arrayLayers`也为1。
189189

@@ -268,7 +268,7 @@ m_textureImage.bindMemory(m_textureImageMemory, 0);
268268

269269
上面的内存分配方式和缓冲区的分配几乎完全一致。
270270

271-
现在函数已经变得很大了,我们应该像前面缓冲区的创建一个,独立出一个辅助函数 `createImage` 以便后续重用代码:
271+
现在函数已经变得很大了,我们应该像前面缓冲区的做法一样,独立出一个辅助函数 `createImage` 以便后续重用代码:
272272

273273
```cpp
274274
void createImage(
@@ -353,7 +353,7 @@ void createTextureImage() {
353353
}
354354
```
355355

356-
## 布局转换
356+
## **布局转换**
357357

358358
我们现在要编写的函数再次涉及命令缓冲的记录和执行,现在是时候将此逻辑分离成两个独立函数了。
359359

@@ -387,7 +387,7 @@ void endSingleTimeCommands(vk::raii::CommandBuffer commandBuffer) {
387387
}
388388
```
389389
390-
> 使用`endSingleTimeCommands`时需要通过移动语义,将命令缓冲移入,函数结束时自动销毁。
390+
> 使用`endSingleTimeCommands`时需要通过移动语义将命令缓冲移入,函数结束时自动销毁。
391391
392392
现在可以优化 `copyBuffer` 函数:
393393
@@ -449,7 +449,7 @@ barrier.subresourceRange.baseArrayLayer = 0;
449449
barrier.subresourceRange.layerCount = 1;
450450
```
451451

452-
我们的图像不是数组,也没有 mipmapping 级别,因此只知道一个级别和层级
452+
我们的图像不是数组,也没有 mipmapping 级别,因此只有一个级别和层级
453453

454454
屏障主要用于同步,所以你必须指定屏障开始和等待的操作类型。
455455
及时我们通过其他方式进行了同步,也必须填写这两个参数。
@@ -487,7 +487,7 @@ commandBuffer.pipelineBarrier(
487487

488488
最后三个参数是三种管线屏障的代理数组,即内存屏障、缓冲内存屏障和图像内存屏障,我们只有图像内存屏障。
489489

490-
## 复制缓冲区内容到图像
490+
## **复制缓冲区内容到图像**
491491

492492
现在创建一个`copyBufferToImage`辅助函数,用于复制数据:
493493

@@ -538,9 +538,9 @@ commandBuffer.copyBufferToImage(
538538
);
539539
```
540540

541-
第四个参数接受代理数组,我们现在只将一块像素复制到整个读取,但你可以通过多个 `vk::BufferImageCopy` 信息在一次操作中实现多种不同的复制。
541+
第四个参数接受代理数组,我们现在只需要复制一块区域,但你可以通过多个 `vk::BufferImageCopy` 信息在一次操作中实现多种不同的复制。
542542

543-
## 准备纹理图像
543+
## **准备纹理图像**
544544

545545
现在我们回到`createTextureImage`函数,先调用刚才编写的布局转换函数,再调用数据复制函数:
546546

@@ -574,7 +574,7 @@ transitionImageLayout(
574574
);
575575
```
576576

577-
## 修改屏障掩码
577+
## **修改屏障掩码**
578578

579579
如果你现在运行程序,会发现验证层提示StageMask的设置不合法。
580580
我们现在需要设置 `transitionImageLayout` 中没有填写的`StageMask``AccessMask`
@@ -584,7 +584,7 @@ transitionImageLayout(
584584
1. undefined -> tranfer destination
585585
2. transfer destination -> shader read only
586586

587-
第一个变换时,我们不需要任何同步。第二个变变换时,我们需要保证着色器的读取在数据写入之后才能进行
587+
第一个变换时,我们不需要任何同步。第二个变换时,我们需要保证着色器在数据写入之后才能进行读取
588588

589589

590590
那么我们可以这样设置:
@@ -629,7 +629,7 @@ commandBuffer.pipelineBarrier(
629629

630630
图像将在同一管线阶段写入,随后由片段着色器读取,这就是为什么我们在片段着色器管线阶段指定着色器读取访问。
631631

632-
## 延伸
632+
## **延伸**
633633

634634
注意的一件事是,命令缓冲区提交会导致开始时隐式的 `vk::AccessFlagBits::eHostWrite` 同步,用于同步 CPU 和 GPU 之间的内存访问,保证了GPU图像管线转写发生在CPU命令提交之后。
635635

docs/md/0401_sampler.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# 图像视图与采样器
1+
# **图像视图与采样器**
22

33
本节我们将创建两个图形管线对图像进行采样所需的资源。
4-
第一个是图像视图(ImageView),我们在交换链的章节已经见过了。
5-
第二个是采样器,它决定了着色器如何读取图像中的纹素。
4+
第一个是图像视图\(ImageView\),我们在交换链的章节已经见过了。
5+
第二个是采样器\(Sampler\),它决定了着色器如何读取图像中的纹素。
66

7-
## 纹理图像视图
7+
## **纹理图像视图**
88

99
### 1. 创建纹理图像视图
1010

@@ -88,14 +88,14 @@ void createImageViews() {
8888
}
8989
```
9090

91-
## 采样器
91+
## **采样器**
9292

9393
### 1. 采样器介绍
9494

9595
虽然着色器可以之间从图像中读取纹素,但这对于纹理读取并不常见。
9696
纹理通常通过采样器读取,它可以对纹素实现一些过滤和变换操作然后得到最终色彩。
9797

98-
过滤器可以处理类似超采样的问题,考虑把纹理图像映射到一个像素更多的几何体,如果采样时直接选取最近的纹素,就会出现显著的马赛克效应,想下方的第一幅图片一样
98+
过滤器可以处理类似超采样的问题,考虑把纹理图像映射到一个像素更多的几何体,如果采样时直接选取最近的纹素,就会出现显著的马赛克效应,像下方的第一幅图片一样
9999

100100
![texture_filter](../images/texture_filtering.png)
101101

@@ -260,7 +260,7 @@ bool isDeviceSuitable(const vk::raii::PhysicalDevice& physicalDevice) {
260260
}
261261
```
262262
263-
当然除了强制启用,你也可以通过布尔值简单的不适应它
263+
当然除了强制启用,你也可以通过布尔值简单的禁用它
264264
265265
```cpp
266266
samplerInfo.anisotropyEnable = false;

docs/md/0402_combined.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# 组合图像采样器
1+
# **组合图像采样器**
22

3-
## 前言
3+
## **前言**
44

55
我们在uniform缓冲的章节介绍了一种描述符,本章我们将看到新的一种:组合图像采样器\(Combined image sampler\)
66
此描述符允许着色器通过采样器实例访问图像资源。
77

88
我们会修改描述符布局/池/集,从而加入一个组合图像采样器。
99
然后用我们的`Vertex`结构添加纹理坐标,并修改片段着色器让它使用纹理色彩。
1010

11-
## 更新描述符
11+
## **更新描述符**
1212

1313
### 1. 修改描述符布局
1414

@@ -55,7 +55,11 @@ poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
5555

5656
尽管驱动程序可能允许超限分配,但开发者仍应遵循描述符池的初始限制。这是为了避免潜在的性能问题或兼容性问题。
5757

58-
### 绑定描述符与图像和采样器资源
58+
> `maxSets` 指定描述符集合的最大数量
59+
> `poolSizeCount` 指定描述符集合的类型数
60+
> `descriptorCount` 指定单个描述符集合中描述符实例的数量
61+
62+
### 3. 绑定描述符与图像和采样器资源
5963

6064
最后一步是将实际的图像和采样器资源绑定到描述符集中的描述符。转到 `createDescriptorSets` 函数:
6165

@@ -75,9 +79,9 @@ for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
7579
}
7680
```
7781

78-
组合图像采样器的资源必须在 `vk::DescriptorImageInfo` 结构中指定,就像上面的uniform缓冲资源一样.
82+
组合图像采样器的资源必须在 `vk::DescriptorImageInfo` 结构中指定,就像之前的uniform缓冲资源一样。
7983

80-
必须使用此图像信息更新描述符,就像缓冲一样。这次我们使用 `ImageInfo` 数组而不是 `BufferInfo`
84+
必须使用此图像信息更新描述符,这次我们使用 `ImageInfo` 数组而不是 `BufferInfo`
8185

8286
```cpp
8387
std::array<vk::WriteDescriptorSet, 2> descriptorWrites;
@@ -97,12 +101,12 @@ m_device.updateDescriptorSets(descriptorWrites, nullptr);
97101

98102
描述符现在已准备好供着色器使用!
99103

100-
## 纹理坐标
104+
## **纹理坐标**
101105

102106
纹理映射还缺少一个重要的成分,那就是每个顶点的实际坐标。坐标决定了图像实际如何映射到几何体。
103107

104108
修改 `Vertex` 结构以包含纹理坐标的 `vec2`
105-
确保还添加 `vk::VertexInputAttributeDescription` ,以便我们可以在顶点着色器中使用纹理坐标作为输入。
109+
还需添加 `vk::VertexInputAttributeDescription` ,以便我们可以在顶点着色器中使用纹理坐标作为输入。
106110
这样才能将它们传递到片段着色器并在正方形表面上进行插值。
107111

108112
```cpp
@@ -155,7 +159,7 @@ inline static const std::vector<Vertex> vertices = {
155159

156160
在本教程中,我将通过使用从左上角的 `0, 0` 到右下角的 `1, 1` 的坐标来简单地用纹理填充正方形。然后尝试使用低于 0 或高于 1 的坐标来查看寻址模式的实际效果。你可以随意尝试不同的坐标!
157161

158-
## 着色器
162+
## **着色器**
159163

160164
### 1. 调试
161165

@@ -180,8 +184,6 @@ void main() {
180184
就像每个顶点的颜色一样,`fragTexCoord` 值将由光栅化器在正方形区域上平滑插值。
181185
我们可以通过让片段着色器将纹理坐标作为颜色输出,来可视化这一点
182186

183-
您应该看到类似下图的图像。不要忘记重新编译着色器!
184-
185187
```glsl
186188
#version 450
187189
@@ -250,15 +252,15 @@ void main() {
250252
}
251253
```
252254

253-
我在这里分离了 RGB 和 alpha 通道,以不缩放 alpha 通道
255+
我在这里分离了 RGB 和 alpha 通道,防止透明度被变换
254256

255257
![texture_on_square_colorized](../images/texture_on_square_colorized.png)
256258

257259
---
258260

259261
您现在知道如何在着色器中访问图像了!
260262

261-
当它与那些写入帧缓冲区的图像结合使用时是一种非常强大的技术
263+
当它与那些写入帧缓冲区的图像结合使用时具有非常强大的功能
262264
您可以使用这些图像作为输入来实现很酷的效果,例如后处理和 3D 世界中的相机显示。
263265

264266
---

0 commit comments

Comments
 (0)