LearnOpenGL

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

Cubemaps.html (42128B)


      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">Cubemaps</h1>
    320 <h1 id="content-url" style='display:none;'>Advanced-OpenGL/Cubemaps</h1>
    321 <p>
    322   We've been using 2D textures for a while now, but there are more texture types we haven't explored yet and in this chapter we'll discuss a texture type that is a combination of multiple textures mapped into one: a <def>cube map</def>.
    323 </p>
    324 
    325 <p>
    326   A cubemap is a texture that contains 6 individual 2D textures that each form one side of a cube: a textured cube. You may be wondering what the point is of such a cube? Why bother combining 6 individual textures into a single entity instead of just using 6 individual textures? Well, cube maps have the useful property that they can be indexed/sampled using a direction vector. Imagine we have a 1x1x1 unit cube with the origin of a direction vector residing at its center. Sampling a texture value from the cube map with an orange direction vector looks a bit like this:
    327 </p>
    328 
    329 <img src="/img/advanced/cubemaps_sampling.png" class="clean" alt="Indexing/Sampling from a cubemap in OpenGL"/>
    330 
    331 <note>
    332   The magnitude of the direction vector doesn't matter. As long as a direction is supplied, OpenGL retrieves the corresponding texels that the direction hits (eventually) and returns the properly sampled texture value.
    333 </note>
    334 
    335 <p>
    336   If we imagine we have a cube shape that we attach such a cubemap to, this direction vector would be similar to the (interpolated) local vertex position of the cube. This way we can sample the cubemap using the cube's actual position vectors as long as the cube is centered on the origin. We thus consider all vertex positions of the cube to be its texture coordinates when sampling a cubemap. The result is a texture coordinate that accesses the proper individual <def>face</def> texture of the cubemap.
    337 </p>
    338 
    339 <h2>Creating a cubemap</h2>
    340 <p>
    341   A cubemap is a texture like any other texture, so to create one we generate a texture and bind it to the proper texture target before we do any further texture operations. This time binding it to <var>GL_TEXTURE_CUBE_MAP</var>:
    342 </p>
    343 
    344 <pre class="cpp"><code>
    345 unsigned int textureID;
    346 <function id='50'>glGenTextures</function>(1, &textureID);
    347 <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, textureID);
    348 </code></pre>
    349 
    350 <p>
    351   Because a cubemap contains 6 textures, one for each face, we have to call <fun><function id='52'>glTexImage2D</function></fun> six times with their parameters set similarly to the previous chapters. This time however, we have to set the texture <em>target</em> parameter to match a specific face of the cubemap, telling OpenGL which side of the cubemap we're creating a texture for. This means we have to call <fun><function id='52'>glTexImage2D</function></fun> once for each face of the cubemap.  
    352 </p>
    353 
    354 <p>
    355   Since we have 6 faces OpenGL gives us 6 special texture targets for targeting a face of the cubemap:
    356 </p>
    357 
    358 <table>
    359   <tr>
    360     <th>Texture target</th>
    361     <th>Orientation</th>
    362   </tr>
    363   <tr>
    364     <td><code>GL_TEXTURE_CUBE_MAP_POSITIVE_X</code></td>
    365     <td>Right</td>
    366   </tr>
    367  <tr>
    368     <td><code>GL_TEXTURE_CUBE_MAP_NEGATIVE_X</code></td>
    369     <td>Left</td>
    370   </tr>
    371   <tr>
    372     <td><code>GL_TEXTURE_CUBE_MAP_POSITIVE_Y</code></td>
    373     <td>Top</td>
    374   </tr>
    375   <tr>
    376     <td><code>GL_TEXTURE_CUBE_MAP_NEGATIVE_Y</code></td>
    377     <td>Bottom</td>
    378   </tr>
    379   <tr>
    380     <td><code>GL_TEXTURE_CUBE_MAP_POSITIVE_Z</code></td>
    381     <td>Back</td>
    382   </tr>
    383   <tr>
    384     <td><code>GL_TEXTURE_CUBE_MAP_NEGATIVE_Z</code></td>
    385     <td>Front</td>
    386   </tr>  
    387 </table>
    388 
    389 <p>
    390   Like many of OpenGL's enums, their behind-the-scenes <fun>int</fun> value is linearly incremented, so if we were to have an array or vector of texture locations we could loop over them by starting with <var>GL_TEXTURE_CUBE_MAP_POSITIVE_X</var> and incrementing the enum by 1 each iteration, effectively looping through all the texture targets:
    391 </p>
    392 
    393 <pre><code>
    394 int width, height, nrChannels;
    395 unsigned char *data;  
    396 for(unsigned int i = 0; i &lt; textures_faces.size(); i++)
    397 {
    398     data = stbi_load(textures_faces[i].c_str(), &width, &height, &nrChannels, 0);
    399     <function id='52'>glTexImage2D</function>(
    400         GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 
    401         0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
    402     );
    403 }
    404 </code></pre>
    405 
    406 <p>
    407   Here we have a <fun>vector</fun> called <var>textures_faces</var> that contain the locations of all the textures required for the cubemap in the order as given in the table. This generates a texture for each face of the currently bound cubemap.
    408 </p>
    409 
    410 <p>
    411   Because a cubemap is a texture like any other texture, we will also specify its wrapping and filtering methods:
    412 </p>
    413 
    414 <pre><code>
    415 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    416 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    417 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    418 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    419 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);  
    420 </code></pre>
    421 
    422 <p>
    423   Don't be scared by the <var>GL_TEXTURE_WRAP_R</var>, this simply sets the wrapping method for the texture's <code>R</code> coordinate which corresponds to the texture's 3rd dimension (like <code>z</code> for positions). We set the wrapping method to <var>GL_CLAMP_TO_EDGE</var> since texture coordinates that are exactly between two faces may not hit an exact face (due to some hardware limitations) so by using <var>GL_CLAMP_TO_EDGE</var> OpenGL always returns their edge values whenever we sample between faces.
    424 </p>
    425 
    426 <p>
    427   Then before drawing the objects that will use the cubemap, we activate the corresponding texture unit and bind the cubemap before rendering; not much of a difference compared to normal 2D textures.  
    428 </p>
    429 
    430 <p>
    431   Within the fragment shader we also have to use a different sampler of the type <code>samplerCube</code> that we sample from using the <fun>texture</fun> function, but this time using a <code>vec3</code> direction vector instead of a <code>vec2</code>. An example of fragment shader using a cubemap looks like this:
    432 </p>
    433 
    434 <pre><code>
    435 in vec3 textureDir; // direction vector representing a 3D texture coordinate
    436 uniform samplerCube cubemap; // cubemap texture sampler
    437 
    438 void main()
    439 {             
    440     FragColor = texture(cubemap, textureDir);
    441 }  
    442 </code></pre>
    443 
    444 
    445 <p>
    446   That is still great and all, but why bother? Well, it just so happens that there are quite a few interesting techniques that are a lot easier to implement with a cubemap. One of those techniques is creating a <def>skybox</def>.
    447 </p>
    448 
    449 <h1>Skybox</h1>
    450 <p>
    451   A skybox is a (large) cube that encompasses the entire scene and contains 6 images of a surrounding environment, giving the player the illusion that the environment he's in is actually much larger than it actually is. Some examples of skyboxes used in videogames are images of mountains, of clouds, or of a starry night sky. An example of a skybox, using starry night sky images, can be seen in the following screenshot of the third elder scrolls game:
    452 </p>
    453 
    454 <img src="/img/advanced/cubemaps_morrowind.jpg" alt="Image of morrowind with a skybox"/>
    455 
    456 <p>
    457   You probably guessed by now that skyboxes like this suit cubemaps perfectly: we have a cube that has 6 faces and needs to be textured per face. In the previous image they used several images of a night sky to give the illusion the player is in some large universe while he's actually inside a tiny little box. 
    458 </p>
    459 
    460 <p>
    461   There are usually enough resources online where you could find skyboxes like that. These skybox images usually have the following pattern:
    462 </p>
    463 
    464 <img src="/img/advanced/cubemaps_skybox.png" class="clean" alt="Image of a skybox for a cubemap in OpenGL"/>
    465 
    466 <p>
    467   If you would fold those 6 sides into a cube you'd get the completely textured cube that simulates a large landscape. Some resources provide the skybox in a format like that in which case you'd have to manually extract the 6 face images, but in most cases they're provided as 6 single texture images.
    468 </p>
    469 
    470 <p>
    471   This particular (high-quality) skybox is what we'll use for our scene and can be downloaded <a href="/img/textures/skybox.zip" target="_blank">here</a>.
    472 </p>
    473 
    474 <h2>Loading a skybox</h2>
    475 <p>
    476   Since a skybox is by itself just a cubemap, loading a skybox isn't too different from what we've seen at the start of this chapter. To load the skybox we're going to use the following function that accepts a <fun>vector</fun> of 6 texture locations:
    477 </p>
    478 
    479 <pre><code>
    480 unsigned int loadCubemap(vector&lt;std::string&gt; faces)
    481 {
    482     unsigned int textureID;
    483     <function id='50'>glGenTextures</function>(1, &textureID);
    484     <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, textureID);
    485 
    486     int width, height, nrChannels;
    487     for (unsigned int i = 0; i &lt; faces.size(); i++)
    488     {
    489         unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
    490         if (data)
    491         {
    492             <function id='52'>glTexImage2D</function>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 
    493                          0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
    494             );
    495             stbi_image_free(data);
    496         }
    497         else
    498         {
    499             std::cout &lt;&lt; "Cubemap tex failed to load at path: " &lt;&lt; faces[i] &lt;&lt; std::endl;
    500             stbi_image_free(data);
    501         }
    502     }
    503     <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    504     <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    505     <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    506     <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    507     <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    508 
    509     return textureID;
    510 }  
    511 </code></pre>
    512 
    513 <p>
    514   The function itself shouldn't be too surprising. It is basically all the cubemap code we've seen in the previous section, but combined in a single manageable function.
    515 </p>
    516 
    517 <p>
    518   Now, before we call this function we'll load the appropriate texture paths in a vector in the order as specified by the cubemap enums:
    519 </p>
    520 
    521 <pre><code>
    522 vector&lt;std::string&gt; faces;
    523 {
    524     "right.jpg",
    525     "left.jpg",
    526     "top.jpg",
    527     "bottom.jpg",
    528     "front.jpg",
    529     "back.jpg"
    530 };
    531 unsigned int cubemapTexture = loadCubemap(faces);  
    532 </code></pre>
    533 
    534 <p>
    535   We loaded the skybox as a cubemap with <var>cubemapTexture</var> as its id. We can now finally bind it to a cube to replace that lame clear color we've been using all this time.
    536 </p>
    537 
    538 <h2>Displaying a skybox</h2>
    539 <p>
    540   Because a skybox is drawn on a cube we'll need another VAO, VBO and a fresh set of vertices like any other 3D object. You can get its vertex data <a href="/code_viewer.php?code=advanced/cubemaps_skybox_data" target="_blank">here</a>.   
    541 </p>
    542 
    543 <p>
    544   A cubemap used to texture a 3D cube can be sampled using the local positions of the cube as its texture coordinates. When a cube is centered on the origin (0,0,0) each of its position vectors is also a direction vector from the origin. This direction vector is exactly what we need to get the corresponding texture value at that specific cube's position. For this reason we only need to supply position vectors and don't need texture coordinates.
    545 </p>
    546 
    547 <p>
    548   To render the skybox we'll need a new set of shaders which aren't too complicated. Because we only have one vertex attribute the vertex shader is quite simple:
    549 </p>
    550 
    551 <pre><code>
    552 #version 330 core
    553 layout (location = 0) in vec3 aPos;
    554 
    555 out vec3 TexCoords;
    556 
    557 uniform mat4 projection;
    558 uniform mat4 view;
    559 
    560 void main()
    561 {
    562     TexCoords = aPos;
    563     gl_Position = projection * view * vec4(aPos, 1.0);
    564 }  
    565 </code></pre>
    566 
    567 <p>
    568   The interesting part of this vertex shader is that we set the incoming local position vector as the outcoming texture coordinate for (interpolated) use in the fragment shader. The fragment shader then takes these as input to sample a <code>samplerCube</code>:
    569 </p>
    570 
    571 <pre><code>
    572 #version 330 core
    573 out vec4 FragColor;
    574 
    575 in vec3 TexCoords;
    576 
    577 uniform samplerCube skybox;
    578 
    579 void main()
    580 {    
    581     FragColor = texture(skybox, TexCoords);
    582 }
    583 </code></pre>
    584 
    585 <p>
    586   The fragment shader is relatively straightforward. We take the vertex attribute's interpolated position vector as the texture's direction vector and use it to sample the texture values from the cubemap.
    587 </p>
    588 
    589 <p>
    590   Rendering the skybox is easy now that we have a cubemap texture, we simply bind the cubemap texture and the <var>skybox</var> sampler is automatically filled with the skybox cubemap. To draw the skybox we're going to draw it as the first object in the scene and disable depth writing. This way the skybox will always be drawn at the background of all the other objects since the unit cube is most likely smaller than the rest of the scene.
    591 </p>
    592 
    593 <pre><code>
    594 <function id='65'>glDepthMask</function>(GL_FALSE);
    595 skyboxShader.use();
    596 // ... set view and projection matrix
    597 <function id='27'>glBindVertexArray</function>(skyboxVAO);
    598 <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, cubemapTexture);
    599 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 36);
    600 <function id='65'>glDepthMask</function>(GL_TRUE);
    601 // ... draw rest of the scene
    602 </code></pre>
    603 
    604 <p>
    605   If you run this you will get into difficulties though. We want the skybox to be centered around the player so that no matter how far the player moves, the skybox won't get any closer, giving the impression the surrounding environment is extremely large. The current view matrix however transforms all the skybox's positions by rotating, scaling and translating them, so if the player moves, the cubemap moves as well! We want to remove the translation part of the view matrix so only rotation will affect the skybox's position vectors. 
    606 </p>
    607 
    608 <p>
    609   You may remember from the <a href="https://learnopengl.com/Lighting/Basic-Lighting" target="_blank">basic lighting</a> chapter that we can remove the translation section of transformation matrices by taking the upper-left 3x3 matrix of the 4x4 matrix. We can achieve this by converting the view matrix to a 3x3 matrix (removing translation) and converting it back to a 4x4 matrix:
    610 </p>
    611 
    612 <pre><code>
    613 glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));  
    614 </code></pre>
    615 
    616 <p>
    617   This removes any translation, but keeps all rotation transformations so the user can still look around the scene. 
    618 </p>
    619 
    620 <p>
    621   The result is a scene that instantly looks enormous due to our skybox. If you'd fly around the basic container you immediately get a sense of scale which dramatically improves the realism of the scene. The result looks something like this:
    622 </p>
    623 
    624 <img src="/img/advanced/cubemaps_skybox_result.png" class="clean" alt="Image of a skybox in an OpenGL scene"/>
    625 
    626 <p>
    627   Try experimenting with different skyboxes and see how they can have an enormous impact on the look and feel of your scene.
    628 </p>
    629 
    630 <h2>An optimization</h2>
    631 <p>
    632   Right now we've rendered the skybox first before we rendered all the other objects in the scene. This works great, but isn't too efficient. If we render the skybox first we're running the fragment shader for each pixel on the screen even though only a small part of the skybox will eventually be visible; fragments that could have easily been discarded using <def>early depth testing</def> saving us valuable bandwidth.
    633 </p>
    634 
    635 <p>
    636   So to give us a slight performance boost we're going to render the skybox last. This way, the depth buffer is completely filled with all the scene's depth values so we only have to render the skybox's fragments wherever the early depth test passes, greatly reducing the number of fragment shader calls. The problem is that the skybox will most likely render on top of all other objects since it's only a 1x1x1 cube, succeeding most depth tests. Simply rendering it without depth testing is not a solution since the skybox will then still overwrite all the other objects in the scene as it's rendered last. We need to trick the depth buffer into believing that the skybox has the maximum depth value of <code>1.0</code> so that it fails the depth test wherever there's a different object in front of it.
    637 </p>
    638 
    639 <p>
    640   In the <a href="https://learnopengl.com/Getting-started/Coordinate-Systems" target="_blank">coordinate systems</a> chapter we said that <em>perspective division</em> is performed after the vertex shader has run, dividing the <var>gl_Position</var>'s <code>xyz</code> coordinates by its <code>w</code> component. We also know from the <a href="https://learnopengl.com/Advanced-OpenGL/Depth-testing" target="_blank">depth testing</a> chapter that the <code>z</code> component of the resulting division is equal to that vertex's depth value. Using this information we can set the <code>z</code> component of the output position equal to its <code>w</code> component which will result in a <code>z</code> component that is always equal to <code>1.0</code>, because when the perspective division is applied its <code>z</code> component translates to <code>w</code> / <code>w</code> = <code>1.0</code>:
    641 </p>
    642 
    643 <pre><code>
    644 void main()
    645 {
    646     TexCoords = aPos;
    647     vec4 pos = projection * view * vec4(aPos, 1.0);
    648     gl_Position = pos.xyww;
    649 }  
    650 </code></pre>
    651 
    652 <p>
    653   The resulting <em>normalized device coordinates</em> will then always have a <code>z</code> value equal to <code>1.0</code>: the maximum depth value. The skybox will as a result only be rendered wherever there are no objects visible (only then it will pass the depth test, everything else is in front of the skybox).
    654 </p>
    655 
    656 <p>
    657   We do have to change the depth function a little by setting it to <var>GL_LEQUAL</var> instead of the default <var>GL_LESS</var>. The depth buffer will be filled with values of <code>1.0</code> for the skybox, so we need to make sure the skybox passes the depth tests with values <em>less than or equal</em> to the depth buffer instead of <em>less than</em>. 
    658 </p>
    659 
    660 <p>
    661   You can find the more optimized version of the source code <a href="/code_viewer_gh.php?code=src/4.advanced_opengl/6.1.cubemaps_skybox/cubemaps_skybox.cpp" target="_blank">here</a>.
    662 </p>
    663 
    664 <h1>Environment mapping</h1>
    665 <p>
    666   We now have the entire surrounding environment mapped in a single texture object and we could use that information for more than just a skybox. Using a cubemap with an environment, we could give objects reflective or refractive properties. Techniques that use an environment cubemap like this are called <def>environment mapping</def> techniques and the two most popular ones are <def>reflection</def> and <def>refraction</def>.
    667 </p>
    668 
    669 <h2>Reflection</h2>
    670 <p>
    671   Reflection is the property that an object (or part of an object) <def>reflects</def> its surrounding environment e.g. the object's colors are more or less equal to its environment based on the angle of the viewer. A mirror for example is a reflective object: it reflects its surroundings based on the viewer's angle.
    672 </p>
    673 
    674 <p>
    675   The basics of reflection are not that difficult. The following image shows how we can calculate a <def>reflection vector</def> and use that vector to sample from a cubemap:
    676 </p>
    677 
    678 <img src="/img/advanced/cubemaps_reflection_theory.png" class="clean" alt="Image of how to calculate reflection."/>
    679 
    680 <p>
    681   We calculate a reflection vector \(\color{green}{\bar{R}}\) around the object's normal vector \(\color{red}{\bar{N}}\) based on the view direction vector \(\color{gray}{\bar{I}}\). We can calculate this reflection vector using GLSL's built-in <fun>reflect</fun> function. The resulting vector \(\color{green}{\bar{R}}\) is then used as a direction vector to index/sample the cubemap, returning a color value of the environment. The resulting effect is that the object seems to reflect the skybox.
    682 </p>
    683 
    684 <p>
    685   Since we already have a skybox setup in our scene, creating reflections isn't too difficult. We'll change the fragment shader used by the container to give the container reflective properties:
    686 </p>
    687 
    688 <pre><code>
    689 #version 330 core
    690 out vec4 FragColor;
    691 
    692 in vec3 Normal;
    693 in vec3 Position;
    694 
    695 uniform vec3 cameraPos;
    696 uniform samplerCube skybox;
    697 
    698 void main()
    699 {             
    700     vec3 I = normalize(Position - cameraPos);
    701     vec3 R = reflect(I, normalize(Normal));
    702     FragColor = vec4(texture(skybox, R).rgb, 1.0);
    703 }
    704 </code></pre>
    705 
    706 <p>
    707   We first calculate the view/camera direction vector <var>I</var> and use this to calculate the reflect vector <var>R</var> which we then use to sample from the skybox cubemap. Note that we have the fragment's interpolated <var>Normal</var> and <var>Position</var> variable again so we'll need to adjust the vertex shader as well:
    708 </p>
    709 
    710 <pre><code>
    711 #version 330 core
    712 layout (location = 0) in vec3 aPos;
    713 layout (location = 1) in vec3 aNormal;
    714 
    715 out vec3 Normal;
    716 out vec3 Position;
    717 
    718 uniform mat4 model;
    719 uniform mat4 view;
    720 uniform mat4 projection;
    721 
    722 void main()
    723 {
    724     Normal = mat3(transpose(inverse(model))) * aNormal;
    725     Position = vec3(model * vec4(aPos, 1.0));
    726     gl_Position = projection * view * vec4(Position, 1.0);
    727 }  
    728 </code></pre>
    729 
    730 <p>
    731   We're using normal vectors so we'll want to transform them with a normal matrix again. The <var>Position</var> output vector is a world-space position vector. This <var>Position</var> output of the vertex shader is used to calculate the view direction vector in the fragment shader.
    732 </p>
    733 
    734 <p>
    735   Because we're using normals you'll want to update the <a href="/code_viewer.php?code=lighting/basic_lighting_vertex_data" target="_blank">vertex data</a> and update the attribute pointers as well. Also make sure to set the <var>cameraPos</var> uniform.
    736 </p>
    737 
    738 <p>
    739   Then we also want to bind the cubemap texture before rendering the container:
    740 </p>
    741 
    742 <pre class="cpp"><code>
    743 <function id='27'>glBindVertexArray</function>(cubeVAO);
    744 <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, skyboxTexture);  		
    745 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 36);	  
    746 </code></pre>
    747 
    748 <p>
    749   Compiling and running your code gives you a container that acts like a perfect mirror. The surrounding skybox is perfectly reflected on the container:
    750 </p>
    751 
    752 <img src="/img/advanced/cubemaps_reflection.png" class="clean" alt="Image of a cube reflecting a skybox via cubemaps via environment mapping."/>
    753 
    754 <p>
    755   You can find the full source code <a href="/code_viewer_gh.php?code=src/4.advanced_opengl/6.2.cubemaps_environment_mapping/cubemaps_environment_mapping.cpp" target="_blank">here</a>.
    756 </p>
    757 
    758 <p>
    759   When reflection is applied to an entire object (like the container) the object looks as if it has a high reflective material like steel or chrome. If we were to load a more interesting object (like the backpack model from the <a href="https://learnopengl.com/Model-Loading/Model" target="_blank">model loading</a> chapters) we'd get the effect that the object looks to be entirely made out of chrome:
    760 </p>
    761 
    762 <img src="/img/advanced/cubemaps_reflection_nanosuit.png" alt="Image of a Backpack model reflecting a skybox via cubemaps via environment mapping."/>
    763 
    764 <p>
    765   This looks quite awesome, but in reality most models aren't all completely reflective. We could for instance introduce <def>reflection maps</def> that give the models another extra level of detail. Just like diffuse and specular maps, reflection maps are texture images that we can sample to determine the reflectivity of a fragment. Using these reflection maps we can determine which parts of the model show reflection and by what intensity. <!--In the exercise of this chapter it's up to you to introduce reflection maps in the model loader we created earlier, significantly boosting the detail of the 3D object.-->
    766 </p>
    767 
    768 <h2>Refraction</h2>
    769 <p>
    770   Another form of environment mapping is called <def>refraction</def> and is similar to reflection. Refraction is the change in direction of light due to the change of the material the light flows through. Refraction is what we commonly see with water-like surfaces where the light doesn't enter straight through, but bends a little. It's like looking at your arm when it's halfway in the water.
    771 </p>
    772 
    773 <p>
    774   Refraction is described by <a href="http://en.wikipedia.org/wiki/Snell%27s_law" target="_blank">Snell's law</a> that with environment maps looks a bit like this:
    775 </p>
    776 
    777 <img src="/img/advanced/cubemaps_refraction_theory.png" class="clean" alt="Image explaining refraction of light for use with cubemaps."/>
    778 
    779 <p>
    780   Again, we have a view vector \(\color{gray}{\bar{I}}\), a normal vector \(\color{red}{\bar{N}}\) and this time a resulting refraction vector \(\color{green}{\bar{R}}\). As you can see, the direction of the view vector is slightly bend. This resulting bended vector \(\color{green}{\bar{R}}\) is then used to sample from the cubemap.
    781 </p>
    782 
    783 <p>
    784   Refraction is fairly easy to implement using GLSL's built-in <fun>refract</fun> function that expects a normal vector, a view direction, and a ratio between both materials' <def>refractive indices</def>.
    785 </p>
    786 
    787 <p>
    788   The refractive index determines the amount light distorts/bends in a material where each material has its own refractive index. A list of the most common refractive indices are given in the following table:
    789 </p>
    790 
    791 <table>
    792   <tr>
    793     <th>Material</th>
    794     <th>Refractive index</th>
    795   </tr>
    796   <tr>
    797     <td>Air</td>
    798     <td>1.00</td>
    799   </tr>
    800   <tr>
    801     <td>Water</td>
    802     <td>1.33</td>
    803   </tr>
    804   <tr>
    805     <td>Ice</td>
    806     <td>1.309</td>
    807   </tr>
    808   <tr>
    809     <td>Glass</td>
    810     <td>1.52</td>
    811   </tr>
    812   <tr>
    813     <td>Diamond</td>
    814     <td>2.42</td>
    815   </tr>
    816 </table>
    817 
    818 <p>
    819   We use these refractive indices to calculate the ratio between both materials the light passes through. In our case, the light/view ray goes from <em>air</em> to <em>glass</em> (if we assume the object is made of glass) so the ratio becomes \(\frac{1.00}{1.52} = 0.658\).
    820 </p>
    821 
    822 <p>
    823   We already have the cubemap bound, supplied the vertex data with normals, and set the camera position as a uniform. The only thing we have to change is the fragment shader:
    824 </p>
    825 
    826 <pre><code>
    827 void main()
    828 {             
    829     float ratio = 1.00 / 1.52;
    830     vec3 I = normalize(Position - cameraPos);
    831     vec3 R = refract(I, normalize(Normal), ratio);
    832     FragColor = vec4(texture(skybox, R).rgb, 1.0);
    833 }  
    834 </code></pre>
    835 
    836 <p>
    837   By changing the refractive indices you can create completely different visual results. Compiling the application and running the results on the container object is not so interesting though as it doesn't really show the effect refraction has aside that it acts as a magnifying glass right now. Using the same shaders on the loaded 3D model however does show us the effect we're looking for: a glass-like object.
    838 </p>
    839 
    840 <img src="/img/advanced/cubemaps_refraction.png" alt="Image of environment maps using refraction in OpenGL"/>
    841 
    842 <p>
    843   You can imagine that with the right combination of lighting, reflection, refraction and vertex movement, you can create pretty neat water graphics. Do note that for physically accurate results we should refract the light <strong>again</strong> when it leaves the object; now we simply used single-sided refraction which is fine for most purposes.
    844 </p>
    845 
    846 <h2>Dynamic environment maps</h2>
    847 <p>
    848   Right now we've been using a static combination of images as the skybox, which looks great, but it doesn't include the actual 3D scene with possibly moving objects. We didn't really notice this so far, because we only used a single object. If we had a mirror-like objects with multiple surrounding objects, only the skybox would be visible in the mirror as if it was the only object in the scene.
    849 </p>
    850 
    851 <p>
    852   Using framebuffers it is possible to create a texture of the scene for all 6 different angles from the object in question and store those in a cubemap each frame. We can then use this (dynamically generated) cubemap to create realistic reflection and refractive surfaces that include all other objects. This is called <def>dynamic environment mapping</def>, because we dynamically create a cubemap of an object's surroundings and use that as its environment map.
    853 </p>
    854 
    855 <p>
    856   While it looks great, it has one enormous disadvantage: we have to render the scene 6 times per object using an environment map, which is an enormous performance penalty on your application. Modern applications try to use the skybox as much as possible and where possible pre-render cubemaps wherever they can to still sort-of create dynamic environment maps. While dynamic environment mapping is a great technique, it requires a lot of clever tricks and hacks to get it working in an actual rendering application without too many performance drops.
    857 </p>
    858 
    859 
    860 
    861 <!--<h2>Exercises</h2>
    862 <ul>
    863   <li>Try to introduce reflection maps into the model loader we created in the <a href="https://learnopengl.com/Model-Loading/Assimp" target="_blank">model loading</a> chapters. You can find the upgraded nanosuit model with reflection maps included <a href="/objects/nanosuit_reflection.zip" target="_blank">here</a>. There are a few things to note though:</li>
    864   <ul>
    865     <li>Assimp doesn't really seem to like reflection maps in most object formats so we cheated a little by storing the reflection maps as <em>ambient maps</em>. You can then load the reflection maps by specifying <var>aiTextureType_AMBIENT</var> as the texture type when loading materials.</li>  
    866     <li>I sort of hastily created reflection map textures from the specular texture images, so the reflection maps won't map exactly to the model in some places :).</li>
    867     <li>Since the model loader by itself already takes up 3 texture units in the shader, you'll have to bind the skybox to a 4th texture unit since we'll also sample from the skybox in the same shader.</li>    
    868     </ul>
    869    <li>If you did things right it'll look something like <a href="/img/advanced/cubemaps_reflection_map.png" target="_blank">this</a>.
    870   </li>
    871 </ul>
    872 -->       
    873 
    874     </div>
    875     
    876 	</main>
    877 </body>
    878 </html>