Skip to content

Commit

Permalink
Implement cascaded shadow maps
Browse files Browse the repository at this point in the history
Only for terrain so far
  • Loading branch information
Pursche committed Jul 28, 2024
1 parent cbee128 commit 349134c
Show file tree
Hide file tree
Showing 35 changed files with 777 additions and 587 deletions.
2 changes: 1 addition & 1 deletion Source/Game/Game/ECS/Components/Camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace ECS::Components
f32 fov = 90.0f;
f32 aspectRatio = 1.0f;
f32 nearClip = 0.01f;
f32 farClip = 100000.0f;
f32 farClip = 2500.0f;

mat4x4 clipToView;
mat4x4 clipToWorld;
Expand Down
2 changes: 2 additions & 0 deletions Source/Game/Game/ECS/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "Game/ECS/Components/Camera.h"

#include "Game/ECS/Systems/CalculateCameraMatrices.h"
#include "Game/ECS/Systems/CalculateShadowCameraMatrices.h"
#include "Game/ECS/Systems/DrawDebugMesh.h"
#include "Game/ECS/Systems/FreeflyingCamera.h"
#include "Game/ECS/Systems/OrbitalCamera.h"
Expand Down Expand Up @@ -58,6 +59,7 @@ namespace ECS
Systems::FreeflyingCamera::Update(registry, deltaTime);
Systems::OrbitalCamera::Update(registry, deltaTime);
Systems::CalculateCameraMatrices::Update(registry, deltaTime);
Systems::CalculateShadowCameraMatrices::Update(registry, deltaTime);
Systems::UpdateSkyboxes::Update(registry, deltaTime);
Systems::CalculateTransformMatrices::Update(registry, deltaTime);
Systems::UpdatePhysics::Update(registry, deltaTime);
Expand Down
3 changes: 3 additions & 0 deletions Source/Game/Game/ECS/Systems/CalculateCameraMatrices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

AutoCVar_Int CVAR_CameraLockCullingFrustum(CVarCategory::Client | CVarCategory::Rendering, "cameraLockCullingFrustum", "Lock the frustum used for culling", 0, CVarFlags::EditCheckbox);

AutoCVar_Float CVAR_CameraFarClip(CVarCategory::Client | CVarCategory::Rendering, "cameraFarClip", "The far clip distance of the camera", 2500.0f);

namespace ECS::Systems
{
inline vec4 EncodePlane(vec3 position, vec3 normal)
Expand All @@ -34,6 +36,7 @@ namespace ECS::Systems
auto view = registry.view<Components::Transform, Components::Camera>();
view.each([&](entt::entity e, Components::Transform& transform, Components::Camera& camera)
{
camera.farClip = CVAR_CameraFarClip.GetFloat();
if (e != activeCamera.entity)
{
// TODO: Multiple cameras (picture-in-picture I guess?) would need to change this
Expand Down
54 changes: 30 additions & 24 deletions Source/Game/Game/ECS/Systems/CalculateShadowCameraMatrices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@

AutoCVar_Int CVAR_ShadowsStable(CVarCategory::Client | CVarCategory::Rendering, "shadowStable", "stable shadows", 1, CVarFlags::EditCheckbox);

//AutoCVar_Int CVAR_ShadowCascadeNum(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum", "number of shadow cascades", 4);
AutoCVar_Int CVAR_ShadowCascadeNum(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum", "number of shadow cascades", 4);
AutoCVar_Float CVAR_ShadowCascadeSplitLambda(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeSplitLambda", "split lambda for cascades, between 0.0f and 1.0f", 0.5f);

AutoCVar_Int CVAR_ShadowCascadeTextureSize(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeSize", "size of biggest cascade (per side)", 4096);

AutoCVar_VecFloat CVAR_DirectionalLightDirection(CVarCategory::Client | CVarCategory::Rendering, "directionalLightDirection", "direction of the directional light", glm::vec4(0.0f, 1.0f, -1.0f, 0.0f));

namespace ECS::Systems
{
inline vec4 EncodePlane(vec3 position, vec3 normal)
Expand All @@ -38,32 +40,38 @@ namespace ECS::Systems

RenderResources& renderResources = gameRenderer->GetRenderResources();

u32 numCascades = 0;// CVAR_ShadowCascadeNum.GetU32();
std::vector<Camera>& gpuCameras = renderResources.cameras.Get();

u32 numCascades = CVAR_ShadowCascadeNum.GetU32();
i32 cascadeTextureSize = CVAR_ShadowCascadeTextureSize.Get();
bool stableShadows = CVAR_ShadowsStable.Get() == 1;

// Initialize any new shadow cascades
while (numCascades > renderResources.shadowDepthCascades.size())
{
u32 cascadeIndex = static_cast<u32>(renderResources.shadowDepthCascades.size());

// Shadow depth rendertarget
Renderer::DepthImageDesc shadowDepthDesc;
shadowDepthDesc.dimensions = vec2(cascadeTextureSize, cascadeTextureSize);
shadowDepthDesc.dimensionType = Renderer::ImageDimensionType::DIMENSION_ABSOLUTE;
shadowDepthDesc.format = Renderer::DepthImageFormat::D32_FLOAT;
shadowDepthDesc.sampleCount = Renderer::SampleCount::SAMPLE_COUNT_1;
shadowDepthDesc.depthClearValue = 0.0f;
shadowDepthDesc.debugName = "ShadowDepthCascade" + std::to_string(cascadeIndex);

Renderer::DepthImageID cascadeDepthImage = renderer->CreateDepthImage(shadowDepthDesc);
renderResources.shadowDepthCascades.push_back(cascadeDepthImage);
if (numCascades != renderResources.shadowDepthCascades.size())
{
gpuCameras.resize(numCascades + 1); // + 1 because of main camera

//renderResources.shadowDescriptorSet.BindArray("_shadowCascadeRTs", cascadeDepthImage, cascadeIndex); // TODO: This needs to be bound in the rendergraph I guess
}
while (numCascades > renderResources.shadowDepthCascades.size())
{
u32 cascadeIndex = static_cast<u32>(renderResources.shadowDepthCascades.size());

// Shadow depth rendertarget
Renderer::DepthImageDesc shadowDepthDesc;
shadowDepthDesc.dimensions = vec2(cascadeTextureSize, cascadeTextureSize);
shadowDepthDesc.dimensionType = Renderer::ImageDimensionType::DIMENSION_ABSOLUTE;
shadowDepthDesc.format = Renderer::DepthImageFormat::D32_FLOAT;
shadowDepthDesc.sampleCount = Renderer::SampleCount::SAMPLE_COUNT_1;
shadowDepthDesc.depthClearValue = 0.0f;
shadowDepthDesc.debugName = "ShadowDepthCascade" + std::to_string(cascadeIndex);

Renderer::DepthImageID cascadeDepthImage = renderer->CreateDepthImage(shadowDepthDesc);
renderResources.shadowDepthCascades.push_back(cascadeDepthImage);
}
}

// Get light settings
vec3 lightDirection = vec3(0.0f, -1.0f, 0.0f); // TODO
vec3 lightDirection = glm::normalize(vec3(CVAR_DirectionalLightDirection.Get()));
lightDirection.y = -lightDirection.y;

// Get active render camera
entt::registry::context& ctx = registry.ctx();
Expand Down Expand Up @@ -212,8 +220,7 @@ namespace ECS::Systems
f32 nearPlane = minExtents.z;

// Come up with a new orthographic projection matrix for the shadow caster
mat4x4 projMatrix = glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, farPlane - nearPlane, -250.0f); // TODO: I had to use this one to fix issues
//mat4x4 projMatrix = glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, cascadeExtents.z, 0.0f); // TODO: This was the original, but I have flipped min and max Z because of inversed Z
mat4x4 projMatrix = glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, farPlane - nearPlane, 0.0f);
mat4x4 viewMatrix = glm::lookAt(shadowCameraPos, frustumCenter, upDir);

if (stableShadows)
Expand All @@ -234,7 +241,6 @@ namespace ECS::Systems
}

// Store split distance and matrix in cascade camera
std::vector<Camera> gpuCameras = renderResources.cameras.Get();
Camera& cascadeCamera = gpuCameras[i + 1]; // +1 because the first camera is the main camera

cascadeCamera.worldToView = viewMatrix;
Expand All @@ -246,7 +252,7 @@ namespace ECS::Systems
cascadeCamera.worldToClip = cascadeCamera.viewToClip * cascadeCamera.worldToView;
cascadeCamera.clipToWorld = cascadeCamera.viewToWorld * cascadeCamera.clipToView;

f32 splitDepth = (farClip - (nearClip + splitDist * clipRange)) * -1.0f;
f32 splitDepth = (farClip - (nearClip + splitDist * clipRange));// *-1.0f;
cascadeCamera.eyePosition = vec4(shadowCameraPos, splitDepth); // w holds split depth

vec3 scale;
Expand Down
40 changes: 22 additions & 18 deletions Source/Game/Game/Editor/PerformanceDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace Editor
const std::string rightHeaderText = "Survived / Total (%)";
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit /*| ImGuiTableFlags_BordersOuter*/ | ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersH | ImGuiTableFlags_ContextMenuInBody;

u32 numCascades = 0;// *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "numShadowCascades"_h);
u32 numCascades = *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum"_h);

ImGui::Spacing();

Expand Down Expand Up @@ -586,9 +586,10 @@ namespace Editor
u32 viewDrawCalls = 0;
u32 viewDrawCallsSurvived = 0;

bool viewSupportsOcclusionCulling = viewID == 0; // Only main view supports occlusion culling so far
bool viewSupportsTerrainOcclusionCulling = true;
bool viewSupportsModelsOcclusionCulling = viewID == 0;

bool viewRendersTerrainCulling = true; // Only main view supports terrain culling so far
bool viewRendersTerrainCulling = true;
bool viewRendersOpaqueModelsCulling = true;
bool viewRendersTransparentModelsCulling = viewID == 0; // Only main view supports transparent cmodel culling so far
bool viewRendersLiquidCulling = viewID == 0; // Only main view supports mapObjectgs culling so far
Expand All @@ -601,9 +602,9 @@ namespace Editor
viewDrawCalls += drawCalls;

// Occluders
if (viewSupportsOcclusionCulling)
if (viewSupportsTerrainOcclusionCulling)
{
u32 drawCallsSurvived = terrainRenderer->GetNumOccluderDrawCalls();
u32 drawCallsSurvived = terrainRenderer->GetNumOccluderDrawCalls(viewID);
DrawCullingStatsEntry("Terrain Occluders", drawCalls, drawCallsSurvived);
viewDrawCallsSurvived += drawCallsSurvived;
}
Expand All @@ -620,33 +621,35 @@ namespace Editor
if (viewRendersOpaqueModelsCulling)
{
CullingResourcesBase& cullingResources = modelRenderer->GetOpaqueCullingResources();
DrawCullingResourcesDrawCalls("Model (O)", viewID, cullingResources, viewSupportsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
DrawCullingResourcesDrawCalls("Model (O)", viewID, cullingResources, viewSupportsModelsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
}

// Transparent Models
if (viewRendersTransparentModelsCulling)
{
CullingResourcesBase& cullingResources = modelRenderer->GetTransparentCullingResources();
DrawCullingResourcesDrawCalls("Model (T)", viewID, cullingResources, viewSupportsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
DrawCullingResourcesDrawCalls("Model (T)", viewID, cullingResources, viewSupportsModelsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
}

// Liquid
if (viewRendersLiquidCulling)
{
CullingResourcesBase& cullingResources = liquidRenderer->GetCullingResources();
DrawCullingResourcesDrawCalls("Liquid", viewID, cullingResources, viewSupportsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
DrawCullingResourcesDrawCalls("Liquid", viewID, cullingResources, viewSupportsModelsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
}

// Jolt Debug
if (viewRendersJoltDebug)
{
CullingResourcesBase& indexedCullingResources = joltDebugRenderer->GetIndexedCullingResources();
DrawCullingResourcesDrawCalls("Jolt Debug Indexed", viewID, indexedCullingResources, viewSupportsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
DrawCullingResourcesDrawCalls("Jolt Debug Indexed", viewID, indexedCullingResources, viewSupportsModelsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);

CullingResourcesBase& cullingResources = joltDebugRenderer->GetCullingResources();
DrawCullingResourcesDrawCalls("Jolt Debug", viewID, cullingResources, viewSupportsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
DrawCullingResourcesDrawCalls("Jolt Debug", viewID, cullingResources, viewSupportsModelsOcclusionCulling, viewDrawCalls, viewDrawCallsSurvived);
}

ImGui::Separator();
ImGui::Separator();

// If showDrawcalls we always want to draw Total, if we are collapsed it will go on the collapsable header
//DrawCullingStatsEntry("View Total", viewDrawCalls, viewDrawCallsSurvived, !showView);
Expand Down Expand Up @@ -692,7 +695,8 @@ namespace Editor
u32 viewTriangles = 0;
u32 viewTrianglesSurvived = 0;

bool viewSupportsOcclusionCulling = viewID == 0; // Only main view supports occlusion culling so far
bool viewSupportsTerrainOcclusionCulling = true;
bool viewSupportsModelsOcclusionCulling = viewID == 0;

bool viewRendersTerrainCulling = true; // Only main view supports terrain culling so far
bool viewRendersOpaqueModelsCulling = true;
Expand All @@ -707,9 +711,9 @@ namespace Editor
viewTriangles += triangles;

// Occluders
if (viewSupportsOcclusionCulling)
if (viewSupportsTerrainOcclusionCulling)
{
u32 trianglesSurvived = terrainRenderer->GetNumOccluderTriangles();
u32 trianglesSurvived = terrainRenderer->GetNumOccluderTriangles(viewID);
DrawCullingStatsEntry("Terrain Occluders", triangles, trianglesSurvived);
viewTrianglesSurvived += trianglesSurvived;
}
Expand All @@ -726,31 +730,31 @@ namespace Editor
if (viewRendersOpaqueModelsCulling)
{
CullingResourcesBase& cullingResources = modelRenderer->GetOpaqueCullingResources();
DrawCullingResourcesTriangle("Model (O)", viewID, cullingResources, true, viewSupportsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
DrawCullingResourcesTriangle("Model (O)", viewID, cullingResources, true, viewSupportsModelsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
}

// Transparent Models
if (viewRendersTransparentModelsCulling)
{
CullingResourcesBase& cullingResources = modelRenderer->GetTransparentCullingResources();
DrawCullingResourcesTriangle("Model (T)", viewID, cullingResources, true, viewSupportsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
DrawCullingResourcesTriangle("Model (T)", viewID, cullingResources, true, viewSupportsModelsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
}

// Liquid
if (viewRendersLiquidCulling)
{
CullingResourcesBase& cullingResources = liquidRenderer->GetCullingResources();
DrawCullingResourcesTriangle("Liquid", viewID, cullingResources, true, viewSupportsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
DrawCullingResourcesTriangle("Liquid", viewID, cullingResources, true, viewSupportsModelsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
}

// Jolt Debug
if (viewRendersJoltDebug)
{
CullingResourcesBase& indexedCullingResources = joltDebugRenderer->GetIndexedCullingResources();
DrawCullingResourcesTriangle("Jolt Debug Indexed", viewID, indexedCullingResources, true, viewSupportsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
DrawCullingResourcesTriangle("Jolt Debug Indexed", viewID, indexedCullingResources, true, viewSupportsModelsOcclusionCulling, viewTriangles, viewTrianglesSurvived);

CullingResourcesBase& cullingResources = joltDebugRenderer->GetCullingResources();
DrawCullingResourcesTriangle("Jolt Debug", viewID, cullingResources, true, viewSupportsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
DrawCullingResourcesTriangle("Jolt Debug", viewID, cullingResources, true, viewSupportsModelsOcclusionCulling, viewTriangles, viewTrianglesSurvived);
}

// If showTriangles we always want to draw Total, if we are collapsed it will go on the collapsable header
Expand Down
8 changes: 4 additions & 4 deletions Source/Game/Game/Rendering/Debug/JoltDebugRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ void JoltDebugRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, Rende
params.globalDescriptorSet = data.globalSet;
params.cullingDescriptorSet = data.cullingSet;

params.numCascades = 0;// *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "numShadowCascades"_h);
params.numCascades = 0;
params.occlusionCull = CVAR_JoltDebugOcclusionCullingEnabled.Get();

params.cullingDataIsWorldspace = false;
Expand Down Expand Up @@ -431,7 +431,7 @@ void JoltDebugRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, Rende
params.globalDescriptorSet = data.globalSet;
params.cullingDescriptorSet = data.cullingSet;

params.numCascades = 0;// *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "numShadowCascades"_h);
params.numCascades = 0;
params.occlusionCull = CVAR_JoltDebugOcclusionCullingEnabled.Get();

params.cullingDataIsWorldspace = false;
Expand Down Expand Up @@ -530,7 +530,7 @@ void JoltDebugRenderer::AddGeometryPass(Renderer::RenderGraph* renderGraph, Rend
params.enableDrawing = CVAR_JoltDebugDrawGeometry.Get();
params.cullingEnabled = cullingEnabled;
params.useInstancedCulling = true;
params.numCascades = 0;// *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "numShadowCascades"_h);
params.numCascades = 0;

GeometryPass(params);

Expand Down Expand Up @@ -611,7 +611,7 @@ void JoltDebugRenderer::AddGeometryPass(Renderer::RenderGraph* renderGraph, Rend
params.enableDrawing = CVAR_JoltDebugDrawGeometry.Get();
params.cullingEnabled = cullingEnabled;
params.useInstancedCulling = true;
params.numCascades = 0;// *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "numShadowCascades"_h);
params.numCascades = 0;

GeometryPass(params);

Expand Down
7 changes: 4 additions & 3 deletions Source/Game/Game/Rendering/GameRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ GameRenderer::GameRenderer(InputManager* inputManager)
_canvasRenderer = new CanvasRenderer(_renderer);
_uiRenderer = new UIRenderer(_renderer);
_effectRenderer = new EffectRenderer(_renderer);
//_shadowRenderer = new ShadowRenderer(_renderer, _debugRenderer, _terrainRenderer, _modelRenderer, _resources);
_shadowRenderer = new ShadowRenderer(_renderer, _debugRenderer, _terrainRenderer, _modelRenderer, _resources);
_pixelQuery = new PixelQuery(_renderer);

CreatePermanentResources();
Expand Down Expand Up @@ -196,6 +196,7 @@ void GameRenderer::UpdateRenderers(f32 deltaTime)
_canvasRenderer->Update(deltaTime);
_uiRenderer->Update(deltaTime);
_effectRenderer->Update(deltaTime);
_shadowRenderer->Update(deltaTime, _resources);
}

f32 GameRenderer::Render()
Expand Down Expand Up @@ -296,6 +297,8 @@ f32 GameRenderer::Render()
_skyboxRenderer->AddSkyboxPass(&renderGraph, _resources, _frameIndex);
_modelRenderer->AddSkyboxPass(&renderGraph, _resources, _frameIndex);

_shadowRenderer->AddShadowPass(&renderGraph, _resources, _frameIndex);

// Occluder passes
_terrainRenderer->AddOccluderPass(&renderGraph, _resources, _frameIndex);
_modelRenderer->AddOccluderPass(&renderGraph, _resources, _frameIndex);
Expand Down Expand Up @@ -353,8 +356,6 @@ f32 GameRenderer::Render()
_modelRenderer->AddCullingPass(&renderGraph, _resources, _frameIndex);
_modelRenderer->AddGeometryPass(&renderGraph, _resources, _frameIndex);

//_shadowRenderer->AddShadowPass(&renderGraph, _resources, _frameIndex);

_joltDebugRenderer->AddCullingPass(&renderGraph, _resources, _frameIndex);
_joltDebugRenderer->AddGeometryPass(&renderGraph, _resources, _frameIndex);

Expand Down
Loading

0 comments on commit 349134c

Please sign in to comment.