LearnOpenGL

Translation in progress of learnopengl.com.
git clone https://git.mtkn.jp/LearnOpenGL
Log | Files | Refs

Anti-Aliasing.html (32272B)


      1 <!DOCTYPE html>
      2 <html lang="ja"> 
      3 <head>
      4     <meta charset="utf-8"/>
      5     <title>LearnOpenGL</title>
      6     <link rel="shortcut icon" type="image/ico" href="/favicon.ico"  />
      7 	<link rel="stylesheet" href="../static/style.css" />
      8 	<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"> </script>
      9 	<script src="/static/functions.js"></script>
     10 </head>
     11 <body>
     12 	<nav>
     13 <ol>
     14 	<li id="Introduction">
     15 		<a href="https://learnopengl.com/Introduction">はじめに</a>
     16 	</li>
     17 	<li id="Getting-started">
     18 		<span class="closed">入門</span>
     19 		<ol>
     20 			<li id="Getting-started/OpenGL">
     21 				<a href="https://learnopengl.com/Getting-started/OpenGL">OpenGL </a>
     22 			</li>
     23 			<li id="Getting-started/Creating-a-window">
     24 				<a href="https://learnopengl.com/Getting-started/Creating-a-window">ウィンドウの作成</a>
     25 			</li>
     26 			<li id="Getting-started/Hello-Window">
     27 				<a href="https://learnopengl.com/Getting-started/Hello-Window">最初のウィンドウ</a>
     28 			</li>
     29 			<li id="Getting-started/Hello-Triangle">
     30 				<a href="https://learnopengl.com/Getting-started/Hello-Triangle">最初の三角形</a>
     31 			</li>
     32 			<li id="Getting-started/Shaders">
     33 				<a href="https://learnopengl.com/Getting-started/Shaders">シェーダー</a>
     34 			</li>
     35 			<li id="Getting-started/Textures">
     36 				<a href="https://learnopengl.com/Getting-started/Textures">テクスチャ</a>
     37 			</li>
     38 			<li id="Getting-started/Transformations">
     39 				<a href="https://learnopengl.com/Getting-started/Transformations">座標変換</a>
     40 			</li>
     41 			<li id="Getting-started/Coordinate-Systems">
     42 				<a href="https://learnopengl.com/Getting-started/Coordinate-Systems">座標系</a>
     43 			</li>
     44 			<li id="Getting-started/Camera">
     45 				<a href="https://learnopengl.com/Getting-started/Camera">カメラ</a>
     46 			</li>
     47 			<li id="Getting-started/Review">
     48 				<a href="https://learnopengl.com/Getting-started/Review">まとめ</a>
     49 			</li>
     50 		</ol>
     51 	</li>
     52 	<li id="Lighting">
     53 		<span class="closed">Lighting </span>
     54 		<ol>
     55 			<li id="Lighting/Colors">
     56 				<a href="https://learnopengl.com/Lighting/Colors">Colors </a>
     57 			</li>
     58 			<li id="Lighting/Basic-Lighting">
     59 				<a href="https://learnopengl.com/Lighting/Basic-Lighting">Basic Lighting </a>
     60 			</li>
     61 			<li id="Lighting/Materials">
     62 				<a href="https://learnopengl.com/Lighting/Materials">Materials </a>
     63 			</li>
     64 			<li id="Lighting/Lighting-maps">
     65 				<a href="https://learnopengl.com/Lighting/Lighting-maps">Lighting maps </a>
     66 			</li>
     67 			<li id="Lighting/Light-casters">
     68 				<a href="https://learnopengl.com/Lighting/Light-casters">Light casters </a>
     69 			</li>
     70 			<li id="Lighting/Multiple-lights">
     71 				<a href="https://learnopengl.com/Lighting/Multiple-lights">Multiple lights </a>
     72 			</li>
     73 			<li id="Lighting/Review">
     74 				<a href="https://learnopengl.com/Lighting/Review">Review </a>
     75 			</li>
     76 		</ol>
     77 	</li>
     78 	<li id="Model-Loading">
     79 		<span class="closed">Model Loading </span>
     80 		<ol>
     81 			<li id="Model-Loading/Assimp">
     82 				<a href="https://learnopengl.com/Model-Loading/Assimp">Assimp </a>
     83 			</li>
     84 			<li id="Model-Loading/Mesh">
     85 				<a href="https://learnopengl.com/Model-Loading/Mesh">Mesh </a>
     86 			</li>
     87 			<li id="Model-Loading/Model">
     88 				<a href="https://learnopengl.com/Model-Loading/Model">Model </a>
     89 			</li>
     90 		</ol>
     91 	</li>
     92 	<li id="Advanced-OpenGL">
     93 		<span class="closed">Advanced OpenGL </span>
     94 		<ol>
     95 			<li id="Advanced-OpenGL/Depth-testing">
     96 				<a href="https://learnopengl.com/Advanced-OpenGL/Depth-testing">Depth testing </a>
     97 			</li>
     98 			<li id="Advanced-OpenGL/Stencil-testing">
     99 				<a href="https://learnopengl.com/Advanced-OpenGL/Stencil-testing">Stencil testing </a>
    100 			</li>
    101 			<li id="Advanced-OpenGL/Blending">
    102 				<a href="https://learnopengl.com/Advanced-OpenGL/Blending">Blending </a>
    103 			</li>
    104 			<li id="Advanced-OpenGL/Face-culling">
    105 				<a href="https://learnopengl.cm/Advanced-OpenGL/Face-culling">Face culling </a>
    106 			</li>
    107 			<li id="Advanced-OpenGL/Framebuffers">
    108 				<a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers">Framebuffers </a>
    109 			</li>
    110 			<li id="Advanced-OpenGL/Cubemaps">
    111 				<a href="https://learnopengl.com/Advanced-OpenGL/Cubemaps">Cubemaps </a>
    112 			</li>
    113 			<li id="Advanced-OpenGL/Advanced-Data">
    114 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-Data">Advanced Data </a>
    115 			</li>
    116 			<li id="Advanced-OpenGL/Advanced-GLSL">
    117 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL">Advanced GLSL </a>
    118 			</li>
    119 			<li id="Advanced-OpenGL/Geometry-Shader">
    120 				<a href="https://learnopengl.com/Advanced-OpenGL/Geometry-Shader">Geometry Shader </a>
    121 			</li>
    122 			<li id="Advanced-OpenGL/Instancing">
    123 				<a href="https://learnopengl.com/Advanced-OpenGL/Instancing">Instancing </a>
    124 			</li>
    125 			<li id="Advanced-OpenGL/Anti-Aliasing">
    126 				<a href="https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing">Anti Aliasing </a>
    127 			</li>
    128 		</ol>
    129 	</li>
    130 	<li id="Advanced-Lighting">
    131 		<span class="closed">Advanced Lighting </span>
    132 		<ol>
    133 			<li id="Advanced-Lighting/Advanced-Lighting">
    134 				<a href="https://learnopengl.com/Advanced-Lighting/Advanced-Lighting">Advanced Lighting </a>
    135 			</li>
    136 			<li id="Advanced-Lighting/Gamma-Correction">
    137 				<a href="https://learnopengl.com/Advanced-Lighting/Gamma-Correction">Gamma Correction </a>
    138 			</li>
    139 			<li id="Advanced-Lighting/Shadows">
    140 				<span class="closed">Shadows </span>
    141 				<ol>
    142 					<li id="Advanced-Lighting/Shadows/Shadow-Mapping">
    143 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping">Shadow Mapping </a>
    144 					</li>
    145 					<li id="Advanced-Lighting/Shadows/Point-Shadows">
    146 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows">Point Shadows </a>
    147 					</li>
    148 				</ol>
    149 			</li>
    150 			<li id="Advanced-Lighting/Normal-Mapping">
    151 				<a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping">Normal Mapping </a>
    152 			</li>
    153 			<li id="Advanced-Lighting/Parallax-Mapping">
    154 				<a href="https://learnopengl.com/Advanced-Lighting/Parallax-Mapping">Parallax Mapping </a>
    155 			</li>
    156 			<li id="Advanced-Lighting/HDR">
    157 				<a href="https://learnopengl.com/Advanced-Lighting/HDR">HDR </a>
    158 			</li>
    159 			<li id="Advanced-Lighting/Bloom">
    160 				<a href="https://learnopengl.com/Advanced-Lighting/Bloom">Bloom </a>
    161 			</li>
    162 			<li id="Advanced-Lighting/Deferred-Shading">
    163 				<a href="https://learnopengl.com/Advanced-Lighting/Deferred-Shading">Deferred Shading </a>
    164 			</li>
    165 			<li id="Advanced-Lighting/SSAO">
    166 				<a href="https://learnopengl.com/Advanced-Lighting/SSAO">SSAO </a>
    167 			</li>
    168 		</ol>
    169 	</li>
    170 	<li id="PBR">
    171 		<span class="closed">PBR </span>
    172 		<ol>
    173 			<li id="PBR/Theory">
    174 				<a href="https://learnopengl.com/PBR/Theory">Theory </a>
    175 			</li>
    176 			<li id="PBR/Lighting">
    177 				<a href="https://learnopengl.com/PBR/Lighting">Lighting </a>
    178 			</li>
    179 			<li id="PBR/IBL">
    180 				<span class="closed">IBL </span>
    181 				<ol>
    182 					<li id="PBR/IBL/Diffuse-irradiance">
    183 						<a href="https://learnopengl.com/PBR/IBL/Diffuse-irradiance">Diffuse irradiance </a>
    184 					</li>
    185 					<li id="PBR/IBL/Specular-IBL">
    186 						<a href="https://learnopengl.com/PBR/IBL/Specular-IBL">Specular IBL </a>
    187 					</li>
    188 				</ol>
    189 			</li>
    190 		</ol>
    191 	</li>
    192 	<li id="In-Practice">
    193 		<span class="closed">In Practice </span>
    194 		<ol>
    195 			<li id="In-Practice/Debugging">
    196 				<a href="https://learnopengl.com/In-Practice/Debugging">Debugging </a>
    197 			</li>
    198 			<li id="In-Practice/Text-Rendering">
    199 				<a href="https://learnopengl.com/In-Practice/Text-Rendering">Text Rendering </a>
    200 			</li>
    201 			<li id="In-Practice/2D-Game">
    202 				<span class="closed">2D Game </span>
    203 				<ol>
    204 					<li id="In-Practice/2D-Game/Breakout">
    205 						<a href="https://learnopengl.com/In-Practice/2D-Game/Breakout">Breakout </a>
    206 					</li>
    207 					<li id="In-Practice/2D-Game/Setting-up">
    208 						<a href="https://learnopengl.com/In-Practice/2D-Game/Setting-up">Setting up </a>
    209 					</li>
    210 					<li id="In-Practice/2D-Game/Rendering-Sprites">
    211 						<a href="https://learnopengl.com/In-Practice/2D-Game/Rendering-Sprites">Rendering Sprites </a>
    212 					</li>
    213 					<li id="In-Practice/2D-Game/Levels">
    214 						<a href="https://learnopengl.com/In-Practice/2D-Game/Levels">Levels </a>
    215 					</li>
    216 					<li id="In-Practice/2D-Game/Collisions">
    217 						<span class="closed">Collisions </span>
    218 						<ol>
    219 							<li id="In-Practice/2D-Game/Collisions/Ball">
    220 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Ball">Ball </a>
    221 							</li>
    222 							<li id="In-Practice/2D-Game/Collisions/Collision-detection">
    223 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection">Collision detection </a>
    224 							</li>
    225 							<li id="In-Practice/2D-Game/Collisions/Collision-resolution">
    226 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-resolution">Collision resolution </a>
    227 							</li>
    228 						</ol>
    229 					</li>
    230 					<li id="In-Practice/2D-Game/Particles">
    231 						<a href="https://learnopengl.com/In-Practice/2D-Game/Particles">Particles </a>
    232 					</li>
    233 					<li id="In-Practice/2D-Game/Postprocessing">
    234 						<a href="https://learnopengl.com/In-Practice/2D-Game/Postprocessing">Postprocessing </a>
    235 					</li>
    236 					<li id="In-Practice/2D-Game/Powerups">
    237 						<a href="https://learnopengl.com/In-Practice/2D-Game/Powerups">Powerups </a>
    238 					</li>
    239 					<li id="In-Practice/2D-Game/Audio">
    240 						<a href="https://learnopengl.com/In-Practice/2D-Game/Audio">Audio </a>
    241 					</li>
    242 					<li id="In-Practice/2D-Game/Render-text">
    243 						<a href="https://learnopengl.com/In-Practice/2D-Game/Render-text">Render text </a>
    244 					</li>
    245 					<li id="In-Practice/2D-Game/Final-thoughts">
    246 						<a href="https://learnopengl.com/In-Practice/2D-Game/Final-thoughts">Final thoughts </a>
    247 					</li>
    248 				</ol>
    249 			</li>
    250 		</ol>
    251 	</li>
    252 	<li id="Guest-Articles">
    253 		<span class="closed">Guest Articles </span>
    254 		<ol>
    255 			<li id="Guest-Articles/How-to-publish">
    256 				<a href="https://learnopengl.com/Guest-Articles/How-to-publish">How to publish </a>
    257 			</li>
    258 			<li id="Guest-Articles/2020">
    259 				<span class="closed">2020 </span>
    260 				<ol>
    261 					<li id="Guest-Articles/2020/OIT">
    262 						<span class="closed">OIT </span>
    263 						<ol>
    264 							<li id="Guest-Articles/2020/OIT/Introduction">
    265 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Introduction">Introduction </a>
    266 							</li>
    267 							<li id="Guest-Articles/2020/OIT/Weighted-Blended">
    268 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Weighted-Blended">Weighted Blended </a>
    269 							</li>
    270 						</ol>
    271 					</li>
    272 					<li id="Guest-Articles/2020/Skeletal-Animation">
    273 						<a href="https://learnopengl.com/Guest-Articles/2020/Skeletal-Animation">Skeletal Animation </a>
    274 					</li>
    275 				</ol>
    276 			</li>
    277 			<li id="Guest-Articles/2021">
    278 				<span class="closed">2021 </span>
    279 				<ol>
    280 					<li id="Guest-Articles/2021/CSM">
    281 						<a href="https://learnopengl.com/Guest-Articles/2021/CSM">CSM </a>
    282 					</li>
    283 					<li id="Guest-Articles/2021/Scene">
    284 						<span class="closed">Scene </span>
    285 						<ol>
    286 							<li id="Guest-Articles/2021/Scene/Scene-Graph">
    287 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Scene-Graph">Scene Graph </a>
    288 							</li>
    289 							<li id="Guest-Articles/2021/Scene/Frustum-Culling">
    290 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling">Frustum Culling </a>
    291 							</li>
    292 						</ol>
    293 					</li>
    294 					<li id="Guest-Articles/2021/Tessellation">
    295 						<span class="closed">Tessellation </span>
    296 						<ol>
    297 							<li id="Guest-Articles/2021/Tessellation/Height-map">
    298 								<a href="https://learnopengl.com/Guest-Articles/2021/Tessellation/Height-map">Height map </a>
    299 							</li>
    300 						</ol>
    301 					</li>
    302 				</ol>
    303 			</li>
    304 		</ol>
    305 	</li>
    306 	<li id="Code-repository">
    307 		<a href="https://learnopengl.com/Code-repository">Code repository </a>
    308 	</li>
    309 	<li id="Translations">
    310 		<a href="https://learnopengl.com/Translations">Translations </a>
    311 	</li>
    312 	<li id="About">
    313 		<a href="https://learnopengl.com/About">About </a>
    314 	</li>
    315 </ol>
    316 	</nav>
    317 	<main>
    318     <div id="content">
    319     <h1 id="content-title">Anti Aliasing</h1>
    320 <h1 id="content-url" style='display:none;'>Advanced-OpenGL/Anti-Aliasing</h1>
    321 <p>
    322   Somewhere in your adventurous rendering journey you probably came across some jagged saw-like patterns along the edges of your models. The reason these <def>jagged edges</def> appear is due to how the rasterizer transforms the vertex data into actual fragments behind the scene. An example of what these jagged edges look like can already be seen when drawing a simple cube:
    323 </p>
    324 
    325 <img src="/img/advanced/anti_aliasing_aliasing.png" class="clean" alt="Container with visible aliasing"/>
    326 
    327 <p>
    328   While not immediately visible, if you take a closer look at the edges of the cube you'll see a jagged pattern. If we zoom in you'd see the following:
    329 </p>
    330 
    331 <img src="/img/advanced/anti_aliasing_zoomed.png" alt="Zoomed in on contanier with visible aliasing"/>
    332 
    333 <p>
    334   This is clearly not something we want in a final version of an application. This effect, of clearly seeing the pixel formations an edge is composed of, is called <def>aliasing</def>. There are quite a few techniques out there called <def>anti-aliasing</def> techniques that fight this aliasing behavior by producing <em>smoother</em> edges.
    335 </p>
    336 
    337 <p>
    338   At first we had a technique called <def>super sample anti-aliasing</def> (SSAA) that temporarily uses a much higher resolution render buffer to render the scene in (super sampling). Then when the full scene is rendered, the resolution is downsampled back to the normal resolution. This <em>extra</em> resolution was used to prevent these jagged edges. While it did provide us with a solution to the aliasing problem, it came with a major performance drawback since we have to draw <strong>a lot</strong> more fragments than usual. This technique therefore only had a short glory moment.
    339 </p>
    340 
    341 <p>
    342   This technique did give birth to a more modern technique called <def>multisample anti-aliasing</def> or MSAA that borrows from the concepts behind SSAA while implementing a much more efficient approach. In this chapter we'll be extensively discussing this MSAA technique that is built-in in OpenGL.
    343 </p>
    344 
    345 <h2>Multisampling</h2>
    346 <p>
    347   To understand what multisampling is and how it works into solving the aliasing problem we first need to delve a bit further into the inner workings of OpenGL's rasterizer.
    348 </p>
    349 
    350 <p>
    351   The rasterizer is the combination of all algorithms and processes that sit between your final processed vertices and the fragment shader. The rasterizer takes all vertices belonging to a single primitive and transforms this to a set of fragments. Vertex coordinates can theoretically have any coordinate, but fragments can't since they are bound by the resolution of your screen. There will almost never be a one-on-one mapping between vertex coordinates and fragments, so the rasterizer has to determine in some way what fragment/screen-coordinate each specific vertex will end up at.
    352 </p>
    353 
    354 <img src="/img/advanced/anti_aliasing_rasterization.png" alt="Image of a triangle being rasterized in OpenGL"/>
    355 
    356 <p>
    357   Here we see a grid of screen pixels where the center of each pixel contains a <def>sample point</def> that is used to determine if a pixel is covered by the triangle. The red sample points are covered by the triangle and a fragment will be generated for that covered pixel. Even though some parts of the triangle edges still enter certain screen pixels, the pixel's sample point is not covered by the inside of the triangle so this pixel won't be influenced by any fragment shader.
    358 </p>
    359 
    360 <p>
    361   You can probably already figure out the origin of aliasing right now. The complete rendered version of the triangle would look like this on your screen:
    362 </p>
    363 
    364 <img src="/img/advanced/anti_aliasing_rasterization_filled.png"  alt="Filled triangle as a result of rasterization in OpenGL"/>
    365 
    366 <p>
    367   Due to the limited amount of screen pixels, some pixels will be rendered along an edge and some won't. The result is that we're rendering primitives with non-smooth edges giving rise to the jagged edges we've seen before. 
    368 </p>
    369 
    370 <p>
    371   What multisampling does, is not use a single sampling point for determining coverage of the triangle, but multiple sample points (guess where it got its name from). Instead of a single sample point at the center of each pixel we're going to place <code>4</code> <def>subsamples</def> in a general pattern and use those to determine pixel coverage. 
    372 </p>
    373 
    374 <img src="/img/advanced/anti_aliasing_sample_points.png" class="clean" alt="Multisampling in OpenGL"/>
    375 
    376 <p>
    377   The left side of the image shows how we would normally determine the coverage of a triangle. This specific pixel won't run a fragment shader (and thus remains blank) since its sample point wasn't covered by the triangle. The right side of the image shows a multisampled version where each pixel contains <code>4</code> sample points. Here we can see that only <code>2</code> of the sample points cover the triangle.
    378 </p>
    379 
    380 <note>
    381   The amount of sample points can be any number we'd like with more samples giving us better coverage precision. 
    382 </note>
    383 
    384 <p>
    385   This is where multisampling becomes interesting. We determined that <code>2</code> subsamples were covered by the triangle so the next step is to determine a color for this specific pixel. Our initial guess would be that we run the fragment shader for each covered subsample and later average the colors of each subsample per pixel. In this case we'd run the fragment shader twice on the interpolated vertex data at each subsample and store the resulting color in those sample points. This is (fortunately) <strong>not</strong> how it works, because this would mean we need to run a lot more fragment shaders than without multisampling, drastically reducing performance. 
    386 </p>
    387 
    388 <p>
    389   How MSAA really works is that the fragment shader is only run <strong>once</strong> per pixel (for each primitive) regardless of how many subsamples the triangle covers; the fragment shader runs with the vertex data interpolated to the <strong>center</strong> of the pixel. MSAA then uses a larger depth/stencil buffer to determine subsample coverage. The number of subsamples covered determines how much the pixel color contributes to the framebuffer. Because only 2 of the 4 samples were covered in the previous image, half of the triangle's color is mixed with the framebuffer color (in this case the clear color) resulting in a light blue-ish color.
    390 </p>
    391 
    392 <p>
    393   The result is a higher resolution buffer (with higher resolution depth/stencil) where all the primitive edges now produce a smoother pattern. Let's see what multisampling looks like when we determine the coverage of the earlier triangle:
    394 </p>
    395 
    396 <img src="/img/advanced/anti_aliasing_rasterization_samples.png"  alt="Rasterization of triangle with multisampling in OpenGL"/>
    397 
    398 <p>
    399   Here each pixel contains 4 subsamples (the irrelevant samples were hidden) where the blue subsamples are covered by the triangle and the gray sample points aren't. Within the inner region of the triangle all pixels will run the fragment shader once where its color output is stored directly in the framebuffer (assuming no blending). At the inner edges of the triangle however not all subsamples will be covered so the result of the fragment shader won't fully contribute to the framebuffer. Based on the number of covered samples, more or less of the triangle fragment's color ends up at that pixel.
    400 </p>
    401 
    402 <p>
    403   For each pixel, the less subsamples are part of the triangle, the less it takes the color of the triangle. If we were to fill in the actual pixel colors we get the following image:
    404 </p>
    405 
    406 <img src="/img/advanced/anti_aliasing_rasterization_samples_filled.png"  alt="Rasterized triangle with multisampling in OpenGL"/>
    407 
    408 <p>
    409   The hard edges of the triangle are now surrounded by colors slightly lighter than the actual edge color, which causes the edge to appear smooth when viewed from a distance.
    410 </p>
    411 
    412 <p>
    413   Depth and stencil values are stored per subsample and, even though we only run the fragment shader once, color values are stored per subsample as well for the case of multiple triangles overlapping a single pixel. For depth testing the vertex's depth value is interpolated to each subsample before running the depth test, and for stencil testing we store the stencil values per subsample. This does mean that the size of the buffers are now increased by the amount of subsamples per pixel.
    414 </p>
    415 
    416 <p>
    417   What we've discussed so far is a basic overview of how multisampled anti-aliasing works behind the scenes. The actual logic behind the rasterizer is a bit more complicated, but this brief description should be enough to understand the concept and logic behind multisampled anti-aliasing; enough to delve into the practical aspects.
    418 </p>
    419 
    420 <h2>MSAA in OpenGL</h2>
    421 <p>
    422   If we want to use MSAA in OpenGL we need to use a buffer that is able to store more than one sample value per pixel. We need a new type of buffer that can store a given amount of multisamples and this is called a <def>multisample buffer</def>. 
    423 </p>
    424 
    425 <p>
    426   Most windowing systems are able to provide us a multisample buffer instead of a default buffer. GLFW also gives us this functionality and all we need to do is <em>hint</em> GLFW that we'd like to use a multisample buffer with N samples instead of a normal buffer by calling <fun><function id='18'>glfwWindowHint</function></fun> before creating the window:
    427 </p>
    428 
    429 <pre class="cpp"><code>
    430 <function id='18'>glfwWindowHint</function>(GLFW_SAMPLES, 4);
    431 </code></pre>
    432 
    433 <p>
    434   When we now call <fun><function id='20'>glfwCreateWindow</function></fun> we create a rendering window, but this time with a buffer containing 4 subsamples per screen coordinate. This does mean that the size of the buffer is increased by 4.
    435 </p>
    436 
    437 <p>
    438   Now that we asked GLFW for multisampled buffers we need to enable multisampling by calling <fun><function id='60'>glEnable</function></fun> with <var>GL_MULTISAMPLE</var>. On most OpenGL drivers, multisampling is enabled by default so this call is then a bit redundant, but it's usually a good idea to enable it anyways. This way all OpenGL implementations have multisampling enabled.
    439 </p>
    440 
    441 <pre><code>
    442 <function id='60'>glEnable</function>(GL_MULTISAMPLE);  
    443 </code></pre>
    444 
    445 <p>
    446   Because the actual multisampling algorithms are implemented in the rasterizer in your OpenGL drivers there's not much else we need to do. If we now were to render the green cube from the start of this chapter we should see smoother edges:
    447 </p>
    448 
    449 <img src="/img/advanced/anti_aliasing_multisampled.png" class="clean" alt="Image of a multisampled cube in OpenGL"/>
    450 
    451 <p>
    452   The cube does indeed look a lot smoother and the same will apply for any other object you're drawing in your scene. You can find the source code for this simple example <a href="/code_viewer_gh.php?code=src/4.advanced_opengl/11.1.anti_aliasing_msaa/anti_aliasing_msaa.cpp" target="_blank">here</a>.
    453 </p>
    454 
    455 <h2>Off-screen MSAA</h2>
    456 <p>
    457   Because GLFW takes care of creating the multisampled buffers, enabling MSAA is quite easy. If we want to use our own framebuffers however, we have to generate the multisampled buffers ourselves; now we <strong>do</strong> need to take care of creating multisampled buffers.
    458 </p>
    459 
    460 <p>
    461   There are two ways we can create multisampled buffers to act as attachments for framebuffers: texture attachments and renderbuffer attachments. Quite similar to normal attachments like we've discussed in the <a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers" target="_blank">framebuffers</a> chapter.
    462 </p>
    463 
    464 <h3>Multisampled texture attachments</h3>
    465 <p>
    466   To create a texture that supports storage of multiple sample points we use <fun><function id='101'><function id='52'>glTexImage2D</function>Multisample</function></fun> instead of <fun><function id='52'>glTexImage2D</function></fun> that accepts <var>GL_TEXTURE_2D_MULTISAPLE</var> as its texture target:
    467 </p>
    468 
    469 <pre class="cpp"><code>
    470 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D_MULTISAMPLE, tex);
    471 <function id='101'><function id='52'>glTexImage2D</function>Multisample</function>(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
    472 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D_MULTISAMPLE, 0);  
    473 </code></pre>
    474 
    475 <p>
    476   The second argument sets the number of samples we'd like the texture to have. If the last argument is set to <var>GL_TRUE</var>, the image will use identical sample locations and the same number of subsamples for each texel.
    477 </p>
    478 
    479 <p>
    480   To attach a multisampled texture to a framebuffer we use <fun><function id='81'>glFramebufferTexture2D</function></fun>, but this time with <var>GL_TEXTURE_2D_MULTISAMPLE</var> as the texture type:
    481 </p>
    482 
    483 <pre class="cpp"><code>
    484 <function id='81'>glFramebufferTexture2D</function>(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0); 
    485 </code></pre>
    486 
    487 <p>
    488   The currently bound framebuffer now has a multisampled color buffer in the form of a texture image.
    489 </p>
    490 
    491 <h3>Multisampled renderbuffer objects</h3>
    492 <p>
    493   Like textures, creating a multisampled renderbuffer object isn't difficult. It is even quite easy since all we need to change is <fun><function id='88'>glRenderbufferStorage</function></fun> to <fun><function id='102'><function id='88'>glRenderbufferStorage</function>Multisample</function></fun> when we configure the (currently bound) renderbuffer's memory storage:
    494 </p>
    495 
    496 <pre class="cpp"><code>
    497 <function id='102'><function id='88'>glRenderbufferStorage</function>Multisample</function>(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);  
    498 </code></pre>
    499 
    500 <p>
    501   The one thing that changed here is the extra second parameter where we set the amount of samples we'd like to use; 4 in this particular case.
    502 </p>
    503 
    504 <h3>Render to multisampled framebuffer</h3>
    505 <p>
    506   Rendering to a multisampled framebuffer is straightforward. Whenever we draw anything while the framebuffer object is bound, the rasterizer will take care of all the multisample operations. However, because a multisampled buffer is a bit special, we can't directly use the buffer for other operations like sampling it in a shader. 
    507 </p>
    508 
    509 <p>
    510   A multisampled image contains much more information than a normal image so what we need to do is downscale or <def>resolve</def> the image. Resolving a multisampled framebuffer is generally done through <fun><function id='103'>glBlitFramebuffer</function></fun> that copies a region from one framebuffer to the other while also resolving any multisampled buffers. 
    511 </p>
    512 
    513 <p>
    514   <fun><function id='103'>glBlitFramebuffer</function></fun> transfers a given <def>source</def> region defined by 4 screen-space coordinates to a given <def>target</def> region also defined by 4 screen-space coordinates. You may remember from the <a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers" target="_blank">framebuffers</a> chapter that if we bind to <var>GL_FRAMEBUFFER</var> we're binding to both the read and draw framebuffer targets. We could also bind to those targets individually by binding framebuffers to <var>GL_READ_FRAMEBUFFER</var> and <var>GL_DRAW_FRAMEBUFFER</var> respectively. The <fun><function id='103'>glBlitFramebuffer</function></fun> function reads from those two targets to determine which is the source and which is the target framebuffer. We could then transfer the multisampled framebuffer output to the actual screen by <def>blitting</def> the image to the default framebuffer like so:
    515 </p>
    516 
    517 <pre class="cpp"><code>
    518 <function id='77'>glBindFramebuffer</function>(GL_READ_FRAMEBUFFER, multisampledFBO);
    519 <function id='77'>glBindFramebuffer</function>(GL_DRAW_FRAMEBUFFER, 0);
    520 <function id='103'>glBlitFramebuffer</function>(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); 
    521 </code></pre>
    522 
    523 <p>
    524   If we then were to render the same application we should get the same output: a lime-green cube displayed with MSAA and again showing significantly less jagged edges:
    525 </p>
    526 
    527 <img src="/img/advanced/anti_aliasing_multisampled.png" class="clean" alt="Image of a multisampled cube in OpenGL"/>
    528 
    529 <p>
    530   You can find the source code <a href="/code_viewer_gh.php?code=src/4.advanced_opengl/11.2.anti_aliasing_offscreen/anti_aliasing_offscreen.cpp" target="_blank">here</a>.
    531 </p>
    532   
    533 <p>
    534   But what if we wanted to use the texture result of a multisampled framebuffer to do stuff like post-processing? We can't directly use the multisampled texture(s) in the fragment shader. What we can do however is blit the multisampled buffer(s) to a different FBO with a non-multisampled texture attachment. We then use this ordinary color attachment texture for post-processing, effectively post-processing an image rendered via multisampling. This does mean we have to generate a new FBO that acts solely as an intermediate framebuffer object to resolve the multisampled buffer into; a normal 2D texture we can use in the fragment shader. This process looks a bit like this in pseudocode:
    535 </p>
    536 
    537 <pre><code>
    538 unsigned int msFBO = CreateFBOWithMultiSampledAttachments();
    539 // then create another FBO with a normal texture color attachment
    540 [...]
    541 <function id='81'>glFramebufferTexture2D</function>(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0);
    542 [...]
    543 while(!<function id='14'>glfwWindowShouldClose</function>(window))
    544 {
    545     [...]
    546     
    547     <function id='77'>glBindFramebuffer</function>(msFBO);
    548     ClearFrameBuffer();
    549     DrawScene();
    550     // now resolve multisampled buffer(s) into intermediate FBO
    551     <function id='77'>glBindFramebuffer</function>(GL_READ_FRAMEBUFFER, msFBO);
    552     <function id='77'>glBindFramebuffer</function>(GL_DRAW_FRAMEBUFFER, intermediateFBO);
    553     <function id='103'>glBlitFramebuffer</function>(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    554     // now scene is stored as 2D texture image, so use that image for post-processing
    555     <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, 0);
    556     ClearFramebuffer();
    557     <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, screenTexture);
    558     DrawPostProcessingQuad();  
    559   
    560     [...] 
    561 }
    562 </code></pre>
    563 
    564 <p>
    565   If we then implement this into the post-processing code of the <a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers" target="_blank">framebuffers</a> chapter we're able to create all kinds of cool post-processing effects on a texture of a scene with (almost) no jagged edges. With a grayscale postprocessing filter applied it'll look something like this:
    566 </p>
    567 
    568 <img src="/img/advanced/anti_aliasing_post_processing.png" class="clean" alt="Image of post-processing on a scene drawn with MSAA in OpenGL"/>
    569 
    570 <note>
    571   Because the screen texture is a normal (non-multisampled) texture again, some post-processing filters like <em>edge-detection</em> will introduce jagged edges again. To accommodate for this you could blur the texture afterwards or create your own anti-aliasing algorithm. 
    572 </note>
    573   
    574 <p>
    575     You can see that when we want to combine multisampling with off-screen rendering we need to take care of some extra steps. The steps are worth the extra effort though since multisampling significantly boosts the visual quality of your scene. Do note that enabling multisampling can noticeably reduce performance the more samples you use. 
    576 </p>
    577   
    578 <h2>Custom Anti-Aliasing algorithm</h2>
    579 <p>
    580    It is possible to directly pass a multisampled texture image to a fragment shader instead of first resolving it. GLSL gives us the option to sample the texture image per subsample so we can create our own custom anti-aliasing algorithms.  
    581 </p>
    582   
    583 <p>
    584     To get a texture value per subsample you'd have to define the texture uniform sampler as a <fun>sampler2DMS</fun> instead of the usual <fun>sampler2D</fun>:
    585 </p>
    586  
    587 <pre><code>
    588 uniform sampler2DMS screenTextureMS;    
    589 </code></pre>
    590   
    591   <p>
    592     Using the <fun>texelFetch</fun> function it is then possible to retrieve the color value per sample:
    593   </p>
    594   
    595 <pre><code>
    596 vec4 colorSample = texelFetch(screenTextureMS, TexCoords, 3);  // 4th subsample
    597 </code></pre>
    598   
    599 <p>
    600   We won't go into the details of creating custom anti-aliasing techniques here, but this may be enough to get started on building one yourself.
    601 </p>
    602          
    603 
    604     </div>
    605     
    606 	</main>
    607 </body>
    608 </html>