LearnOpenGL

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

Weighted-Blended.html (40199B)


      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">Weighted Blended</h1>
    320 <h1 id="content-url" style='display:none;'>Guest-Articles/2020/OIT/Weighted-Blended</h1>
    321     <p>
    322         Weighted, Blended is an approximate order-independent transparency technique which was published in the <a href="http://jcgt.org/published/0002/02/09/">journal of computer graphics techniques</a> in 2013 by Morgan McGuire and Louis Bavoil at NVIDIA to address the transparency problem on a broad class of then gaming platforms.
    323     </p>
    324 
    325     <p>
    326         Their approach to avoid the cost of storing and sorting primitives or fragments is to alter the compositing operator so that it is order independent, thus allowing a pure streaming approach.
    327     </p>
    328 
    329     <p>
    330         Most games have ad-hoc and scene-dependent ways of working around transparent surface rendering limitations. These include limited sorting, additive-only blending, and hard-coded render and composite ordering. Most of these methods also break at some point during gameplay and create visual artifacts. One not-viable alternative is <a href="http://developer.download.nvidia.com/SDK/10/opengl/screenshots/samples/dual_depth_peeling.html" target="_blank">depth peeling</a>, which produces good images, but is too slow for scenes with many layers both in theory and practice.
    331     </p>
    332 
    333     <p>
    334         There are many <a href="https://en.wikipedia.org/wiki/Asymptotic_analysis" target="_blank">asymptotically</a> fast solutions for transparency rendering, such as bounded A-buffer approximations using programmable blending (e.g., <a href="http://software.intel.com/en-us/articles/multi-layer-alpha-blending">Marco Salvi's work</a>), stochastic transparency (as <a href="https://www.computer.org/csdl/journal/tg/2011/08/ttg2011081036/13rRUxBa55X" target="_blank">explained by Eric Enderton and others</a>), and ray tracing. One or more of these will probably dominate at some point, but all were impractical on the game platforms of five or six years ago, including PC DX11/GL4 GPUs, mobile devices with OpenGL ES 3.0 GPUs, and last-generation consoles like PlayStation 4.
    335     </p>
    336 
    337     <note>
    338         In mathematical analysis, asymptotic analysis, also known as asymptotics, is a method of describing limiting behavior.
    339     </note>
    340 
    341     <p>
    342         The below image is a transparent CAD view of a car engine rendered by this technique.
    343     </p>
    344 
    345 <img src="/img/guest/2020/oit/cad_view_of_an_engine.png" width="560" alt="A transparent CAD view of a car engine rendered by this technique.">
    346 
    347     <h2>Theory</h2>
    348 
    349     <p>
    350         This technique renders non-refractive, monochrome transmission through surfaces that themselves have color, without requiring sorting or new hardware features. In fact, it can be implemented with a simple shader for any GPU that supports blending to render targets with more than 8 bits per channel.
    351     </p>
    352 
    353     <p>
    354         It works best on GPUs with multiple render targets and floating-point texture, where it is faster than sorted transparency and avoids sorting artifacts and popping for particle systems. It also consumes less bandwidth than even a 4-deep RGBA8 K-buffer and allows mixing low-resolution particles with full-resolution surfaces such as glass.
    355     </p>
    356 
    357     <p>
    358         For the mixed resolution case, the peak memory cost remains that of the higher resolution render target but bandwidth cost falls based on the proportional of low-resolution surfaces.
    359     </p>
    360 
    361     <p>
    362         The basic idea of Weighted, Blended method is to compute the coverage of the background by transparent surfaces exactly, but to only approximate the light scattered towards the camera by the transparent surfaces themselves. The algorithm imposes a heuristic on inter-occlusion factor among transparent surfaces that increases with distance from the camera.
    363     </p>
    364 
    365     <note>
    366         A heuristic technique, or a heuristic, is any approach to problem solving or self-discovery that employs a practical method that is not guaranteed to be optimal, perfect, or rational, but is nevertheless sufficient for reaching an immediate, short-term goal or approximation. In our case, the heuristic is the weighting function.
    367     </note>
    368 
    369     <p>
    370         After all transparent surfaces have been rendered, it then performs a full-screen normalization and compositing pass to reduce errors where the heuristic was a poor approximation of the true inter-occlusion.
    371     </p>
    372 
    373     <p>
    374         The below image is a glass chess set rendered with this technique. Note that the glass pieces are not refracting any light.
    375     </p>
    376 
    377       <img src="/img/guest/2020/oit/a_glass_chess_set.png" width="560" alt="A glass chess set rendered with this technique.">
    378 
    379     <p>
    380         For a better understanding and a more detailed explanation of the weight function, please refer to page 5, 6 and 7 of the original paper as the Blended OIT has been implemented and improved by different methods along the years. Link to the paper is provided at the end of this article.
    381     </p>
    382 
    383     <h2>Limitation</h2>
    384 
    385     <p>
    386         The primary limitation of the technique is that the weighting heuristic must be tuned for the anticipated depth range and opacity of transparent surfaces.
    387     </p>
    388 
    389     <p>
    390         The technique was implemented in OpenGL for the <a href="http://g3d.sf.net/">G3D Innovation Engine</a> and DirectX for the <a href="http://www.unrealengine.com/">Unreal Engine</a> to produce the results live and in the paper. Dan Bagnell and Patrick Cozzi <a href="http://bagnell.github.io/cesium/Apps/Sandcastle/gallery/OIT.html">implemented it in WebGL</a> for their open-source Cesium engine (see also their <a href="http://cesiumjs.org/2014/03/14/Weighted-Blended-Order-Independent-Transparency/">blog post</a> discussing it).
    391     </p>
    392 
    393     <p>
    394         From those implementations, a good set of weighting functions were found, which are reported in the journal paper. In the paper, they also discuss how to spot artifacts from a poorly-tuned weighting function and fix them.
    395     </p>
    396 
    397     <p>
    398         Also, I haven't been able to find a proper way to implement this technique in a deferred renderer. Since pixels override each other in a deferred renderer, we lose information about the previous layers so we cannot correctly accumulate the color values for the lighting stage.
    399     </p>
    400 
    401     <p>
    402         One feasible solution is to apply this technique as you would ordinarily do in a forward renderer. This is basically borrowing the transparency pass of a forward renderer and incorporate it in a deferred one.
    403     </p>
    404 
    405     <h2>Implementation</h2>
    406 
    407     <p>
    408         This technique is fairly straight forward to implement and the shader modifications are very simple. If you're familiar with how Framebuffers work in OpenGL, you're almost halfway there.
    409     </p>
    410 
    411     <p>
    412         The only caveat is we need to write our code in OpenGL ^4.0 to be able to use blending to multiple render targets (e.g. utilizing <fun><function id='70'>glBlendFunc</function>i</fun>). In the paper, different ways of implementation have been discussed for libraries that do not support rendering or blending to multiple targets.
    413     </p>
    414 
    415     <warning>Don't forget to change your OpenGL version when initializng GLFW and also your GLSL version in your shaders.</warning>
    416 
    417     <h3>Overview</h3>
    418 
    419     <p>
    420         During the transparent surface rendering, shade surfaces as usual, but output to two render targets. The first render target (<def>accum</def>) must have at least <var>RGBA16F</var> precision and the second (<def>revealage</def>) must have at least <var>R8</var> precision. Clear the first render target to <var>vec4(0)</var> and the second render target to 1 (using a pixel shader or <fun><function id='10'>glClear</function>Buffer</fun> + <fun><function id='10'>glClear</function></fun>).
    421     </p>
    422 
    423     <p>
    424         Then, render the surfaces in any order to these render targets, adding the following to the bottom of the pixel shader and using the specified blending modes:
    425     </p>
    426 
    427 <pre><code>
    428 // your first render target which is used to accumulate pre-multiplied color values
    429 layout (location = 0) out vec4 accum;
    430 
    431 // your second render target which is used to store pixel revealage
    432 layout (location = 1) out float reveal;
    433 
    434 ...
    435 
    436 // output linear (not gamma encoded!), unmultiplied color from the rest of the shader
    437 vec4 color = ... // regular shading code
    438 
    439 // insert your favorite weighting function here. the color-based factor
    440 // avoids color pollution from the edges of wispy clouds. the z-based
    441 // factor gives precedence to nearer surfaces
    442 float weight =
    443     max(min(1.0, max(max(color.r, color.g), color.b) * color.a), color.a) *
    444     clamp(0.03 / (1e-5 + pow(z / 200, 4.0)), 1e-2, 3e3);
    445 
    446 // blend func: GL_ONE, GL_ONE
    447 // switch to pre-multiplied alpha and weight
    448 accum = vec4(color.rgb * color.a, color.a) * weight;
    449 
    450 // blend func: GL_ZERO, GL_ONE_MINUS_SRC_ALPHA
    451 reveal = color.a;
    452 </code></pre>
    453 
    454     <p>
    455         Finally, after all surfaces have been rendered, composite the result onto the screen using a full-screen pass:
    456     </p>
    457 
    458 <pre><code>
    459 // bind your accum render target to this texture unit
    460 layout (binding = 0) uniform sampler2D rt0;
    461 
    462 // bind your reveal render target to this texture unit
    463 layout (binding = 1) uniform sampler2D rt1;
    464 
    465 // shader output
    466 out vec4 color;
    467 
    468 // fetch pixel information
    469 vec4 accum = texelFetch(rt0, int2(gl_FragCoord.xy), 0);
    470 float reveal = texelFetch(rt1, int2(gl_FragCoord.xy), 0).r;
    471 
    472 // blend func: GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA
    473 color = vec4(accum.rgb / max(accum.a, 1e-5), reveal);
    474 </code></pre>
    475 
    476     <p>
    477         Use this table as a reference for your render targets:
    478     </p>
    479 
    480     <table border="1">
    481         <tbody>
    482             <tr><td>Render Target</td><td>Format</td><td>Clear</td><td>Src Blend</td><td>Dst Blend</td><td>Write ("Src")</td></tr>
    483             <tr><td>accum</td><td>RGBA16F</td><td>(0,0,0,0)</td><td>ONE</td><td>ONE</td><td><code>(r*a, g*a, b*a, a) * w</code></td></tr>
    484             <tr><td>revealage</td><td>R8</td><td>(1,0,0,0)</td><td>ZERO</td><td>ONE_MINUS_SRC_COLOR</td><td><code>a</code></td></tr>
    485         </tbody>
    486     </table>
    487 
    488     <p>
    489         A total of three rendering passes are needed to accomplish the finished result which is down below:
    490     </p>
    491 
    492       <img src="/img/guest/2020/oit/weighted_blended_result.png" width="640" alt="Weighted, Blended result.">
    493 
    494     <h3>Details</h3>
    495 
    496     <p>
    497         To get started, we would have to setup a quad for our solid and transparent surfaces. The red quad will be the solid one, and the green and blue will be the transparent one. Since we're using the same quad for our screen quad as well, here we define UV values for texture mapping purposes at the screen pass.
    498     </p>
    499 
    500 <pre><code>
    501 float quadVertices[] = {
    502     // positions        // uv
    503     -1.0f, -1.0f, 0.0f,	0.0f, 0.0f,
    504      1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
    505      1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
    506 
    507      1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
    508     -1.0f,  1.0f, 0.0f, 0.0f, 1.0f,
    509     -1.0f, -1.0f, 0.0f, 0.0f, 0.0f
    510 };
    511 
    512 // quad VAO
    513 unsigned int quadVAO, quadVBO;
    514 <function id='33'>glGenVertexArrays</function>(1, &quadVAO);
    515 <function id='12'>glGenBuffers</function>(1, &quadVBO);
    516 <function id='27'>glBindVertexArray</function>(quadVAO);
    517 <function id='32'>glBindBuffer</function>(GL_ARRAY_BUFFER, quadVBO);
    518 <function id='31'>glBufferData</function>(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
    519 <function id='29'><function id='60'>glEnable</function>VertexAttribArray</function>(0);
    520 <function id='30'>glVertexAttribPointer</function>(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    521 <function id='29'><function id='60'>glEnable</function>VertexAttribArray</function>(1);
    522 <function id='30'>glVertexAttribPointer</function>(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    523 <function id='27'>glBindVertexArray</function>(0);
    524 </code></pre>
    525 
    526     <p>
    527         Next, we will create two framebuffers for our solid and transparent passes. Our solid pass needs a color buffer and a depth buffer to store color and depth information. Our transparent pass needs two color buffers to store color accumulation and pixel revealage threshold. We will also attach the opaque framebuffer's depth texture to our transparent framebuffer, to utilize it for depth testing when rendering our transparent surfaces.
    528     </p>
    529 
    530 <pre><code>
    531 // set up framebuffers
    532 unsigned int opaqueFBO, transparentFBO;
    533 <function id='76'>glGenFramebuffers</function>(1, &opaqueFBO);
    534 <function id='76'>glGenFramebuffers</function>(1, &transparentFBO);
    535 
    536 // set up attachments for opaque framebuffer
    537 unsigned int opaqueTexture;
    538 <function id='50'>glGenTextures</function>(1, &opaqueTexture);
    539 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, opaqueTexture);
    540 <function id='52'>glTexImage2D</function>(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_HALF_FLOAT, NULL);
    541 <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    542 <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    543 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, 0);
    544 
    545 unsigned int depthTexture;
    546 <function id='50'>glGenTextures</function>(1, &depthTexture);
    547 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, depthTexture);
    548 <function id='52'>glTexImage2D</function>(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT,
    549              0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    550 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, 0);
    551 
    552 ...
    553 
    554 // set up attachments for transparent framebuffer
    555 unsigned int accumTexture;
    556 <function id='50'>glGenTextures</function>(1, &accumTexture);
    557 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, accumTexture);
    558 <function id='52'>glTexImage2D</function>(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_HALF_FLOAT, NULL);
    559 <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    560 <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    561 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, 0);
    562 
    563 unsigned int revealTexture;
    564 <function id='50'>glGenTextures</function>(1, &revealTexture);
    565 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, revealTexture);
    566 <function id='52'>glTexImage2D</function>(GL_TEXTURE_2D, 0, GL_R8, SCR_WIDTH, SCR_HEIGHT, 0, GL_RED, GL_FLOAT, NULL);
    567 <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    568 <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    569 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, 0);
    570 
    571 ...
    572 
    573 // don't forget to explicitly tell OpenGL that your transparent framebuffer has two draw buffers
    574 const GLenum transparentDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
    575 glDrawBuffers(2, transparentDrawBuffers);
    576 </code></pre>
    577 
    578     <note>
    579         For the sake of this article, we are creating two separate framebuffers, so it would be easier to understand how the technique unfolds. We could omit the opaque framebuffer and use backbuffer for our solid pass or just create a single framebuffer with four attachments all together (opaque, accumulation, revealage, depth) and render to different render targets at each pass.
    580     </note>
    581 
    582     <p>
    583         Before rendering, setup some model matrices for your quads. You can set the Z axis however you want since this is an order-independent technique and objects closer or further to the camera would not impose any problem.
    584     </p>
    585 
    586 <pre><code>glm::mat4 redModelMat = calculate_model_matrix(glm::vec3(0.0f, 0.0f, 0.0f));
    587 glm::mat4 greenModelMat = calculate_model_matrix(glm::vec3(0.0f, 0.0f, 1.0f));
    588 glm::mat4 blueModelMat = calculate_model_matrix(glm::vec3(0.0f, 0.0f, 2.0f));
    589 </code></pre>
    590 
    591     <p>
    592         At this point, we have to perform our solid pass, so configure the render states and bind the opaque framebuffer.
    593     </p>
    594 
    595 <pre><code>
    596 // configure render states
    597 <function id='60'>glEnable</function>(GL_DEPTH_TEST);
    598 <function id='66'>glDepthFunc</function>(GL_LESS);
    599 <function id='65'>glDepthMask</function>(GL_TRUE);
    600 glDisable(GL_BLEND);
    601 <function id='13'><function id='10'>glClear</function>Color</function>(0.0f, 0.0f, 0.0f, 0.0f);
    602 
    603 // bind opaque framebuffer to render solid objects
    604 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, opaqueFBO);
    605 <function id='10'>glClear</function>(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    606 </code></pre>
    607 
    608     <p>
    609         We have to reset our depth function and depth mask for the solid pass at every frame since pipeline changes these states further down the line.
    610     </p>
    611 
    612     <p>
    613         Now, draw the solid objects using the solid shader. You can draw alpha cutout objects both at this stage and the next stage as well. The solid shader is just a simple shader that transforms the vertices and draws the mesh with the supplied color.
    614     </p>
    615 
    616 <pre><code>
    617 // use solid shader
    618 solidShader.use();
    619 
    620 // draw red quad
    621 solidShader.setMat4("mvp", vp * redModelMat);
    622 solidShader.setVec3("color", glm::vec3(1.0f, 0.0f, 0.0f));
    623 <function id='27'>glBindVertexArray</function>(quadVAO);
    624 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    625 </code></pre>
    626 
    627     <p>
    628         So far so good. For our transparent pass, like in the solid pass, configure the render states to blend to these render targets as below, then bind the transparent framebuffer and clear its two color buffers to <var>vec4(0.0f)</var> and <var>vec4(1.0)</var>.
    629     </p>
    630 
    631 <pre><code>
    632 // configure render states
    633 // disable depth writes so transparent objects wouldn't interfere with solid pass depth values
    634 <function id='65'>glDepthMask</function>(GL_FALSE);
    635 <function id='60'>glEnable</function>(GL_BLEND);
    636 <function id='70'>glBlendFunc</function>i(0, GL_ONE, GL_ONE); // accumulation blend target
    637 <function id='70'>glBlendFunc</function>i(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); // revealge blend target
    638 <function id='72'>glBlendEquation</function>(GL_FUNC_ADD);
    639 
    640 // bind transparent framebuffer to render transparent objects
    641 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, transparentFBO);
    642 // use a four component float array or a glm::vec4(0.0)
    643 <function id='10'>glClear</function>Bufferfv(GL_COLOR, 0, &zeroFillerVec[0]); 
    644  // use a four component float array or a glm::vec4(1.0)
    645 <function id='10'>glClear</function>Bufferfv(GL_COLOR, 1, &oneFillerVec[0]);
    646 </code></pre>
    647 
    648     <p>
    649         Then, draw the transparent surfaces with your preferred alpha values.
    650     </p>
    651 
    652 <pre><code>
    653 // use transparent shader
    654 transparentShader.use();
    655 
    656 // draw green quad
    657 transparentShader.setMat4("mvp", vp * greenModelMat);
    658 transparentShader.setVec4("color", glm::vec4(0.0f, 1.0f, 0.0f, 0.5f));
    659 <function id='27'>glBindVertexArray</function>(quadVAO);
    660 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    661 
    662 // draw blue quad
    663 transparentShader.setMat4("mvp", vp * blueModelMat);
    664 transparentShader.setVec4("color", glm::vec4(0.0f, 0.0f, 1.0f, 0.5f));
    665 <function id='27'>glBindVertexArray</function>(quadVAO);
    666 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    667 </code></pre>
    668 
    669     <p>
    670         The transparent shader is where half the work is done. It's primarily a shader that collects pixel information for our composite pass:
    671     </p>
    672 
    673 <pre><code>
    674 // shader outputs
    675 layout (location = 0) out vec4 accum;
    676 layout (location = 1) out float reveal;
    677 
    678 // material color
    679 uniform vec4 color;
    680 
    681 void main()
    682 {
    683     // weight function
    684     float weight = clamp(pow(min(1.0, color.a * 10.0) + 0.01, 3.0) * 1e8 * 
    685                          pow(1.0 - gl_FragCoord.z * 0.9, 3.0), 1e-2, 3e3);
    686 
    687     // store pixel color accumulation
    688     accum = vec4(color.rgb * color.a, color.a) * weight;
    689 
    690     // store pixel revealage threshold
    691     reveal = color.a;
    692 }
    693 </code></pre>
    694 
    695 	<p>
    696 		Note that, we are directly using the color passed to the shader as our final fragment color. Normally, if you are in a lighting shader, you want to use the final result of the lighting to store in accumulation and revealage render targets.
    697 	</p>
    698 
    699     <p>
    700         Now that everything has been rendered, we have to <def>composite</def> these two images so we can have the finished result.
    701     </p>
    702 
    703     <note>
    704         Compositing is a common method in many techniques that use a post-processing quad drawn all over the screen. Think of it as merging two layers in a photo editing software like Photoshop or Gimp.
    705     </note>
    706 
    707     <p>
    708         In OpenGL, we can achieve this by color blending feature:
    709     </p>
    710 
    711 <pre><code>
    712 // set render states
    713 <function id='66'>glDepthFunc</function>(GL_ALWAYS);
    714 <function id='60'>glEnable</function>(GL_BLEND);
    715 <function id='70'>glBlendFunc</function>(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    716 
    717 // bind opaque framebuffer
    718 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, opaqueFBO);
    719 
    720 // use composite shader
    721 compositeShader.use();
    722 
    723 // draw screen quad
    724 <function id='49'>glActiveTexture</function>(GL_TEXTURE0);
    725 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, accumTexture);
    726 <function id='49'>glActiveTexture</function>(GL_TEXTURE1);
    727 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, revealTexture);
    728 <function id='27'>glBindVertexArray</function>(quadVAO);
    729 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    730 </code></pre>
    731 
    732     <p>
    733         Composite shader is where the other half of the work is done. We're basically merging two layers, one being the solid objects image and the other being the transparent objects image. Accumulation buffer tells us about the color and revealage buffer determines the visibility of the the underlying pixel:
    734     </p>
    735 
    736 <pre><code>
    737 // shader outputs
    738 layout (location = 0) out vec4 frag;
    739 
    740 // color accumulation buffer
    741 layout (binding = 0) uniform sampler2D accum;
    742 
    743 // revealage threshold buffer
    744 layout (binding = 1) uniform sampler2D reveal;
    745 
    746 // epsilon number
    747 const float EPSILON = 0.00001f;
    748 
    749 // calculate floating point numbers equality accurately
    750 bool isApproximatelyEqual(float a, float b)
    751 {
    752     return abs(a - b) &lt;= (abs(a) &lt; abs(b) ? abs(b) : abs(a)) * EPSILON;
    753 }
    754 
    755 // get the max value between three values
    756 float max3(vec3 v)
    757 {
    758     return max(max(v.x, v.y), v.z);
    759 }
    760 
    761 void main()
    762 {
    763     // fragment coordination
    764     ivec2 coords = ivec2(gl_FragCoord.xy);
    765 
    766     // fragment revealage
    767     float revealage = texelFetch(reveal, coords, 0).r;
    768 
    769     // save the blending and color texture fetch cost if there is not a transparent fragment
    770     if (isApproximatelyEqual(revealage, 1.0f))
    771         discard;
    772 
    773     // fragment color
    774     vec4 accumulation = texelFetch(accum, coords, 0);
    775 
    776     // suppress overflow
    777     if (isinf(max3(abs(accumulation.rgb))))
    778         accumulation.rgb = vec3(accumulation.a);
    779 
    780     // prevent floating point precision bug
    781     vec3 average_color = accumulation.rgb / max(accumulation.a, EPSILON);
    782 
    783     // blend pixels
    784     frag = vec4(average_color, 1.0f - revealage);
    785 }
    786 </code></pre>
    787 
    788     <p>
    789         Note that, we are using some helper functions like <fun>isApproximatelyEqual</fun> or <fun>max3</fun> to help us with the accurate calculation of floating-point numbers. Due to inaccuracy of floating-point numbers calculation in current generation processors, we need to compare our values with an extremely small amount called an <def>epsilon</def> to avoid underflows or overflows.
    790     </p>
    791 
    792     <p>
    793         Also, we don't need an intermediate framebuffer to do compositing. We can use our opaque framebuffer as the base framebuffer and paint over it since it already has the opaque pass information. Plus, we're stating that all depth tests should pass since we want to paint over the opaque image.
    794     </p>
    795 
    796     <p>
    797         Finally, draw your composited image (which is the opaque texture attachment since you rendered your transparent image over it in the last pass) onto the backbuffer and observe the result.
    798     </p>
    799 
    800 <pre><code>
    801 // set render states
    802 glDisable(GL_DEPTH);
    803 <function id='65'>glDepthMask</function>(GL_TRUE); // enable depth writes so <function id='10'>glClear</function> won't ignore clearing the depth buffer
    804 glDisable(GL_BLEND);
    805 
    806 // bind backbuffer
    807 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, 0);
    808 <function id='13'><function id='10'>glClear</function>Color</function>(0.0f, 0.0f, 0.0f, 0.0f);
    809 <function id='10'>glClear</function>(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    810 
    811 // use screen shader
    812 screenShader.use();
    813 
    814 // draw final screen quad
    815 <function id='49'>glActiveTexture</function>(GL_TEXTURE0);
    816 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, opaqueTexture);
    817 <function id='27'>glBindVertexArray</function>(quadVAO);
    818 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    819 </code></pre>
    820 
    821     <p>
    822         Screen shader is just a simple post-processing shader which draws a full-screen quad.
    823     </p>
    824 
    825     <p>
    826         In a regular pipeline, you would also apply gamma-correction, tone-mapping, etc. in an intermediate post-processing framebuffer before you render to backbuffer, but ensure you are not applying them while rendering your solid and transparent surfaces and also not before composition since this transparency technique needs raw color values for calculating transparent pixels.
    827     </p>
    828 
    829     <p>
    830         Now, the interesting part is to play with the Z axis of your objects to see order-independence in action. Try to place your transparent objects behind the solid object or mess up the orders entirely.
    831     </p>
    832 
    833       <img src="/img/guest/2020/oit/weighted_blended_reordered.png" width="640" alt="Weighted, Blended reordered.">
    834 
    835     <p>
    836         In the image above, the green quad is rendered after the red quad, but behind it, and if you move the camera around to see the green quad from behind, you won't see any artifacts.
    837     </p>
    838 
    839     <p>
    840         As stated earlier, one limitation that this technique imposes is that for scenes with higher depth/alpha complexity we need to tune the weighting function to achieve the correct result. Luckily, a number of tested weighting functions are provided in the paper which you can refer and investigate them for your environment.
    841     </p>
    842 
    843     <p>
    844         Be sure to also check the colored transmission transparency which is the improved version of this technique in the links below.
    845     </p>
    846 
    847     <p>
    848         You can find the source code for this demo <a href="/code_viewer_gh.php?code=src/8.guest/2020/oit/weighted_blended.cpp" target="_blank">here</a>.
    849     </p>
    850 
    851     <h2>Further reading</h2>
    852 
    853     <ul>
    854         <li><a href="http://jcgt.org/published/0002/02/09" href="_blank">Weighted, Blended paper</a>: The original paper published in the journal of computer graphics. A brief history of the transparency and the emergence of the technique itself is provided. This is a must for the dedicated readers.</li>
    855         <li><a href="http://casual-effects.blogspot.com/2014/03/weighted-blended-order-independent.html" href="_blank">Weighted, Blended introduction</a>: Casual Effects is Morgan McGuire's personal blog. This post is the introduction of their technique which goes into further details and is definitely worth to read. Plus, there are videos of their implementation live in action that you would not want to miss.</li>
    856         <li><a href="http://casual-effects.blogspot.com/2015/03/implemented-weighted-blended-order.html" href="_blank">Weighted, Blended for implementors</a>: And also another blog post by him on implementing the technique for implementors.</li>
    857         <li><a href="http://casual-effects.blogspot.com/2015/03/colored-blended-order-independent.html" href="_blank">Weighted, Blended and colored transmission</a>: And another blog post on colored transmission for transparent surfaces.</li>
    858         <li><a href="http://bagnell.github.io/cesium/Apps/Sandcastle/gallery/OIT.html" href="_blank">A live implementation of the technique</a>: This is a live WebGL visualization from Cesium engine which accepts weighting functions for you to test in your browser!</li>
    859     </ul>
    860         
    861 <author>
    862   <strong>Article by: </strong>Mahan Heshmati Moghaddam<br/>
    863   <strong>Contact: </strong><a href="mailto:mahangm@gmail.com" target="_blank">e-mail</a>
    864 </author>       
    865 
    866     </div>
    867     
    868 	</main>
    869 </body>
    870 </html>