Skip to content

Commit 15d4bc9

Browse files
committed
Tutorial 14 - Normal Map
Uso de texturas para almacenar los vectores normales y dar mayor relieve a los modelos 3D.
1 parent 4496821 commit 15d4bc9

File tree

5 files changed

+570
-0
lines changed

5 files changed

+570
-0
lines changed

Tutorial-14/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
project(14-NormalMaps)
2+
3+
file(COPY normal-map.vs.glsl normal-map.fs.glsl DESTINATION shaders)
4+
file(COPY ../Data/cyborg DESTINATION model)
5+
6+
set(ASSIMP_DIR $ENV{ASSIMP_DIR} CACHE PATH "Assimp Directory")
7+
8+
find_package(ASSIMP REQUIRED)
9+
10+
link_directories(${ASSIMP_LIBRARY_DIRS})
11+
include_directories(${ASSIMP_INCLUDE_DIRS})
12+
13+
add_executable( ${PROJECT_NAME} normal-map.cpp
14+
modelmesh.hpp
15+
shaders/normal-map.fs.glsl
16+
shaders/normal-map.vs.glsl
17+
../common/openglwindow.hpp
18+
../common/openglshader.hpp
19+
../common/openglcamera.hpp )
20+
21+
target_link_libraries( ${PROJECT_NAME} ${GRAPHIC_LIBS} ${ASSIMP_LIBRARIES})

Tutorial-14/ModelMesh.hpp

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
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

Comments
 (0)