388 lines
11 KiB
C++
388 lines
11 KiB
C++
// 9.延迟渲染
|
|
// 简单的延迟渲染测试,仅一个太阳光
|
|
|
|
#include"VulkanAppFramework.h"
|
|
#include<hgl/filesystem/FileSystem.h>
|
|
#include<hgl/graph/InlineGeometry.h>
|
|
#include<hgl/graph/VKRenderResource.h>
|
|
#include<hgl/graph/VKRenderableInstance.h>
|
|
#include<hgl/graph/RenderList.h>
|
|
#include<hgl/graph/VKTexture.h>
|
|
#include<hgl/graph/VKImageView.h>
|
|
#include<hgl/graph/VKSampler.h>
|
|
#include<hgl/graph/VKFramebuffer.h>
|
|
#include<hgl/Time.h>
|
|
|
|
using namespace hgl;
|
|
using namespace hgl::graph;
|
|
|
|
VK_NAMESPACE_BEGIN
|
|
Texture2D *CreateTextureFromFile(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)]={UFMT_RGB565,FMT_RG8UN};
|
|
constexpr VkFormat gbuffer_depth_format=FMT_D16UN;
|
|
|
|
struct alignas(16) PhongPointLight
|
|
{
|
|
Vector3f color;
|
|
Vector4f position;
|
|
float radius;
|
|
};//
|
|
|
|
class TestApp:public CameraAppFramework
|
|
{
|
|
private:
|
|
|
|
SceneNode render_root;
|
|
RenderList render_list;
|
|
|
|
struct
|
|
{
|
|
RenderTarget *rt;
|
|
GPUCmdBuffer *cmd;
|
|
|
|
public:
|
|
|
|
bool Submit(GPUSemaphore *sem)
|
|
{
|
|
return rt->Submit(cmd,sem);
|
|
}
|
|
}gbuffer;
|
|
|
|
PhongPointLight lights;
|
|
|
|
GPUBuffer *ubo_lights;
|
|
|
|
struct SubpassParam
|
|
{
|
|
Material * material;
|
|
MaterialInstance * material_instance;
|
|
Pipeline * pipeline_fan;
|
|
Pipeline * pipeline_triangles;
|
|
};//
|
|
|
|
SubpassParam sp_gbuffer;
|
|
SubpassParam sp_composition;
|
|
|
|
Renderable *ro_plane,
|
|
*ro_cube,
|
|
*ro_sphere,
|
|
*ro_torus,
|
|
*ro_cylinder,
|
|
*ro_cone,
|
|
|
|
*ro_gbc_plane;
|
|
RenderableInstance *ro_gbc_plane_ri;
|
|
|
|
Sampler * sampler=nullptr;
|
|
|
|
struct
|
|
{
|
|
Texture2DPointer color=nullptr;
|
|
Texture2DPointer normal=nullptr;
|
|
}texture;
|
|
|
|
public:
|
|
|
|
~TestApp()
|
|
{
|
|
delete gbuffer.cmd;
|
|
delete gbuffer.rt;
|
|
}
|
|
|
|
private:
|
|
|
|
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->CreateCommandBuffer(size_t(GBufferAttachment::RANGE_SIZE)+1);
|
|
|
|
return(gbuffer.rt);
|
|
}
|
|
|
|
bool InitSubpass(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.rt->CreatePipeline(sp->material,InlinePipeline::Solid3D,Prim::Triangles);
|
|
if(!sp->pipeline_triangles)
|
|
return(false);
|
|
|
|
sp->pipeline_fan =gbuffer.rt->CreatePipeline(sp->material,InlinePipeline::Solid3D,Prim::Fan);
|
|
|
|
return sp->pipeline_fan;
|
|
}
|
|
|
|
bool InitCompositionPipeline(SubpassParam *sp)
|
|
{
|
|
sp->pipeline_fan=sc_render_target->CreatePipeline(sp->material,InlinePipeline::Solid2D,Prim::Fan);
|
|
|
|
return sp->pipeline_fan;
|
|
}
|
|
|
|
bool InitLightsUBO()
|
|
{
|
|
ubo_lights=db->CreateUBO(sizeof(lights),&lights);
|
|
return ubo_lights;
|
|
}
|
|
|
|
bool InitMaterial()
|
|
{
|
|
if(!InitLightsUBO())return(false);
|
|
|
|
if(!InitSubpass(&sp_gbuffer, OS_TEXT("res/material/opaque")))return(false);
|
|
if(!InitSubpass(&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"));
|
|
texture.normal =db->LoadTexture2D(OS_TEXT("res/image/Brickwall/Normal.Tex2D"));
|
|
|
|
VkSamplerCreateInfo sampler_create_info=
|
|
{
|
|
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,
|
|
VK_TRUE,
|
|
device->GetGPUPhysicalDevice()->GetMaxSamplerAnisotropy(),
|
|
false,
|
|
VK_COMPARE_OP_NEVER,
|
|
0.0f,
|
|
static_cast<float>(texture.color->GetMipLevel()),
|
|
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
|
|
false
|
|
};
|
|
|
|
sampler=db->CreateSampler(&sampler_create_info);
|
|
|
|
sp_gbuffer.material_instance->BindUBO("world",GetCameraMatrixBuffer());
|
|
sp_gbuffer.material_instance->BindSampler("TexColor" ,texture.color, sampler);
|
|
sp_gbuffer.material_instance->BindSampler("TexNormal" ,texture.normal, sampler);
|
|
sp_gbuffer.material_instance->Update();
|
|
|
|
sp_composition.material_instance->BindUBO("world",GetCameraMatrixBuffer());
|
|
sp_composition.material_instance->BindUBO("lights",ubo_lights);
|
|
sp_composition.material_instance->BindSampler("GB_Color" ,gbuffer.rt->GetColorTexture((uint)GBufferAttachment::Color),sampler);
|
|
sp_composition.material_instance->BindSampler("GB_Normal" ,gbuffer.rt->GetColorTexture((uint)GBufferAttachment::Normal),sampler);
|
|
sp_composition.material_instance->BindSampler("GB_Depth" ,gbuffer.rt->GetDepthTexture(),sampler);
|
|
sp_composition.material_instance->Update();
|
|
|
|
return(true);
|
|
}
|
|
|
|
void CreateRenderObject(Material *mtl)
|
|
{
|
|
{
|
|
struct PlaneCreateInfo pci;
|
|
|
|
ro_plane=CreateRenderablePlane(db,mtl,&pci);
|
|
}
|
|
|
|
{
|
|
struct CubeCreateInfo cci;
|
|
ro_cube=CreateRenderableCube(db,mtl,&cci);
|
|
}
|
|
|
|
{
|
|
ro_sphere=CreateRenderableSphere(db,mtl,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=CreateRenderableTorus(db,mtl,&tci);
|
|
}
|
|
|
|
{
|
|
CylinderCreateInfo cci;
|
|
|
|
cci.halfExtend=10;
|
|
cci.radius=10;
|
|
cci.numberSlices=32;
|
|
|
|
ro_cylinder=CreateRenderableCylinder(db,mtl,&cci);
|
|
}
|
|
|
|
{
|
|
ConeCreateInfo cci;
|
|
|
|
cci.halfExtend=10;
|
|
cci.radius=10;
|
|
cci.numberSlices=128;
|
|
cci.numberStacks=32;
|
|
|
|
ro_cone=CreateRenderableCone(db,mtl,&cci);
|
|
}
|
|
}
|
|
|
|
bool InitCompositionRenderable()
|
|
{
|
|
ro_gbc_plane=CreateRenderableGBufferComposition(db,sp_composition.material);
|
|
if(!ro_gbc_plane)return(false);
|
|
|
|
ro_gbc_plane_ri=db->CreateRenderableInstance(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);
|
|
render_root.Add(db->CreateRenderableInstance(ro_plane ,sp->material_instance,sp->pipeline_fan ),scale(100,100,1));
|
|
render_root.Add(db->CreateRenderableInstance(ro_torus ,sp->material_instance,sp->pipeline_triangles),translate(0,0,0));
|
|
render_root.Add(db->CreateRenderableInstance(ro_sphere ,sp->material_instance,sp->pipeline_triangles),scale(20,20,20));
|
|
render_root.Add(db->CreateRenderableInstance(ro_cube ,sp->material_instance,sp->pipeline_triangles),translate(-30, 0,10)*scale(10,10,10));
|
|
render_root.Add(db->CreateRenderableInstance(ro_cylinder ,sp->material_instance,sp->pipeline_triangles),translate( 30, 30,10)*scale(1,1,2));
|
|
render_root.Add(db->CreateRenderableInstance(ro_cone ,sp->material_instance,sp->pipeline_triangles),translate( 0,-30, 0)*scale(1,1,2));
|
|
|
|
render_root.RefreshMatrix();
|
|
render_root.ExpendToList(&render_list);
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool InitGBufferCommandBuffer()
|
|
{
|
|
if(!gbuffer.cmd)
|
|
return(false);
|
|
|
|
gbuffer.cmd->Begin();
|
|
if(!gbuffer.cmd->BindFramebuffer(gbuffer.rt->GetRenderPass(),gbuffer.rt->GetFramebuffer()))
|
|
return(false);
|
|
|
|
render_list.Render(gbuffer.cmd);
|
|
|
|
gbuffer.cmd->EndRenderPass();
|
|
gbuffer.cmd->End();
|
|
|
|
return(true);
|
|
}
|
|
|
|
public:
|
|
|
|
bool Init()
|
|
{
|
|
if(!CameraAppFramework::Init(SCREEN_WIDTH,SCREEN_HEIGHT))
|
|
return(false);
|
|
|
|
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, 50.0f, 0.0f);
|
|
lights.color = Vector3f(15.0f);
|
|
lights.radius = 150.0f;
|
|
|
|
lights.position.x = sin(hgl_rad2ang(timer/100)) * 100.0f;
|
|
lights.position.y = cos(hgl_rad2ang(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();
|
|
|
|
CameraAppFramework::Draw();
|
|
}
|
|
};//class TestApp:public CameraAppFramework
|
|
|
|
int main(int,char **)
|
|
{
|
|
TestApp app;
|
|
|
|
if(!app.Init())
|
|
return(-1);
|
|
|
|
while(app.Run());
|
|
|
|
return 0;
|
|
}
|