opengl-playground/src/model.cpp

146 lines
4.2 KiB
C++

#include <opengl-playground/model.hpp>
#include <opengl-playground/material.hpp>
#include <iostream>
Model::Model(const std::string &path, const glm::vec4 &static_color, std::shared_ptr<OpenGlShaderProgram> shader)
: OpenGlGraphics(shader)
{
this->model_path = path;
this->static_color = static_color;
}
void Model::render()
{
for (unsigned int i = 0; i < meshes.size(); i++) {
meshes[i].render(this->model_matrix, this->normal_matrix);
}
}
void Model::realize()
{
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(this->model_path, aiProcess_Triangulate | aiProcess_FlipUVs);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cout << "Error: Assimp: " << importer.GetErrorString() << std::endl;
return;
}
this->directory = this->model_path.substr(0, this->model_path.find_last_of('/'));
this->processNode(scene->mRootNode, scene);
importer.FreeScene();
}
void Model::processNode(aiNode *node, const aiScene *scene)
{
for(unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
this->meshes.push_back(this->processMesh(mesh, scene));
}
for(unsigned int i = 0; i < node->mNumChildren; i++)
{
this->processNode(node->mChildren[i], scene);
}
}
std::vector<std::shared_ptr<OpenGlTexture>> Model::loadMaterialTextures(aiMaterial *mat, aiTextureType type)
{
std::vector<std::shared_ptr<OpenGlTexture>> tex_vector;
for (unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
aiString str;
mat->GetTexture(type, i, &str);
bool already_loaded = false;
for (unsigned int j = 0; j < this->allocated_textures.size(); j++) {
if (std::strcmp(this->allocated_textures[j]->getPath().c_str(), str.C_Str()) == 0) {
/* texture already loaded */
tex_vector.push_back(this->allocated_textures[j]);
already_loaded = true;
break;
}
}
if (!already_loaded) {
auto new_texture = std::make_shared<OpenGlTexture>(str.C_Str());
new_texture->loadFromImagePath(this->directory);
tex_vector.push_back(new_texture);
this->allocated_textures.push_back(new_texture);
}
}
return tex_vector;
}
Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene)
{
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
Material mesh_material;
for(unsigned int i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
glm::vec3 vector;
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
if(mesh->mTextureCoords[0]) {
glm::vec2 vec;
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TextureCoords = vec;
} else {
vertex.TextureCoords = glm::vec2(0.0f, 0.0f);
}
vertices.push_back(vertex);
}
// process indices
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)
{
aiColor3D col;
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
auto diffuseTextures = loadMaterialTextures(material, aiTextureType_DIFFUSE);
auto specularTextures = loadMaterialTextures(material, aiTextureType_SPECULAR);
auto ambientTextures = loadMaterialTextures(material, aiTextureType_AMBIENT);
mesh_material.pushDiffuseTexture(diffuseTextures);
mesh_material.pushSpecularTexture(specularTextures);
mesh_material.pushAmbientTexture(ambientTextures);
if (!material->Get(AI_MATKEY_COLOR_AMBIENT, col))
mesh_material.setAmbientColor(glm::vec3(col.r, col.g, col.b));
if (!material->Get(AI_MATKEY_COLOR_SPECULAR, col))
mesh_material.setSpecularColor(glm::vec3(col.r, col.g, col.b));
if (!material->Get(AI_MATKEY_COLOR_DIFFUSE, col))
mesh_material.setDiffuseColor(glm::vec3(col.r, col.g, col.b));
material->Get(AI_MATKEY_SHININESS, mesh_material.shininess);
material->Get(AI_MATKEY_SHININESS_STRENGTH, mesh_material.shininess_strength);
std::cout << "Material: " << mesh_material << std::endl;
}
Mesh my_mesh = Mesh(vertices, indices, mesh_material, this->shaderprog);
my_mesh.realize();
return my_mesh;
}