ArchitectureColoredPainting/ArchitectureColoredPainting/Model.cpp

199 lines
6.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "Model.h"
#include <QOpenGLTexture>
#include <QOpenGLContext>
#include <QTextCodec>
#include <iostream>
Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram)
: context(context)
, shaderProgram(shaderProgram)
, directory(path)
{
Assimp::Importer import;
const aiScene* scene = import.ReadFile(directory.absolutePath().toUtf8(), aiProcess_Triangulate | aiProcess_FlipUVs);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
qDebug() << "ERROR::ASSIMP::" << import.GetErrorString() << endl;
return;
}
qDebug() << directory.absolutePath() << "Load Successfully";
qDebug() << "NumMeshes: " << scene->mNumMeshes;
qDebug() << "NumMaterials: " << scene->mNumMaterials;
qDebug() << "NumTextures: " << scene->mNumTextures;
directory.cdUp();
processNode(scene->mRootNode, scene);
}
Model::~Model() //销毁对象
{
for (auto& it : textures_loaded) {
it->texture.destroy();
delete it;
}
for (auto& it : meshes) {
delete it;
}
}
void Model::draw() {
shaderProgram->bind();
for (Mesh* mesh : meshes) {
mesh->Draw();
}
}
void Model::destroy()
{
delete this;
context->doneCurrent();
}
Model* Model::createModel(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram)
{
return new Model(path, context, shaderProgram);
}
void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)
{
// 处理节点所有的网格(如果有的话)
for (unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene, mat4));
}
// 接下来对它的子节点重复这一过程
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene, mat4 * node->mChildren[i]->mTransformation);
}
}
Mesh* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 model)
{
// 初始化网格
Mesh* m_mesh = new Mesh(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>(), shaderProgram, model);
// 遍历网格的每个顶点
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
QVector3D vector; //将assimp的数据转化为QtOpenGL支持的数据
// 位置
vector.setX(mesh->mVertices[i].x);
vector.setY(mesh->mVertices[i].y);
vector.setZ(mesh->mVertices[i].z);
vertex.Position = vector;
// 法向量
if (mesh->mNormals) {
vector.setX(mesh->mNormals[i].x);
vector.setY(mesh->mNormals[i].y);
vector.setZ(mesh->mNormals[i].z);
vertex.Normal = vector;
}
// 纹理坐标
if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
{
QVector2D vec;
//一个顶点最多可以包含8个不同的纹理坐标。因此我们假设我们不用
//使用一个顶点可以有多个纹理坐标的模型,所以我们总是取第一个集合(0)。
vec.setX(mesh->mTextureCoords[0][i].x);
vec.setY(mesh->mTextureCoords[0][i].y);
vertex.TexCoords = vec;
}
else {
vertex.TexCoords = QVector2D(0, 0);
}
if (mesh->mTangents) {
// tangent
vector.setX(mesh->mTangents[i].x);
vector.setY(mesh->mTangents[i].y);
vector.setZ(mesh->mTangents[i].z);
vertex.Tangent = vector;
}
if (mesh->mBitangents) {
vector.setX(mesh->mBitangents[i].x);
vector.setY(mesh->mBitangents[i].y);
vector.setZ(mesh->mBitangents[i].z);
vertex.Bitangent = vector;
}
// bitangent
m_mesh->vertices.push_back(vertex);
}
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
// 将所有面的索引数据添加到索引数组中
for (unsigned int j = 0; j < face.mNumIndices; j++) {
m_mesh->indices.push_back(face.mIndices[j]);
}
}
// 处理材质
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
// 1. 漫反射贴图
QVector<Texture*> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
for (auto& it : diffuseMaps)
m_mesh->textures.push_back(it);
// 2. 镜面贴图
QVector<Texture*> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
for (auto& it : specularMaps)
m_mesh->textures.push_back(it);
// 3. 法向量图
QVector<Texture*> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
for (auto& it : normalMaps)
m_mesh->textures.push_back(it);
// 4. 高度图
QVector<Texture*> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
for (auto& it : heightMaps)
m_mesh->textures.push_back(it);
m_mesh->setupMesh();
return m_mesh;
}
QVector<Texture*> Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, QString typeName)
{
QVector<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.toStdString().c_str(), str.C_Str()) == 0)
{
textures.push_back(textures_loaded[j]);
skip = true; //【优化】 带有相同filepath的纹理已经加载继续到下一个
break;
}
}
if (!skip)
{ // 如果材质还没有加载,加载它
Texture* texture = new Texture;
QImage data(directory.filePath(str.C_Str()));
if (!data.isNull()) {
texture->texture.setData(data);
texture->type = typeName;
texture->path = str.C_Str();
textures.push_back(texture);
textures_loaded.push_back(texture); // store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
}
else {
qDebug() << "未能成功加载纹理:" << directory.filePath(str.C_Str());
}
}
}
return textures;
}