1#include <IO/AssimpLoader/AssimpGeometryDataLoader.hpp>
3#include <assimp/mesh.h>
4#include <assimp/scene.h>
6#include <Core/Utils/Log.hpp>
8#include <Core/Asset/BlinnPhongMaterialData.hpp>
13using namespace Core::Utils;
14using namespace Core::Asset;
16AssimpGeometryDataLoader::AssimpGeometryDataLoader(
const std::string& filepath,
17 const bool VERBOSE_MODE ) :
18 DataLoader<GeometryData>( VERBOSE_MODE ), m_filepath( filepath ) {}
20AssimpGeometryDataLoader::~AssimpGeometryDataLoader() =
default;
22void AssimpGeometryDataLoader::loadData(
const aiScene* scene,
26 if ( scene ==
nullptr ) {
27 LOG( logINFO ) <<
"AssimpGeometryDataLoader : scene is nullptr.";
31 if ( !sceneHasGeometry( scene ) ) {
32 LOG( logINFO ) <<
"AssimpGeometryDataLoader : scene has no mesh.";
37 LOG( logINFO ) <<
"File contains geometry.";
38 LOG( logINFO ) <<
"Geometry Loading begin...";
41 loadGeometryData( scene, data );
43 if ( m_verbose ) { LOG( logINFO ) <<
"Geometry Loading end.\n"; }
46bool AssimpGeometryDataLoader::sceneHasGeometry(
const aiScene* scene )
const {
47 return ( sceneGeometrySize( scene ) != 0 );
50uint AssimpGeometryDataLoader::sceneGeometrySize(
const aiScene* scene )
const {
52 if ( scene->HasMeshes() ) {
53 const uint size = scene->mNumMeshes;
54 for ( uint i = 0; i < size; ++i ) {
55 aiMesh* mesh = scene->mMeshes[i];
56 if ( mesh->HasPositions() ) { ++mesh_size; }
62void AssimpGeometryDataLoader::loadMeshAttrib(
const aiMesh& mesh,
66 fetchName( mesh, data, usedNames );
67 fetchType( mesh, data );
74 mesh.mVertices, mesh.mNumVertices, geo, Core::Geometry::MeshAttrib::VERTEX_POSITION );
75 if ( mesh.HasNormals() ) {
76 fetchAttribute( mesh.mNormals,
79 Core::Geometry::MeshAttrib::VERTEX_NORMAL );
81 if ( mesh.HasTangentsAndBitangents() ) {
82 fetchAttribute( mesh.mTangents,
85 Core::Geometry::MeshAttrib::VERTEX_TANGENT );
86 fetchAttribute( mesh.mBitangents,
89 Core::Geometry::MeshAttrib::VERTEX_BITANGENT );
93 if ( mesh.GetNumUVChannels() > 1 ) {
95 <<
"Assimp loader : several UV channels are set, Radium will use only the 1st";
97 if ( mesh.HasTextureCoords( 0 ) ) {
98 fetchAttribute( mesh.mTextureCoords[0],
101 Core::Geometry::MeshAttrib::VERTEX_TEXCOORD );
104 if ( mesh.HasVertexColors( 0 ) ) {
105 fetchAttribute( mesh.mColors[0],
108 Core::Geometry::MeshAttrib::VERTEX_COLOR );
114 case GeometryData::GeometryType::LINE_MESH:
115 fetchIndexLayer<Core::Geometry::LineIndexLayer>( mesh.mFaces, mesh.mNumFaces, geo );
117 case GeometryData::GeometryType::TRI_MESH:
118 fetchIndexLayer<Core::Geometry::TriangleIndexLayer>( mesh.mFaces, mesh.mNumFaces, geo );
120 case GeometryData::GeometryType::QUAD_MESH:
121 fetchIndexLayer<Core::Geometry::QuadIndexLayer>( mesh.mFaces, mesh.mNumFaces, geo );
123 case GeometryData::GeometryType::POLY_MESH:
124 fetchIndexLayer<Core::Geometry::PolyIndexLayer>( mesh.mFaces, mesh.mNumFaces, geo );
126 case GeometryData::GeometryType::POINT_CLOUD:
129 std::make_unique<Core::Geometry::PointCloudIndexLayer>(
size_t( mesh.mNumVertices ) );
138void AssimpGeometryDataLoader::loadMeshFrame(
140 const Core::Transform& parentFrame,
143 const uint child_size = node->mNumChildren;
144 const uint mesh_size = node->mNumMeshes;
145 if ( ( child_size == 0 ) && ( mesh_size == 0 ) ) {
return; }
147 Core::Transform frame = parentFrame * assimpToCore( node->mTransformation );
148 for ( uint i = 0; i < mesh_size; ++i ) {
149 const uint ID = node->mMeshes[i];
150 auto it = indexTable.
find( ID );
151 if ( it != indexTable.
end() ) { data[it->second]->
setFrame( frame ); }
154 for ( uint i = 0; i < child_size; ++i ) {
155 loadMeshFrame( node->mChildren[i], frame, indexTable, data );
159void AssimpGeometryDataLoader::fetchName(
const aiMesh& mesh,
163 while ( usedNames.
find( name ) != usedNames.
end() ) {
170void AssimpGeometryDataLoader::fetchType(
const aiMesh& mesh, GeometryData& data )
const {
171 data.setType( GeometryData::UNKNOWN );
175 for ( uint i = 0; i < mesh.mNumFaces; ++i ) {
176 face_max =
std::max( face_max, mesh.mFaces[i].mNumIndices );
177 face_min =
std::min( face_min, mesh.mFaces[i].mNumIndices );
179 switch ( face_max ) {
182 data.setType( GeometryData::POINT_CLOUD );
185 data.setType( GeometryData::LINE_MESH );
188 data.setType( GeometryData::TRI_MESH );
191 if ( face_max - face_min == 0 ) { data.setType( GeometryData::QUAD_MESH ); }
192 else { data.setType( GeometryData::POLY_MESH ); }
195 data.setType( GeometryData::POLY_MESH );
200void AssimpGeometryDataLoader::fetchPolyhedron(
const aiMesh& mesh, GeometryData& data )
const {
206void AssimpGeometryDataLoader::loadMaterial(
const aiMaterial& material,
211 if ( AI_SUCCESS == material.Get( AI_MATKEY_NAME, assimpName ) ) {
212 matName = assimpName.C_Str();
216 auto blinnPhongMaterial =
new BlinnPhongMaterialData( matName );
217 if ( AI_DEFAULT_MATERIAL_NAME != matName ) {
223 if ( AI_SUCCESS == material.Get( AI_MATKEY_COLOR_DIFFUSE, color ) ) {
224 blinnPhongMaterial->m_hasDiffuse =
true;
225 blinnPhongMaterial->m_diffuse = assimpToCore( color );
228 if ( AI_SUCCESS == material.Get( AI_MATKEY_COLOR_SPECULAR, color ) ) {
229 blinnPhongMaterial->m_hasSpecular =
true;
230 blinnPhongMaterial->m_specular = assimpToCore( color );
233 if ( AI_SUCCESS == material.Get( AI_MATKEY_SHININESS, shininess ) ) {
234 blinnPhongMaterial->m_hasShininess =
true;
236 blinnPhongMaterial->m_shininess = shininess * 4;
239 if ( AI_SUCCESS == material.Get( AI_MATKEY_OPACITY, opacity ) ) {
240 blinnPhongMaterial->m_hasOpacity =
true;
244 blinnPhongMaterial->m_opacity = opacity < 1e-5 ? 1 : opacity;
247 if ( AI_SUCCESS == material.Get( AI_MATKEY_TEXTURE( aiTextureType_DIFFUSE, 0 ), name ) ) {
248 blinnPhongMaterial->m_texDiffuse = m_filepath +
"/" + assimpToCore( name );
249 blinnPhongMaterial->m_hasTexDiffuse =
true;
252 if ( AI_SUCCESS == material.Get( AI_MATKEY_TEXTURE( aiTextureType_SPECULAR, 0 ), name ) ) {
253 blinnPhongMaterial->m_texSpecular = m_filepath +
"/" + assimpToCore( name );
254 blinnPhongMaterial->m_hasTexSpecular =
true;
257 if ( AI_SUCCESS == material.Get( AI_MATKEY_TEXTURE( aiTextureType_SHININESS, 0 ), name ) ) {
258 blinnPhongMaterial->m_texShininess = m_filepath +
"/" + assimpToCore( name );
259 blinnPhongMaterial->m_hasTexShininess =
true;
262 if ( AI_SUCCESS == material.Get( AI_MATKEY_TEXTURE( aiTextureType_NORMALS, 0 ), name ) ) {
263 blinnPhongMaterial->m_texNormal = m_filepath +
"/" + assimpToCore( name );
264 blinnPhongMaterial->m_hasTexNormal =
true;
268 if ( AI_SUCCESS == material.Get( AI_MATKEY_TEXTURE( aiTextureType_HEIGHT, 0 ), name ) ) {
269 blinnPhongMaterial->m_texNormal = m_filepath +
"/" + assimpToCore( name );
270 blinnPhongMaterial->m_hasTexNormal =
true;
273 if ( AI_SUCCESS == material.Get( AI_MATKEY_TEXTURE( aiTextureType_OPACITY, 0 ), name ) ) {
274 blinnPhongMaterial->m_texOpacity = m_filepath +
"/" + assimpToCore( name );
275 blinnPhongMaterial->m_hasTexOpacity =
true;
278 else { LOG( logINFO ) <<
"Found assimp default material " << matName; }
282void AssimpGeometryDataLoader::loadGeometryData(
283 const aiScene* scene,
285 const uint size = scene->mNumMeshes;
288 for ( uint i = 0; i < size; ++i ) {
289 aiMesh* mesh = scene->mMeshes[i];
290 if ( mesh->HasPositions() ) {
291 if ( m_verbose ) { LOG( logINFO ) <<
"Loading mesh attribs..."; }
293 loadMeshAttrib( *mesh, *geometry, usedNames );
294 if ( m_verbose ) { LOG( logINFO ) <<
"Mesh attribs loaded."; }
296 if ( scene->HasMaterials() ) {
297 const uint matID = mesh->mMaterialIndex;
298 if ( matID < scene->mNumMaterials ) {
299 aiMaterial* material = scene->mMaterials[matID];
300 loadMaterial( *material, *geometry );
304 indexTable[i] = data.
size() - 1;
306 if ( m_verbose ) { geometry->displayInfo(); }
309 loadMeshFrame( scene->mRootNode, Core::Transform::Identity(), indexTable, data );
bool isTetraMesh() const
Return true if the object is a Tetrahedron Mesh.
bool isHexMesh() const
Return true if the object is a Hexahedron Mesh.
void setMaterial(MaterialData *material)
Set the MaterialData for the object.
void setPrimitiveCount(int n)
Used to track easily the number of primitives in the geometry data.
GeometryType getType() const
Return the type of geometry.
Geometry::MultiIndexedGeometry & getGeometry()
Read/write access to the multiIndexedGeometry;.
void setFrame(const Transform &frame)
Set the Transform of the object.
void setName(const std::string &name)
Return the name of the object.
hepler function to manage enum as underlying types in VariableSet