// 简单传统延迟渲染,使用多个RenderPass,多个CommandBuffer #include"VulkanAppFramework.h" #include #include #include #include #include #include #include #include #include #include using namespace hgl; using namespace hgl::graph; VK_NAMESPACE_BEGIN Texture2D *CreateTexture2DFromFile(GPUDevice *device,const OSString &filename); VK_NAMESPACE_END constexpr uint32_t SCREEN_WIDTH=1280; constexpr uint32_t SCREEN_HEIGHT=SCREEN_WIDTH/16*9; using Texture2DPointer=Texture2D *; enum class GBufferAttachment { Color=0, Normal, ENUM_CLASS_RANGE(Color,Normal) };// constexpr VkFormat gbuffer_color_format[size_t(GBufferAttachment::RANGE_SIZE)]={UPF_RGB565,UPF_RG8}; constexpr VkFormat gbuffer_depth_format=PF_D16UN; struct alignas(16) PhongPointLight { Vector4f color; Vector4f position; float radius; };// class TestApp:public CameraAppFramework { private: SceneNode render_root; RenderList *render_list=nullptr; struct { RenderTarget *rt=nullptr; RenderPass *rp=nullptr; RenderCmdBuffer *cmd=nullptr; Sampler *sampler=nullptr; public: bool Submit(Semaphore *sem) { return rt->Submit(cmd,sem); } }gbuffer; PhongPointLight lights; DeviceBuffer *ubo_lights; struct SubpassParam { Material * material; MaterialInstance * material_instance; Pipeline * pipeline_fan; Pipeline * pipeline_triangles; };// SubpassParam sp_gbuffer; SubpassParam sp_composition; Primitive *ro_plane, *ro_cube, *ro_sphere, *ro_torus, *ro_cylinder, *ro_cone, *ro_gbc_plane, *ro_axis; Renderable *ro_gbc_plane_ri; struct { Texture2DPointer color=nullptr; Texture2DPointer normal=nullptr; Sampler * color_sampler=nullptr; Sampler * normal_sampler=nullptr; }texture; public: ~TestApp() { SAFE_CLEAR(render_list); SAFE_CLEAR(gbuffer.cmd); SAFE_CLEAR(gbuffer.rt); } private: void CreateGBufferSampler() { VkSamplerCreateInfo sci= { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, nullptr, 0, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0.0f, false, 1.0f, false, VK_COMPARE_OP_NEVER, 0.0f, 0.0f, VK_BORDER_COLOR_INT_OPAQUE_BLACK, false }; gbuffer.sampler=db->CreateSampler(&sci); #ifdef _DEBUG { auto da=device->GetDeviceAttribute(); if(da->debug_maker) { da->debug_maker->SetSampler(*(gbuffer.sampler), "[debug maker] GBuffer_Sampler"); } if(da->debug_utils) { da->debug_utils->SetSampler(*(gbuffer.sampler), "[debug utils] GBuffer_Sampler"); } } #endif//_DEBUG } bool InitGBuffer() { FramebufferInfo fbi(gbuffer_color_format,size_t(GBufferAttachment::RANGE_SIZE),gbuffer_depth_format); fbi.SetExtent(SCREEN_WIDTH,SCREEN_HEIGHT); gbuffer.rt=device->CreateRenderTarget(&fbi); if(!gbuffer.rt)return(false); gbuffer.cmd=device->CreateRenderCommandBuffer(); gbuffer.rp=gbuffer.rt->GetRenderPass(); CreateGBufferSampler(); #ifdef _DEBUG { auto da=device->GetDeviceAttribute(); VkQueue q=*(gbuffer.rt->GetQueue()); VkFramebuffer fbo= gbuffer.rt->GetFramebuffer()->GetFramebuffer(); VkRenderPass rp= gbuffer.rp->GetVkRenderPass(); VkSemaphore sem=*(gbuffer.rt->GetRenderCompleteSemaphore()); VkCommandBuffer cb=*(gbuffer.cmd); VkSampler s=*(gbuffer.sampler); if(da->debug_maker) { da->debug_maker->SetQueue( q, "[debug maker] GBufferQueue"); da->debug_maker->SetFramebuffer( fbo,"[debug maker] GBufferFBO"); da->debug_maker->SetRenderPass( rp, "[debug maker] GBufferRenderpass"); da->debug_maker->SetCommandBuffer( cb, "[debug maker] GBufferCommandBuffer"); da->debug_maker->SetSampler( s, "[debug maker] GBufferSampler"); da->debug_maker->SetSemaphore( sem,"[debug maker] GBufferSemaphore"); } if(da->debug_utils) { da->debug_utils->SetQueue( q, "[debug utils] GBufferQueue"); da->debug_utils->SetFramebuffer( fbo,"[debug utils] GBufferFBO"); da->debug_utils->SetRenderPass( rp, "[debug utils] GBufferRenderpass"); da->debug_utils->SetCommandBuffer( cb, "[debug utils] GBufferCommandBuffer"); da->debug_utils->SetSampler( s, "[debug utils] GBufferSampler"); da->debug_utils->SetSemaphore( sem,"[debug utils] GBufferSemaphore"); } } #endif//_DEBUG return(gbuffer.rt); } bool InitMaterial(SubpassParam *sp,const OSString &material_filename) { sp->material=db->CreateMaterial(material_filename); if(!sp->material) return(false); sp->material_instance=db->CreateMaterialInstance(sp->material); return(true); } bool InitGBufferPipeline(SubpassParam *sp) { sp->pipeline_triangles =gbuffer.rp->CreatePipeline(sp->material_instance,InlinePipeline::Solid3D,Prim::Triangles); if(!sp->pipeline_triangles) return(false); sp->pipeline_fan =gbuffer.rp->CreatePipeline(sp->material_instance,InlinePipeline::Solid3D,Prim::Fan); if(!sp->pipeline_fan) return(false); #ifdef _DEBUG { auto da=device->GetDeviceAttribute(); if(da->debug_maker) { da->debug_maker->SetPipeline(*(sp->pipeline_triangles), "[debug maker] GBuffer_Pipeline_Triangles"); da->debug_maker->SetPipeline(*(sp->pipeline_fan), "[debug maker] GBuffer_Pipeline_Fan"); } if(da->debug_utils) { da->debug_utils->SetPipeline(*(sp->pipeline_triangles), "[debug utils] GBuffer_Pipeline_Triangles"); da->debug_utils->SetPipeline(*(sp->pipeline_fan), "[debug utils] GBuffer_Pipeline_Fan"); } } #endif//_DEBUG return(true); } bool InitCompositionPipeline(SubpassParam *sp) { sp->pipeline_fan=device_render_pass->CreatePipeline(sp->material_instance,InlinePipeline::Solid2D,Prim::Fan); return sp->pipeline_fan; } bool InitLightsUBO() { ubo_lights=db->CreateUBO(sizeof(lights),&lights); return ubo_lights; } Sampler *CreateSampler(Texture *tex) { VkSamplerCreateInfo sci= { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, nullptr, 0, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, 0.0f, false, 1.0f, false, VK_COMPARE_OP_NEVER, 0.0f, 0.0f, VK_BORDER_COLOR_INT_OPAQUE_BLACK, false }; sci.maxLod=tex->GetMipLevel(); return db->CreateSampler(&sci); } bool InitMaterial() { if(!InitLightsUBO())return(false); if(!InitMaterial(&sp_gbuffer, OS_TEXT("res/material/opaque")))return(false); if(!InitMaterial(&sp_composition,OS_TEXT("res/material/composition")))return(false); if(!InitGBufferPipeline(&sp_gbuffer))return(false); if(!InitCompositionPipeline(&sp_composition))return(false); texture.color =db->LoadTexture2D(OS_TEXT("res/image/Brickwall/Albedo.Tex2D")); if(!texture.color)return(false); texture.normal =db->LoadTexture2D(OS_TEXT("res/image/Brickwall/Normal.Tex2D")); if(!texture.normal)return(false); texture.color_sampler=CreateSampler(texture.color); texture.normal_sampler=CreateSampler(texture.normal); BindCameraUBO(sp_gbuffer.material_instance); { MaterialParameters *mp=sp_gbuffer.material_instance->GetMP(DescriptorSetType::Value); if(!mp) return(false); mp->BindImageSampler("TexColor" ,texture.color, texture.color_sampler); mp->BindImageSampler("TexNormal" ,texture.normal, texture.normal_sampler); mp->Update(); } BindCameraUBO(sp_composition.material_instance); { MaterialParameters *mp=sp_composition.material_instance->GetMP(DescriptorSetType::Value); if(!mp) return(false); mp->BindUBO("lights",ubo_lights); mp->BindImageSampler("GB_Color" ,gbuffer.rt->GetColorTexture((uint)GBufferAttachment::Color),gbuffer.sampler); mp->BindImageSampler("GB_Normal" ,gbuffer.rt->GetColorTexture((uint)GBufferAttachment::Normal),gbuffer.sampler); mp->BindImageSampler("GB_Depth" ,gbuffer.rt->GetDepthTexture(),gbuffer.sampler); mp->Update(); } return(true); } void CreateRenderObject(const VIL *vil) { using namespace inline_geometry; { struct PlaneCreateInfo pci; ro_plane=CreatePlane(db,vil,&pci); } { struct CubeCreateInfo cci; ro_cube=CreateCube(db,vil,&cci); } { ro_sphere=CreateSphere(db,vil,64); } { TorusCreateInfo tci; tci.innerRadius=50; tci.outerRadius=70; tci.numberSlices=128; tci.numberStacks=64; tci.uv_scale.x=4; tci.uv_scale.y=1; ro_torus=CreateTorus(db,vil,&tci); } { CylinderCreateInfo cci; cci.halfExtend=10; cci.radius=10; cci.numberSlices=32; ro_cylinder=CreateCylinder(db,vil,&cci); } { ConeCreateInfo cci; cci.halfExtend=10; cci.radius=10; cci.numberSlices=128; cci.numberStacks=32; ro_cone=CreateCone(db,vil,&cci); } } bool InitCompositionRenderable() { ro_gbc_plane=inline_geometry::CreateGBufferCompositionRectangle(db,sp_composition.material_instance->GetVIL()); if(!ro_gbc_plane)return(false); ro_gbc_plane_ri=db->CreateRenderable(ro_gbc_plane,sp_composition.material_instance,sp_composition.pipeline_fan); if(!ro_gbc_plane_ri)return(false); return(true); } bool InitScene(SubpassParam *sp) { CreateRenderObject(sp->material_instance->GetVIL()); render_root.CreateSubNode( scale(100,100,1), db->CreateRenderable(ro_plane ,sp->material_instance,sp->pipeline_fan )); render_root.CreateSubNode( db->CreateRenderable(ro_torus ,sp->material_instance,sp->pipeline_triangles)); render_root.CreateSubNode( scale(20,20,20), db->CreateRenderable(ro_sphere ,sp->material_instance,sp->pipeline_triangles)); render_root.CreateSubNode(translate(-30, 0,10)*scale(10,10,10), db->CreateRenderable(ro_cube ,sp->material_instance,sp->pipeline_triangles)); render_root.CreateSubNode(translate( 30, 30,10)*scale(1,1,2), db->CreateRenderable(ro_cylinder ,sp->material_instance,sp->pipeline_triangles)); render_root.CreateSubNode(translate( 0,-30, 0)*scale(1,1,2), db->CreateRenderable(ro_cone ,sp->material_instance,sp->pipeline_triangles)); render_root.RefreshMatrix(); render_list->Expend(GetCameraInfo(),&render_root); return(true); } bool InitGBufferCommandBuffer() { if(!gbuffer.cmd) return(false); gbuffer.cmd->Begin(); if(!gbuffer.cmd->BindFramebuffer(gbuffer.rt->GetRenderPass(),gbuffer.rt->GetFramebuffer())) return(false); gbuffer.cmd->BeginRegion("GBuffer Begin",Color4f(1,0,0,1)); if(!gbuffer.cmd->BeginRenderPass()) return(false); render_list->Render(gbuffer.cmd); gbuffer.cmd->EndRenderPass(); gbuffer.cmd->EndRegion(); gbuffer.cmd->End(); return(true); } public: bool Init() { if(!CameraAppFramework::Init(SCREEN_WIDTH,SCREEN_HEIGHT)) return(false); render_list=new RenderList(device); if(!InitGBuffer()) return(false); if(!InitMaterial()) return(false); if(!InitScene(&sp_gbuffer)) return(false); if(!InitGBufferCommandBuffer()) return(false); if(!InitCompositionRenderable()) return(false); return(true); } void UpdateLights() { const double timer=GetDoubleTime(); // White lights.position = Vector4f(0.0f, 0.0f, 25.0f, 0.0f); lights.color = Vector4f(15.0f); lights.radius = 155.0f; lights.position.x = sin(rad2deg(timer/100)) * 100.0f; lights.position.y = cos(rad2deg(timer/100)) * 100.0f; ubo_lights->Write(&lights); } virtual void SubmitDraw(int index) override { gbuffer.Submit(sc_render_target->GetPresentCompleteSemaphore()); VkCommandBuffer cb=*cmd_buf[index]; sc_render_target->Submit(cb,gbuffer.rt->GetRenderCompleteSemaphore()); sc_render_target->PresentBackbuffer(); sc_render_target->WaitQueue(); sc_render_target->WaitFence(); gbuffer.rt->WaitQueue(); gbuffer.rt->WaitFence(); } void BuildCommandBuffer(uint32_t index) override { VulkanApplicationFramework::BuildCommandBuffer(index,ro_gbc_plane_ri); } void Draw()override { UpdateLights(); render_root.RefreshMatrix(); render_list->Expend(GetCameraInfo(),&render_root); CameraAppFramework::Draw(); } };//class TestApp:public CameraAppFramework int main(int,char **) { TestApp app; if(!app.Init()) return(-1); while(app.Run()); return 0; }