Add chapter on mipmapping#72
Conversation
| ```c++ | ||
| barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; | ||
| barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | ||
| barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
There was a problem hiding this comment.
srcAccessMask should probably be VK_ACCESS_TRANSFER_READ_BIT here since the (LAYOUT_TRANSFER_SRC_OPTIMAL) image was read, not written.
|
Thank you very much for writing this! I'll review it and get back to you. |
| mipLevels = 1; | ||
| int32_t mipWidth = texWidth; | ||
| int32_t mipHeight = texHeight; | ||
| while (mipWidth > 1 && mipHeight > 1) { |
There was a problem hiding this comment.
Replace this with a logarithm calculation. The loop in the generateMipmaps function is fine.
There was a problem hiding this comment.
This is how I calculate number of mips in my runtime mip-map generation example:
texture.mipLevels = floor(log2(std::max(texture.width, texture.height))) + 1;
This matches the Vulkan/GL specs on how number of mip levels is calculated.
| ``` | ||
| This will leave each level of the texture image in `VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL`. | ||
|
|
||
| We're now going to write the function generates the mip maps: |
| 1, &blit, VK_FILTER_LINEAR); | ||
| ``` | ||
|
|
||
| Now, we record the blit command. Note that `textureImage` is used for both the `srcImage` and `dstImage` parameter. 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`. The last parameter says to use a linear filter when scaling the data. |
There was a problem hiding this comment.
Mention VkFilter and that you have the same interpolation options as with texture sampling in general
| We're now going to write the function generates the mip maps: | ||
|
|
||
| ```c++ | ||
| void generateMipmaps(int32_t texWidth, int32_t texHeight) { |
There was a problem hiding this comment.
Make it a bit more generic by making the image and miplevels parameters.
|
|
||
|  | ||
|
|
||
| The left image is our new program. The right image is our program without mipmaps. The most noticeable difference is the writing on the signs. With mipmaps, the writing has been blurred. Without mipmaps, the writing has harsh edges and gaps from Moiré artifacts. |
There was a problem hiding this comment.
Perhaps change "blurred" to "smoothed" since this is arguably a desirable change
|
|
||
|  | ||
|
|
||
| This is how higher mip levels will be used when objects are further away from the camera. |
|
I think it would be good idea to add a chapter on anisotropic filtering. If you're going to use mip maps you're most of the time also going to use anisotropic filtering. |
| } | ||
| ``` | ||
|
|
||
| This configures the sampler to sample from all mip levels up to `mipLevels`. |
There was a problem hiding this comment.
It would be nice to add some explanation why minLod and maxLoad are floats and what mipLodBias does. You can direct readers who want to learn all the advanced details to https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#textures-level-of-detail-operation
|
@SaschaWillems The chapter about image views and samplers already mentions anisotropic filtering, but it may be nice to mention it again in the mipmapping chapter. |
Use a single word for consistency
|
Thanks for the feedback. I've added most of changes suggested. I'm not sure what to write regarding anisotropic filtering, since the specification doesn't specify how mipmapping affects it. How did you get the image used for anisotropic filtering in the "Image view and sampler" chapter? Did you make it yourself, or did you find it somewhere? |
Make formatting consistent with other chapters
|
@vazgriz Yeah, I made that image in Blender :) I guess we can skip anisotropic filtering for now. I'll do a final review tomorrow and if it looks good, then I'll merge and publish it. |
| You can play around with the sampler settings to see how they affect mipmapping. For example, by changing `minLod`, you can force the sampler to not use the lowest mip levels: | ||
|
|
||
| ```c++ | ||
| samplerInfo.minLod = static_cast<float>(mipLevels / 2); |
|
|
||
| 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`. | ||
|
|
||
| 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. |
|
If you could just fix the remaining comments (the two just now and the |
|
Done |
|
Could you update the text to reflect your change to |
|
Ok. I think this has to be done a new pull request. See #74 |
I've written a chapter that explains how to generate mip maps. I figured this was a basic effect that fell under the scope of vulkan-tutorial.com. This chapter comes after Model Loading.