#include"AssimpLoaderMesh.h" #include #include #include #include #include #include #include using namespace hgl::filesystem; namespace { const aiScene *LoadSceneFromFile(const OSString &filename) { if(filename.IsEmpty())return(nullptr); uint filesize; char *filedata; filesize=filesystem::LoadFileToMemory(filename,(void **)&filedata); if(!filedata) return(nullptr); #ifdef _WIN32 const UTF8String ext_name=ToUTF8String(filesystem::ClipFileExtName(filename,false)); #else const UTF8String ext_name=filesystem::ClipFileExtName(filename); #endif// const aiScene *scene=aiImportFileFromMemory(filedata,filesize,aiProcessPreset_TargetRealtime_MaxQuality|aiProcess_FlipUVs|aiProcess_FlipWindingOrder|aiProcess_Triangulate,ext_name.c_str()); delete[] filedata; if(!scene) return(nullptr); return scene; } #define LOG_BR LOG_INFO(OS_TEXT("------------------------------------------------------------")); #define aisgl_min(x,y) (xx?y:x) const Color4f COLOR_PURE_BLACK(0,0,0,1); const Color4f COLOR_PURE_WHITE(1,1,1,1); inline const vec pos_to_vec(const aiVector3D &v3d){return vec(v3d.x,v3d.y,v3d.z,1.0);} void VecCopy(List &target,const aiVector3D *source,const uint count) { target.SetCount(count); if(count<=0)return; Vector3f *tp=target.GetData(); for(uint i=0;ix=source->x; tp->y=source->y; tp->z=source->z; ++source; ++tp; } } uint8 *ColorF2B(uint8 *tp,const aiColor4D *c4,const int count) { for(int i=0;ir*255;++tp; *tp=c4->g*255;++tp; *tp=c4->b*255;++tp; *tp=c4->a*255;++tp; ++c4; } return tp; } template void Face2Indices(List &indices,const aiFace *face,const uint count) { indices.SetCount(count*3); T *tp=indices.GetData(); for(uint i=0;imIndices[0];++tp; *tp=face->mIndices[1];++tp; *tp=face->mIndices[2];++tp; ++face; } } AABB GetAABB(const List &pos) { const Vector3f *vertex=pos.GetData(); const uint count=pos.GetCount(); Vector3f minPoint=*vertex; Vector3f maxPoint=*vertex; ++vertex; for(uint i=1;ix); minPoint.y = aisgl_min(minPoint.y,vertex->y); minPoint.z = aisgl_min(minPoint.z,vertex->z); maxPoint.x = aisgl_max(maxPoint.x,vertex->x); maxPoint.y = aisgl_max(maxPoint.y,vertex->y); maxPoint.z = aisgl_max(maxPoint.z,vertex->z); ++vertex; } return AABB(POINT_VEC(minPoint),POINT_VEC(maxPoint)); } Matrix4f MatrixConvert(const aiMatrix4x4 &s) { return Matrix4f(s.a1,s.a2,s.a3,s.a4, s.b1,s.b2,s.b3,s.b4, s.c1,s.c2,s.c3,s.c4, s.d1,s.d2,s.d3,s.d4); } }//namespace class AssimpLoaderMesh { OSString filename; const aiScene *scene; ModelData *model_data; private: void GetBoundingBox(const aiNode * node, aiVector3D *min_pos, aiVector3D *max_pos, const Matrix4f &up_matrix) { Matrix4f cur_matrix=up_matrix*MatrixConvert(node->mTransformation); uint n, t; for (n=0; n < node->mNumMeshes; ++n) { const aiMesh *mesh=scene->mMeshes[node->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { aiVector3D gl_tmp = mesh->mVertices[t]; Vector4f tmp=cur_matrix*Vector4f(gl_tmp.x, gl_tmp.y, gl_tmp.z, 1.0f); min_pos->x = aisgl_min(min_pos->x,tmp.x); min_pos->y = aisgl_min(min_pos->y,tmp.y); min_pos->z = aisgl_min(min_pos->z,tmp.z); max_pos->x = aisgl_max(max_pos->x,tmp.x); max_pos->y = aisgl_max(max_pos->y,tmp.y); max_pos->z = aisgl_max(max_pos->z,tmp.z); } } for (n = 0; n < node->mNumChildren; ++n) GetBoundingBox(node->mChildren[n],min_pos,max_pos,cur_matrix); } void AssimpLoaderMesh::GetBoundingBox(const aiNode *node,aiVector3D *min_pos,aiVector3D *max_pos) { Matrix4f root_matrix=hgl::graph::GetOpenGL2VulkanMatrix(); min_pos->x = min_pos->y = min_pos->z = 1e10f; max_pos->x = max_pos->y = max_pos->z = -1e10f; GetBoundingBox(node,min_pos,max_pos,root_matrix); } public: AssimpLoaderMesh(const OSString &fn,const aiScene *s):filename(fn),scene(s) { model_data=new ModelData; aiVector3D scene_min,scene_max; GetBoundingBox(scene->mRootNode,&scene_min,&scene_max); model_data->bounding_box.minPoint=pos_to_vec(scene_min); model_data->bounding_box.maxPoint=pos_to_vec(scene_max); } ~AssimpLoaderMesh()=default; ModelData *GetModelData(){return model_data;} private: bool Load(const aiMesh *mesh) { MeshData *md=new MeshData; md->name=mesh->mName.C_Str(); if(mesh->HasPositions()) VecCopy(md->position,mesh->mVertices,mesh->mNumVertices); if(mesh->HasNormals()) { VecCopy(md->normal,mesh->mNormals,mesh->mNumVertices); if(mesh->HasTangentsAndBitangents()) { VecCopy(md->tangent, mesh->mTangents, mesh->mNumVertices); VecCopy(md->bitangent, mesh->mBitangents, mesh->mNumVertices); } } const uint num_color_channels=mesh->GetNumColorChannels(); if(num_color_channels>0) { md->colors.SetCount(num_color_channels*4*mesh->mNumVertices); uint8 *ctp=md->colors.GetData(); for(uint i=0;imColors[i],mesh->mNumVertices); } if(mesh->mNumVertices>0xFFFF) Face2Indices(md->indices32,mesh->mFaces,mesh->mNumFaces); else Face2Indices(md->indices16,mesh->mFaces,mesh->mNumFaces); md->bounding_box=GetAABB(md->position); model_data->Add(md); return(true); } public: bool LoadMesh() { if(!scene->HasMeshes())return(false); for(uint i=0;imNumMeshes;i++) if(!Load(scene->mMeshes[i])) return(false); return(true); } private: bool Load(int level,ModelSceneNode *msn,const aiNode *node) { for(int i=0;imName.C_Str()<name=node->mName.C_Str(); msn->local_matrix=MatrixConvert(node->mTransformation); if(node->mNumMeshes>0) { msn->mesh_index.SetCount(node->mNumMeshes); hgl_cpy(msn->mesh_index.GetData(),node->mMeshes,node->mNumMeshes); } if(node->mNumChildren<=0) return(true); for(uint i=0;imNumChildren;i++) { ModelSceneNode *sub=new ModelSceneNode; if(!Load(level+1,sub,node->mChildren[i])) { delete sub; return(false); } msn->children_node.Add(sub); } return(true); } public: bool LoadScene() { model_data->root_node=new ModelSceneNode; std::cout<<"SceneRoot"<root_node,scene->mRootNode)) return(false); model_data->root_node->local_matrix=hgl::graph::GetOpenGL2VulkanMatrix()*model_data->root_node->local_matrix; return(true); } };//class AssimpLoaderMesh ModelData *AssimpLoadModel(const OSString &filename) { const aiScene *scene=LoadSceneFromFile(filename); if(!scene)return(nullptr); AutoDelete alm=new AssimpLoaderMesh(ClipFileMainname(filename),scene); if(alm->LoadMesh()) if(alm->LoadScene()) return alm->GetModelData(); return(nullptr); }