From d63464ce4c758b544d35c0fea09f6c1d260a0cb5 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 17 Apr 2015 20:15:28 +0200 Subject: AssimpParser: create most appropriate texture material Also fixed material loading issue (was using wrong material index) Note: the flag aiProcess_FlipUVs was required to have textures displayed correctly. Change-Id: I3f5b436fad20d6bf50c8e5ddca56f78948b44fec Reviewed-by: Sean Harmer --- src/plugins/sceneparsers/assimp/assimpparser.cpp | 133 ++++++++++++++++------- src/plugins/sceneparsers/assimp/assimpparser_p.h | 1 - 2 files changed, 95 insertions(+), 39 deletions(-) diff --git a/src/plugins/sceneparsers/assimp/assimpparser.cpp b/src/plugins/sceneparsers/assimp/assimpparser.cpp index 9673deceb..e0b1713cd 100644 --- a/src/plugins/sceneparsers/assimp/assimpparser.cpp +++ b/src/plugins/sceneparsers/assimp/assimpparser.cpp @@ -43,11 +43,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -111,8 +114,73 @@ const QString TANGENT_ATTRIBUTE_NAME = QMeshData::defaultTangentAttributeName(); const QString TEXTCOORD_ATTRIBUTE_NAME = QMeshData::defaultTextureCoordinateAttributeName(); const QString COLOR_ATTRIBUTE_NAME = QMeshData::defaultColorAttributeName(); +/*! + * Returns a QMatrix4x4 from \a matrix; + */ +QMatrix4x4 aiMatrix4x4ToQMatrix4x4(const aiMatrix4x4 &matrix) Q_DECL_NOEXCEPT +{ + return QMatrix4x4(matrix.a1, matrix.a2, matrix.a3, matrix.a4, + matrix.b1, matrix.b2, matrix.b3, matrix.b4, + matrix.c1, matrix.c2, matrix.c3, matrix.c4, + matrix.d1, matrix.d2, matrix.d3, matrix.d4); +} + +QMaterial *createBestApproachingMaterial(const aiMaterial *assimpMaterial) Q_DECL_NOEXCEPT +{ + aiString path; // unused but necessary + const bool hasDiffuseTexture = (assimpMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &path) == AI_SUCCESS); + const bool hasSpecularTexture = (assimpMaterial->GetTexture(aiTextureType_SPECULAR, 0, &path) == AI_SUCCESS); + + if (hasDiffuseTexture && hasSpecularTexture) + return new QDiffuseSpecularMapMaterial(); + if (hasDiffuseTexture) + return new QDiffuseMapMaterial(); + return new QPhongMaterial(); +} + +QString texturePath(aiString path) +{ + QString p = QString::fromUtf8(path.data); + if (p.startsWith('/')) + p.remove(0, 1); + return p; +} + +/*! + * Returns the Qt3D::QParameter with named \a name if contained by the material + * \a material. If the material doesn't contain the named parameter, a new + * Qt3D::QParameter is created and inserted into the material. + */ +QParameter *findNamedParameter(const QString &name, QMaterial *material) +{ + // Does the material contain the parameter ? + foreach (QParameter *p , material->parameters()) + if (p->name() == name) + return p; + + // Does the material's effect contain the parameter ? + if (material->effect()) { + const QEffect *e = material->effect(); + foreach (QParameter *p, e->parameters()) + if (p->name() == name) + return p; + } + + // Create and add parameter to material + QParameter *p = new QParameter(material); + p->setName(name); + material->addParameter(p); + return p; } +void setParameterValue(const QString &name, QMaterial *material, const QVariant &value) +{ + QParameter *p = findNamedParameter(name, material); + p->setValue(value); +} + +} // anonymous + QStringList AssimpParser::assimpSupportedFormatsList = AssimpParser::assimpSupportedFormats(); /*! @@ -259,17 +327,6 @@ bool AssimpParser::isAssimpPath(const QString &path) return true; } -/*! - * Returns a QMatrix4x4 from \a matrix; - */ -QMatrix4x4 AssimpParser::aiMatrix4x4ToQMatrix4x4(const aiMatrix4x4 &matrix) -{ - return QMatrix4x4(matrix.a1, matrix.a2, matrix.a3, matrix.a4, - matrix.b1, matrix.b2, matrix.b3, matrix.b4, - matrix.c1, matrix.c2, matrix.c3, matrix.c4, - matrix.d1, matrix.d2, matrix.d3, matrix.d4); -} - /*! * Sets the \a source used by the parser to load the asset file. * If the file is valid, this will trigger parsing of the file. @@ -351,8 +408,9 @@ QEntity *AssimpParser::node(aiNode *node) uint meshIdx = node->mMeshes[i]; AssimpMesh * mesh = m_scene->m_meshes[meshIdx]; // mesh material - if (m_scene->m_materials.contains(meshIdx)) - entityNode->addComponent(m_scene->m_materials[meshIdx]); + uint materialIndex = m_scene->m_aiScene->mMeshes[meshIdx]->mMaterialIndex; + if (m_scene->m_materials.contains(materialIndex)) + entityNode->addComponent(m_scene->m_materials[materialIndex]); // mesh entityNode->addComponent(mesh); } @@ -368,7 +426,7 @@ QEntity *AssimpParser::node(aiNode *node) } // Add Transformations - QMatrix4x4 qTransformMatrix = AssimpParser::aiMatrix4x4ToQMatrix4x4(node->mTransformation); + const QMatrix4x4 qTransformMatrix = aiMatrix4x4ToQMatrix4x4(node->mTransformation); QTransform *transform = new QTransform(new QMatrixTransform(qTransformMatrix)); entityNode->addComponent(transform); @@ -403,7 +461,8 @@ void AssimpParser::readSceneFile(const QString &path) aiProcess_SortByPType| aiProcess_Triangulate| aiProcess_JoinIdenticalVertices| - aiProcess_GenSmoothNormals); + aiProcess_GenSmoothNormals| + aiProcess_FlipUVs); if (m_scene->m_aiScene == Q_NULLPTR) { qCWarning(AssimpParserLog) << "Assimp scene import failed"; return ; @@ -453,8 +512,9 @@ void AssimpParser::parse() */ void AssimpParser::loadMaterial(uint materialIndex) { - QMaterial *material = new QPhongMaterial(); + // Generates default material based on what the assimp material contains aiMaterial *assimpMaterial = m_scene->m_aiScene->mMaterials[materialIndex]; + QMaterial *material = createBestApproachingMaterial(assimpMaterial); // Material Name copyMaterialName(material, assimpMaterial); copyMaterialColorProperties(material, assimpMaterial); @@ -464,9 +524,7 @@ void AssimpParser::loadMaterial(uint materialIndex) // Add textures to materials dict copyMaterialTextures(material, assimpMaterial); - // TO DO : Set Material Effect and Technique - - m_scene->m_materials[materialIndex] = material; + m_scene->m_materials.insert(materialIndex, material); } /*! @@ -709,17 +767,17 @@ void AssimpParser::copyMaterialColorProperties(QMaterial *material, aiMaterial * { aiColor3D color; if (assimpMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_DIFFUSE_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + setParameterValue(ASSIMP_MATERIAL_DIFFUSE_COLOR, material, QColor::fromRgbF(color.r, color.g, color.b)); if (assimpMaterial->Get(AI_MATKEY_COLOR_SPECULAR, color) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_SPECULAR_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + setParameterValue(ASSIMP_MATERIAL_SPECULAR_COLOR, material, QColor::fromRgbF(color.r, color.g, color.b)); if (assimpMaterial->Get(AI_MATKEY_COLOR_AMBIENT, color) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_AMBIENT_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + setParameterValue(ASSIMP_MATERIAL_AMBIENT_COLOR, material, QColor::fromRgbF(color.r, color.g, color.b)); if (assimpMaterial->Get(AI_MATKEY_COLOR_EMISSIVE, color) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_EMISSIVE_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + setParameterValue(ASSIMP_MATERIAL_EMISSIVE_COLOR, material, QColor::fromRgbF(color.r, color.g, color.b)); if (assimpMaterial->Get(AI_MATKEY_COLOR_TRANSPARENT, color) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_TRANSPARENT_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + setParameterValue(ASSIMP_MATERIAL_TRANSPARENT_COLOR, material, QColor::fromRgbF(color.r, color.g, color.b)); if (assimpMaterial->Get(AI_MATKEY_COLOR_REFLECTIVE, color) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_REFLECTIVE_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + setParameterValue(ASSIMP_MATERIAL_REFLECTIVE_COLOR, material, QColor::fromRgbF(color.r, color.g, color.b)); } /*! @@ -729,9 +787,9 @@ void AssimpParser::copyMaterialBoolProperties(QMaterial *material, aiMaterial *a { int value; if (assimpMaterial->Get(AI_MATKEY_TWOSIDED, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_IS_TWOSIDED, (value == 0) ? false : true)); + setParameterValue(ASSIMP_MATERIAL_IS_TWOSIDED, material, (value == 0) ? false : true); if (assimpMaterial->Get(AI_MATKEY_ENABLE_WIREFRAME, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_IS_WIREFRAME, (value == 0) ? false : true)); + setParameterValue(ASSIMP_MATERIAL_IS_WIREFRAME, material, (value == 0) ? false : true); } void AssimpParser::copyMaterialShadingModel(QMaterial *material, aiMaterial *assimpMaterial) @@ -767,8 +825,7 @@ void AssimpParser::copyMaterialTextures(QMaterial *material, aiMaterial *assimpM aiTextureType_OPACITY, aiTextureType_REFLECTION, aiTextureType_SHININESS, - aiTextureType_SPECULAR, - /*aiTextureType_UNKNOWN*/}; + aiTextureType_SPECULAR}; if (m_scene->m_textureToParameterName.isEmpty()) { m_scene->m_textureToParameterName.insert(aiTextureType_AMBIENT, ASSIMP_MATERIAL_AMBIENT_TEXTURE); @@ -787,18 +844,18 @@ void AssimpParser::copyMaterialTextures(QMaterial *material, aiMaterial *assimpM for (unsigned int i = 0; i < sizeof(textureType)/sizeof(textureType[0]); i++) { aiString path; if (assimpMaterial->GetTexture(textureType[i], 0, &path) == AI_SUCCESS) { - QString fullPath = m_sceneDir.absoluteFilePath(QString::fromUtf8(path.data)); + QString fullPath = m_sceneDir.absoluteFilePath(texturePath(path)); // Load texture if not already loaded if (!m_scene->m_materialTextures.contains(fullPath)) { QAbstractTextureProvider *tex = new QTexture2D(); QTextureImage *texImage = new QTextureImage(); - texImage->setSource(fullPath); + texImage->setSource(QUrl::fromLocalFile(fullPath)); tex->addTextureImage(texImage); m_scene->m_materialTextures.insert(fullPath, tex); qCDebug(AssimpParserLog) << Q_FUNC_INFO << " Loaded Texture " << fullPath; } - material->addParameter(new QParameter(m_scene->m_textureToParameterName[textureType[i]], - m_scene->m_materialTextures[fullPath])); + setParameterValue(m_scene->m_textureToParameterName[textureType[i]], + material, QVariant::fromValue(m_scene->m_materialTextures[fullPath])); } } } @@ -810,15 +867,15 @@ void AssimpParser::copyMaterialFloatProperties(QMaterial *material, aiMaterial * { float value = 0; if (assimpMaterial->Get(AI_MATKEY_OPACITY, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_OPACITY, value)); + setParameterValue(ASSIMP_MATERIAL_OPACITY, material, value); if (assimpMaterial->Get(AI_MATKEY_SHININESS, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_SHININESS, value)); + setParameterValue(ASSIMP_MATERIAL_SHININESS, material, value); if (assimpMaterial->Get(AI_MATKEY_SHININESS_STRENGTH, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_SHININESS_STRENGTH, value)); + setParameterValue(ASSIMP_MATERIAL_SHININESS_STRENGTH, material, value); if (assimpMaterial->Get(AI_MATKEY_REFRACTI, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_REFRACTI, value)); + setParameterValue(ASSIMP_MATERIAL_REFRACTI, material, value); if (assimpMaterial->Get(AI_MATKEY_REFLECTIVITY, value) == aiReturn_SUCCESS) - material->addParameter(new QParameter(ASSIMP_MATERIAL_REFLECTIVITY, value)); + setParameterValue(ASSIMP_MATERIAL_REFLECTIVITY, material, value); } AssimpMesh::AssimpMesh(QNode *parent) diff --git a/src/plugins/sceneparsers/assimp/assimpparser_p.h b/src/plugins/sceneparsers/assimp/assimpparser_p.h index d24472522..b0267d472 100644 --- a/src/plugins/sceneparsers/assimp/assimpparser_p.h +++ b/src/plugins/sceneparsers/assimp/assimpparser_p.h @@ -85,7 +85,6 @@ public: private: static bool isAssimpPath(const QString &path); static QStringList assimpSupportedFormats(); - static QMatrix4x4 aiMatrix4x4ToQMatrix4x4(const aiMatrix4x4 &matrix); QEntity *node(aiNode *node); -- cgit v1.2.3