1
+ #ifndef MODEL_MESH_H
2
+ #define MODEL_MESH_H
3
+
4
+ #include < GL\glew.h>
5
+ #include < GL\GL.h>
6
+
7
+ #include < assimp\Importer.hpp>
8
+ #include < assimp\scene.h>
9
+ #include < assimp\postprocess.h>
10
+
11
+ #include < glm\glm.hpp>
12
+ #include < glm\gtc\type_ptr.hpp>
13
+
14
+ #define STB_IMAGE_IMPLEMENTATION
15
+ #include " stb\stb_image.h"
16
+
17
+ #include < string>
18
+ #include < vector>
19
+ #include < map>
20
+ #include < memory>
21
+ #include < iostream>
22
+
23
+ using namespace std ;
24
+
25
+ class Model {
26
+
27
+ class Mesh {
28
+
29
+ private:
30
+ Model* model;
31
+
32
+ public:
33
+ Mesh (const aiMesh* mesh, Model* model) :
34
+ buffer{ 0 }, vao{ 0 },
35
+ texture_diffuse{ 0 },
36
+ texture_specular{ 0 },
37
+ texture_ambient{ 0 },
38
+ texture_normal{ 0 } {
39
+ this ->model = model;
40
+ load (mesh);
41
+ create ();
42
+ }
43
+
44
+ ~Mesh () {
45
+ glDeleteBuffers (4 , buffer);
46
+ glDeleteVertexArrays (1 , &vao);
47
+ }
48
+
49
+ // dibujar el mesh
50
+ void draw () {
51
+ glBindVertexArray (vao);
52
+ glDrawElements (GL_TRIANGLES, indices.size (), GL_UNSIGNED_INT, NULL );
53
+ glBindVertexArray (0 );
54
+ };
55
+
56
+ void draw (GLuint program) {
57
+ activeTextureNum (0 , texture_diffuse, program, " material.diffuse" );
58
+ activeTextureNum (1 , texture_normal, program, " material.normal" );
59
+ activeTextureNum (2 , texture_specular, program, " material.specular" );
60
+ activeTextureNum (3 , texture_ambient, program, " material.ambient" );
61
+
62
+
63
+ // glUniform3fv(glGetUniformLocation(program, "material.ambient"), 1, color_ambient);
64
+ // glUniform3fv(glGetUniformLocation(program, "material.diffuse"), 1, color_diffuse);
65
+ // glUniform3fv(glGetUniformLocation(program, "material.specular"), 1, color_specular);
66
+ // glUniform3fv(glGetUniformLocation(program, "material.emissive"), 1, color_emissive);
67
+ glUniform1f (glGetUniformLocation (program, " material.shininess" ), shininess);
68
+ glUniform1f (glGetUniformLocation (program, " material.shininess_strength" ), shininess_strength);
69
+
70
+ glBindVertexArray (vao);
71
+ glDrawElements (GL_TRIANGLES, indices.size (), GL_UNSIGNED_INT, NULL );
72
+ glBindVertexArray (0 );
73
+
74
+ disableAllTexture ();
75
+ };
76
+
77
+ void activeTextureNum (int num, GLuint id, GLuint program, const string& name) {
78
+ glActiveTexture (GL_TEXTURE0 + num);
79
+ glBindTexture (GL_TEXTURE_2D, id);
80
+ glUniform1i (glGetUniformLocation (program, name.c_str ()), num);
81
+ }
82
+
83
+ void disableAllTexture () {
84
+ for (size_t i = 0 ; i < 8 ; i++) {
85
+ glActiveTexture (GL_TEXTURE0 + i);
86
+ glBindTexture (GL_TEXTURE_2D, 0 );
87
+ }
88
+ }
89
+
90
+ // inicializar el mesh
91
+ void init (const aiMesh* mesh) {
92
+ load (mesh);
93
+ create ();
94
+ };
95
+
96
+ private:
97
+ vector<glm::vec3> vertex;
98
+ vector<glm::vec3> normal ;
99
+ vector<glm::vec3> tangent, bitangent;
100
+ vector<glm::vec2> uv;
101
+
102
+ vector<unsigned int > indices;
103
+
104
+ GLuint buffer[6 ];
105
+ GLuint vao;
106
+ GLuint texture_ambient, texture_diffuse, texture_specular, texture_normal;
107
+
108
+ float shininess, shininess_strength;
109
+ float color_ambient[4 ] = { 1 , 1 , 1 , 1 };
110
+ float color_diffuse[4 ] = { 1 , 1 , 1 , 1 };
111
+ float color_specular[4 ] = { 0.0 };
112
+ float color_emissive[4 ] = { 0.0 };
113
+
114
+ // obtener los datos de cada mesh
115
+ void load (const aiMesh* mesh) {
116
+
117
+ vertex.reserve (mesh->mNumVertices );
118
+ uv.reserve (mesh->mNumVertices );
119
+ normal .reserve (mesh->mNumVertices );
120
+ tangent.reserve (mesh->mNumVertices );
121
+ indices.reserve (3 * mesh->mNumFaces );
122
+
123
+ for (unsigned int i = 0 ; i < mesh->mNumVertices ; i++) {
124
+
125
+ // Obtener la posicion de cada vertice
126
+ const aiVector3D* pos = &(mesh->mVertices [i]);
127
+ vertex.push_back (glm::vec3 (pos->x , pos->y , pos->z ));
128
+
129
+ // Obtener las coordenadas de textura
130
+ if (mesh->HasTextureCoords (0 )) {
131
+ const aiVector3D* UVW = &(mesh->mTextureCoords [0 ][i]);
132
+ uv.push_back (glm::vec2 (UVW->x , UVW->y ));
133
+ }
134
+ else uv.push_back (glm::vec2 (0 , 0 ));
135
+
136
+ // Obtener los vectores normales
137
+ if (mesh->HasNormals ()) {
138
+ const aiVector3D* n = &(mesh->mNormals [i]);
139
+ normal .push_back (glm::vec3 (n->x , n->y , n->z ));
140
+ }
141
+
142
+ if (mesh->HasTangentsAndBitangents ()) {
143
+ const aiVector3D* t = &(mesh->mTangents [i]);
144
+ const aiVector3D* b = &(mesh->mBitangents [i]);
145
+
146
+ tangent.push_back (glm::vec3 (t->x , t->y , t->z ));
147
+ bitangent.push_back (glm::vec3 (b->x , b->y , b->z ));
148
+ }
149
+ }
150
+
151
+ // Obtener los indices
152
+ for (unsigned int i = 0 ; i < mesh->mNumFaces ; i++) {
153
+ indices.push_back (mesh->mFaces [i].mIndices [0 ]);
154
+ indices.push_back (mesh->mFaces [i].mIndices [1 ]);
155
+ indices.push_back (mesh->mFaces [i].mIndices [2 ]);
156
+ }
157
+
158
+ load_material (mesh, aiTextureType_AMBIENT, texture_ambient);
159
+ load_material (mesh, aiTextureType_DIFFUSE, texture_diffuse);
160
+ load_material (mesh, aiTextureType_SPECULAR, texture_specular);
161
+ load_material (mesh, aiTextureType_HEIGHT, texture_normal);
162
+
163
+ if (mesh->mMaterialIndex >= 0 ) {
164
+ // obtener el material correspondiente a este Mesh
165
+ const aiMaterial* material = model->scene ->mMaterials [mesh->mMaterialIndex ];
166
+
167
+ if (material->Get (AI_MATKEY_SHININESS, shininess) != AI_SUCCESS) shininess = 128.0 ;
168
+ if (material->Get (AI_MATKEY_SHININESS_STRENGTH, shininess_strength) != AI_SUCCESS) shininess_strength = 1.0 ;
169
+
170
+ aiColor4D diffuse, ambient, specular, emisive;
171
+
172
+ if (aiGetMaterialColor (material, AI_MATKEY_COLOR_DIFFUSE, &diffuse) == AI_SUCCESS) {
173
+ aiColorToFloat (diffuse, color_diffuse);
174
+ }
175
+
176
+ if (aiGetMaterialColor (material, AI_MATKEY_COLOR_SPECULAR, &specular) == AI_SUCCESS) {
177
+ aiColorToFloat (specular, color_specular);
178
+ }
179
+
180
+ if (aiGetMaterialColor (material, AI_MATKEY_COLOR_AMBIENT, &ambient) == AI_SUCCESS) {
181
+ aiColorToFloat (ambient, color_ambient);
182
+ }
183
+
184
+ if (aiGetMaterialColor (material, AI_MATKEY_COLOR_EMISSIVE, &emisive) == AI_SUCCESS) {
185
+ aiColorToFloat (emisive, color_emissive);
186
+ }
187
+ }
188
+ }
189
+
190
+ inline void aiColorToFloat (aiColor4D& src, float dst[4 ]) {
191
+ dst[0 ] = src.r ;
192
+ dst[1 ] = src.g ;
193
+ dst[2 ] = src.b ;
194
+ dst[3 ] = src.a ;
195
+ }
196
+
197
+ void load_material (const aiMesh* mesh, aiTextureType ttype, GLuint& texture) {
198
+ if (mesh->mMaterialIndex >= 0 ) {
199
+ const aiMaterial* material = model->scene ->mMaterials [mesh->mMaterialIndex ];
200
+
201
+ for (unsigned int i = 0 ; i < material->GetTextureCount (ttype); i++) {
202
+ aiString path;
203
+ if (AI_SUCCESS == material->GetTexture (ttype, i, &path)) {
204
+ const string tex_path = path.C_Str ();
205
+
206
+ if (model->textures .count (tex_path) == 0 ) {
207
+ texture = TextureFromFile (texture_path (path.C_Str ()));
208
+ model->textures .insert ({ tex_path, texture });
209
+ }
210
+ else texture = model->textures [tex_path];
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ GLint TextureFromFile (const std::string& filename)
217
+ {
218
+ int width, height, comp;
219
+ unsigned char *image = stbi_load (filename.c_str (), &width, &height, &comp, 3 );
220
+
221
+ if (image == nullptr ) {
222
+ cout << " Error al leer: " << filename << endl;
223
+ return 0 ;
224
+ }
225
+
226
+ cout << " Loading: " << filename << endl;
227
+
228
+ GLuint textureID = 0 ;
229
+ glGenTextures (1 , &textureID);
230
+ glBindTexture (GL_TEXTURE_2D, textureID);
231
+
232
+ glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGB, width, height, 0 , GL_RGB, GL_UNSIGNED_BYTE, image);
233
+
234
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
235
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
236
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
237
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
238
+
239
+ glBindTexture (GL_TEXTURE_2D, 0 );
240
+
241
+ stbi_image_free (image);
242
+
243
+ return textureID;
244
+ }
245
+
246
+ std::string texture_path (const std::string& path) {
247
+ size_t start = path.find_last_of (" \\ /" );
248
+ string tex_path = start == string::npos ? path : path.substr (start + 1 );
249
+ return model->directory .empty () ? tex_path : model->directory + " /" + tex_path;
250
+ }
251
+
252
+ void create () {
253
+ // generar y activar el VAO
254
+ glGenVertexArrays (1 , &vao);
255
+ glBindVertexArray (vao);
256
+
257
+ // generar dos ids para los buffer
258
+ glGenBuffers (6 , buffer);
259
+
260
+ // buffer de vertices
261
+ glBindBuffer (GL_ARRAY_BUFFER, buffer[0 ]);
262
+ glBufferData (GL_ARRAY_BUFFER, vertex.size () * sizeof (glm::vec3), &vertex[0 ], GL_STATIC_DRAW);
263
+ glVertexAttribPointer (0 , 3 , GL_FLOAT, GL_FALSE, 0 , NULL );
264
+ glEnableVertexAttribArray (0 );
265
+
266
+ // buffer de textura
267
+ if (!uv.empty ()) {
268
+ glBindBuffer (GL_ARRAY_BUFFER, buffer[1 ]);
269
+ glBufferData (GL_ARRAY_BUFFER, uv.size () * sizeof (glm::vec2), &uv[0 ], GL_STATIC_DRAW);
270
+ glVertexAttribPointer (1 , 2 , GL_FLOAT, GL_FALSE, 0 , NULL );
271
+ glEnableVertexAttribArray (1 );
272
+ }
273
+
274
+ // buffer de normales
275
+ if (!normal .empty ()) {
276
+ glBindBuffer (GL_ARRAY_BUFFER, buffer[2 ]);
277
+ glBufferData (GL_ARRAY_BUFFER, normal .size () * sizeof (glm::vec3), &normal [0 ], GL_STATIC_DRAW);
278
+ glVertexAttribPointer (2 , 3 , GL_FLOAT, GL_FALSE, 0 , NULL );
279
+ glEnableVertexAttribArray (2 );
280
+ }
281
+
282
+ if (!tangent.empty ()) {
283
+ glBindBuffer (GL_ARRAY_BUFFER, buffer[3 ]);
284
+ glBufferData (GL_ARRAY_BUFFER, tangent.size () * sizeof (glm::vec3), &tangent[0 ], GL_STATIC_DRAW);
285
+ glVertexAttribPointer (3 , 3 , GL_FLOAT, GL_FALSE, 0 , NULL );
286
+ glEnableVertexAttribArray (3 );
287
+ }
288
+
289
+ if (!bitangent.empty ()) {
290
+ glBindBuffer (GL_ARRAY_BUFFER, buffer[4 ]);
291
+ glBufferData (GL_ARRAY_BUFFER, bitangent.size () * sizeof (glm::vec3), &bitangent[0 ], GL_STATIC_DRAW);
292
+ glVertexAttribPointer (4 , 3 , GL_FLOAT, GL_FALSE, 0 , NULL );
293
+ glEnableVertexAttribArray (4 );
294
+ }
295
+
296
+ // buffer de indices
297
+ glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffer[5 ]);
298
+ glBufferData (GL_ELEMENT_ARRAY_BUFFER, indices.size () * sizeof (unsigned int ), &indices[0 ], GL_STATIC_DRAW);
299
+
300
+ // desactivar el VAO
301
+ glBindVertexArray (0 );
302
+ }
303
+ };
304
+
305
+ public:
306
+ string directory;
307
+ const aiScene* scene;
308
+ map<string, GLuint> textures;
309
+
310
+ private:
311
+ vector<shared_ptr<Mesh>> meshes;
312
+
313
+ // procesar recusivamente cada nodo de la escena
314
+ void processNode (const aiNode* node, const aiScene* scene)
315
+ {
316
+ // obtener los mesh de esta escena
317
+ for (unsigned int i = 0 ; i < node->mNumMeshes ; i++) {
318
+ shared_ptr<Mesh> mesh (new Mesh (scene->mMeshes [node->mMeshes [i]], this ));
319
+ meshes.push_back (mesh);
320
+ }
321
+
322
+ // procesar los hijos del nodo
323
+ for (unsigned int i = 0 ; i < node->mNumChildren ; i++)
324
+ this ->processNode (node->mChildren [i], scene);
325
+ }
326
+
327
+ public:
328
+ // cargar el archivo deseado
329
+ void init (const std::string& file_name) {
330
+
331
+ size_t index = file_name.find_last_of (" \\ /" );
332
+ directory = index == string::npos ? " " : file_name.substr (0 , index );
333
+
334
+ Assimp::Importer importer;
335
+ scene = importer.ReadFile (file_name, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
336
+
337
+ if (scene && scene->mRootNode )
338
+ processNode (scene->mRootNode , scene);
339
+ else cout << importer.GetErrorString () << endl;
340
+ }
341
+
342
+ // dibujar la escena completa
343
+ void draw () {
344
+ for (auto & m : meshes) m->draw ();
345
+ }
346
+
347
+ void draw (GLuint program) {
348
+ for (auto & m : meshes) m->draw (program);
349
+ }
350
+ };
351
+
352
+ #endif
0 commit comments