Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f85e351

Browse files
committed
Updated introduction section in multisampling chapter.
1 parent 371c74a commit f85e351

2 files changed

Lines changed: 27 additions & 15 deletions

File tree

10_Multisampling.md

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
## Introduction
2-
Our program can now load and render 3D models. In this chapter, we will add one more feature, mipmap generation. Mipmaps are widely used in games and rendering software, and Vulkan gives us complete control over how they are created.
32

4-
Mipmaps are precalculated, downscaled versions of an image. Each new image is half the width and height of the previous one. Mipmaps are used as a form of *Level of Detail* or *LOD.* Objects that are far away from the camera will sample their textures from the smaller mip images. Using smaller images increases the rendering speed and avoids artifacts such as [Moiré patterns](https://en.wikipedia.org/wiki/Moir%C3%A9_pattern). An example of what mipmaps look like:
3+
Our program can now load multiple levels of detail for textures which fixes artifacts when rendering objects far away from the viewer. The image is now a lot smoother, however on closer inspection you will notice jagged saw-like patterns along the edges of drawn geometric shapes. This is especially visible in one of our early programs when we rendered a quad:
54

6-
![](/images/mipmaps_example.jpg)
5+
![](/images/texcoord_visualization.png)
76

8-
## Checking for multisampling support
7+
This undesired effect is called "aliasing" and it's a result of a limited numbers of pixels that are available for rendering. Since there are no displays out there with unlimited resolution, it will be always visible to some extent. There's a number of ways to fix this and in this chapter we'll focus on one of the more popular ones: [Multisample anti-aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing) (MSAA).
98

10-
First, add a class member that will store the number of samples used by the renderer. This number will be used in various places in our code:
9+
In ordinary rendering, the pixel color is determined based on a single sample point which in most cases is the center of target pixel on screen. If part of the drawn line passes through a certain pixel but doesn't cover the sample point, that pixel will be left blank, leading to the jagged "staircase" effect.
10+
11+
![](/images/aliasing.png)
12+
13+
What MSAA does is it uses multiple sample points per pixel (hence the name) to determine its final color. As one might expect, more samples lead to better results, however it is also more computationally expensive.
14+
15+
In our implementation, we will focus on using the maximum available sample count. Depending on your application this may not always be the best approach and it might be better to use less samples for the sake of higher performance if the final result meets your quality demands.
16+
17+
18+
## Getting available sample count
19+
20+
Let's start off by determining how many samples our hardware can use. Most modern GPUs support at least 8 samples but this number is not guaranteed to be the same everywhere. We'll keep track of it by adding a new class member:
1121

1222
```c++
1323
...
1424
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
1525
...
1626
```
1727

18-
We now need to determine what is the maximum number of samples supported by the hardware. This information can be extracted from `VkPhysicalDeviceProperties` associated with our selected physical device. We're using a depth buffer, so we have to take into account the sample count for both color and depth - the lower number will be the maximum we can support. If the hardware supports only one sample (unlikely on modern graphics cards) the final image will look unchanged.
28+
The exact maximum sample count can be extracted from `VkPhysicalDeviceProperties` associated with our selected physical device. We're using a depth buffer, so we have to take into account the sample count for both color and depth - the lower number will be the maximum we can support. If the hardware supports only one sample the final image will look unchanged. Add a function that will fetch this information for us:
1929

2030
```c++
2131
VkSampleCountFlagBits getMaxUsableSampleCount() {
@@ -48,7 +58,7 @@ void pickPhysicalDevice() {
4858
}
4959
```
5060

51-
Next, update `createImage` functions to allow us to specify the number of samples by adding a `numSmaples` parameter - this will become important later:
61+
Next, update `createImage` function to allow us to specify the number of used samples by adding a `numSmaples` parameter - this will become important later:
5262

5363
```c++
5464
void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
@@ -57,7 +67,7 @@ void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCo
5767
...
5868
```
5969
60-
For now, update all calls to these functions using `VK_SAMPLE_COUNT_1_BIT` - we will be replacing this with proper values as we progress with implementation:
70+
For now, update all calls to this function using `VK_SAMPLE_COUNT_1_BIT` - we will be replacing this with proper values as we progress with implementation:
6171
6272
```c++
6373
createImage(swapChainExtent.width, swapChainExtent.height, 1, VK_SAMPLE_COUNT_1_BIT, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);
@@ -67,7 +77,7 @@ createImage(texWidth, texHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G
6777

6878
## Setting up render targets
6979

70-
Multisampling requires additional render targets. Add following class members:
80+
In MSAA, each pixel is sampled in an offscreen buffer which is then rendered to the screen. These new buffers are slightly different from regular images we've been rendering to - they have to be able to store more than one sample per pixel. Once a multisampled buffer is created, it has to be attached to the default framebuffer (which stores only a single sample per pixel). This is why we have to create additional render targets and modify our current drawing process. Add following class members:
7181

7282
```c++
7383
...
@@ -81,7 +91,7 @@ VkImageView depthMsaaImageView;
8191
...
8292
```
8393

84-
We will now create a multisampled color buffer. Add a `createColorResources` function and note that we're using `msaaSamples` here as a function parameter to `createImage`. We're also using only one mip level, since this buffer will be rendered fullscreen at all times and Vulkan specifications states that an image buffer with sample count greater than 1 can only have a single mip level:
94+
We will now create a multisampled color buffer. Add a `createColorResources` function and note that we're using `msaaSamples` here as a function parameter to `createImage`. We're also using only one mip level, since this is enforced by the Vulkan specification in case of images with more than one sample per pixel:
8595

8696
```c++
8797
void createColorResources() {
@@ -105,7 +115,7 @@ void initVulkan() {
105115
}
106116
```
107117

108-
You may notice that the newly created color image transitions from undefined state to `VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL` which is a new case for us to handle. Let's update `transitionImageLayout` function to take this into account:
118+
You may notice that the newly created color image uses a transition path from `VK_IMAGE_LAYOUT_UNDEFINED` to `VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL` which is a new case for us to handle. Let's update `transitionImageLayout` function to take this into account:
109119

110120
```c++
111121
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) {
@@ -148,9 +158,11 @@ void cleanupSwapChain() {
148158
...
149159
```
150160
151-
## Using multisampling
161+
With only a few simple steps we created additional buffers and image views necessary for multsampling - it's now time to put it all together and see the results!
162+
163+
## Adding new attachments
152164
153-
With only a few simple steps we created additional buffers and image views necessary for multsampling and also determined how many samples we can use on our hardware - it's now time to put it all together and see the results! Let's take care of the render pass first. Modify `createRenderPass` and update color and depth attachment creation info structs:
165+
Let's take care of the render pass first. Modify `createRenderPass` and update color and depth attachment creation info structs:
154166
155167
```c++
156168
void createRenderPass() {
@@ -188,7 +200,7 @@ Apart from the obvious change that tells the attachments to use more samples, yo
188200
...
189201
```
190202

191-
Add atachment reference for color:
203+
We now have to add new color resolve attachment to the subpass. Create a new attachment reference and update the `pResolveAttachments` pointer:
192204

193205
```c++
194206
...
@@ -208,7 +220,7 @@ Update render pass info struct with new attachments:
208220
...
209221
```
210222
211-
With render pass in place, modify `createFrameBuffers` and add additional attachments:
223+
With render pass in place, modify `createFrameBuffers` and add new image views to the list:
212224
213225
```c++
214226
void createFrameBuffers() {

images/aliasing.png

26.2 KB
Loading

0 commit comments

Comments
 (0)