LearnOpenGL

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

Model.html (36096B)


      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">Model</h1>
    320 <h1 id="content-url" style='display:none;'>Model-Loading/Model</h1>
    321 <p>
    322   Now it is time to get our hands dirty with Assimp and start creating the actual loading and translation code. The goal of this chapter is to create another class that represents a model in its entirety, that is, a model that contains multiple meshes, possibly with multiple textures. A house, that contains a wooden balcony, a tower, and perhaps a swimming pool, could still be loaded as a single model. We'll load the model via Assimp and translate it to multiple <fun>Mesh</fun> objects we've created in the <a href="https://learnopengl.com/Model-Loading/Mesh" target="_blank">previous</a> chapter.
    323 </p>
    324 
    325 <p>
    326   Without further ado, I present you the class structure of the <fun>Model</fun> class:
    327 </p>
    328 
    329 <pre><code>
    330 class Model 
    331 {
    332     public:
    333         Model(char *path)
    334         {
    335             loadModel(path);
    336         }
    337         void Draw(Shader &shader);	
    338     private:
    339         // model data
    340         vector&lt;Mesh&gt; meshes;
    341         string directory;
    342 
    343         void loadModel(string path);
    344         void processNode(aiNode *node, const aiScene *scene);
    345         Mesh processMesh(aiMesh *mesh, const aiScene *scene);
    346         vector&lt;Texture&gt; loadMaterialTextures(aiMaterial *mat, aiTextureType type, 
    347                                              string typeName);
    348 };
    349 </code></pre>
    350 
    351 <p>
    352   The <fun>Model</fun> class contains a vector of <fun>Mesh</fun> objects and requires us to give it a file location in its constructor. It then loads the file right away via the <fun>loadModel</fun> function that is called in the constructor. The private functions are all designed to process a part of Assimp's import routine and we'll cover them shortly. We also store the directory of the file path that we'll later need when loading textures.
    353 </p>
    354 
    355 <p>
    356   The <fun>Draw</fun> function is nothing special and basically loops over each of the meshes to call their respective <fun>Draw</fun> function:
    357 </p>
    358 
    359 <pre><code>
    360 void Draw(Shader &shader)
    361 {
    362     for(unsigned int i = 0; i &lt; meshes.size(); i++)
    363         meshes[i].Draw(shader);
    364 }  
    365 </code></pre>
    366 
    367 <h2>Importing a 3D model into OpenGL</h2>
    368 <p>
    369   To import a model and translate it to our own structure, we first need to include the appropriate headers of Assimp:
    370 </p>
    371 
    372 <pre><code>
    373 #include &lt;assimp/Importer.hpp&gt;
    374 #include &lt;assimp/scene.h&gt;
    375 #include &lt;assimp/postprocess.h&gt;
    376 </code></pre>
    377 
    378 <p>
    379   The first function we're calling is <fun>loadModel</fun>, that's directly called from the constructor. Within <fun>loadModel</fun>, we use Assimp to load the model into a data structure of Assimp called a <u>scene</u> object. You may remember from the <a href="https://learnopengl.com/Model-Loading/Assimp" target="_blank">first</a> chapter of the model loading series that this is the root object of Assimp's data interface. Once we have the scene object, we can access all the data we need from the loaded model.
    380 </p>
    381 
    382 <p>
    383   The great thing about Assimp is that it neatly abstracts from all the technical details of loading all the different file formats and does all this with a single one-liner:
    384 </p>
    385 
    386 <pre><code>
    387 Assimp::Importer importer;
    388 const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); 
    389 </code></pre>
    390 
    391 <p>
    392   We first declare an <fun>Importer</fun> object from Assimp's namespace and then call its <fun>ReadFile</fun> function. The function expects a file path and several <def>post-processing</def> options as its second argument. Assimp allows us to specify several options that forces Assimp to do extra calculations/operations on the imported data. By setting <var>aiProcess_Triangulate</var> we tell Assimp that if the model does not (entirely) consist of triangles, it should transform all the model's primitive shapes to triangles first. The <var>aiProcess_FlipUVs</var> flips the texture coordinates on the y-axis where necessary during processing (you may remember from the <a href="https://learnopengl.com/Getting-started/Textures" target="_blank">Textures</a> chapter that most images in OpenGL were reversed around the y-axis; this little postprocessing option fixes that for us). A few other useful options are:
    393   
    394   <ul>
    395     <li><var>aiProcess_GenNormals</var>: creates normal vectors for each vertex if the model doesn't contain normal vectors.</li>
    396     <li><var>aiProcess_SplitLargeMeshes</var>: splits large meshes into smaller sub-meshes which is useful if your rendering has a maximum number of vertices allowed and can only process smaller meshes.</li>
    397     <li><var>aiProcess_OptimizeMeshes</var>: does the reverse by trying to join several meshes into one larger mesh, reducing drawing calls for optimization.</li>
    398   </ul>
    399   
    400   Assimp provides a great set of postprocessing options and you can find all of them <a href="http://assimp.sourceforge.net/lib_html/postprocess_8h.html" target="_blank">here</a>. Loading a model via Assimp is (as you can see) surprisingly easy. The hard work is in using the returned scene object to translate the loaded data to an array of <code>Mesh</code> objects.
    401 </p>
    402 
    403 <p>
    404   The complete <fun>loadModel</fun> function is listed here:
    405 </p>
    406 
    407 <pre><code>
    408 void loadModel(string path)
    409 {
    410     Assimp::Importer import;
    411     const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);	
    412 	
    413     if(!scene || scene-&gt;mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene-&gt;mRootNode) 
    414     {
    415         cout &lt;&lt; "ERROR::ASSIMP::" &lt;&lt; import.GetErrorString() &lt;&lt; endl;
    416         return;
    417     }
    418     directory = path.substr(0, path.find_last_of('/'));
    419 
    420     processNode(scene-&gt;mRootNode, scene);
    421 }  
    422 </code></pre>
    423 
    424 <p>
    425   After we load the model, we check if the scene and the root node of the scene are not null and check one of its flags to see if the returned data is incomplete. If any of these error conditions are met, we report the error retrieved from the importer's <fun>GetErrorString</fun> function and return. We also retrieve the directory path of the given file path.
    426 </p>
    427 
    428 <p>
    429   If nothing went wrong, we want to process all of the scene's nodes. We pass the first node (root node) to the recursive <fun>processNode</fun> function. Because each node (possibly) contains a set of children we want to first process the node in question, and then continue processing all the node's children and so on. This fits a recursive structure, so we'll be defining a recursive function. A recursive function is a function that does some processing and <def>recursively</def> calls the same function with different parameters until a certain condition is met. In our case the <def>exit condition</def> is met when all nodes have been processed.
    430 </p>
    431 
    432 <p>
    433   As you may remember from Assimp's structure, each node contains a set of mesh indices where each index points to a specific mesh located in the scene object. We thus want to retrieve these mesh indices, retrieve each mesh, process each mesh, and then do this all again for each of the node's children nodes. The content of the <fun>processNode</fun> function is shown below:
    434 </p>
    435 
    436 <pre><code>
    437 void processNode(aiNode *node, const aiScene *scene)
    438 {
    439     // process all the node's meshes (if any)
    440     for(unsigned int i = 0; i &lt; node-&gt;mNumMeshes; i++)
    441     {
    442         aiMesh *mesh = scene-&gt;mMeshes[node-&gt;mMeshes[i]]; 
    443         meshes.push_back(processMesh(mesh, scene));			
    444     }
    445     // then do the same for each of its children
    446     for(unsigned int i = 0; i &lt; node-&gt;mNumChildren; i++)
    447     {
    448         processNode(node-&gt;mChildren[i], scene);
    449     }
    450 }  
    451 </code></pre>
    452 
    453 <p>
    454   We first check each of the node's mesh indices and retrieve the corresponding mesh by indexing the scene's <var>mMeshes</var> array. The returned mesh is then passed to the <fun>processMesh</fun> function that returns a <fun>Mesh</fun> object that we can store in the <var>meshes</var> list/vector. 
    455 </p>
    456 
    457 <p>
    458   Once all the meshes have been processed, we iterate through all of the node's children and call the same <fun>processNode</fun> function for each its children. Once a node no longer has any children, the recursion stops.
    459 </p>
    460 
    461 <note>
    462   A careful reader may have noticed that we could forget about processing any of the nodes and simply loop through all of the scene's meshes directly, without doing all this complicated stuff with indices. The reason we're doing this is that the initial idea for using nodes like this is that it defines a parent-child relation between meshes. By recursively iterating through these relations, we can define certain meshes to be parents of other meshes.<br/>
    463   An example use case for such a system is when you want to translate a car mesh and make sure that all its children (like an engine mesh, a steering wheel mesh, and its tire meshes) translate as well; such a system is easily created using parent-child relations.<br/><br/>
    464   Right now however we're not using such a system, but it is generally recommended to stick with this approach for whenever you want extra control over your mesh data. These node-like relations are after all defined by the artists who created the models.
    465 </note>
    466 
    467 <p>
    468   The next step is to process Assimp's data into the <fun>Mesh</fun> class from the previous chapter.
    469 </p>
    470 
    471 <h3>Assimp to Mesh</h3>
    472 <p>
    473   Translating an <code>aiMesh</code> object to a mesh object of our own is not too difficult. All we need to do, is access each of the mesh's relevant properties and store them in our own object. The general structure of the <fun>processMesh</fun> function then becomes:
    474 </p>
    475 
    476 <pre><code>
    477 Mesh processMesh(aiMesh *mesh, const aiScene *scene)
    478 {
    479     vector&lt;Vertex&gt; vertices;
    480     vector&lt;unsigned int&gt; indices;
    481     vector&lt;Texture&gt; textures;
    482 
    483     for(unsigned int i = 0; i &lt; mesh-&gt;mNumVertices; i++)
    484     {
    485         Vertex vertex;
    486         // process vertex positions, normals and texture coordinates
    487         [...]
    488         vertices.push_back(vertex);
    489     }
    490     // process indices
    491     [...]
    492     // process material
    493     if(mesh-&gt;mMaterialIndex &gt;= 0)
    494     {
    495         [...]
    496     }
    497 
    498     return Mesh(vertices, indices, textures);
    499 }  
    500 </code></pre>
    501 
    502 <p>
    503   Processing a mesh is a 3-part process: retrieve all the vertex data, retrieve the mesh's indices, and finally retrieve the relevant material data. The processed data is stored in one of the <code>3</code> vectors and from those a <fun>Mesh</fun> is created and returned to the function's caller.
    504 </p>
    505 
    506 <p>
    507   Retrieving the vertex data is pretty simple: we define a <fun>Vertex</fun> struct that we add to the <var>vertices</var> array after each loop iteration. We loop for as much vertices there exist within the mesh (retrieved via <code>mesh-&gt;mNumVertices</code>). Within the iteration we want to fill this struct with all the relevant data. For vertex positions this is done as follows:
    508 </p>
    509 
    510 <pre><code>
    511 glm::vec3 vector; 
    512 vector.x = mesh-&gt;mVertices[i].x;
    513 vector.y = mesh-&gt;mVertices[i].y;
    514 vector.z = mesh-&gt;mVertices[i].z; 
    515 vertex.Position = vector;
    516 </code></pre>
    517 
    518 <p>
    519   Note that we define a temporary <code>vec3</code> for transferring Assimp's data to. This is necessary as Assimp maintains its own data types for vector, matrices, strings etc. and they don't convert that well to glm's data types.
    520 </p>
    521 
    522 <note>
    523   Assimp calls their vertex position array <var>mVertices</var> which isn't the most intuitive name.
    524 </note>
    525 
    526 <p>
    527   The procedure for normals should come as no surprise now:
    528 </p>
    529 
    530 <pre><code>
    531 vector.x = mesh-&gt;mNormals[i].x;
    532 vector.y = mesh-&gt;mNormals[i].y;
    533 vector.z = mesh-&gt;mNormals[i].z;
    534 vertex.Normal = vector;  
    535 </code></pre>
    536 
    537 <p>
    538   Texture coordinates are roughly the same, but Assimp allows a model to have up to 8 different texture coordinates per vertex. We're not going to use 8, we only care about the first set of texture coordinates. We'll also want to check if the mesh actually contains texture coordinates (which may not be always the case):
    539 </p>
    540 
    541 <pre><code>
    542 if(mesh-&gt;mTextureCoords[0]) // does the mesh contain texture coordinates?
    543 {
    544     glm::vec2 vec;
    545     vec.x = mesh-&gt;mTextureCoords[0][i].x; 
    546     vec.y = mesh-&gt;mTextureCoords[0][i].y;
    547     vertex.TexCoords = vec;
    548 }
    549 else
    550     vertex.TexCoords = glm::vec2(0.0f, 0.0f);  
    551 </code></pre>
    552 
    553 <p>
    554   The <var>vertex</var> struct is now completely filled with the required vertex attributes and we can push it to the back of the <var>vertices</var> vector at the end of the iteration. This process is repeated for each of the mesh's vertices. 
    555 </p>
    556 
    557 <h3>Indices</h3>
    558 <p>
    559   Assimp's interface defines each mesh as having an array of faces, where each face represents a single primitive, which in our case (due to the <var>aiProcess_Triangulate</var> option) are always triangles. A face contains the indices of the vertices we need to draw in what order for its primitive. So if we iterate over all the faces and store all the face's indices in the <var>indices</var> vector we're all set:
    560 </p>
    561 
    562 <pre><code>
    563 for(unsigned int i = 0; i &lt; mesh-&gt;mNumFaces; i++)
    564 {
    565     aiFace face = mesh-&gt;mFaces[i];
    566     for(unsigned int j = 0; j &lt; face.mNumIndices; j++)
    567         indices.push_back(face.mIndices[j]);
    568 }  
    569 </code></pre>
    570 
    571 <p>
    572   After the outer loop has finished, we now have a complete set of vertices and index data for drawing the mesh via <fun><function id='2'>glDrawElements</function></fun>. However, to finish the discussion and to add some detail to the mesh, we want to process the mesh's material as well.
    573 </p>
    574 
    575 <h3>Material</h3>
    576 <p>
    577   Similar to nodes, a mesh only contains an index to a material object. To retrieve the material of a mesh, we need to index the scene's <var>mMaterials</var> array. The mesh's material index is set in its <var>mMaterialIndex</var> property, which we can also query to check if the mesh contains a material or not:
    578 </p>
    579 
    580 <pre><code>
    581 if(mesh-&gt;mMaterialIndex &gt;= 0)
    582 {
    583     aiMaterial *material = scene-&gt;mMaterials[mesh-&gt;mMaterialIndex];
    584     vector&lt;Texture&gt; diffuseMaps = loadMaterialTextures(material, 
    585                                         aiTextureType_DIFFUSE, "texture_diffuse");
    586     textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
    587     vector&lt;Texture&gt; specularMaps = loadMaterialTextures(material, 
    588                                         aiTextureType_SPECULAR, "texture_specular");
    589     textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
    590 }  
    591 </code></pre>
    592 
    593 <p>
    594   We first retrieve the <code>aiMaterial</code> object from the scene's <var>mMaterials</var> array. Then we want to load the mesh's diffuse and/or specular textures. A material object internally stores an array of texture locations for each texture type. The different texture types are all prefixed with <code>aiTextureType_</code>. We use a helper function called <fun>loadMaterialTextures</fun> to retrieve, load, and initialize the textures from the material. The function returns a vector of <fun>Texture</fun> structs that we store at the end of the model's <var>textures</var> vector.
    595 </p>
    596 
    597 <p>
    598   The <fun>loadMaterialTextures</fun> function iterates over all the texture locations of the given texture type, retrieves the texture's file location and then loads and generates the texture and stores the information in a <fun>Vertex</fun> struct. It looks like this:
    599 </p>
    600 
    601 <pre><code>
    602 vector&lt;Texture&gt; loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName)
    603 {
    604     vector&lt;Texture&gt; textures;
    605     for(unsigned int i = 0; i &lt; mat-&gt;GetTextureCount(type); i++)
    606     {
    607         aiString str;
    608         mat-&gt;GetTexture(type, i, &str);
    609         Texture texture;
    610         texture.id = TextureFromFile(str.C_Str(), directory);
    611         texture.type = typeName;
    612         texture.path = str;
    613         textures.push_back(texture);
    614     }
    615     return textures;
    616 }  
    617 </code></pre>
    618 
    619 <p>
    620   We first check the amount of textures stored in the material via its <fun>GetTextureCount</fun> function that expects one of the texture types we've given. We retrieve each of the texture's file locations via the <fun>GetTexture</fun> function that stores the result in an <code>aiString</code>. We then use another helper function called <fun>TextureFromFile</fun> that loads a texture (with <code>stb_image.h</code>) for us and returns the texture's ID. You can check the complete code listing at the end for its content if you're not sure how such a function is written.
    621 </p>
    622 
    623 <note>
    624   Note that we make the assumption that texture file paths in model files are local to the actual model object e.g. in the same directory as the location of the model itself. We can then simply concatenate the texture location string and the directory string we retrieved earlier (in the <fun>loadModel</fun> function) to get the complete texture path (that's why the <fun>GetTexture</fun> function also needs the directory string).<br/><br/>Some models found over the internet use absolute paths for their texture locations, which won't work on each machine. In that case you probably want to manually edit the file to use local paths for the textures (if possible).
    625 </note>
    626 
    627 <p>
    628   And that is all there is to importing a model with Assimp. 
    629 </p>
    630 
    631 <h1>An optimization</h1>
    632 <p>
    633   We're not completely done yet, since there is still a large (but not completely necessary) optimization we want to make. Most scenes re-use several of their textures onto several meshes; think of a house again that has a granite texture for its walls. This texture could also be applied to the floor, its ceilings, the staircase, perhaps a table, and maybe even a small well close by. Loading textures is not a cheap operation and in our current implementation a new texture is loaded and generated for each mesh, even though the exact same texture could have been loaded several times before. This quickly becomes the bottleneck of your model loading implementation.
    634 </p>
    635 
    636 <p>
    637   So we're going to add one small tweak to the model code by storing all of the loaded textures globally. Wherever we want to load a texture, we first check if it hasn't been loaded already. If so, we take that texture and skip the entire loading routine, saving us a lot of processing power. To be able to compare textures we need to store their path as well:
    638 </p>
    639 
    640 <pre><code>
    641 struct Texture {
    642     unsigned int id;
    643     string type;
    644     string path;  // we store the path of the texture to compare with other textures
    645 };
    646 </code></pre>
    647 
    648 <p>
    649   Then we store all the loaded textures in another vector declared at the top of the model's class file as a private variable:
    650 </p>
    651 
    652 <pre><code>
    653 vector&lt;Texture&gt; textures_loaded; 
    654 </code></pre>
    655 
    656 <p>
    657   In the <fun>loadMaterialTextures</fun> function, we want to compare the texture path with all the textures in the <var>textures_loaded</var> vector to see if the current texture path equals any of those. If so, we skip the texture loading/generation part and simply use the located texture struct as the mesh's texture. The (updated) function is shown below:
    658 </p>
    659 
    660 <pre><code>
    661 vector&lt;Texture&gt; loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName)
    662 {
    663     vector&lt;Texture&gt; textures;
    664     for(unsigned int i = 0; i &lt; mat-&gt;GetTextureCount(type); i++)
    665     {
    666         aiString str;
    667         mat-&gt;GetTexture(type, i, &str);
    668         bool skip = false;
    669         for(unsigned int j = 0; j &lt; textures_loaded.size(); j++)
    670         {
    671             if(std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0)
    672             {
    673                 textures.push_back(textures_loaded[j]);
    674                 skip = true; 
    675                 break;
    676             }
    677         }
    678         if(!skip)
    679         {   // if texture hasn't been loaded already, load it
    680             Texture texture;
    681             texture.id = TextureFromFile(str.C_Str(), directory);
    682             texture.type = typeName;
    683             texture.path = str.C_Str();
    684             textures.push_back(texture);
    685             textures_loaded.push_back(texture); // add to loaded textures
    686         }
    687     }
    688     return textures;
    689 }  
    690 </code></pre>
    691 
    692 <warning>
    693   Some versions of Assimp tend to load models quite slow when using the debug version and/or the debug mode of your IDE, so be sure to test it out with release versions as well if you run into slow loading times.
    694 </warning>
    695 
    696 <p>
    697   You can find the complete source code of the <fun>Model</fun> class <a href="/code_viewer_gh.php?code=includes/learnopengl/model.h" target="_blank">here</a>.
    698 </p>
    699 
    700 <h1>No more containers!</h1>
    701 <p>
    702   So let's give our implementation a spin by actually importing a model created by genuine artists, not something done by the creative genius that I am. Because I don't want to give myself too much credit, I'll occasionally allow some other artists to join the ranks and this time we're going to load this amazing  <a href="https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36" target="_blank">Survival Guitar Backpack</a> by Berk Gedik. I've modified the material and paths a bit so it works directly with the way we've set up the model loading. The model is exported as a <code>.obj</code> file together with a <code>.mtl</code> file that links to the model's diffuse, specular, and normal maps (we'll get to those later). You can download the adjusted model for this chapter <a href="/data/models/backpack.zip" target="_blank">here</a>. Note that there's a few extra texture types we won't be using yet, and that all the textures and the model file(s) should be located in the same directory for the textures to load.
    703 </p>
    704 
    705 <note>
    706   The modified version of the backpack uses local relative texture paths, and renamed the albedo and metallic textures to diffuse and specular respectively. 
    707 </note>
    708 
    709 <p>
    710   Now, declare a <fun>Model</fun> object and pass in the model's file location. The model should then automatically load and (if there were no errors) render the object in the render loop using its <fun>Draw</fun> function and that is it. No more buffer allocations, attribute pointers, and render commands, just a simple one-liner. If you create a simple set of shaders where the fragment shader only outputs the object's diffuse texture, the result looks a bit like this:
    711 </p>
    712 
    713 <img src="/img/model_loading/model_diffuse.png"/>
    714 
    715 <p>
    716   You can find the complete source code <a href="/code_viewer_gh.php?code=src/3.model_loading/1.model_loading/model_loading.cpp" target="_blank">here</a>. Note that we tell <code>stb_image.h</code> to flip textures vertically, if you haven't done so already, before we load the model. Otherwise the textures will look all messed up.
    717 </p>
    718 
    719 <p>
    720   We can also get more creative and introduce point lights to the render equation as we learned from the <a href="https://learnopengl.com/Lighting/Light-casters" target="_blank">Lighting</a> chapters and together with specular maps get amazing results:
    721 </p>
    722 
    723 <img src="/img/model_loading/model_lighting.png"/>
    724 
    725 <p>
    726   Even I have to admit that this is maybe a bit more fancy than the containers we've used so far.  
    727   Using Assimp you can load tons of models found over the internet. There are quite a few resource websites that offer free 3D models for you to download in several file formats. Do note that some models still won't load properly, have texture paths that won't work, or are simply exported in a format even Assimp can't read. 
    728 </p>
    729 
    730 <h2>Further reading</h2>
    731 <ul>
    732     <li><a href="https://www.youtube.com/watch?v=4DQquG_o-Ac" target="_blank">How-To Texture Wavefront (.obj) Models for OpenGL</a>: great video guide by Matthew Early on how to set up 3D models in Blender so they directly work with the current model loader (as the texture setup we've chosen doesn't always work out of the box).</li>
    733 </ul>
    734 <!--
    735 <h2>Exercises</h2>
    736 <p>
    737   <ul>
    738     <li>Can you re-create the last scene with the two point lights?: <a href="/code_viewer.php?code=model_loading/model-exercise1" target="_blank">solution</a>, <a href="/code_viewer.php?code=model_loading/model-exercise1-shaders" target="_blank">shaders</a>.</li>
    739   </ul>
    740 </p>
    741 -->
    742        
    743 
    744     </div>
    745     
    746 	</main>
    747 </body>
    748 </html>