You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
7.9 KiB
264 lines
7.9 KiB
#include "mesh.h" |
|
#include "stb_image.h" |
|
#include "glerror.h" |
|
#include <assimp/postprocess.h> |
|
#include <fmt/core.h> |
|
|
|
|
|
Mesh::Mesh(std::vector<struct vertex> vertices, std::vector<unsigned int> indices, |
|
std::vector<struct texture> textures) |
|
{ |
|
this->vertices = vertices; |
|
this->indices = indices; |
|
this->textures = textures; |
|
|
|
setupMesh(); |
|
} |
|
|
|
|
|
void Mesh::setupMesh() |
|
{ |
|
glGenVertexArrays(1, &VAO); |
|
glGenBuffers(1, &VBO); |
|
glGenBuffers(1, &EBO); |
|
|
|
glBindVertexArray(VAO); |
|
glBindBuffer(GL_ARRAY_BUFFER, VBO); |
|
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), &vertices[0], GL_STATIC_DRAW); |
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); |
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), |
|
&indices[0], GL_STATIC_DRAW); |
|
|
|
glEnableVertexAttribArray(0); |
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)0); |
|
|
|
glEnableVertexAttribArray(1); |
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)offsetof(vertex, normal)); |
|
|
|
glEnableVertexAttribArray(2); |
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)offsetof(vertex, texture_coords)); |
|
|
|
glEnableVertexAttribArray(4); |
|
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)offsetof(vertex, tangent)); |
|
|
|
glCheckError(); |
|
glBindVertexArray(0); |
|
|
|
} |
|
|
|
void Mesh::draw(Shader *shader) { |
|
glCheckError(); |
|
unsigned int specularNr = 1; |
|
unsigned int diffuseNr = 1; |
|
unsigned int normalNr= 1; |
|
for(unsigned int i = 0; i < textures.size(); i++) |
|
{ |
|
glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding |
|
glCheckError(); |
|
// retrieve texture number (the N in diffuse_textureN) |
|
std::string number; |
|
std::string name = textures[i].type; |
|
if(name == "texture_diffuse") { |
|
number = std::to_string(diffuseNr++); |
|
} else if(name == "texture_specular") { |
|
number = std::to_string(specularNr++); |
|
} else if(name == "texture_normal") { |
|
number = std::to_string(normalNr++); |
|
} |
|
|
|
glCheckError(); |
|
shader->setInt(("material." + name + number).c_str(), i); |
|
glCheckError(); |
|
glBindTexture(GL_TEXTURE_2D, textures[i].id); |
|
glCheckError(); |
|
} |
|
|
|
// draw mesh |
|
glCheckError(); |
|
glBindVertexArray(VAO); |
|
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); |
|
glCheckError(); |
|
glBindVertexArray(0); |
|
glCheckError(); |
|
glActiveTexture(GL_TEXTURE0); |
|
glCheckError(); |
|
} |
|
|
|
|
|
|
|
/** Model */ |
|
|
|
void Model::draw(Shader *shader) |
|
{ |
|
shader->use(); |
|
for(auto mesh : meshes) { |
|
mesh.draw(shader); |
|
} |
|
} |
|
|
|
void Model::load_model(std::string path) { |
|
const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_OptimizeMeshes | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); |
|
|
|
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) |
|
{ |
|
std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl; |
|
throw std::exception(); |
|
return; |
|
} |
|
|
|
directory = path.substr(0, path.find_last_of('/')); |
|
|
|
process_node(scene->mRootNode, scene); |
|
glCheckError(); |
|
} |
|
|
|
void Model::process_node(aiNode *node, const aiScene *scene) |
|
{ |
|
for (unsigned int i = 0; i < node->mNumMeshes; i++) { |
|
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; |
|
meshes.push_back(process_mesh(mesh, scene)); |
|
} |
|
|
|
// recurse |
|
for (unsigned int i = 0; i < node->mNumChildren; i++) { |
|
process_node(node->mChildren[i], scene); |
|
} |
|
glCheckError(); |
|
} |
|
|
|
Mesh Model::process_mesh(aiMesh *mesh, const aiScene *scene) |
|
{ |
|
std::vector<vertex> vertices; |
|
std::vector<unsigned int> indices; |
|
std::vector<texture> textures; |
|
|
|
for (unsigned int i = 0 ; i < mesh->mNumVertices; i++) { |
|
glm::vec3 pos = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); |
|
glm::vec3 norm = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z); |
|
glm::vec3 tangent = glm::vec3(mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z); |
|
|
|
vertex v; |
|
v.position = pos; |
|
v.normal = norm; |
|
v.tangent = tangent; |
|
|
|
if(mesh->mTextureCoords[0]) // does the mesh contain texture coordinates? |
|
{ |
|
glm::vec2 vec; |
|
vec.x = mesh->mTextureCoords[0][i].x; |
|
vec.y = mesh->mTextureCoords[0][i].y; |
|
v.texture_coords = vec; |
|
} else { |
|
v.texture_coords = glm::vec2(0.0f); |
|
} |
|
|
|
vertices.push_back(v); |
|
} |
|
|
|
for(unsigned int i = 0; i < mesh->mNumFaces; i++) |
|
{ |
|
aiFace face = mesh->mFaces[i]; |
|
for(unsigned int j = 0; j < face.mNumIndices; j++) |
|
indices.push_back(face.mIndices[j]); |
|
} |
|
|
|
if (mesh->mMaterialIndex >= 0) { |
|
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; |
|
|
|
std::vector<texture> diffuseMaps = load_material_textures(material, aiTextureType_DIFFUSE, "texture_diffuse"); |
|
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); |
|
|
|
std::vector<texture> specularMaps = load_material_textures(material, aiTextureType_SPECULAR, "texture_specular"); |
|
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); |
|
|
|
|
|
std::vector<texture> normalMaps = load_material_textures(material, aiTextureType_HEIGHT, "texture_normal"); |
|
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end()); |
|
|
|
} |
|
|
|
glCheckError(); |
|
return Mesh(vertices, indices, textures); |
|
|
|
} |
|
|
|
|
|
unsigned int Model::texture_from_file(const char *fname, std::string directory) { |
|
std::string filename = std::string(fname); |
|
filename = directory + '/' + filename; |
|
|
|
unsigned int textureID; |
|
glGenTextures(1, &textureID); |
|
|
|
int width, height, nrComponents; |
|
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0); |
|
if (data) |
|
{ |
|
GLenum format; |
|
GLenum formatout; |
|
if (nrComponents == 1) { |
|
format = GL_RED; |
|
formatout = GL_RED; |
|
} |
|
else if (nrComponents == 3) { |
|
format = GL_RGB; |
|
formatout = GL_SRGB; |
|
} |
|
else if (nrComponents == 4) { |
|
format = GL_RGBA; |
|
formatout = GL_SRGB_ALPHA; |
|
} else { |
|
throw std::exception(); |
|
} |
|
|
|
glBindTexture(GL_TEXTURE_2D, textureID); |
|
glTexImage2D(GL_TEXTURE_2D, 0, formatout, width, height, 0, format, GL_UNSIGNED_BYTE, data); |
|
glGenerateMipmap(GL_TEXTURE_2D); |
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
|
|
stbi_image_free(data); |
|
} |
|
else |
|
{ |
|
stbi_image_free(data); |
|
} |
|
|
|
glCheckError(); |
|
return textureID; |
|
} |
|
|
|
|
|
std::vector<texture> Model::load_material_textures(aiMaterial *mat, aiTextureType type, std::string typeName) { |
|
std::vector<texture> textures; |
|
for (unsigned int i = 0; i < mat->GetTextureCount(type); i++) { |
|
aiString str; |
|
mat->GetTexture(type, i, &str); |
|
bool skip = false; |
|
|
|
for (unsigned int j = 0; j < textures_loaded.size(); j++) { |
|
if (std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0) { |
|
textures.push_back(textures_loaded[j]); |
|
skip = true; |
|
break; |
|
} |
|
} |
|
|
|
if (!skip) { |
|
texture texture; |
|
texture.id = texture_from_file(str.C_Str(), directory); |
|
texture.type = typeName; |
|
texture.path = str.C_Str(); |
|
textures.push_back(texture); |
|
textures_loaded.push_back(texture); |
|
} |
|
} |
|
|
|
glCheckError(); |
|
return textures; |
|
} |
|
|
|
|