Skip to content

Commit

Permalink
add msaa
Browse files Browse the repository at this point in the history
  • Loading branch information
shi-yan committed Jul 31, 2024
1 parent 565a01d commit c0b2a5d
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 23 deletions.
Binary file added Basics/antialiasing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 22 additions & 20 deletions Basics/multi_sample_anti_aliasing.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,26 +156,28 @@

<div id="article-container">
<article>
<h2 >1.17 Multi-Sample Anti-Aliasing (MSAA)</h2><p>we perceive the world using sampling, when</p><p>Now, let's explore the world of multi-sample anti-aliasing (MSAA). When the output resolution is relatively low, you might notice some unpleasant artifacts, especially along the edges where jagged, pixelated boundaries become apparent.</p><p>This type of artifact is referred to as aliasing, and it becomes more noticeable as the output resolution decreases. In such situations, we employ a set of algorithms collectively known as anti-aliasing to combat this issue. For example, anti-aliasing is commonly applied to text rendering to enhance quality, even when each glyph is quite small and has limited resolution.</p><p>In this tutorial, we'll introduce the fundamental anti-aliasing method known as multi-sample anti-aliasing (MSAA). The concept behind MSAA is straightforward: we first render the result with four samples for each pixel. Afterward, we downscale the image back to the desired size by averaging these four samples for each pixel. This averaging essentially blurs the sharp edges with their backgrounds, making jagged edge issues less noticeable.</p><pre><code class="language-javascript code-block"> const msaaTexture = device.createTexture({
size: [canvas.width, canvas.height],
sampleCount: 4,
format: navigator.gpu.getPreferredCanvasFormat(),
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});

const depthTextureDesc = {
size: [canvas.width, canvas.height, 1],
sampleCount: 4,
dimension: '2d',
format: 'depth24plus-stencil8',
usage: GPUTextureUsage.RENDER_ATTACHMENT
};</code></pre><p>There's no need to change the shader for this sample because MSAA operates transparently to the shader. What requires modification is when we define the render target. We introduce a new field called <code>sampleCount</code> and set it to four, indicating that there are four samples for each pixel. We do the same for the depth map.</p><pre><code class="language-javascript code-block"> let colorAttachment = {
view: msaaTexture.createView(),
resolveTarget: colorTextureView,
clearValue: { r: 1, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store'
};</code></pre><p>When defining the color attachment, we specify two render targets. The multi-sampled texture replaces the old render target, while the actual canvas texture becomes the resolved target, containing the final output. The rest of the process is handled automatically.</p>
<h2 >1.17 Multi-Sample Anti-Aliasing (MSAA)</h2><p>We perceive the world through sampling. For example, our eyes sample at a frame rate between 30 to 60 Hz. Insufficient sampling rates can result in unpleasant artifacts. In computer graphics, managing sampling limits is a constant challenge.</p><a href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html#1_17_msaa" target="_blank" class="comment"><svg style="margin-right:10px;vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" height="32"
width="32" fill="#dadadb" viewBox="0 -960 960 960"><path d="M189-160q-60 0-102.5-43T42-307q0-9 1-18t3-18l84-336q14-54 57-87.5t98-33.5h390q55 0 98 33.5t57 87.5l84 336q2 9 3.5 18.5T919-306q0 61-43.5 103.5T771-160q-42 0-78-22t-54-60l-28-58q-5-10-15-15t-21-5H385q-11 0-21 5t-15 15l-28 58q-18 38-54 60t-78 22Zm3-80q19 0 34.5-10t23.5-27l28-57q15-31 44-48.5t63-17.5h190q34 0 63 18t45 48l28 57q8 17 23.5 27t34.5 10q28 0 48-18.5t21-46.5q0 1-2-19l-84-335q-7-27-28-44t-49-17H285q-28 0-49.5 17T208-659l-84 335q-2 6-2 18 0 28 20.5 47t49.5 19Zm348-280q17 0 28.5-11.5T580-560q0-17-11.5-28.5T540-600q-17 0-28.5 11.5T500-560q0 17 11.5 28.5T540-520Zm80-80q17 0 28.5-11.5T660-640q0-17-11.5-28.5T620-680q-17 0-28.5 11.5T580-640q0 17 11.5 28.5T620-600Zm0 160q17 0 28.5-11.5T660-480q0-17-11.5-28.5T620-520q-17 0-28.5 11.5T580-480q0 17 11.5 28.5T620-440Zm80-80q17 0 28.5-11.5T740-560q0-17-11.5-28.5T700-600q-17 0-28.5 11.5T660-560q0 17 11.5 28.5T700-520Zm-360 60q13 0 21.5-8.5T370-490v-40h40q13 0 21.5-8.5T440-560q0-13-8.5-21.5T410-590h-40v-40q0-13-8.5-21.5T340-660q-13 0-21.5 8.5T310-630v40h-40q-13 0-21.5 8.5T240-560q0 13 8.5 21.5T270-530h40v40q0 13 8.5 21.5T340-460Zm140-20Z"/></svg>Launch Playground - 1_17_msaa</a><p>A typical problem relates to image resolution, particularly during rasterization. We've previously likened this process to laying bricks (pixels) to cover a triangle's area. When zooming in on a triangle's edge, the situation can be illustrated as follows:</p><p><div class="img-container"><img class="img" onclick="openImage(this)" src="antialiasing.png" alt="A Close-Up Look of the Rasterization Process" sources='[]' /><div class="img-title">A Close-Up Look of the Rasterization Process</div></div></p><p>During rasterization, we need a heuristic to determine if a pixel is inside or outside a triangle. A simple approach is to check the pixel's center. In the example above, only one pixel's center falls completely inside the triangle. For the two pixels crossing the edge, despite having large overlapping areas with the triangle, their centers are outside, so they're considered entirely outside. A more reasonable coloring strategy for these pixels might involve mixing the triangle's color with the background color based on the overlap ratio.</p><p>This type of artifact is called aliasing, and it becomes more noticeable at lower output resolutions. Insufficient sampling rates can also cause other strange artifacts. For instance, in our example, although a pixel is modeled as a square, its color is determined solely by its center. If we have a structure smaller than a pixel, the entire pixel will be colored based on what the center point samples from that small structure. A more reasonable approach would be to average the colors of the small structure.</p><p>Fortunately, there are ways to improve sampling quality without physically upgrading your monitor. We use a set of algorithms collectively known as anti-aliasing to address this issue. For example, anti-aliasing is commonly applied to text rendering to enhance quality, even when each glyph is quite small and has limited resolution.</p><p>In this tutorial, we'll introduce the fundamental anti-aliasing method known as multi-sample anti-aliasing (MSAA). The concept behind MSAA is straightforward: we first render the result with four samples for each pixel. Afterward, we downscale the image to the desired size by averaging these four samples per pixel. This averaging implements our strategy of creating a mixed color based on the overlapping area of the background and the triangle. It avoids expensive calculations of the actual overlap ratio by simply examining more samples.</p><p>MSAA is a built-in feature of the WebGPU API, making its implementation as simple as adding some extra configurations. Let's explore how to achieve this.</p><p>First, we create a multi-sampled texture:</p><div class="code-fragments"><pre><code class="language-javascript code-block" startNumber=277>const msaaTexture = device.createTexture({
size: [canvas.width, canvas.height],
sampleCount: 4,
format: navigator.gpu.getPreferredCanvasFormat(),
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
</pre></code><div class="code-fragments-caption"><a target="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=276:281#1_17_msaa">1_17_msaa/index.html:277-282 Create a New Texture With 4 Samples Each Pixel</a></div></div><p>We also need to update our depth texture to support multi-sampling:</p><div class="code-fragments"><pre><code class="language-javascript code-block" startNumber=267>const depthTextureDesc = {
size: [canvas.width, canvas.height, 1],
sampleCount: 4,
dimension: '2d',
format: 'depth24plus-stencil8',
usage: GPUTextureUsage.RENDER_ATTACHMENT
};
</pre></code><div class="code-fragments-caption"><a target="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=266:272#1_17_msaa">1_17_msaa/index.html:267-273 Update the Depth Texture With 4 Samples Each Pixel</a></div></div><p>In both cases, we introduce a new sampleCount property and set it to 4, indicating that we want four samples per pixel. The format and usage properties remain the same as in non-MSAA configurations.</p><p>It's worth noting that we don't need to modify our shaders for MSAA, as it operates transparently to them. The primary changes occur when we define the render target.</p><p>Next, we update our color attachment configuration:</p><div class="code-fragments"><pre><code class="language-javascript code-block" startNumber=288>let colorAttachment = {
view: view,
resolveTarget: colorTextureView,
clearValue: { r: 1, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store'
};
</pre></code><div class="code-fragments-caption"><a target="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=287:293#1_17_msaa">1_17_msaa/index.html:288-294 Create the Color Attachment</a></div></div><p>In this configuration, we specify two render targets:</p><ol><li><p>The view property now points to our multi-sampled texture (msaaTexture.createView()).</p></li><li><p>We introduce a new resolveTarget property, which points to the actual canvas texture view (colorTextureView). This is where the final, resolved output will be stored.</p></li></ol><p>The rendering process now occurs in two stages:</p><ol><li><p>The scene is first rendered to the multi-sampled texture (msaaTexture).</p></li><li><p>The result is then automatically resolved (averaged) and output to the resolveTarget.</p></li></ol><p>This two-stage process happens transparently, requiring no additional code beyond the configuration changes we've made.</p><p>To illustrate the effectiveness of MSAA, we can compare zoomed-in views of a rendered scene before and after enabling MSAA. The difference should be noticeable, with smoother edges and reduced aliasing artifacts in the MSAA-enabled version.</p>
</article>
<a href="https://github.com/shi-yan/WebGPUUnleashed/discussions" target="_blank" class="comment"><svg
style="margin-right:10px;vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" height="32"
Expand Down
3 changes: 0 additions & 3 deletions code/1_17_msaa/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@

let depthTexture = device.createTexture(depthTextureDesc);
let depthTextureView = depthTexture.createView();

const msaaTexture = device.createTexture({
size: [canvas.width, canvas.height],
sampleCount: 4,
Expand All @@ -286,15 +285,13 @@

let colorTexture = context.getCurrentTexture();
let colorTextureView = colorTexture.createView();

let colorAttachment = {
view: view,
resolveTarget: colorTextureView,
clearValue: { r: 1, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store'
};

const depthAttachment = {
view: depthTextureView,
depthClearValue: 1,
Expand Down

0 comments on commit c0b2a5d

Please sign in to comment.