verus/Verus/src/CGI/DeferredShading.cpp

1000 lines
34 KiB
C++

// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#include "verus.h"
using namespace verus;
using namespace verus::CGI;
DeferredShading::UB_PerFrame DeferredShading::s_ubPerFrame;
DeferredShading::UB_TexturesFS DeferredShading::s_ubTexturesFS;
DeferredShading::UB_PerMeshVS DeferredShading::s_ubPerMeshVS;
DeferredShading::UB_ShadowFS DeferredShading::s_ubShadowFS;
DeferredShading::UB_PerObject DeferredShading::s_ubPerObject;
DeferredShading::UB_AmbientVS DeferredShading::s_ubAmbientVS;
DeferredShading::UB_AmbientFS DeferredShading::s_ubAmbientFS;
DeferredShading::UB_ComposeVS DeferredShading::s_ubComposeVS;
DeferredShading::UB_ComposeFS DeferredShading::s_ubComposeFS;
DeferredShading::UB_ReflectionVS DeferredShading::s_ubReflectionVS;
DeferredShading::UB_ReflectionFS DeferredShading::s_ubReflectionFS;
DeferredShading::UB_BakeSpritesVS DeferredShading::s_ubBakeSpritesVS;
DeferredShading::UB_BakeSpritesFS DeferredShading::s_ubBakeSpritesFS;
DeferredShading::DeferredShading()
{
}
DeferredShading::~DeferredShading()
{
Done();
}
void DeferredShading::Init()
{
VERUS_INIT();
VERUS_LOG_INFO("<DeferredShadingInit>");
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
_rph = renderer->CreateRenderPass(
{
RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer1", Format::unormR10G10B10A2).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccAmb", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccDiff", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccSpec", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).LoadOpClear().Layout(ImageLayout::depthStencilAttachment, ImageLayout::depthStencilReadOnly)
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("GBuffer0", ImageLayout::colorAttachment),
RP::Ref("GBuffer1", ImageLayout::colorAttachment),
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
RP::Subpass("Sp1").Input(
{
RP::Ref("GBuffer0", ImageLayout::fsReadOnly),
RP::Ref("GBuffer1", ImageLayout::fsReadOnly),
RP::Ref("GBuffer2", ImageLayout::fsReadOnly),
RP::Ref("GBuffer3", ImageLayout::fsReadOnly),
RP::Ref("Depth", ImageLayout::depthStencilReadOnly)
}).Color(
{
RP::Ref("LightAccAmb", ImageLayout::colorAttachment),
RP::Ref("LightAccDiff", ImageLayout::colorAttachment),
RP::Ref("LightAccSpec", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
},
{
RP::Dependency("Sp0", "Sp1").Mode(1)
});
_rphCompose = renderer->CreateRenderPass(
{
RP::Attachment("ComposedA", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("ComposedB", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpDontCare().Layout(ImageLayout::fsReadOnly)
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("ComposedA", ImageLayout::colorAttachment),
RP::Ref("ComposedB", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
})
},
{});
// Extra stuff, which is not using deferred shading, for example water and sky:
_rphForwardRendering = renderer->CreateRenderPass(
{
RP::Attachment("ComposedA", Format::floatR11G11B10).Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilReadOnly, ImageLayout::depthStencilAttachment)
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("ComposedA", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment))
},
{});
// Reflection is added using additive blending:
_rphReflection = renderer->CreateSimpleRenderPass(Format::floatR11G11B10, RP::Attachment::LoadOp::load);
_shader[SHADER_LIGHT].Init("[Shaders]:DS.hlsl");
_shader[SHADER_LIGHT]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings._limits._ds_ubPerFrameCapacity);
_shader[SHADER_LIGHT]->CreateDescriptorSet(1, &s_ubTexturesFS, sizeof(s_ubTexturesFS), settings._limits._ds_ubTexturesFSCapacity,
{
Sampler::input, // GBuffer0
Sampler::input, // GBuffer1
Sampler::input, // GBuffer2
Sampler::input, // GBuffer3
Sampler::input, // Depth
Sampler::shadow, // ShadowCmp
Sampler::nearestClampMipN // Shadow
}, ShaderStageFlags::fs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings._limits._ds_ubPerMeshVSCapacity, {}, ShaderStageFlags::vs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(3, &s_ubShadowFS, sizeof(s_ubShadowFS), settings._limits._ds_ubShadowFSCapacity, {}, ShaderStageFlags::fs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(4, &s_ubPerObject, sizeof(s_ubPerObject), 0);
_shader[SHADER_LIGHT]->CreatePipelineLayout();
_shader[SHADER_AMBIENT].Init("[Shaders]:DS_Ambient.hlsl");
_shader[SHADER_AMBIENT]->CreateDescriptorSet(0, &s_ubAmbientVS, sizeof(s_ubAmbientVS), 2);
_shader[SHADER_AMBIENT]->CreateDescriptorSet(1, &s_ubAmbientFS, sizeof(s_ubAmbientFS), 2,
{
Sampler::input, // GBuffer0
Sampler::input, // GBuffer1
Sampler::input, // GBuffer2
Sampler::input, // GBuffer3
Sampler::input, // Depth
CGI::Sampler::linearClampMipN, // TerrainHeightmap
CGI::Sampler::anisoClamp // TerrainBlend
}, ShaderStageFlags::fs);
_shader[SHADER_AMBIENT]->CreatePipelineLayout();
ShaderDesc shaderDesc("[Shaders]:DS_Compose.hlsl");
String userDefines;
if (settings._postProcessCinema)
userDefines += " CINEMA";
if (settings._postProcessBloom)
userDefines += " BLOOM";
if (!userDefines.empty())
{
userDefines = userDefines.substr(1);
shaderDesc._userDefines = _C(userDefines);
}
_shader[SHADER_COMPOSE].Init(shaderDesc);
_shader[SHADER_COMPOSE]->CreateDescriptorSet(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 4, {}, ShaderStageFlags::vs);
_shader[SHADER_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 4,
{
Sampler::nearestClampMipN, // GBuffer0
Sampler::nearestClampMipN, // GBuffer1
Sampler::linearClampMipN, // GBuffer2|Composed
Sampler::nearestClampMipN, // Depth
Sampler::nearestClampMipN, // Ambient
Sampler::nearestClampMipN, // Diffuse
Sampler::linearClampMipN // Specular|Bloom
}, ShaderStageFlags::fs);
_shader[SHADER_COMPOSE]->CreatePipelineLayout();
_shader[SHADER_REFLECTION].Init("[Shaders]:DS_Reflection.hlsl");
_shader[SHADER_REFLECTION]->CreateDescriptorSet(0, &s_ubReflectionVS, sizeof(s_ubReflectionVS), 2);
_shader[SHADER_REFLECTION]->CreateDescriptorSet(1, &s_ubReflectionFS, sizeof(s_ubReflectionFS), 2,
{
Sampler::nearestClampMipN,
Sampler::nearestClampMipN
}, ShaderStageFlags::fs);
_shader[SHADER_REFLECTION]->CreatePipelineLayout();
_shader[SHADER_BAKE_SPRITES].Init("[Shaders]:DS_BakeSprites.hlsl");
_shader[SHADER_BAKE_SPRITES]->CreateDescriptorSet(0, &s_ubBakeSpritesVS, sizeof(s_ubBakeSpritesVS), 1000);
_shader[SHADER_BAKE_SPRITES]->CreateDescriptorSet(1, &s_ubBakeSpritesFS, sizeof(s_ubBakeSpritesFS), 1000,
{
Sampler::nearestClampMipN, // GBuffer0
Sampler::nearestClampMipN, // GBuffer1
Sampler::nearestClampMipN, // GBuffer2
Sampler::nearestClampMipN // GBuffer3
}, ShaderStageFlags::fs);
_shader[SHADER_BAKE_SPRITES]->CreatePipelineLayout();
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_AMBIENT], "#", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "";
pipeDesc._colorAttachWriteMasks[2] = "";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_AMBIENT].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#Compose", _rphCompose);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "b";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_COMPOSE].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_REFLECTION], "#", _rphReflection);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_REFLECTION].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_REFLECTION], "#DebugCubeMap", _rphReflection);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_REFLECTION_DEBUG].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#ToneMapping", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_TONE_MAPPING].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), renderer.GetShaderQuad(), "#", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_QUAD].Init(pipeDesc);
}
OnSwapChainResized(true, false);
VERUS_LOG_INFO("</DeferredShadingInit>");
}
void DeferredShading::InitGBuffers(int w, int h)
{
TextureDesc texDesc;
// GB0:
texDesc._clearValue = GetClearValueForGBuffer0();
texDesc._name = "DeferredShading.GBuffer0";
texDesc._format = Format::srgbR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_0].Init(texDesc);
// GB1:
texDesc._clearValue = GetClearValueForGBuffer1();
texDesc._name = "DeferredShading.GBuffer1";
texDesc._format = Format::unormR10G10B10A2;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_1].Init(texDesc);
// GB2:
texDesc._clearValue = GetClearValueForGBuffer2();
texDesc._name = "DeferredShading.GBuffer2";
texDesc._format = Format::unormR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_2].Init(texDesc);
// GB3:
texDesc._clearValue = GetClearValueForGBuffer3();
texDesc._name = "DeferredShading.GBuffer3";
texDesc._format = Format::unormR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_3].Init(texDesc);
}
void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
{
VERUS_QREF_RENDERER;
if (texShadow)
_texAtmoShadow = texShadow;
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
_cshLight = _shader[SHADER_LIGHT]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
renderer.GetTexDepthStencil(),
_texAtmoShadow ? _texAtmoShadow : _tex[TEX_GBUFFER_0],
_texAtmoShadow ? _texAtmoShadow : _tex[TEX_GBUFFER_1]
});
}
void DeferredShading::InitByBloom(TexturePtr tex)
{
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_COMPOSED_A],
_tex[TEX_COMPOSED_A],
tex,
tex,
tex
});
}
void DeferredShading::InitByTerrain(TexturePtr texHeightmap, TexturePtr texBlend, int mapSide)
{
VERUS_QREF_RENDERER;
if (texHeightmap)
_texTerrainHeightmap = texHeightmap;
if (texBlend)
_texTerrainBlend = texBlend;
if (mapSide > 1)
_terrainMapSide = mapSide;
_shader[SHADER_AMBIENT]->FreeDescriptorSet(_cshAmbient);
_cshAmbient = _shader[SHADER_AMBIENT]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
renderer.GetTexDepthStencil(),
_texTerrainHeightmap ? _texTerrainHeightmap : _tex[TEX_GBUFFER_0],
_texTerrainBlend ? _texTerrainBlend : _tex[TEX_GBUFFER_1]
});
}
void DeferredShading::Done()
{
VERUS_DONE(DeferredShading);
}
void DeferredShading::OnSwapChainResized(bool init, bool done)
{
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
if (done)
{
VERUS_FOR(i, VERUS_COUNT_OF(_cshQuad))
renderer.GetShaderQuad()->FreeDescriptorSet(_cshQuad[i]);
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
_shader[SHADER_REFLECTION]->FreeDescriptorSet(_cshReflection);
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose);
_shader[SHADER_AMBIENT]->FreeDescriptorSet(_cshAmbient);
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
renderer->DeleteFramebuffer(_fbhReflection);
renderer->DeleteFramebuffer(_fbhForwardRendering);
renderer->DeleteFramebuffer(_fbhCompose);
renderer->DeleteFramebuffer(_fbh);
_tex[TEX_COMPOSED_B].Done();
_tex[TEX_COMPOSED_A].Done();
_tex[TEX_LIGHT_ACC_SPECULAR].Done();
_tex[TEX_LIGHT_ACC_DIFFUSE].Done();
_tex[TEX_LIGHT_ACC_AMBIENT].Done();
_tex[TEX_GBUFFER_3].Done();
_tex[TEX_GBUFFER_2].Done();
_tex[TEX_GBUFFER_1].Done();
_tex[TEX_GBUFFER_0].Done();
}
if (init)
{
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
const int scaledSwapChainHeight = settings.Scale(renderer.GetSwapChainHeight());
InitGBuffers(scaledSwapChainWidth, scaledSwapChainHeight);
TextureDesc texDesc;
// Light accumulation buffers:
// See: https://bartwronski.com/2017/04/02/small-float-formats-r11g11b10f-precision/
texDesc._format = Format::floatR11G11B10;
texDesc._width = scaledSwapChainWidth;
texDesc._height = scaledSwapChainHeight;
texDesc._flags = TextureDesc::Flags::colorAttachment;
texDesc._name = "DeferredShading.LightAccAmbient";
_tex[TEX_LIGHT_ACC_AMBIENT].Init(texDesc);
texDesc._name = "DeferredShading.LightAccDiffuse";
_tex[TEX_LIGHT_ACC_DIFFUSE].Init(texDesc);
texDesc._name = "DeferredShading.LightAccSpecular";
_tex[TEX_LIGHT_ACC_SPECULAR].Init(texDesc);
texDesc._name = "DeferredShading.ComposedA";
_tex[TEX_COMPOSED_A].Init(texDesc);
texDesc._name = "DeferredShading.ComposedB";
_tex[TEX_COMPOSED_B].Init(texDesc);
_fbh = renderer->CreateFramebuffer(_rph,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR],
renderer.GetTexDepthStencil()
},
scaledSwapChainWidth, scaledSwapChainHeight);
_fbhCompose = renderer->CreateFramebuffer(_rphCompose,
{
_tex[TEX_COMPOSED_A],
_tex[TEX_COMPOSED_B],
_tex[TEX_GBUFFER_3]
},
scaledSwapChainWidth, scaledSwapChainHeight);
_fbhForwardRendering = renderer->CreateFramebuffer(_rphForwardRendering,
{
_tex[TEX_COMPOSED_A],
renderer.GetTexDepthStencil()
},
scaledSwapChainWidth, scaledSwapChainHeight);
_fbhReflection = renderer->CreateFramebuffer(_rphReflection,
{
_tex[TEX_COMPOSED_A]
},
scaledSwapChainWidth, scaledSwapChainHeight);
_cshCompose = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
renderer.GetTexDepthStencil(),
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
_cshReflection = _shader[SHADER_REFLECTION]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_1],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_COMPOSED_A],
_tex[TEX_COMPOSED_A],
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
VERUS_FOR(i, VERUS_COUNT_OF(_cshQuad))
_cshQuad[i] = renderer.GetShaderQuad()->BindDescriptorSetTextures(1, { _tex[TEX_GBUFFER_0 + i] });
if (_texAtmoShadow)
InitByAtmosphere(_texAtmoShadow);
InitByTerrain(_texTerrainHeightmap, _texTerrainBlend, _terrainMapSide);
}
}
bool DeferredShading::IsLoaded()
{
VERUS_QREF_HELPERS;
Scene::RDeferredLights dl = helpers.GetDeferredLights();
return
dl.Get(LightType::dir).IsLoaded() &&
dl.Get(LightType::omni).IsLoaded() &&
dl.Get(LightType::spot).IsLoaded();
}
void DeferredShading::ResetInstanceCount()
{
VERUS_QREF_HELPERS;
Scene::RDeferredLights dl = helpers.GetDeferredLights();
dl.Get(LightType::dir).ResetInstanceCount();
dl.Get(LightType::omni).ResetInstanceCount();
dl.Get(LightType::spot).ResetInstanceCount();
}
void DeferredShading::Draw(int gbuffer,
RcVector4 rMultiplexer,
RcVector4 gMultiplexer,
RcVector4 bMultiplexer,
RcVector4 aMultiplexer)
{
VERUS_QREF_RENDERER;
const float w = static_cast<float>(renderer.GetSwapChainWidth() / 2);
const float h = static_cast<float>(renderer.GetSwapChainHeight() / 2);
auto cb = renderer.GetCommandBuffer();
auto shader = renderer.GetShaderQuad();
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
renderer.GetUbQuadFS()._rMultiplexer = rMultiplexer.GLM();
renderer.GetUbQuadFS()._gMultiplexer = gMultiplexer.GLM();
renderer.GetUbQuadFS()._bMultiplexer = bMultiplexer.GLM();
renderer.GetUbQuadFS()._aMultiplexer = aMultiplexer.GLM();
cb->BindPipeline(_pipe[PIPE_QUAD]);
shader->BeginBindDescriptors();
cb->BindDescriptors(shader, 0);
if (-1 == gbuffer)
{
cb->SetViewport({ Vector4(0, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[0]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(w, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[1]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, h, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[2]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(w, h, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[3]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
}
else if (-2 == gbuffer)
{
cb->SetViewport({ Vector4(0, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[4]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(w, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[5]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, h, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[6]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
}
else
{
cb->BindDescriptors(shader, 1, _cshQuad[gbuffer]);
renderer.DrawQuad(cb.Get());
}
shader->EndBindDescriptors();
}
void DeferredShading::BeginGeometryPass()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeGeometryPass = true;
_frame = renderer.GetFrameCount();
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
{
_tex[TEX_GBUFFER_0]->GetClearValue(),
_tex[TEX_GBUFFER_1]->GetClearValue(),
_tex[TEX_GBUFFER_2]->GetClearValue(),
_tex[TEX_GBUFFER_3]->GetClearValue(),
_tex[TEX_LIGHT_ACC_AMBIENT]->GetClearValue(),
_tex[TEX_LIGHT_ACC_DIFFUSE]->GetClearValue(),
_tex[TEX_LIGHT_ACC_SPECULAR]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
}
void DeferredShading::EndGeometryPass()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeGeometryPass = false;
}
bool DeferredShading::BeginLightingPass(bool ambient, bool terrainOcclusion)
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeLightingPass = true;
auto cb = renderer.GetCommandBuffer();
cb->NextSubpass();
if (ambient)
{
VERUS_QREF_ATMO;
VERUS_QREF_SM;
s_ubAmbientVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubAmbientVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubAmbientFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubAmbientFS._matInvP = sm.GetCamera()->GetMatrixInvP().UniformBufferFormat();
s_ubAmbientFS._ambientColorY0 = float4(atmo.GetAmbientColorY0().GLM(), 0);
s_ubAmbientFS._ambientColorY1 = float4(atmo.GetAmbientColorY1().GLM(), 0);
s_ubAmbientFS._invMapSide_minOcclusion.x = 1.f / _terrainMapSide;
s_ubAmbientFS._invMapSide_minOcclusion.y = terrainOcclusion ? 0.f : 1.f;
cb->BindPipeline(_pipe[PIPE_AMBIENT]);
_shader[SHADER_AMBIENT]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_AMBIENT], 0);
cb->BindDescriptors(_shader[SHADER_AMBIENT], 1, _cshAmbient);
_shader[SHADER_AMBIENT]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
}
_shader[SHADER_LIGHT]->BeginBindDescriptors();
if (!IsLoaded())
return false;
if (!_async_initPipe)
{
_async_initPipe = true;
VERUS_QREF_HELPERS;
Scene::RDeferredLights dl = helpers.GetDeferredLights();
{
PipelineDesc pipeDesc(dl.Get(LightType::dir).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedDir", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "rgb";
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc.DisableDepthTest();
_pipe[PIPE_INSTANCED_DIR].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(dl.Get(LightType::omni).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedOmni", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "rgb";
pipeDesc._rasterizationState._cullMode = CullMode::front;
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc._depthCompareOp = CompareOp::greater;
pipeDesc._depthWriteEnable = false;
_pipe[PIPE_INSTANCED_OMNI].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(dl.Get(LightType::spot).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedSpot", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "rgb";
pipeDesc._rasterizationState._cullMode = CullMode::front;
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc._depthCompareOp = CompareOp::greater;
pipeDesc._depthWriteEnable = false;
_pipe[PIPE_INSTANCED_SPOT].Init(pipeDesc);
}
}
return true;
}
void DeferredShading::EndLightingPass()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass && !_activeForwardRendering);
_activeLightingPass = false;
_shader[SHADER_LIGHT]->EndBindDescriptors();
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::BeginComposeAndForwardRendering(bool underwaterMask)
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
VERUS_QREF_WATER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeForwardRendering = true;
const Matrix4 matInvVP = VMath::inverse(sm.GetCamera()->GetMatrixVP());
auto cb = renderer.GetCommandBuffer();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matInvVP = matInvVP.UniformBufferFormat();
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
s_ubComposeFS._exposure_underwaterMask.y = underwaterMask ? 1.f : 0.f;
s_ubComposeFS._backgroundColor = _backgroundColor.GLM();
s_ubComposeFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
s_ubComposeFS._waterDiffColorShallow = float4(water.GetDiffuseColorShallow().GLM(), water.GetFogDensity());
s_ubComposeFS._waterDiffColorDeep = float4(water.GetDiffuseColorDeep().GLM(), water.IsUnderwater() ? 1.f : 0.f);
// Compose buffers, that is perform "final color = albedo * diffuse + specular" computation. Result is still HDR:
cb->BeginRenderPass(_rphCompose, _fbhCompose,
{
_tex[TEX_COMPOSED_A]->GetClearValue(),
_tex[TEX_COMPOSED_B]->GetClearValue(),
_tex[TEX_GBUFFER_3]->GetClearValue()
});
cb->BindPipeline(_pipe[PIPE_COMPOSE]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_COMPOSE], 0);
cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshCompose);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
// Begin drawing extra stuff, which is not using deferred shading, for example water (updates depth buffer) and sky:
cb->BeginRenderPass(_rphForwardRendering, _fbhForwardRendering,
{
_tex[TEX_COMPOSED_A]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
}
void DeferredShading::EndComposeAndForwardRendering()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && _activeForwardRendering);
_activeForwardRendering = false;
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::DrawReflection()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SSR;
auto cb = renderer.GetCommandBuffer();
s_ubReflectionVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubReflectionVS._matV = Math::ToUVMatrix().UniformBufferFormat();
cb->BeginRenderPass(_rphReflection, _fbhReflection, { _tex[TEX_COMPOSED_A]->GetClearValue() });
cb->BindPipeline(ssr.IsCubeMapDebugMode() ? _pipe[PIPE_REFLECTION_DEBUG] : _pipe[PIPE_REFLECTION]);
_shader[SHADER_REFLECTION]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_REFLECTION], 0);
cb->BindDescriptors(_shader[SHADER_REFLECTION], 1, _cshReflection);
_shader[SHADER_REFLECTION]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
void DeferredShading::ToneMapping()
{
VERUS_QREF_RENDERER;
auto cb = renderer.GetCommandBuffer();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
// Convert HDR image to SDR. First multiply by exposure, then apply tone mapping curve:
cb->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
_shader[SHADER_COMPOSE]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_COMPOSE], 0);
cb->BindDescriptors(_shader[SHADER_COMPOSE], 1, _cshToneMapping);
_shader[SHADER_COMPOSE]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
}
bool DeferredShading::IsLightUrl(CSZ url)
{
return
!strcmp(url, "DIR") ||
!strcmp(url, "OMNI") ||
!strcmp(url, "SPOT");
}
void DeferredShading::OnNewLightType(CommandBufferPtr cb, LightType type, bool wireframe)
{
VERUS_QREF_ATMO;
VERUS_QREF_SM;
s_ubPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat();
s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubPerFrame._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubPerFrame._matInvP = sm.GetCamera()->GetMatrixInvP().UniformBufferFormat();
switch (type)
{
case LightType::dir:
{
cb->BindPipeline(_pipe[PIPE_INSTANCED_DIR]);
}
break;
case LightType::omni:
{
cb->BindPipeline(_pipe[PIPE_INSTANCED_OMNI]);
}
break;
case LightType::spot:
{
cb->BindPipeline(_pipe[PIPE_INSTANCED_SPOT]);
}
break;
}
cb->BindDescriptors(_shader[SHADER_LIGHT], 0);
cb->BindDescriptors(_shader[SHADER_LIGHT], 1, _cshLight);
// Shadow:
s_ubShadowFS._matShadow = atmo.GetShadowMapBaker().GetShadowMatrixDS(0).UniformBufferFormat();
s_ubShadowFS._matShadowCSM1 = atmo.GetShadowMapBaker().GetShadowMatrixDS(1).UniformBufferFormat();
s_ubShadowFS._matShadowCSM2 = atmo.GetShadowMapBaker().GetShadowMatrixDS(2).UniformBufferFormat();
s_ubShadowFS._matShadowCSM3 = atmo.GetShadowMapBaker().GetShadowMatrixDS(3).UniformBufferFormat();
s_ubShadowFS._matScreenCSM = atmo.GetShadowMapBaker().GetScreenMatrixP().UniformBufferFormat();
s_ubShadowFS._csmSplitRanges = atmo.GetShadowMapBaker().GetSplitRanges().GLM();
memcpy(&s_ubShadowFS._shadowConfig, &atmo.GetShadowMapBaker().GetConfig(), sizeof(s_ubShadowFS._shadowConfig));
cb->BindDescriptors(_shader[SHADER_LIGHT], 3);
}
void DeferredShading::BindDescriptorsPerMeshVS(CommandBufferPtr cb)
{
cb->BindDescriptors(_shader[SHADER_LIGHT], 2);
}
void DeferredShading::Load()
{
VERUS_QREF_HELPERS;
Scene::RDeferredLights dl = helpers.GetDeferredLights();
Scene::Mesh::Desc meshDesc;
meshDesc._instanceCapacity = 10000;
meshDesc._url = "[Models]:DS/Dir.x3d";
dl.Get(LightType::dir).Init(meshDesc);
meshDesc._url = "[Models]:DS/Omni.x3d";
dl.Get(LightType::omni).Init(meshDesc);
meshDesc._url = "[Models]:DS/Spot.x3d";
dl.Get(LightType::spot).Init(meshDesc);
}
TexturePtr DeferredShading::GetGBuffer(int index)
{
return _tex[index];
}
TexturePtr DeferredShading::GetLightAccAmbientTexture()
{
return _tex[TEX_LIGHT_ACC_AMBIENT];
}
TexturePtr DeferredShading::GetLightAccDiffuseTexture()
{
return _tex[TEX_LIGHT_ACC_DIFFUSE];
}
TexturePtr DeferredShading::GetLightAccSpecularTexture()
{
return _tex[TEX_LIGHT_ACC_SPECULAR];
}
TexturePtr DeferredShading::GetComposedTextureA()
{
return _tex[TEX_COMPOSED_A];
}
TexturePtr DeferredShading::GetComposedTextureB()
{
return _tex[TEX_COMPOSED_B];
}
Vector4 DeferredShading::GetClearValueForGBuffer0(float albedo)
{
return Vector4(albedo, albedo, albedo, 0.5f);
}
Vector4 DeferredShading::GetClearValueForGBuffer1(float normal, float motionBlur)
{
return Vector4(normal, normal, 0, motionBlur);
}
Vector4 DeferredShading::GetClearValueForGBuffer2(float roughness)
{
return Vector4(1, roughness, 0, 0);
}
Vector4 DeferredShading::GetClearValueForGBuffer3(float tangent)
{
return Vector4(tangent, tangent, 0, 0);
}
void DeferredShading::BakeSprites(TexturePtr texGBufferIn[4], TexturePtr texGBufferOut[4], PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
RcVector4 size = texGBufferOut[0]->GetSize();
const int w = static_cast<int>(size.getX());
const int h = static_cast<int>(size.getY());
_rphBakeSprites = renderer->CreateRenderPass(
{
RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer1", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly)
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("GBuffer0", ImageLayout::colorAttachment),
RP::Ref("GBuffer1", ImageLayout::colorAttachment),
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
})
},
{});
_fbhBakeSprites = renderer->CreateFramebuffer(_rphBakeSprites,
{
texGBufferOut[0],
texGBufferOut[1],
texGBufferOut[2],
texGBufferOut[3]
},
w, h);
_cshBakeSprites = _shader[SHADER_BAKE_SPRITES]->BindDescriptorSetTextures(1,
{
texGBufferIn[0],
texGBufferIn[1],
texGBufferIn[2],
texGBufferIn[3]
});
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_BAKE_SPRITES], "#", _rphBakeSprites);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_BAKE_SPRITES].Init(pipeDesc);
}
s_ubBakeSpritesVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubBakeSpritesVS._matV = Math::ToUVMatrix().UniformBufferFormat();
pCB->BeginRenderPass(_rphBakeSprites, _fbhBakeSprites,
{
texGBufferOut[0]->GetClearValue(),
texGBufferOut[1]->GetClearValue(),
texGBufferOut[2]->GetClearValue(),
texGBufferOut[3]->GetClearValue()
});
pCB->BindPipeline(_pipe[PIPE_BAKE_SPRITES]);
_shader[SHADER_BAKE_SPRITES]->BeginBindDescriptors();
pCB->BindDescriptors(_shader[SHADER_BAKE_SPRITES], 0);
pCB->BindDescriptors(_shader[SHADER_BAKE_SPRITES], 1, _cshBakeSprites);
_shader[SHADER_BAKE_SPRITES]->EndBindDescriptors();
renderer.DrawQuad(pCB);
pCB->EndRenderPass();
}
void DeferredShading::BakeSpritesCleanup()
{
VERUS_QREF_RENDERER;
_pipe[PIPE_BAKE_SPRITES].Done();
_shader[SHADER_BAKE_SPRITES]->FreeDescriptorSet(_cshBakeSprites);
renderer->DeleteFramebuffer(_fbhBakeSprites);
renderer->DeleteRenderPass(_rphBakeSprites);
}