From cb29a3775513f82b787ae2264093a949b353829b Mon Sep 17 00:00:00 2001 From: hyzboy Date: Mon, 10 Jun 2019 22:11:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E7=9A=84AssimpLoader=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E6=B5=8B=E8=AF=95=E6=B8=B2=E6=9F=93=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=BC=BC=E4=B9=8E=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/Vulkan/AssimpLoaderMesh.cpp | 333 ++++++++++++++++++++++++++++ example/Vulkan/AssimpLoaderMesh.h | 55 +++++ example/Vulkan/CMakeLists.txt | 4 +- example/Vulkan/LoadModel.cpp | 183 +++++++++++---- inc/hgl/filesystem/FileSystem.h | 7 +- inc/hgl/graph/vulkan/VKMaterial.h | 2 +- res/shader/OnlyPosition3D.vert | 25 +++ res/shader/shader_compile.sh | 3 +- src/SceneGraph/CMakeLists.txt | 4 +- 9 files changed, 565 insertions(+), 51 deletions(-) create mode 100644 example/Vulkan/AssimpLoaderMesh.cpp create mode 100644 example/Vulkan/AssimpLoaderMesh.h create mode 100644 res/shader/OnlyPosition3D.vert diff --git a/example/Vulkan/AssimpLoaderMesh.cpp b/example/Vulkan/AssimpLoaderMesh.cpp new file mode 100644 index 00000000..aea26026 --- /dev/null +++ b/example/Vulkan/AssimpLoaderMesh.cpp @@ -0,0 +1,333 @@ +#include"AssimpLoaderMesh.h" +#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,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.z,v3d.y,1.0);} + inline const vec dir_to_vec(const aiVector3D &v3d){return vec(v3d.x,-v3d.z,v3d.y,0.0);} + + void VecY2Z(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->z; + tp->z= source->y; + + ++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 MatrixRotate(const aiMatrix4x4 &s) + { + //return Matrix4f(s.a1,s.b1,s.c1,s.d1, + // s.a2,s.b2,s.c2,s.d2, + // s.a3,s.b3,s.c3,s.d3, + // s.a4,s.b4,s.c4,s.d4); + + 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 aiMatrix4x4 &up_matrix) + { + aiMatrix4x4 cur_matrix; + uint n = 0, t; + + cur_matrix = up_matrix; + + aiMultiplyMatrix4(&cur_matrix,&node->mTransformation); + + for (; n < node->mNumMeshes; ++n) + { + const aiMesh *mesh=scene->mMeshes[node->mMeshes[n]]; + + for (t = 0; t < mesh->mNumVertices; ++t) + { + aiVector3D tmp = mesh->mVertices[t]; + aiTransformVecByMatrix4(&tmp,&cur_matrix); + + 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) + { + aiMatrix4x4 root_matrix; + + aiIdentityMatrix4(&root_matrix); + + 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()) + VecY2Z(md->position,mesh->mVertices,mesh->mNumVertices); + + if(mesh->HasNormals()) + { + VecY2Z(md->normal,mesh->mNormals,mesh->mNumVertices); + + if(mesh->HasTangentsAndBitangents()) + { + VecY2Z(md->tangent, mesh->mTangents, mesh->mNumVertices); + VecY2Z(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(ModelSceneNode *msn,const aiNode *node) + { + msn->name=node->mName.C_Str(); + msn->local_matrix=MatrixRotate(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(sub,node->mChildren[i])) + { + delete sub; + return(false); + } + + msn->children_node.Add(sub); + } + + return(true); + } + +public: + + bool LoadScene() + { + model_data->root_node=new ModelSceneNode; + + return Load(model_data->root_node,scene->mRootNode); + } +};//class AssimpLoaderMesh + +ModelData *AssimpLoadModel(const OSString &filename) +{ + const aiScene *scene=LoadSceneFromFile(filename); + + if(!scene)return(nullptr); + + AssimpLoaderMesh *alm=new AssimpLoaderMesh(ClipFileMainname(filename),scene); + + ModelData *data=nullptr; + + if(alm->LoadMesh()) + { + if(alm->LoadScene()) + data=alm->GetModelData(); + } + + delete alm; + return data; +} diff --git a/example/Vulkan/AssimpLoaderMesh.h b/example/Vulkan/AssimpLoaderMesh.h new file mode 100644 index 00000000..91d4148d --- /dev/null +++ b/example/Vulkan/AssimpLoaderMesh.h @@ -0,0 +1,55 @@ +#pragma once +#include +#include +#include +#include + +using namespace hgl; + +struct MeshData +{ + UTF8String name; + + List position, //顶点 + normal, //法线 + tangent, //切线 + bitangent; //副切线 + + List colors; //颜色 + + List indices16; //16位索引 + List indices32; //32位索引 + + AABB bounding_box; +};//struct MeshData + +struct ModelSceneNode +{ + UTF8String name; + + Matrix4f local_matrix; + + List mesh_index; + + ObjectList children_node; //子节点 +};//struct MeshNode + +struct ModelData +{ + AABB bounding_box; + + ObjectList mesh_data; + Map mesh_by_name; + + ModelSceneNode *root_node; + +public: + + void Add(MeshData *md) + { + mesh_data.Add(md); + mesh_by_name.Add(md->name,md); + } +};//struct ModelData + +ModelData *AssimpLoadModel(const OSString &filename); diff --git a/example/Vulkan/CMakeLists.txt b/example/Vulkan/CMakeLists.txt index 0d7d33f2..6b06e5f9 100644 --- a/example/Vulkan/CMakeLists.txt +++ b/example/Vulkan/CMakeLists.txt @@ -8,4 +8,6 @@ CreateProject(1.indices_rect indices_rect.cpp) CreateProject(2.texture_rect texture_rect.cpp TGATexture.cpp) CreateProject(3.Geometry2D Geometry2D.cpp) CreateProject(4.Geometry3D Geometry3D.cpp) -CreateProject(5.LoadModel LoadModel.cpp TGATexture.cpp AssimpLoader.h AssimpLoader.cpp) +CreateProject(5.LoadModel LoadModel.cpp TGATexture.cpp AssimpLoaderMesh.h AssimpLoaderMesh.cpp) + +target_link_libraries(5.LoadModel assimp) diff --git a/example/Vulkan/LoadModel.cpp b/example/Vulkan/LoadModel.cpp index e5b20552..5a506e19 100644 --- a/example/Vulkan/LoadModel.cpp +++ b/example/Vulkan/LoadModel.cpp @@ -8,12 +8,75 @@ #include #include +#include"AssimpLoaderMesh.h" +#include + using namespace hgl; using namespace hgl::graph; constexpr uint32_t SCREEN_WIDTH=256; constexpr uint32_t SCREEN_HEIGHT=256; +vulkan::Renderable *CreateMeshRenderable(SceneDB *db,vulkan::Material *mtl,const MeshData *mesh) +{ + const vulkan::VertexShaderModule *vsm=mtl->GetVertexShaderModule(); + + uint draw_count=0; + + if(mesh->indices16.GetCount()>0) + draw_count=mesh->indices16.GetCount(); + else + draw_count=mesh->indices32.GetCount(); + + vulkan::Renderable *render_obj=nullptr; + { + const int vertex_binding=vsm->GetStageInputBinding("Vertex"); + + if(vertex_binding==-1) + return(nullptr); + + vulkan::VertexBuffer *vbo=db->CreateVBO(FMT_RGB32F,mesh->position.GetCount(),mesh->position.GetData()); + + render_obj=mtl->CreateRenderable(); + render_obj->Set(vertex_binding,vbo); + render_obj->SetBoundingBox(mesh->bounding_box); + } + + const int normal_binding=vsm->GetStageInputBinding("Normal"); + + if(normal_binding!=-1) + { + vulkan::VertexBuffer *vbo=db->CreateVBO(FMT_RGB32F,mesh->normal.GetCount(),mesh->normal.GetData()); + + render_obj->Set(normal_binding,vbo); + } + + const int tagent_binding=vsm->GetStageInputBinding("Tangent"); + + if(tagent_binding!=-1) + { + vulkan::VertexBuffer *vbo=db->CreateVBO(FMT_RGB32F,mesh->tangent.GetCount(),mesh->tangent.GetData()); + + render_obj->Set(tagent_binding,vbo); + } + + const int bitagent_binding=vsm->GetStageInputBinding("Bitangent"); + + if(bitagent_binding!=-1) + { + vulkan::VertexBuffer *vbo=db->CreateVBO(FMT_RGB32F,mesh->bitangent.GetCount(),mesh->bitangent.GetData()); + + render_obj->Set(bitagent_binding,vbo); + } + + if(mesh->indices16.GetCount()>0) + render_obj->Set(db->CreateIBO16(mesh->indices16.GetCount(),mesh->indices16.GetData())); + else + render_obj->Set(db->CreateIBO32(mesh->indices32.GetCount(),mesh->indices32.GetData())); + + return(render_obj); +} + class TestApp:public VulkanApplicationFramework { private: @@ -34,6 +97,12 @@ private: vulkan::Pipeline * pipeline_line =nullptr; vulkan::CommandBuffer ** cmd_buf =nullptr; +private: + + ModelData *model_data; + + vulkan::Renderable **mesh_renderable; + public: ~TestApp() @@ -47,9 +116,15 @@ private: void InitCamera() { + math::vec center_point=model_data->bounding_box.CenterPoint(); + math::vec min_point=model_data->bounding_box.minPoint; + math::vec max_point=model_data->bounding_box.maxPoint; + camera.type=CameraType::Perspective; - camera.center.Set(0,0,0); - camera.eye.Set(100,100,100); + camera.center=center_point.xyz(); + camera.eye=max_point.xyz(); + //camera.center.Set(0,0,0); + //camera.eye.Set(10,10,5); camera.up_vector.Set(0,0,1); camera.forward_vector.Set(0,1,0); camera.znear=4; @@ -63,7 +138,7 @@ private: bool InitMaterial() { - material=shader_manage->CreateMaterial(OS_TEXT("PositionColor3D.vert.spv"), + material=shader_manage->CreateMaterial(OS_TEXT("OnlyPosition3D.vert.spv"), OS_TEXT("FlatColor.frag.spv")); if(!material) return(false); @@ -77,33 +152,15 @@ private: void CreateRenderObject() { + const uint count=model_data->mesh_data.GetCount(); + MeshData **md=model_data->mesh_data.GetData(); + + mesh_renderable=new vulkan::Renderable *[count]; + + for(uint i=0;iGetRenderPass(),device->GetExtent()); - pipeline_creater->SetDepthTest(true); - pipeline_creater->SetDepthWrite(true); + pipeline_creater->SetDepthTest(false); + pipeline_creater->SetDepthWrite(false); + pipeline_creater->SetPolygonMode(VK_POLYGON_MODE_LINE); pipeline_creater->CloseCullFace(); - pipeline_creater->Set(PRIM_LINES); + pipeline_creater->Set(PRIM_TRIANGLES); pipeline_line=pipeline_creater->Create(); if(!pipeline_line) @@ -146,13 +204,38 @@ private: return pipeline_line; } + void CreateRenderableInstance(SceneNode *scene_node,ModelSceneNode *model_node) + { + scene_node->SetLocalMatrix(model_node->local_matrix); + + { + const uint count=model_node->mesh_index.GetCount(); + const uint32 *mesh_index=model_node->mesh_index.GetData(); + + for(uint i=0;iAdd(db->CreateRenderableInstance(pipeline_line,descriptor_sets,mesh_renderable[*mesh_index])); + + ++mesh_index; + } + } + + { + const uint count=model_node->children_node.GetCount(); + ModelSceneNode **sub_model_node=model_node->children_node.GetData(); + + for(uint i=0;iCreateSubNode(),*sub_model_node); + + ++sub_model_node; + } + } + } + bool InitScene() { - const float rad90=hgl_ang2rad(90); - - render_root.Add(db->CreateRenderableInstance(pipeline_line,descriptor_sets,ro_plane_grid[0])); - render_root.Add(db->CreateRenderableInstance(pipeline_line,descriptor_sets,ro_plane_grid[1]),rotate(rad90,0,1,0)); - render_root.Add(db->CreateRenderableInstance(pipeline_line,descriptor_sets,ro_plane_grid[2]),rotate(rad90,1,0,0)); + CreateRenderableInstance(&render_root,model_data->root_node); render_root.RefreshMatrix(); render_root.ExpendToList(&render_list); @@ -183,8 +266,13 @@ private: public: - bool Init() + bool Init(ModelData *md) { + if(!md) + return(false); + + model_data=md; + if(!VulkanApplicationFramework::Init(SCREEN_WIDTH,SCREEN_HEIGHT)) return(false); @@ -192,13 +280,13 @@ public: db=new SceneDB(device); - InitCamera(); - if(!InitMaterial()) return(false); CreateRenderObject(); + InitCamera(); + if(!InitUBO()) return(false); @@ -224,14 +312,21 @@ public: } };//class TestApp:public VulkanApplicationFramework -int main(int,char **) +#ifdef _WIN32 +int wmain(int argc,wchar_t **argv) +#else +int main(int argc,char **argv) +#endif// { TestApp app; - if(!app.Init()) - return(-1); + ModelData *model_data=AssimpLoadModel(argv[1]); - while(app.Run()); + if(app.Init(model_data)) + while(app.Run()); + + if(model_data) + delete model_data; return 0; } diff --git a/inc/hgl/filesystem/FileSystem.h b/inc/hgl/filesystem/FileSystem.h index 6ece55c8..c3b831e7 100644 --- a/inc/hgl/filesystem/FileSystem.h +++ b/inc/hgl/filesystem/FileSystem.h @@ -83,9 +83,11 @@ namespace hgl /** * 截取完整文件名中的扩展名 + * @param fullname 完整文件名 + * @param include_dot 是否包括点 */ template - inline BaseString ClipFileExtName(const BaseString &fullname) + inline BaseString ClipFileExtName(const BaseString &fullname,bool include_dot=true) { int end=fullname.FindChar(T('?')); //url的文件名,以?为结束 @@ -97,7 +99,8 @@ namespace hgl if(pos==-1) return BaseString(); - return fullname.SubString(pos+1,end-(pos+1)); + return include_dot? fullname.SubString(pos, end- pos ): + fullname.SubString(pos+1, end-(pos+1)); } /** diff --git a/inc/hgl/graph/vulkan/VKMaterial.h b/inc/hgl/graph/vulkan/VKMaterial.h index 9832b3de..d1697adb 100644 --- a/inc/hgl/graph/vulkan/VKMaterial.h +++ b/inc/hgl/graph/vulkan/VKMaterial.h @@ -57,7 +57,7 @@ public: void Write(VkPipelineVertexInputStateCreateInfo &vis)const; - Renderable *CreateRenderable(const uint32_t draw_count); + Renderable *CreateRenderable(const uint32_t draw_count=0); };//class Material VK_NAMESPACE_END #endif//HGL_GRAPH_VULKAN_MATERIAL_INCLUDE diff --git a/res/shader/OnlyPosition3D.vert b/res/shader/OnlyPosition3D.vert new file mode 100644 index 00000000..8ccb9042 --- /dev/null +++ b/res/shader/OnlyPosition3D.vert @@ -0,0 +1,25 @@ +#version 450 core + +layout(location = 0) in vec3 Vertex; + +layout(binding = 0) uniform WorldMatrix +{ + mat4 two_dim; + mat4 projection; + mat4 modelview; + mat4 mvp; + mat3 normal; +} world; + +layout(push_constant) uniform Consts { + mat4 local_to_world; +} pc; + +layout(location = 0) out vec4 FragmentColor; + +void main() +{ + FragmentColor=vec4(1.0); + + gl_Position=vec4(Vertex,1.0)*pc.local_to_world*world.mvp; +} diff --git a/res/shader/shader_compile.sh b/res/shader/shader_compile.sh index cde82f67..0ee8b39b 100755 --- a/res/shader/shader_compile.sh +++ b/res/shader/shader_compile.sh @@ -6,4 +6,5 @@ glslangValidator -V -o FlatColor.frag.spv FlatColor.frag glslangValidator -V -o FlatTexture.vert.spv FlatTexture.vert glslangValidator -V -o FlatTexture.frag.spv FlatTexture.frag -glslangValidator -V -o PositionColor3D.vert.spv PositionColor3D.vert \ No newline at end of file +glslangValidator -V -o PositionColor3D.vert.spv PositionColor3D.vert +glslangValidator -V -o OnlyPosition3D.vert.spv OnlyPosition3D.vert \ No newline at end of file diff --git a/src/SceneGraph/CMakeLists.txt b/src/SceneGraph/CMakeLists.txt index 4e4c5fe0..2d11515a 100644 --- a/src/SceneGraph/CMakeLists.txt +++ b/src/SceneGraph/CMakeLists.txt @@ -10,7 +10,7 @@ ${ROOT_INCLUDE_PATH}/hgl/graph/VertexBuffer.h ${ROOT_INCLUDE_PATH}/hgl/graph/InlineGeometry.h #${ROOT_INCLUDE_PATH}/hgl/graph/Mesh.h - ${ROOT_INCLUDE_PATH}/hgl/graph/Material.h + #${ROOT_INCLUDE_PATH}/hgl/graph/Material.h ${ROOT_INCLUDE_PATH}/hgl/graph/TextureType.h #${ROOT_INCLUDE_PATH}/hgl/graph/Spline.h ) @@ -22,7 +22,7 @@ SET(SCENE_GRAPH_SOURCE AABox.cpp SceneNode.cpp SceneOrient.cpp InlineGeometry.cpp - Material.cpp + #Material.cpp #Mesh.cpp #SceneFile.cpp )