You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -12,19 +12,19 @@ In Vulkan, each of the mip images is stored in different *mip levels* of a `VkIm
12
12
The number of mip levels is specified when the `VkImage` is created. Up until now, we have always set this value to one. We need to calculate the number of mip levels from the dimensions of the image. First, add a class member to store this number:
13
13
14
14
```c++
15
-
...
16
-
uint32_t mipLevels;
17
-
VkImage textureImage;
18
-
...
15
+
...
16
+
uint32_t mipLevels;
17
+
VkImage textureImage;
18
+
...
19
19
```
20
20
21
21
The value for `mipLevels` can be found once we've loaded the texture in `createTextureImage`:
@@ -33,32 +33,32 @@ This calculates the number of levels in the mip chain. The `max` function select
33
33
To use this value, we need to change the `createImage` and `createImageView` functions to allow us to specify the number of mip levels. Add a `mipLevels` parameter to the functions:
@@ -70,147 +70,146 @@ Our texture image now has multiple mip levels, but the staging buffer can only b
70
70
Like other image operations, `vkCmdBlitImage` depends on the layout of the image it operates on. For optimal performance, the source image should be in `VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL` and the destination image should be in `VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL` while blitting data. Vulkan allows us to transition each mip level of an image independently. `transitionImageLayout` only performs layout transitions on the entire image, so we'll need to write a few more pipeline barrier commands. First, remove the existing transition to `VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL` in `createTextureImage`:
Next, we specify the regions that will be used in the blit operation. The source mip level is `i - 1` and the destination mip level is `i`. The two elements of the `srcOffsets` array determine the 3D region that data will be blitted from. `dstOffsets` determines the region that data will be blitted to. The X and Y dimensions of the `dstOffsets[1]` are divided by two since each mip level is half the size of the previous level. The Z dimension of `srcOffsets[1]` and `dstOffsets[1]` must be 1, since a 2D image has a depth of 1.
149
149
150
150
```c++
151
-
vkCmdBlitImage(commandBuffer,
152
-
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
153
-
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
154
-
1, &blit,
155
-
VK_FILTER_LINEAR);
151
+
vkCmdBlitImage(commandBuffer,
152
+
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
153
+
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
154
+
1, &blit,
155
+
VK_FILTER_LINEAR);
156
156
```
157
157
158
158
Now, we record the blit command. Note that `textureImage` is used for both the `srcImage` and `dstImage` parameter. This is because we're blitting between different levels of the same image. The source mip level was just transitioned to `VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL` and the destination level is still in `VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL` from `createTextureImage`.
159
159
160
160
The last parameter allows us to specify a `VkFilter` to use in the blit. We have the same filtering options here that we had when making the `VkSampler`. We use the `VK_FILTER_LINEAR` to enable filtering.
This barrier transitions mip level `i - 1` to `VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL`.
176
176
177
177
```c++
178
-
...
179
-
if (mipWidth > 1) mipWidth /= 2;
180
-
if (mipHeight > 1) mipHeight /= 2;
181
-
}
178
+
...
179
+
if (mipWidth > 1) mipWidth /= 2;
180
+
if (mipHeight > 1) mipHeight /= 2;
181
+
}
182
182
```
183
183
184
184
At the end of the loop, we divide the current mip dimensions by two. We check each dimension before the division to ensure that dimension never becomes 0. This handles cases where the image is not square, since one of the mip dimensions would reach 1 before the other dimension. When this happens, that dimension should remain 1 for all remaining levels.
Before we end the command buffer, we insert one more pipeline barrier. This barrier transitions the last mip level from `VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL` to `VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL`, since that wasn't handled by the loop.
205
204
206
205
Finally, add the call to `generateMipmaps` in `createTextureImage`:
Our texture image's mipmaps are now completely filled.
@@ -220,43 +219,43 @@ Our texture image's mipmaps are now completely filled.
220
219
While the `VkImage` holds the mipmap data, `VkSampler` controls how that data is read while rendering. Vulkan allows us to specify `minLod`, `maxLod`, `mipLodBias`, and `mipmapMode` ("Lod" means "Level of Detail"). When a texture is sampled, the sampler selects a mip level according to the following pseudocode:
221
220
222
221
```c++
223
-
lod = getLodLevelFromScreenSize(); //smaller when the object is close, may be negative
224
-
lod = clamp(lod + mipLodBias, minLod, maxLod);
225
-
226
-
level = clamp(floor(lod), 0, texture.mipLevels - 1); //clamped to the number of mip levels in the texture
227
-
228
-
if (mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST) {
229
-
color = sample(level);
230
-
} else {
231
-
color = blend(sample(level), sample(level + 1));
232
-
}
222
+
lod = getLodLevelFromScreenSize(); //smaller when the object is close, may be negative
223
+
lod = clamp(lod + mipLodBias, minLod, maxLod);
224
+
225
+
level = clamp(floor(lod), 0, texture.mipLevels - 1); //clamped to the number of mip levels in the texture
226
+
227
+
if (mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST) {
228
+
color = sample(level);
229
+
} else {
230
+
color = blend(sample(level), sample(level + 1));
231
+
}
233
232
```
234
233
235
234
If `samplerInfo.mipmapMode` is `VK_SAMPLER_MIPMAP_MODE_NEAREST`, `lod` selects the mip level to sample from. If the mipmap mode is `VK_SAMPLER_MIPMAP_MODE_LINEAR`, `lod` is used to select two mip levels to be sampled. Those levels are sampled and the results are linearly blended.
236
235
237
236
The sample operation is also affected by `lod`:
238
237
239
238
```c++
240
-
if (lod <= 0) {
241
-
color = readTexture(uv, magFilter);
242
-
} else {
243
-
color = readTexture(uv, minFilter);
244
-
}
239
+
if (lod <= 0) {
240
+
color = readTexture(uv, magFilter);
241
+
} else {
242
+
color = readTexture(uv, minFilter);
243
+
}
245
244
```
246
245
247
246
If the object is close to the camera, `magFilter` is used as the filter. If the object is further from the camera, `minFilter` is used. Normally, `lod` is non-negative, and is only 0 when close the camera. `mipLodBias` lets us force Vulkan to use lower `lod` and `level` than it would normally use.
248
247
249
248
To see the results of this chapter, we need to choose values for our `textureSampler`. We've already set the `minFilter` and `magFilter` to use `VK_FILTER_LINEAR`. We just need to choose values for `minLod`, `maxLod`, `mipLodBias`, and `mipmapMode`.
To allow the full range of mip levels to be used, we set `minLod` to 0, and `maxLod` to the number of mip levels. We have no reason to change the `lod` value , so we set `mipLodBias` to 0.
0 commit comments