From 188b8f9c2ac2c315be6e01b28f9bb47e65d3f846 Mon Sep 17 00:00:00 2001 From: hyzboy Date: Thu, 30 May 2019 20:32:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=B0=E7=9A=84Mesh/Materi?= =?UTF-8?q?al=E6=96=87=E4=BB=B6=EF=BC=8C=E4=BB=A5=E5=8F=8ASceneFile?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E4=BB=A3=E7=A0=81=EF=BC=88=E6=9C=AA=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E4=B8=8D=E5=8F=AF=E7=94=A8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/Vulkan/CMakeLists.txt | 1 + example/Vulkan/Geometry3D.cpp | 4 +- example/Vulkan/LoadModel.cpp | 237 ++++++++++++++++++++++++++++++++ inc/hgl/filesystem/FileSystem.h | 20 ++- inc/hgl/graph/Material.h | 1 + src/SceneGraph/CMakeLists.txt | 11 +- src/SceneGraph/Material.cpp | 68 +++++++++ src/SceneGraph/Mesh.cpp | 150 ++++++++++++++++++++ src/SceneGraph/SceneFile.cpp | 207 ++++++++++++++++++++++++++++ 9 files changed, 694 insertions(+), 5 deletions(-) create mode 100644 example/Vulkan/LoadModel.cpp create mode 100644 src/SceneGraph/Material.cpp create mode 100644 src/SceneGraph/Mesh.cpp create mode 100644 src/SceneGraph/SceneFile.cpp diff --git a/example/Vulkan/CMakeLists.txt b/example/Vulkan/CMakeLists.txt index 4bdc0c9f..d4ff9dc4 100644 --- a/example/Vulkan/CMakeLists.txt +++ b/example/Vulkan/CMakeLists.txt @@ -11,3 +11,4 @@ CreateProject(2.texture_rect texture_rect) target_link_libraries(2.texture_rect TGATexture) CreateProject(3.Geometry2D Geometry2D) CreateProject(4.Geometry3D Geometry3D) +CreateProject(5.LoadModel LoadModel) diff --git a/example/Vulkan/Geometry3D.cpp b/example/Vulkan/Geometry3D.cpp index a5385508..cd32b3de 100644 --- a/example/Vulkan/Geometry3D.cpp +++ b/example/Vulkan/Geometry3D.cpp @@ -10,8 +10,8 @@ using namespace hgl; using namespace hgl::graph; -constexpr uint32_t SCREEN_WIDTH=1280; -constexpr uint32_t SCREEN_HEIGHT=720; +constexpr uint32_t SCREEN_WIDTH=256; +constexpr uint32_t SCREEN_HEIGHT=256; class TestApp:public VulkanApplicationFramework { diff --git a/example/Vulkan/LoadModel.cpp b/example/Vulkan/LoadModel.cpp new file mode 100644 index 00000000..e5b20552 --- /dev/null +++ b/example/Vulkan/LoadModel.cpp @@ -0,0 +1,237 @@ +// 5.LoadModel +// 加载纯色无贴图模型 + +#include"VulkanAppFramework.h" +#include +#include +#include +#include +#include + +using namespace hgl; +using namespace hgl::graph; + +constexpr uint32_t SCREEN_WIDTH=256; +constexpr uint32_t SCREEN_HEIGHT=256; + +class TestApp:public VulkanApplicationFramework +{ +private: + + uint swap_chain_count=0; + + SceneDB * db =nullptr; + SceneNode render_root; + RenderList render_list; + + Camera camera; + + vulkan::Material * material =nullptr; + vulkan::DescriptorSets * descriptor_sets =nullptr; + + vulkan::Buffer * ubo_world_matrix =nullptr; + + vulkan::Pipeline * pipeline_line =nullptr; + vulkan::CommandBuffer ** cmd_buf =nullptr; + +public: + + ~TestApp() + { + SAFE_CLEAR(db); + + SAFE_CLEAR_OBJECT_ARRAY(cmd_buf,swap_chain_count); + } + +private: + + void InitCamera() + { + camera.type=CameraType::Perspective; + camera.center.Set(0,0,0); + camera.eye.Set(100,100,100); + camera.up_vector.Set(0,0,1); + camera.forward_vector.Set(0,1,0); + camera.znear=4; + camera.zfar=1000; + camera.fov=90; + camera.width=SCREEN_WIDTH; + camera.height=SCREEN_HEIGHT; + + camera.Refresh(); //更新矩阵计算 + } + + bool InitMaterial() + { + material=shader_manage->CreateMaterial(OS_TEXT("PositionColor3D.vert.spv"), + OS_TEXT("FlatColor.frag.spv")); + if(!material) + return(false); + + descriptor_sets=material->CreateDescriptorSets(); + + db->Add(material); + db->Add(descriptor_sets); + return(true); + } + + void CreateRenderObject() + { + { + struct PlaneGridCreateInfo pgci; + + pgci.coord[0].Set(-100,-100,0); + pgci.coord[1].Set( 100,-100,0); + pgci.coord[2].Set( 100, 100,0); + pgci.coord[3].Set(-100, 100,0); + + pgci.step.u=20; + pgci.step.v=20; + + pgci.side_step.u=10; + pgci.side_step.v=10; + + pgci.color.Set(0.75,0,0,1); + pgci.side_color.Set(1,0,0,1); + + ro_plane_grid[0]=CreatePlaneGrid(db,material,&pgci); + + pgci.color.Set(0,0.75,0,1); + pgci.side_color.Set(0,1,0,1); + + ro_plane_grid[1]=CreatePlaneGrid(db,material,&pgci); + + pgci.color.Set(0,0,0.75,1); + pgci.side_color.Set(0,0,1,1); + ro_plane_grid[2]=CreatePlaneGrid(db,material,&pgci); + } + } + + bool InitUBO() + { + const VkExtent2D extent=device->GetExtent(); + + ubo_world_matrix=db->CreateUBO(sizeof(WorldMatrix),&camera.matrix); + + if(!ubo_world_matrix) + return(false); + + if(!descriptor_sets->BindUBO(material->GetUBO("world"),*ubo_world_matrix)) + return(false); + + descriptor_sets->Update(); + return(true); + } + + bool InitPipeline() + { + constexpr os_char PIPELINE_FILENAME[]=OS_TEXT("2DSolid.pipeline"); + + { + vulkan::PipelineCreater *pipeline_creater=new vulkan::PipelineCreater(device,material,device->GetRenderPass(),device->GetExtent()); + pipeline_creater->SetDepthTest(true); + pipeline_creater->SetDepthWrite(true); + pipeline_creater->CloseCullFace(); + pipeline_creater->Set(PRIM_LINES); + + pipeline_line=pipeline_creater->Create(); + if(!pipeline_line) + return(false); + + db->Add(pipeline_line); + + delete pipeline_creater; + } + + return pipeline_line; + } + + 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)); + + render_root.RefreshMatrix(); + render_root.ExpendToList(&render_list); + + return(true); + } + + bool InitCommandBuffer() + { + cmd_buf=hgl_zero_new(swap_chain_count); + + for(uint i=0;iCreateCommandBuffer(); + + if(!cmd_buf[i]) + return(false); + + cmd_buf[i]->Begin(); + cmd_buf[i]->BeginRenderPass(device->GetRenderPass(),device->GetFramebuffer(i)); + render_list.Render(cmd_buf[i]); + cmd_buf[i]->EndRenderPass(); + cmd_buf[i]->End(); + } + + return(true); + } + +public: + + bool Init() + { + if(!VulkanApplicationFramework::Init(SCREEN_WIDTH,SCREEN_HEIGHT)) + return(false); + + swap_chain_count=device->GetSwapChainImageCount(); + + db=new SceneDB(device); + + InitCamera(); + + if(!InitMaterial()) + return(false); + + CreateRenderObject(); + + if(!InitUBO()) + return(false); + + if(!InitPipeline()) + return(false); + + if(!InitScene()) + return(false); + + if(!InitCommandBuffer()) + return(false); + + return(true); + } + + void Draw() override + { + const uint32_t frame_index=device->GetCurrentFrameIndices(); + + const vulkan::CommandBuffer *cb=cmd_buf[frame_index]; + + Submit(*cb); + } +};//class TestApp:public VulkanApplicationFramework + +int main(int,char **) +{ + TestApp app; + + if(!app.Init()) + return(-1); + + while(app.Run()); + + return 0; +} diff --git a/inc/hgl/filesystem/FileSystem.h b/inc/hgl/filesystem/FileSystem.h index 6cd772c1..6ece55c8 100644 --- a/inc/hgl/filesystem/FileSystem.h +++ b/inc/hgl/filesystem/FileSystem.h @@ -44,7 +44,6 @@ namespace hgl /** * 截取完整路径中的文件名 - * @param filename 文件名 * @param fullname 完整路径文件名 */ template @@ -63,6 +62,25 @@ namespace hgl return fullname.SubString(pos+1); } + /** + * 截取一个文件名中的主名称(不能带路径) + * @param filename 文件名 + * @param split_char 扩展名分隔符,一般为'.' + */ + template + inline BaseString ClipFileMainname(const BaseString &filename,const T split_char='.') + { + if(filename.Length()<=1) + return(BaseString()); + + const int pos=filename.FindRightChar(split_char); + + if(pos==-1) + return BaseString(filename); + + return filename.SubString(0,pos); + } + /** * 截取完整文件名中的扩展名 */ diff --git a/inc/hgl/graph/Material.h b/inc/hgl/graph/Material.h index 625fdfe3..5d16a932 100644 --- a/inc/hgl/graph/Material.h +++ b/inc/hgl/graph/Material.h @@ -2,6 +2,7 @@ #define HGL_GRAPH_MATERIAL_INCLUDE #include +#include namespace hgl { namespace graph diff --git a/src/SceneGraph/CMakeLists.txt b/src/SceneGraph/CMakeLists.txt index c77b934e..7d049bdf 100644 --- a/src/SceneGraph/CMakeLists.txt +++ b/src/SceneGraph/CMakeLists.txt @@ -8,7 +8,11 @@ ${ROOT_INCLUDE_PATH}/hgl/graph/RenderList.h ${ROOT_INCLUDE_PATH}/hgl/graph/VertexBufferCreater.h ${ROOT_INCLUDE_PATH}/hgl/graph/VertexBuffer.h - ${ROOT_INCLUDE_PATH}/hgl/graph/InlineGeometry.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/TextureType.h + ) SET(SCENE_GRAPH_SOURCE AABox.cpp Camera.cpp @@ -16,7 +20,10 @@ SET(SCENE_GRAPH_SOURCE AABox.cpp SceneDB.cpp SceneNode.cpp SceneOrient.cpp - InlineGeometry.cpp) + InlineGeometry.cpp + Material.cpp + Mesh.cpp + SceneFile.cpp) SOURCE_GROUP("Header Files" FILES ${SCENE_GRAPH_HEADER}) SOURCE_GROUP("Source Files" FILES ${SCENE_GRAPH_SOURCE}) diff --git a/src/SceneGraph/Material.cpp b/src/SceneGraph/Material.cpp new file mode 100644 index 00000000..12bce4d8 --- /dev/null +++ b/src/SceneGraph/Material.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +namespace hgl +{ + namespace graph + { + bool LoadMaterialFile(MaterialData &md,const OSString &filename)//,Texture **tex_list) + { + io::FileInputStream fis; + io::LEDataInputStream dis(&fis); + + if(!fis.Open(filename)) + RETURN_FALSE; + + uint8 flag[9]; + + if(dis.ReadFully(flag,9)!=9) + RETURN_FALSE; + + if(memcmp(flag,"Material\x1A",9)) + RETURN_FALSE; + + uint8 ver; + + if(!dis.ReadUint8(ver))RETURN_FALSE; + + if(ver!=1)RETURN_FALSE; + + if(dis.ReadFloat(md.diffuse,3)!=3)RETURN_FALSE; + if(dis.ReadFloat(md.specular,3)!=3)RETURN_FALSE; + if(dis.ReadFloat(md.ambient,3)!=3)RETURN_FALSE; + if(dis.ReadFloat(md.emission,3)!=3)RETURN_FALSE; + + if(!dis.ReadFloat(md.shininess))RETURN_FALSE; + if(!dis.ReadBool(md.wireframe))RETURN_FALSE; + if(!dis.ReadBool(md.two_sided))RETURN_FALSE; + + if(!dis.ReadUint8(md.tex_count))RETURN_FALSE; + + md.Init(md.tex_count); + + for(uint8 i=0;itype=(TextureType)tt; + + if(!dis.ReadInt32(mtd->tex_id))RETURN_FALSE; + if(!dis.ReadUint8(mtd->uvindex))RETURN_FALSE; + if(!dis.ReadFloat(mtd->blend))RETURN_FALSE; + if(!dis.ReadUint8(mtd->op))RETURN_FALSE; + + uint8 wm[2]; + if(!dis.ReadUint8(wm,2))RETURN_FALSE; + hgl_typecpy(mtd->wrap_mode,wm,2); + + //mtl.SetTexture(mtd->type,tex_list[mtd->tex_id]); + } + + return(true); + } + }//namespace graph +}//namespace hgl diff --git a/src/SceneGraph/Mesh.cpp b/src/SceneGraph/Mesh.cpp new file mode 100644 index 00000000..8fa105fc --- /dev/null +++ b/src/SceneGraph/Mesh.cpp @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include + +namespace hgl +{ + namespace graph + { + bool LoadMeshFile(MeshFileHeader &md,const OSString &filename,MaterialData *md_list) + { + MeshFileHeader mfh; + + io::FileInputStream fis; + io::LEDataInputStream dis(&fis); + + if(!fis.Open(filename)) + RETURN_FALSE; + + if(dis.ReadFully(&mfh,sizeof(mfh))!=sizeof(mfh)) + RETURN_FALSE; + + if(mfh.texcoord_channels<=0) + RETURN_FALSE; + + MaterialData *mtd=&(md_list[mfh.material_index]); + + uint8 *uv_comp=nullptr; + float **uv_data=nullptr; + VertexBufferCreater **uv_vb=nullptr; + + md.va=new VertexArray(mfh.primitive_type); + + { + VB3f *vertex=new VB3f(mfh.vertices_number); + dis.ReadFully(vertex->Begin(),vertex->GetBytes());vertex->End(); + md.va->SetVertex(vertex); + } + + if(mfh.ntb) + { + const uint size=mfh.vertices_number*3*sizeof(float); + + if(mtl->GetLightMode()==HGL_NONE_LIGHT) + { + if(mfh.ntb==NTB_BIT_ALL) + dis.Seek(size*3,io::soCurrent); + else + dis.Seek(size,io::soCurrent); + } + else + { + VB3f *normal=new VB3f(mfh.vertices_number); + + dis.ReadFully(normal->Begin(),normal->GetBytes());normal->End(); + + md.va->SetNormal(normal); + + if(mfh.ntb==NTB_BIT_ALL) + dis.Seek(normal->GetBytes()*2,io::soCurrent); //跳过tangent和bitangent + } + } + + if(mfh.color_channels) + { + VB4ub *color=new VB4ub(mfh.vertices_number); + + dis.ReadFully(color->Begin(),color->GetBytes());color->End(); + + md.va->SetColor(color,HGL_PC_RGBA); + + dis.Seek(mfh.vertices_number*4*(mfh.color_channels-1),io::soCurrent); //跳过vertex color + } + + if(mfh.texcoord_channels) + { + uv_comp=new uint8[mfh.texcoord_channels]; + uv_data=new float *[mfh.texcoord_channels]; + uv_vb=new VertexBufferBase *[mfh.texcoord_channels]; + + dis.ReadUint8(uv_comp,mfh.texcoord_channels); + + uint32 uv_total=0; + for(int i=0;i0xFFFF) + { + VB4u32 *face=new VB4u32(mfh.faces_number*3); + + dis.ReadFully(face->Begin(),face->GetBytes());face->End(); + + md.va->SetIndex(face); + } + else + { + VB4u16 *face=new VB4u16(mfh.faces_number*3); + + dis.ReadFully(face->Begin(),face->GetBytes());face->End(); + + md.va->SetIndex(face); + } + + fis.Close(); + + for(int i=0;itex_count;i++) + { + MaterialTextureData *mt=&(mtd->tex_list[i]); + + md.va->SetVertexBuffer(VertexBufferType(mt->type-mtcDiffuse+vbtDiffuseTexCoord),uv_vb[mt->uvindex]); + } + + md.r=new Renderable(md.va,mtl); + + for(int i=0;itex_count;i++) + { + MaterialTextureData *mt=&(mtd->tex_list[i]); + + md.r->SetTexCoord(mt->type,VertexBufferType(mt->type-mtcDiffuse+vbtDiffuseTexCoord)); + } + + SAFE_CLEAR_OBJECT_ARRAY(uv_data,mfh.texcoord_channels); + //SAFE_CLEAR_OBJECT_ARRAY(uv_vb,mfh.texcoord_channels); + SAFE_CLEAR_ARRAY(uv_comp); + + md.r->AutoCreateShader(true,nullptr,filename); + + return(true); + } + }//namespace graph +}//namespace hgl diff --git a/src/SceneGraph/SceneFile.cpp b/src/SceneGraph/SceneFile.cpp new file mode 100644 index 00000000..c932458e --- /dev/null +++ b/src/SceneGraph/SceneFile.cpp @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace hgl +{ + namespace graph + { + bool LoadMaterialFile(MaterialData &md,const OSString &filename); + bool LoadMeshFile(MeshFileHeader &md,const OSString &filename,MaterialData *md_list); + + namespace + { + class SceneLoader + { + SceneDB *db; + SceneNode *root_node; + + OSString main_filename; + + uint32 tex_count=0; + + private: + + uint32 mtl_count=0; + MaterialData *md_list; + + void LoadMaterial() + { + md_list=new MaterialData[mtl_count]; + + for(int i=0;iAdd(mesh_list[mesh_index[i]]); + } + + bool LoadScene(SceneNode *node,io::DataInputStream *dis) + { + UTF8String node_name; + + if(!dis->ReadUTF8String(node_name)) + RETURN_FALSE; + + //bounding box + { + float box[6]; + + if(dis->ReadFloat(box,6)!=6) + RETURN_FALSE; + + vec bb_min(box[0],box[1],box[2],1); + vec bb_max(box[3],box[4],box[5],1); + + AABB bb(bb_min,bb_max); + + node->SetBoundingBox(bb); + } + + //matrix + { + Matrix4f mat; + + if(dis->ReadFloat((float *)&mat,16)!=16) + RETURN_FALSE; + + node->SetLocalMatrix(mat); + } + + //mesh + { + uint32 count; + + if(!dis->ReadUint32(count)) + RETURN_FALSE; + + uint32 *index=new uint32[count]; + + if(dis->ReadUint32(index,count)!=count) + { + delete[] index; + RETURN_FALSE; + } + + AddMesh(node,index,count); + + delete[] index; + }//mesh + + //children + { + uint32 children_count; + + if(!dis->ReadUint32(children_count)) + RETURN_FALSE; + + for(uint32 i=0;iAdd(sub_node); + } + }//children + + return(true); + } + + public: + + SceneLoader(SceneDB *sdb,SceneNode *rn) + { + db=sdb; + root_node=rn; + } + + bool Load(const OSString &mn,io::DataInputStream *dis) + { + main_filename=mn; + + uint8 flag[6],ver; + + if(dis->ReadFully(flag,6)!=6) + RETURN_FALSE; + + if(memcmp(flag,"SCENE\x1A",6)) + RETURN_FALSE; + + if(!dis->ReadUint8(ver)) + RETURN_FALSE; + + if(ver!=1) + RETURN_FALSE; + + if(!dis->ReadUint32(mtl_count)) + RETURN_FALSE; + + if(!dis->ReadUint32(tex_count)) + RETURN_FALSE; + +// LoadTextures(); + LoadMaterial(); + + if(!dis->ReadUint32(mesh_count)) + RETURN_FALSE; + + LoadMesh(); + + return LoadScene(root_node,dis); + } + };//class SceneLoader + }//namespace + + SceneNode *LoadScene(const OSString &fullname,SceneDB *db) + { + io::OpenFileInputStream fis(fullname); + + if(!fis) + return(nullptr); + + SceneNode *root=new SceneNode; + io::LEDataInputStream *dis=new io::LEDataInputStream(&fis); + + SceneLoader sl(db,root); + + const OSString filename=filesystem::ClipFileMainname(fullname); + + if(!sl.Load(filename,dis)) + { + delete root; + root=nullptr; + } + + delete dis; + return root; + } + }//namespace graph +}//namespace hgl