diff --git a/Source/Game/Game/ECS/Components/Camera.h b/Source/Game/Game/ECS/Components/Camera.h index 74338609..073326f5 100644 --- a/Source/Game/Game/ECS/Components/Camera.h +++ b/Source/Game/Game/ECS/Components/Camera.h @@ -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; diff --git a/Source/Game/Game/ECS/Scheduler.cpp b/Source/Game/Game/ECS/Scheduler.cpp index aee966d0..67eccbf6 100644 --- a/Source/Game/Game/ECS/Scheduler.cpp +++ b/Source/Game/Game/ECS/Scheduler.cpp @@ -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" @@ -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); diff --git a/Source/Game/Game/ECS/Systems/CalculateCameraMatrices.cpp b/Source/Game/Game/ECS/Systems/CalculateCameraMatrices.cpp index 3b36e7da..52ef1998 100644 --- a/Source/Game/Game/ECS/Systems/CalculateCameraMatrices.cpp +++ b/Source/Game/Game/ECS/Systems/CalculateCameraMatrices.cpp @@ -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) @@ -34,6 +36,7 @@ namespace ECS::Systems auto view = registry.view(); 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 diff --git a/Source/Game/Game/ECS/Systems/CalculateShadowCameraMatrices.cpp b/Source/Game/Game/ECS/Systems/CalculateShadowCameraMatrices.cpp index 9768b0fb..3c062716 100644 --- a/Source/Game/Game/ECS/Systems/CalculateShadowCameraMatrices.cpp +++ b/Source/Game/Game/ECS/Systems/CalculateShadowCameraMatrices.cpp @@ -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) @@ -38,32 +40,38 @@ namespace ECS::Systems RenderResources& renderResources = gameRenderer->GetRenderResources(); - u32 numCascades = 0;// CVAR_ShadowCascadeNum.GetU32(); + std::vector& 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(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(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(); @@ -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) @@ -234,7 +241,6 @@ namespace ECS::Systems } // Store split distance and matrix in cascade camera - std::vector gpuCameras = renderResources.cameras.Get(); Camera& cascadeCamera = gpuCameras[i + 1]; // +1 because the first camera is the main camera cascadeCamera.worldToView = viewMatrix; @@ -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; diff --git a/Source/Game/Game/Editor/PerformanceDiagnostics.cpp b/Source/Game/Game/Editor/PerformanceDiagnostics.cpp index 3cc9b347..211d5758 100644 --- a/Source/Game/Game/Editor/PerformanceDiagnostics.cpp +++ b/Source/Game/Game/Editor/PerformanceDiagnostics.cpp @@ -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(); @@ -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 @@ -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; } @@ -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); @@ -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; @@ -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; } @@ -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 diff --git a/Source/Game/Game/Rendering/Debug/JoltDebugRenderer.cpp b/Source/Game/Game/Rendering/Debug/JoltDebugRenderer.cpp index 2a31cbb8..cc139130 100644 --- a/Source/Game/Game/Rendering/Debug/JoltDebugRenderer.cpp +++ b/Source/Game/Game/Rendering/Debug/JoltDebugRenderer.cpp @@ -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; @@ -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; @@ -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); @@ -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); diff --git a/Source/Game/Game/Rendering/GameRenderer.cpp b/Source/Game/Game/Rendering/GameRenderer.cpp index d34a49b0..2c80f119 100644 --- a/Source/Game/Game/Rendering/GameRenderer.cpp +++ b/Source/Game/Game/Rendering/GameRenderer.cpp @@ -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(); @@ -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() @@ -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); @@ -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); diff --git a/Source/Game/Game/Rendering/Material/MaterialRenderer.cpp b/Source/Game/Game/Rendering/Material/MaterialRenderer.cpp index 1aa30628..cdcd71f4 100644 --- a/Source/Game/Game/Rendering/Material/MaterialRenderer.cpp +++ b/Source/Game/Game/Rendering/Material/MaterialRenderer.cpp @@ -122,6 +122,7 @@ void MaterialRenderer::AddMaterialPass(Renderer::RenderGraph* renderGraph, Rende Renderer::ImageResource ambientOcclusion; Renderer::DescriptorSetResource globalSet; + Renderer::DescriptorSetResource shadowSet; Renderer::DescriptorSetResource materialSet; Renderer::DescriptorSetResource terrainSet; Renderer::DescriptorSetResource modelSet; @@ -148,6 +149,7 @@ void MaterialRenderer::AddMaterialPass(Renderer::RenderGraph* renderGraph, Rende Renderer::DescriptorSet& modelDescriptorSet = _modelRenderer->GetMaterialPassDescriptorSet(); data.globalSet = builder.Use(resources.globalDescriptorSet); + data.shadowSet = builder.Use(resources.shadowDescriptorSet); data.materialSet = builder.Use(_materialPassDescriptorSet); data.terrainSet = builder.Use(terrainDescriptorSet); data.modelSet = builder.Use(modelDescriptorSet); @@ -164,7 +166,7 @@ void MaterialRenderer::AddMaterialPass(Renderer::RenderGraph* renderGraph, Rende Renderer::ComputePipelineDesc pipelineDesc; graphResources.InitializePipelineDesc(pipelineDesc); - const i32 shadowFilterMode = 0;// *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "numShadowCascades"_h); + const i32 shadowFilterMode = *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowFilterMode"_h); Renderer::ComputeShaderDesc shaderDesc; shaderDesc.path = "MaterialPass.cs.hlsl"; @@ -189,6 +191,7 @@ void MaterialRenderer::AddMaterialPass(Renderer::RenderGraph* renderGraph, Rende // Bind descriptorset commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::GLOBAL, data.globalSet, frameIndex); + commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::SHADOWS, data.shadowSet, frameIndex); commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::TERRAIN, data.terrainSet, frameIndex); commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::MODEL, data.modelSet, frameIndex); commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::PER_PASS, data.materialSet, frameIndex); @@ -202,7 +205,7 @@ void MaterialRenderer::AddMaterialPass(Renderer::RenderGraph* renderGraph, Rende struct Constants { - uvec4 lightInfo; // x = Directional Light Count, Y = Point Light Count + uvec4 lightInfo; // x = Directional Light Count, Y = Point Light Count, Z = Cascade Count, W = Shadows Enabled vec4 fogColor; vec4 fogSettings; // x = Enabled, y = Begin Fog Blend Dist, z = End Fog Blend Dist, w = UNUSED vec4 mouseWorldPos; @@ -216,7 +219,10 @@ void MaterialRenderer::AddMaterialPass(Renderer::RenderGraph* renderGraph, Rende Constants* constants = graphResources.FrameNew(); - constants->lightInfo = uvec4(static_cast(_directionalLights.Size()), 0, 0, 0); + CVarSystem* cvarSystem = CVarSystem::Get(); + const u32 numCascades = static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum")); + const u32 shadowEnabled = static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowEnabled")); + constants->lightInfo = uvec4(static_cast(_directionalLights.Size()), 0, numCascades, shadowEnabled); constants->fogColor = CVAR_FogColor.Get(); constants->fogSettings.x = CVAR_EnableFog.Get() == ShowFlag::ENABLED; @@ -279,7 +285,7 @@ void MaterialRenderer::CreatePermanentResources() _directionalLights.SetUsage(Renderer::BufferUsage::STORAGE_BUFFER); // Debug directional light - vec3 direction = glm::normalize(vec3(0.0f, -1.0f, -1.0f)); + vec3 direction = glm::normalize(vec3(*CVarSystem::Get()->GetVecFloatCVar(CVarCategory::Client | CVarCategory::Rendering, "directionalLightDirection"_h))); vec3 color = vec3(66.f/255.f, 101.f/255.f, 134.f/255.f); f32 intensity = 1.0f; diff --git a/Source/Game/Game/Rendering/RenderUtils.h b/Source/Game/Game/Rendering/RenderUtils.h index 220a6997..7d7e21fe 100644 --- a/Source/Game/Game/Rendering/RenderUtils.h +++ b/Source/Game/Game/Rendering/RenderUtils.h @@ -110,6 +110,13 @@ class RenderUtils return numBytesNeeded; } + static u32 CalcCullingBitmaskUints(size_t numObjects) + { + u32 numUintsNeeded = static_cast(((numObjects + 31) / 32)); + + return numUintsNeeded; + } + static u32 GetGroupCount(u32 threadCount, u32 localSize) { return (threadCount + localSize - 1) / localSize; diff --git a/Source/Game/Game/Rendering/Shadow/ShadowRenderer.cpp b/Source/Game/Game/Rendering/Shadow/ShadowRenderer.cpp index 6b76baf0..c11caa27 100644 --- a/Source/Game/Game/Rendering/Shadow/ShadowRenderer.cpp +++ b/Source/Game/Game/Rendering/Shadow/ShadowRenderer.cpp @@ -19,13 +19,13 @@ #include #include -AutoCVar_Int CVAR_ShadowsEnabled(CVarCategory::Client | CVarCategory::Rendering, "shadowEnabled", "enable shadows", 0, CVarFlags::EditCheckbox); -AutoCVar_Int CVAR_ShadowsFrozen(CVarCategory::Client | CVarCategory::Rendering, "shadowFreeze", "freeze shadows", 0, CVarFlags::EditCheckbox); +AutoCVar_Int CVAR_ShadowEnabled(CVarCategory::Client | CVarCategory::Rendering, "shadowEnabled", "enable shadows", 0, CVarFlags::EditCheckbox); +AutoCVar_Int CVAR_ShadowFrozen(CVarCategory::Client | CVarCategory::Rendering, "shadowFreeze", "freeze shadows", 0, CVarFlags::EditCheckbox); -AutoCVar_Int CVAR_ShadowCascadeNum(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum", "number of cascades", 0); +AutoCVar_Int CVAR_ShadowDebugMatrices(CVarCategory::Client | CVarCategory::Rendering, "shadowDebugMatrices", "debug shadow matrices by applying them to the camera", 0, CVarFlags::EditCheckbox); +AutoCVar_Int CVAR_ShadowDebugMatrixIndex(CVarCategory::Client | CVarCategory::Rendering, "shadowDebugMatricesIndex", "index of the cascade to debug", 0); -AutoCVar_Int CVAR_ShadowsDebugMatrices(CVarCategory::Client | CVarCategory::Rendering, "shadowDebugMatrices", "debug shadow matrices by applying them to the camera", 0, CVarFlags::EditCheckbox); -AutoCVar_Int CVAR_ShadowsDebugMatrixIndex(CVarCategory::Client | CVarCategory::Rendering, "shadowDebugMatricesIndex", "index of the cascade to debug", 0); +AutoCVar_Int CVAR_ShadowDrawMatrices(CVarCategory::Client | CVarCategory::Rendering, "shadowDrawMatrices", "debug shadow matrices by debug drawing them", 0, CVarFlags::EditCheckbox); AutoCVar_Int CVAR_ShadowFilterMode(CVarCategory::Client | CVarCategory::Rendering, "shadowFilterMode", "0: No filtering, 1: Percentage Closer Filtering, 2: Percentage Closer Soft Shadows", 1); AutoCVar_Float CVAR_ShadowFilterSize(CVarCategory::Client | CVarCategory::Rendering, "shadowFilterSize", "size of the filter used for shadow sampling", 3.0f); @@ -55,78 +55,50 @@ ShadowRenderer::~ShadowRenderer() void ShadowRenderer::Update(f32 deltaTime, RenderResources& resources) { - /*Camera* camera = ServiceLocator::GetCamera(); + CVarSystem* cvarSystem = CVarSystem::Get(); + const u32 numCascades = static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum")); - const u32 numCascades = CVAR_ShadowCascadeNum.Get(); + const bool debugMatrices = CVAR_ShadowDebugMatrices.Get(); + const i32 debugMatrixIndex = CVAR_ShadowDebugMatrixIndex.Get(); + if (debugMatrices && debugMatrixIndex >= 0 && debugMatrixIndex < static_cast(numCascades)) + { + std::vector& gpuCameras = resources.cameras.Get(); + const Camera& debugCascadeCamera = gpuCameras[debugMatrixIndex + 1]; // +1 because the first camera is the main camera - u32 colors[4] = { - 0xff0000ff, // R - 0xff00ff00, // G - 0xffff0000, // B - 0xff00ffff // Yellow - }; + Camera& mainCamera = gpuCameras[0]; - const u32 debugMatrixIndex = CVAR_ShadowsDebugMatrixIndex.Get(); - for (u32 i = 0; i < numCascades; i++) + mainCamera = debugCascadeCamera; + resources.cameras.SetDirtyElement(0); + } + + if (CVAR_ShadowDrawMatrices.Get()) { - //const u32 debugMatrixIndex = i; - - const vec3& near0 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[0]; - const vec3& near1 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[1]; - const vec3& near2 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[2]; - const vec3& near3 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[3]; - - const vec3& far0 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[4]; - const vec3& far1 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[5]; - const vec3& far2 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[6]; - const vec3& far3 = _cascadeDebugInformation[debugMatrixIndex].frustumCorners[7]; - - // Near plane - _debugRenderer->DrawLine3D(near0, near1, colors[i]); - _debugRenderer->DrawLine3D(near1, near2, colors[i]); - _debugRenderer->DrawLine3D(near2, near3, colors[i]); - _debugRenderer->DrawLine3D(near3, near0, colors[i]); - - // Far plane - _debugRenderer->DrawLine3D(far0, far1, colors[i]); - _debugRenderer->DrawLine3D(far1, far2, colors[i]); - _debugRenderer->DrawLine3D(far2, far3, colors[i]); - _debugRenderer->DrawLine3D(far3, far0, colors[i]); - - // Edges - _debugRenderer->DrawLine3D(near0, far0, colors[i]); - _debugRenderer->DrawLine3D(near1, far1, colors[i]); - _debugRenderer->DrawLine3D(near2, far2, colors[i]); - _debugRenderer->DrawLine3D(near3, far3, colors[i]); - - // Draw cascade culling plane normals - f32 scale = 10000.0f;*/ - - /*if (i == debugMatrixIndex) + std::vector& gpuCameras = resources.cameras.Get(); + + Color colors[] = { - vec3 pos = _cascadeDebugInformation[i].frustumPlanePos; - - vec3 left = vec3(_cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Left]) * _cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Left].w * scale; - vec3 right = vec3(_cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Right]) * _cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Right].w * scale; - vec3 bottom = vec3(_cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Bottom]) * _cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Bottom].w * scale; - vec3 top = vec3(_cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Top]) * _cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Top].w * scale; - vec3 near = vec3(_cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Near]) * _cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Near].w * scale; - vec3 far = vec3(_cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Far]) * _cascadeDebugInformation[i].frustumPlanes[(size_t)FrustumPlane::Far].w * scale; - - _debugRenderer->DrawLine3D(pos, pos + left, 0xFF0000FF); - _debugRenderer->DrawLine3D(pos, pos + right, 0xFF000080); - _debugRenderer->DrawLine3D(pos, pos + bottom, 0xFF00FF00); - _debugRenderer->DrawLine3D(pos, pos + top, 0xFF008000); - _debugRenderer->DrawLine3D(pos, pos + near, 0xFFFF0000); - _debugRenderer->DrawLine3D(pos, pos + far, 0xFF800000); + Color::Red, + Color::Green, + Color::Blue, + Color::Yellow, + Color::Magenta, + Color::Cyan, + Color::PastelOrange, + Color::PastelGreen + }; + + for (u32 i = 0; i < numCascades; i++) + { + const Camera& debugCascadeCamera = gpuCameras[i + 1]; // +1 because the first camera is the main camera + _debugRenderer->DrawFrustum(debugCascadeCamera.worldToClip, colors[i]); } - }*/ + } } void ShadowRenderer::AddShadowPass(Renderer::RenderGraph* renderGraph, RenderResources& resources, u8 frameIndex) { - const bool shadowsFrozen = CVAR_ShadowsFrozen.Get(); - if (shadowsFrozen) + const bool shadowFrozen = CVAR_ShadowFrozen.Get(); + if (shadowFrozen) return; struct ShadowPassData @@ -137,169 +109,44 @@ void ShadowRenderer::AddShadowPass(Renderer::RenderGraph* renderGraph, RenderRes }; CVarSystem* cvarSystem = CVarSystem::Get(); - const u32 numCascades = static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum")); + u32 numCascades = static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum")); + numCascades = std::min(numCascades, static_cast(resources.shadowDepthCascades.size())); if (numCascades == 0) return; - const bool shadowsEnabled = CVAR_ShadowsEnabled.Get(); - if (!shadowsEnabled) - { - renderGraph->AddPass("Shadows Pass", - [=](ShadowPassData& data, Renderer::RenderGraphBuilder& builder) - { - for (u32 i = 0; i < numCascades; i++) - { - data.shadowDepthCascades[i] = builder.Write(resources.shadowDepthCascades[i], Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::CLEAR); - } - - return true; // Return true from setup to enable this pass, return false to disable it - }, - [=](ShadowPassData& data, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList) - { - // This is literally just here to clear the shadowDepth... - }); + const bool shadowEnabled = CVAR_ShadowEnabled.Get(); - return; - } - - const bool debugMatrices = CVAR_ShadowsDebugMatrices.Get(); - if (debugMatrices) - { - const u32 debugMatrixIndex = CVAR_ShadowsDebugMatrixIndex.Get(); - - //const ViewData& shadowCascadeViewData = _shadowCascadeViewDatas[frameIndex].ReadGet(debugMatrixIndex); - - //resources.viewConstantBuffer->resource = shadowCascadeViewData; - //resources.viewConstantBuffer->Apply(frameIndex); - } - - const bool terrainCastShadows = CVAR_TerrainCastShadow.Get(); - const bool modelsCastShadows = CVAR_ModelsCastShadow.Get(); - - renderGraph->AddPass("Shadows Pass", - [this, &resources, numCascades](ShadowPassData& data, Renderer::RenderGraphBuilder& builder) + renderGraph->AddPass("Shadow Pass", + [=, &resources](ShadowPassData& data, Renderer::RenderGraphBuilder& builder) { -#if TIMESLICED_CASCADES - data.shadowDepthCascades[_currentCascade] = builder.Write(resources.shadowDepthCascades[_currentCascade], Renderer::PipelineType::GRAPHICS, Renderer::RenderGraphBuilder::LoadMode::CLEAR); -#else for (u32 i = 0; i < numCascades; i++) { data.shadowDepthCascades[i] = builder.Write(resources.shadowDepthCascades[i], Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::CLEAR); } -#endif + data.shadowDescriptorSet = builder.Use(resources.shadowDescriptorSet); return true; // Return true from setup to enable this pass, return false to disable it }, [=](ShadowPassData& data, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList) { - commandList.PushMarker("Init", Color::White); - - Renderer::DepthImageMutableResource cascadeDepthResource; - for (u32 i = 0; i < Renderer::Settings::MAX_SHADOW_CASCADES; i++) - { - if (i < numCascades) - { - cascadeDepthResource = data.shadowDepthCascades[i]; - } - - data.shadowDescriptorSet.BindArray("_shadowCascadeRTs", cascadeDepthResource, i); - } - - uvec2 shadowDepthDimensions = _renderer->GetImageDimensions(resources.shadowDepthCascades[0]); - f32 biasConstantFactor = CVAR_ShadowDepthBiasConstantFactor.GetFloat(); f32 biasClamp = CVAR_ShadowDepthBiasClamp.GetFloat(); f32 biasSlopeFactor = CVAR_ShadowDepthBiasSlopeFactor.GetFloat(); - commandList.SetViewport(0, 0, static_cast(shadowDepthDimensions.x), static_cast(shadowDepthDimensions.y), 0.0f, 1.0f); - commandList.SetScissorRect(0, shadowDepthDimensions.x, 0, shadowDepthDimensions.y); commandList.SetDepthBias(biasConstantFactor, biasClamp, biasSlopeFactor); - commandList.PopMarker(); - - if (terrainCastShadows) - { - /*const u32 numDrawCalls = _terrainRenderer->GetNumDrawCalls(); - commandList.PushMarker("Terrain Draw " + std::to_string(numDrawCalls), Color::White); - - const bool cullingEnabled = *CVarSystem::Get()->GetIntCVar("terrain.culling.Enable") == 1; - - TerrainRenderer::DrawParams drawParams; - drawParams.shadowPass = true; - drawParams.cullingEnabled = cullingEnabled; - drawParams.argumentBuffer = _terrainRenderer->_argumentBuffer; - -#if TIMESLICED_CASCADES - commandList.PushMarker("Cascade " + std::to_string(_currentCascade), Color::White); - drawParams.depth = data.shadowDepthCascades[_currentCascade]; - drawParams.shadowCascade = _currentCascade; - - _terrainRenderer->Draw(resources, frameIndex, graphResources, commandList, drawParams); - commandList.PopMarker(); -#else - for (u32 i = 0; i < numCascades; i++) - { - commandList.PushMarker("Cascade " + std::to_string(i), Color::White); - drawParams.instanceBuffer = cullingEnabled ? _terrainRenderer->_culledInstanceBuffer[i + 1] : _terrainRenderer->_instances.GetBuffer(); - drawParams.depth = data.shadowDepthCascades[i]; - drawParams.shadowCascade = i; - drawParams.argumentsIndex = i + 1; - - _terrainRenderer->Draw(resources, frameIndex, graphResources, commandList, drawParams); - commandList.PopMarker(); - } -#endif - - commandList.PopMarker();*/ - } - - if (modelsCastShadows) + Renderer::DepthImageMutableResource cascadeDepthResource; + for (u32 i = 0; i < Renderer::Settings::MAX_SHADOW_CASCADES; i++) { - /*const u32 numDrawCalls = _mapObjectRenderer->GetNumDrawCalls(); - commandList.PushMarker("MapObject Draw " + std::to_string(numDrawCalls), Color::White); - - const bool cullingEnabled = *CVarSystem::Get()->GetIntCVar("mapObjects.cullEnable") == 1; - const bool deterministicOrder = *CVarSystem::Get()->GetIntCVar("mapObjects.deterministicOrder") == 1; - - MapObjectRenderer::DrawParams drawParams; - drawParams.shadowPass = true; - drawParams.drawCountBuffer = _mapObjectRenderer->_drawCountBuffer; - drawParams.numMaxDrawCalls = numDrawCalls; - -#if TIMESLICED_CASCADES - commandList.PushMarker("Cascade " + std::to_string(_currentCascade), Color::White); - drawParams.depth = data.shadowDepthCascades[_currentCascade]; - drawParams.shadowCascade = _currentCascade; - - _mapObjectRenderer->Draw(resources, frameIndex, graphResources, commandList, drawParams); - commandList.PopMarker(); -#else - for (u32 i = 0; i < numCascades; i++) + if (i < numCascades) { - commandList.PushMarker("Cascade " + std::to_string(i), Color::White); - - drawParams.depth = data.shadowDepthCascades[i]; - drawParams.argumentBuffer = (cullingEnabled) ? _mapObjectRenderer->_culledDrawCallBuffer[i + 1] : _mapObjectRenderer->_drawCalls.GetBuffer(); - drawParams.shadowCascade = i; - drawParams.drawCountIndex = i + 1; - - _mapObjectRenderer->Draw(resources, frameIndex, graphResources, commandList, drawParams); - commandList.PopMarker(); + cascadeDepthResource = data.shadowDepthCascades[i]; } -#endif - commandList.PopMarker();*/ + data.shadowDescriptorSet.BindArray("_shadowCascadeRTs", cascadeDepthResource, i); } - - // Finish by resetting the viewport, scissor and depth bias - vec2 renderSize = _renderer->GetRenderSize(); - commandList.SetViewport(0, 0, renderSize.x, renderSize.y, 0.0f, 1.0f); - commandList.SetScissorRect(0, static_cast(renderSize.x), 0, static_cast(renderSize.y)); - commandList.SetDepthBias(0, 0, 0); - - _currentCascade = (_currentCascade + 1) % numCascades; }); } diff --git a/Source/Game/Game/Rendering/Terrain/TerrainRenderer.cpp b/Source/Game/Game/Rendering/Terrain/TerrainRenderer.cpp index ed22b827..9cf072b0 100644 --- a/Source/Game/Game/Rendering/Terrain/TerrainRenderer.cpp +++ b/Source/Game/Game/Rendering/Terrain/TerrainRenderer.cpp @@ -80,7 +80,10 @@ void TerrainRenderer::Update(f32 deltaTime) u32* count = static_cast(_renderer->MapBuffer(_occluderDrawCountReadBackBuffer)); if (count != nullptr) { - _numOccluderDrawCalls = *count; + for (u32 i = 0; i < Renderer::Settings::MAX_VIEWS; i++) + { + _numOccluderDrawCalls[i] = count[i]; + } } _renderer->UnmapBuffer(_occluderDrawCountReadBackBuffer); } @@ -114,132 +117,138 @@ void TerrainRenderer::AddOccluderPass(Renderer::RenderGraph* renderGraph, Render const bool forceDisableOccluders = CVAR_ForceDisableOccluders.Get(); + CVarSystem* cvarSystem = CVarSystem::Get(); + const u32 numCascades = static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum")); + struct Data { Renderer::ImageMutableResource visibilityBuffer; - Renderer::DepthImageMutableResource depth; + Renderer::DepthImageMutableResource depth[Renderer::Settings::MAX_VIEWS]; Renderer::BufferMutableResource culledInstanceBuffer; Renderer::BufferMutableResource culledInstanceBitMaskBuffer; + Renderer::BufferMutableResource prevCulledInstanceBitMaskBuffer; Renderer::BufferMutableResource argumentBuffer; Renderer::BufferMutableResource occluderDrawCountReadBackBuffer; Renderer::DescriptorSetResource globalSet; - Renderer::DescriptorSetResource occluderFillSet; + Renderer::DescriptorSetResource fillSet; Renderer::DescriptorSetResource drawSet; }; renderGraph->AddPass("Terrain Occluders", - [this, &resources, frameIndex](Data& data, Renderer::RenderGraphBuilder& builder) // Setup + [this, &resources, frameIndex, numCascades](Data& data, Renderer::RenderGraphBuilder& builder) // Setup { using BufferUsage = Renderer::BufferPassUsage; data.visibilityBuffer = builder.Write(resources.visibilityBuffer, Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); - data.depth = builder.Write(resources.depth, Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); + data.depth[0] = builder.Write(resources.depth, Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); + for (u32 i = 1; i < numCascades + 1; i++) + { + data.depth[i] = builder.Write(resources.shadowDepthCascades[i-1], Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); + } builder.Read(_instanceDatas.GetBuffer(), BufferUsage::COMPUTE | BufferUsage::GRAPHICS); builder.Read(_vertices.GetBuffer(), BufferUsage::GRAPHICS); builder.Read(_cellDatas.GetBuffer(), BufferUsage::GRAPHICS); builder.Read(resources.cameras.GetBuffer(), BufferUsage::GRAPHICS); - data.culledInstanceBuffer = builder.Write(_culledInstanceBuffer[0], BufferUsage::TRANSFER | BufferUsage::COMPUTE | BufferUsage::GRAPHICS); + data.culledInstanceBuffer = builder.Write(_culledInstanceBuffer, BufferUsage::TRANSFER | BufferUsage::COMPUTE | BufferUsage::GRAPHICS); data.culledInstanceBitMaskBuffer = builder.Write(_culledInstanceBitMaskBuffer.Get(!frameIndex), BufferUsage::COMPUTE | BufferUsage::TRANSFER); + data.prevCulledInstanceBitMaskBuffer = builder.Write(_culledInstanceBitMaskBuffer.Get(frameIndex), BufferUsage::COMPUTE | BufferUsage::TRANSFER); data.argumentBuffer = builder.Write(_argumentBuffer, BufferUsage::TRANSFER | BufferUsage::GRAPHICS | BufferUsage::COMPUTE); data.occluderDrawCountReadBackBuffer = builder.Write(_occluderDrawCountReadBackBuffer, BufferUsage::TRANSFER); data.globalSet = builder.Use(resources.globalDescriptorSet); - data.occluderFillSet = builder.Use(_occluderFillPassDescriptorSet); + data.fillSet = builder.Use(_fillPassDescriptorSet); data.drawSet = builder.Use(_geometryPassDescriptorSet); return true; // Return true from setup to enable this pass, return false to disable it }, - [this, &resources, frameIndex, forceDisableOccluders, cullingEnabled](Data& data, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList) // Execute + [this, &resources, frameIndex, numCascades, forceDisableOccluders, cullingEnabled](Data& data, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList) // Execute { GPU_SCOPED_PROFILER_ZONE(commandList, TerrainOccluders); - // Reset the counters - for (u32 i = 0; i < Renderer::Settings::MAX_VIEWS; i++) - { - u32 argumentOffset = i * sizeof(Renderer::IndexedIndirectDraw); - commandList.FillBuffer(data.argumentBuffer, argumentOffset + 4, 16, 0); // Reset everything but indexCount to 0 - } - - commandList.BufferBarrier(data.argumentBuffer, Renderer::BufferPassUsage::TRANSFER); - + // Handle disabled occluders u32 cellCount = static_cast(_instanceDatas.Size()); if (forceDisableOccluders) { - commandList.FillBuffer(data.culledInstanceBitMaskBuffer, 0, RenderUtils::CalcCullingBitmaskSize(cellCount), 0); + u32 bitmaskSizePerView = RenderUtils::CalcCullingBitmaskSize(cellCount); + commandList.FillBuffer(data.culledInstanceBitMaskBuffer, 0, bitmaskSizePerView * Renderer::Settings::MAX_VIEWS, 0); commandList.BufferBarrier(data.culledInstanceBitMaskBuffer, Renderer::BufferPassUsage::TRANSFER); } - // Fill the occluders to draw + for (u32 i = 0; i < numCascades + 1; i++) { - commandList.PushMarker("Occlusion Fill", Color::White); + std::string markerName = (i == 0) ? "Main" : "Cascade " + std::to_string(i - 1); + commandList.PushMarker(markerName, Color::White); - Renderer::ComputePipelineDesc pipelineDesc; - pipelineDesc.debugName = "Terrain Occlusion Fill"; - graphResources.InitializePipelineDesc(pipelineDesc); - - Renderer::ComputeShaderDesc shaderDesc; - shaderDesc.path = "Terrain/FillDrawCalls.cs.hlsl"; - pipelineDesc.computeShader = _renderer->LoadShader(shaderDesc); - - Renderer::ComputePipelineID pipeline = _renderer->CreatePipeline(pipelineDesc); - commandList.BeginPipeline(pipeline); - - struct FillDrawCallConstants + // Reset the counters { - u32 numTotalInstances; - }; - - FillDrawCallConstants* fillConstants = graphResources.FrameNew(); - fillConstants->numTotalInstances = cellCount; - commandList.PushConstant(fillConstants, 0, sizeof(FillDrawCallConstants)); + commandList.BufferBarrier(data.argumentBuffer, Renderer::BufferPassUsage::TRANSFER); + commandList.FillBuffer(data.argumentBuffer, 4, 16, 0); // Reset everything but indexCount to 0 + commandList.BufferBarrier(data.argumentBuffer, Renderer::BufferPassUsage::TRANSFER); + } - data.occluderFillSet.Bind("_culledInstancesBitMask"_h, data.culledInstanceBitMaskBuffer); + // Fill the occluders to draw + FillDrawCallsParams fillParams; + fillParams.passName = "Occluders"; + fillParams.cellCount = cellCount; + fillParams.viewIndex = i; + fillParams.diffAgainstPrev = false; + fillParams.culledInstanceBitMaskBuffer = data.culledInstanceBitMaskBuffer; + fillParams.prevCulledInstanceBitMaskBuffer = data.prevCulledInstanceBitMaskBuffer; + fillParams.fillSet = data.fillSet; + + FillDrawCalls(frameIndex, graphResources, commandList, fillParams); + commandList.BufferBarrier(data.culledInstanceBuffer, Renderer::BufferPassUsage::COMPUTE); + commandList.BufferBarrier(data.culledInstanceBuffer, Renderer::BufferPassUsage::GRAPHICS); + + // Draw the occluders + if (CVAR_TerrainOccludersEnabled.Get()) + { + commandList.PushMarker("Occlusion Draw", Color::White); - // Bind descriptorset - //commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::DEBUG, &resources.debugDescriptorSet, frameIndex); - //commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::GLOBAL, &resources.globalDescriptorSet, frameIndex); - //commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::SHADOWS, &resources.shadowDescriptorSet, frameIndex); - commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::PER_PASS, data.occluderFillSet, frameIndex); + if (i == 1) + { + uvec2 shadowDepthDimensions = _renderer->GetImageDimensions(resources.shadowDepthCascades[0]); - commandList.Dispatch((cellCount + 31) / 32, 1, 1); + commandList.SetViewport(0, 0, static_cast(shadowDepthDimensions.x), static_cast(shadowDepthDimensions.y), 0.0f, 1.0f); + commandList.SetScissorRect(0, shadowDepthDimensions.x, 0, shadowDepthDimensions.y); + } - commandList.EndPipeline(pipeline); - commandList.PopMarker(); - } - commandList.BufferBarrier(data.culledInstanceBuffer, Renderer::BufferPassUsage::COMPUTE); + DrawParams drawParams; + drawParams.shadowPass = i != 0; + drawParams.viewIndex = i; + drawParams.cullingEnabled = cullingEnabled; + drawParams.visibilityBuffer = data.visibilityBuffer; + drawParams.depth = data.depth[i]; + drawParams.instanceBuffer = ToBufferResource(data.culledInstanceBuffer); + drawParams.argumentBuffer = ToBufferResource(data.argumentBuffer); - // Draw the occluders - if (CVAR_TerrainOccludersEnabled.Get()) - { - commandList.PushMarker("Occlusion Draw", Color::White); + drawParams.globalDescriptorSet = data.globalSet; + drawParams.drawDescriptorSet = data.drawSet; - DrawParams drawParams; - drawParams.shadowPass = false; - drawParams.cullingEnabled = cullingEnabled; - drawParams.visibilityBuffer = data.visibilityBuffer; - drawParams.depth = data.depth; - drawParams.instanceBuffer = ToBufferResource(data.culledInstanceBuffer); - drawParams.argumentBuffer = ToBufferResource(data.argumentBuffer); + Draw(resources, frameIndex, graphResources, commandList, drawParams); - drawParams.globalDescriptorSet = data.globalSet; - drawParams.drawDescriptorSet = data.drawSet; + commandList.PopMarker(); + } - Draw(resources, frameIndex, graphResources, commandList, drawParams); + // Copy drawn count + { + u32 dstOffset = i * sizeof(u32); + commandList.CopyBuffer(data.occluderDrawCountReadBackBuffer, dstOffset, data.argumentBuffer, 4, 4); + } commandList.PopMarker(); } - for (u32 i = 0; i < Renderer::Settings::MAX_VIEWS; i++) - { - u32 dstOffset = i * sizeof(u32); - u32 argumentOffset = i * sizeof(Renderer::IndexedIndirectDraw); - commandList.CopyBuffer(data.occluderDrawCountReadBackBuffer, dstOffset, data.argumentBuffer, argumentOffset + 4, 4); - } + // Finish by resetting the viewport, scissor and depth bias + vec2 renderSize = _renderer->GetRenderSize(); + commandList.SetViewport(0, 0, renderSize.x, renderSize.y, 0.0f, 1.0f); + commandList.SetScissorRect(0, static_cast(renderSize.x), 0, static_cast(renderSize.y)); + commandList.SetDepthBias(0, 0, 0); }); } @@ -256,7 +265,7 @@ void TerrainRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, RenderR if (_instanceDatas.Size() == 0) return; - u32 numCascades = 0; // *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum"_h); + u32 numCascades = *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum"_h); struct Data { @@ -286,7 +295,7 @@ void TerrainRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, RenderR data.argumentBuffer = builder.Write(_argumentBuffer, BufferUsage::COMPUTE); data.currentInstanceBitMaskBuffer = builder.Write(_culledInstanceBitMaskBuffer.Get(frameIndex), BufferUsage::TRANSFER | BufferUsage::COMPUTE); - builder.Write(_culledInstanceBuffer[0], BufferUsage::COMPUTE); + builder.Write(_culledInstanceBuffer, BufferUsage::COMPUTE); data.debugSet = builder.Use(_debugRenderer->GetDebugDescriptorSet()); data.globalSet = builder.Use(resources.globalDescriptorSet); @@ -317,11 +326,11 @@ void TerrainRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, RenderR struct ResetIndirectBufferConstants { - bool moveCountToFirst; + u32 moveCountToFirst; }; ResetIndirectBufferConstants* resetConstants = graphResources.FrameNew(); - resetConstants->moveCountToFirst = true; // This lets us continue building the instance buffer with + resetConstants->moveCountToFirst = 0; // This lets us continue building the instance buffer with commandList.PushConstant(resetConstants, 0, 4); // Bind descriptorset @@ -335,9 +344,7 @@ void TerrainRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, RenderR } // Reset the bitmask - const u32 cellCount = static_cast(_cellDatas.Size()); - u32 bitmaskSize = RenderUtils::CalcCullingBitmaskSize(cellCount); - commandList.FillBuffer(data.currentInstanceBitMaskBuffer, 0, bitmaskSize, 0); + commandList.FillBuffer(data.currentInstanceBitMaskBuffer, 0, _culledInstanceBitMaskBufferSizePerView * Renderer::Settings::MAX_VIEWS, 0); commandList.BufferBarrier(data.currentInstanceBitMaskBuffer, Renderer::BufferPassUsage::TRANSFER); commandList.BufferBarrier(data.argumentBuffer, Renderer::BufferPassUsage::COMPUTE); @@ -360,6 +367,7 @@ void TerrainRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, RenderR u32 viewportSizeY; u32 numCascades; u32 occlusionEnabled; + u32 bitMaskBufferSizePerView; }; vec2 viewportSize = _renderer->GetRenderSize(); @@ -369,6 +377,8 @@ void TerrainRenderer::AddCullingPass(Renderer::RenderGraph* renderGraph, RenderR cullConstants->viewportSizeY = u32(viewportSize.y); cullConstants->numCascades = numCascades; cullConstants->occlusionEnabled = CVAR_OcclusionCullingEnabled.Get(); + const u32 cellCount = static_cast(_cellDatas.Size()); + cullConstants->bitMaskBufferSizePerView = RenderUtils::CalcCullingBitmaskUints(cellCount); commandList.PushConstant(cullConstants, 0, sizeof(CullConstants)); @@ -400,76 +410,131 @@ void TerrainRenderer::AddGeometryPass(Renderer::RenderGraph* renderGraph, Render const bool cullingEnabled = CVAR_TerrainCullingEnabled.Get(); - // TODO: Fix - const Renderer::BufferID instanceBuffer = cullingEnabled ? _culledInstanceBuffer[0] : _instanceDatas.GetBuffer(); - _materialPassDescriptorSet.Bind("_instanceDatas"_h, instanceBuffer); + CVarSystem* cvarSystem = CVarSystem::Get(); + const u32 numCascades = 0;//static_cast(*cvarSystem->GetIntCVar(CVarCategory::Client | CVarCategory::Rendering, "shadowCascadeNum")); // Reenable this to have shadows draw in geometry pass struct Data { Renderer::ImageMutableResource visibilityBuffer; - Renderer::DepthImageMutableResource depth; + Renderer::DepthImageMutableResource depth[Renderer::Settings::MAX_VIEWS]; - Renderer::BufferResource culledInstanceBuffer; + Renderer::BufferMutableResource culledInstanceBitMaskBuffer; + Renderer::BufferMutableResource prevCulledInstanceBitMaskBuffer; + Renderer::BufferMutableResource culledInstanceBuffer; Renderer::BufferMutableResource argumentBuffer; Renderer::BufferMutableResource drawCountReadBackBuffer; Renderer::BufferMutableResource occluderDrawCountReadBackBuffer; Renderer::DescriptorSetResource globalSet; + Renderer::DescriptorSetResource fillSet; Renderer::DescriptorSetResource geometryPassSet; }; renderGraph->AddPass("TerrainGeometry", - [this, &resources, cullingEnabled](Data& data, Renderer::RenderGraphBuilder& builder) + [this, &resources, frameIndex, cullingEnabled, numCascades](Data& data, Renderer::RenderGraphBuilder& builder) { using BufferUsage = Renderer::BufferPassUsage; data.visibilityBuffer = builder.Write(resources.visibilityBuffer, Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); - data.depth = builder.Write(resources.depth, Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); + data.depth[0] = builder.Write(resources.depth, Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); + for (u32 i = 1; i < numCascades + 1; i++) + { + data.depth[i] = builder.Write(resources.shadowDepthCascades[i - 1], Renderer::PipelineType::GRAPHICS, Renderer::LoadMode::LOAD); + } - data.culledInstanceBuffer = builder.Read(cullingEnabled ? _culledInstanceBuffer[0] : _instanceDatas.GetBuffer(), BufferUsage::GRAPHICS); + data.culledInstanceBitMaskBuffer = builder.Write(_culledInstanceBitMaskBuffer.Get(frameIndex), BufferUsage::COMPUTE | BufferUsage::TRANSFER); + data.prevCulledInstanceBitMaskBuffer = builder.Write(_culledInstanceBitMaskBuffer.Get(!frameIndex), BufferUsage::COMPUTE | BufferUsage::TRANSFER); + data.culledInstanceBuffer = builder.Write(cullingEnabled ? _culledInstanceBuffer : _instanceDatas.GetBuffer(), BufferUsage::GRAPHICS | BufferUsage::COMPUTE); builder.Read(resources.cameras.GetBuffer(), BufferUsage::GRAPHICS); builder.Read(_vertices.GetBuffer(), BufferUsage::GRAPHICS); builder.Read(_cellDatas.GetBuffer(), BufferUsage::GRAPHICS); + builder.Read(_instanceDatas.GetBuffer(), BufferUsage::COMPUTE); - data.argumentBuffer = builder.Write(_argumentBuffer, BufferUsage::TRANSFER | BufferUsage::GRAPHICS); + data.argumentBuffer = builder.Write(_argumentBuffer, BufferUsage::TRANSFER | BufferUsage::GRAPHICS | BufferUsage::COMPUTE); data.drawCountReadBackBuffer = builder.Write(_drawCountReadBackBuffer, BufferUsage::TRANSFER); - data.occluderDrawCountReadBackBuffer = builder.Write(_occluderDrawCountReadBackBuffer, BufferUsage::TRANSFER); + data.occluderDrawCountReadBackBuffer = builder.Write(_occluderDrawCountReadBackBuffer, BufferUsage::TRANSFER); data.globalSet = builder.Use(resources.globalDescriptorSet); + data.fillSet = builder.Use(_fillPassDescriptorSet); data.geometryPassSet = builder.Use(_geometryPassDescriptorSet); return true; // Return true from setup to enable this pass, return false to disable it }, - [this, &resources, frameIndex, cullingEnabled](Data& data, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList) + [this, &resources, frameIndex, cullingEnabled, numCascades](Data& data, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList) { GPU_SCOPED_PROFILER_ZONE(commandList, TerrainGeometryPass); - - if (CVAR_TerrainGeometryEnabled.Get()) + for (u32 i = 0; i < numCascades + 1; i++) { - DrawParams drawParams; - drawParams.shadowPass = false; - drawParams.cullingEnabled = cullingEnabled; - drawParams.visibilityBuffer = data.visibilityBuffer; - drawParams.depth = data.depth; - drawParams.instanceBuffer = data.culledInstanceBuffer; - drawParams.argumentBuffer = ToBufferResource(data.argumentBuffer); - - drawParams.globalDescriptorSet = data.globalSet; - drawParams.drawDescriptorSet = data.geometryPassSet; - - Draw(resources, frameIndex, graphResources, commandList, drawParams); - } + std::string markerName = (i == 0) ? "Main" : "Cascade " + std::to_string(i - 1); + commandList.PushMarker(markerName, Color::White); - if (cullingEnabled) - { - for (u32 i = 0; i < Renderer::Settings::MAX_VIEWS; i++) + // Reset the counters + { + commandList.BufferBarrier(data.argumentBuffer, Renderer::BufferPassUsage::TRANSFER); + commandList.FillBuffer(data.argumentBuffer, 4, 16, 0); // Reset everything but indexCount to 0 + commandList.BufferBarrier(data.argumentBuffer, Renderer::BufferPassUsage::TRANSFER); + } + + if (CVAR_TerrainGeometryEnabled.Get()) + { + const u32 cellCount = static_cast(_cellDatas.Size()); + + // Fill the occluders to draw + FillDrawCallsParams fillParams; + fillParams.passName = "Geometry"; + fillParams.cellCount = cellCount; + fillParams.viewIndex = i; + fillParams.diffAgainstPrev = true; + fillParams.culledInstanceBitMaskBuffer = data.culledInstanceBitMaskBuffer; + fillParams.prevCulledInstanceBitMaskBuffer = data.prevCulledInstanceBitMaskBuffer; + fillParams.fillSet = data.fillSet; + + FillDrawCalls(frameIndex, graphResources, commandList, fillParams); + commandList.BufferBarrier(data.culledInstanceBuffer, Renderer::BufferPassUsage::COMPUTE); + commandList.BufferBarrier(data.culledInstanceBuffer, Renderer::BufferPassUsage::GRAPHICS); + + if (i == 1) + { + uvec2 shadowDepthDimensions = _renderer->GetImageDimensions(resources.shadowDepthCascades[0]); + + commandList.SetViewport(0, 0, static_cast(shadowDepthDimensions.x), static_cast(shadowDepthDimensions.y), 0.0f, 1.0f); + commandList.SetScissorRect(0, shadowDepthDimensions.x, 0, shadowDepthDimensions.y); + } + + commandList.PushMarker("Draw", Color::White); + + DrawParams drawParams; + drawParams.shadowPass = i != 0; + drawParams.viewIndex = i; + drawParams.cullingEnabled = cullingEnabled; + drawParams.visibilityBuffer = data.visibilityBuffer; + drawParams.depth = data.depth[i]; + drawParams.instanceBuffer = ToBufferResource(data.culledInstanceBuffer); + drawParams.argumentBuffer = ToBufferResource(data.argumentBuffer); + + drawParams.globalDescriptorSet = data.globalSet; + drawParams.drawDescriptorSet = data.geometryPassSet; + + Draw(resources, frameIndex, graphResources, commandList, drawParams); + + commandList.PopMarker(); + } + + if (cullingEnabled) { u32 dstOffset = i * sizeof(u32); - u32 argumentOffset = i * sizeof(Renderer::IndexedIndirectDraw); - commandList.CopyBuffer(data.drawCountReadBackBuffer, dstOffset, data.argumentBuffer, argumentOffset + 4, 4); + commandList.CopyBuffer(data.drawCountReadBackBuffer, dstOffset, data.argumentBuffer, 4, 4); } + + commandList.PopMarker(); } + + // Finish by resetting the viewport, scissor and depth bias + vec2 renderSize = _renderer->GetRenderSize(); + commandList.SetViewport(0, 0, renderSize.x, renderSize.y, 0.0f, 1.0f); + commandList.SetScissorRect(0, static_cast(renderSize.x), 0, static_cast(renderSize.y)); + commandList.SetDepthBias(0, 0, 0); }); } @@ -660,7 +725,7 @@ void TerrainRenderer::RegisterMaterialPassBufferUsage(Renderer::RenderGraphBuild builder.Read(_instanceDatas.GetBuffer(), BufferUsage::COMPUTE); builder.Read(_cellDatas.GetBuffer(), BufferUsage::COMPUTE); builder.Read(_chunkDatas.GetBuffer(), BufferUsage::COMPUTE); - builder.Read(_culledInstanceBuffer[0], BufferUsage::COMPUTE); + builder.Read(_culledInstanceBuffer, BufferUsage::COMPUTE); } void TerrainRenderer::CreatePermanentResources() @@ -740,19 +805,15 @@ void TerrainRenderer::CreatePermanentResources() { Renderer::BufferDesc desc; desc.name = "TerrainArgumentBuffer"; - desc.size = sizeof(Renderer::IndexedIndirectDraw) * Renderer::Settings::MAX_VIEWS; + desc.size = sizeof(Renderer::IndexedIndirectDraw); desc.usage = Renderer::BufferUsage::STORAGE_BUFFER | Renderer::BufferUsage::INDIRECT_ARGUMENT_BUFFER | Renderer::BufferUsage::TRANSFER_DESTINATION | Renderer::BufferUsage::TRANSFER_SOURCE; _argumentBuffer = _renderer->CreateBuffer(_argumentBuffer, desc); auto uploadBuffer = _renderer->CreateUploadBuffer(_argumentBuffer, 0, desc.size); memset(uploadBuffer->mappedMemory, 0, desc.size); - for (u32 i = 0; i < Renderer::Settings::MAX_VIEWS; i++) - { - u32 argumentOffset = i * (sizeof(Renderer::IndexedIndirectDraw) / sizeof(u32)); - static_cast(uploadBuffer->mappedMemory)[argumentOffset] = Terrain::CELL_NUM_INDICES; - } + static_cast(uploadBuffer->mappedMemory)[0] = Terrain::CELL_NUM_INDICES; - _occluderFillPassDescriptorSet.Bind("_drawCount"_h, _argumentBuffer); + _fillPassDescriptorSet.Bind("_drawCount"_h, _argumentBuffer); _cullingPassDescriptorSet.Bind("_arguments"_h, _argumentBuffer); desc.size = sizeof(u32) * Renderer::Settings::MAX_VIEWS; @@ -833,24 +894,18 @@ void TerrainRenderer::SyncToGPU() { _geometryPassDescriptorSet.Bind("_instanceDatas", _instanceDatas.GetBuffer()); _materialPassDescriptorSet.Bind("_instanceDatas", _instanceDatas.GetBuffer()); - _occluderFillPassDescriptorSet.Bind("_instances"_h, _instanceDatas.GetBuffer()); + _fillPassDescriptorSet.Bind("_instances"_h, _instanceDatas.GetBuffer()); _cullingPassDescriptorSet.Bind("_instances"_h, _instanceDatas.GetBuffer()); { Renderer::BufferDesc desc; desc.size = sizeof(InstanceData) * static_cast(_instanceDatas.Size()); desc.usage = Renderer::BufferUsage::STORAGE_BUFFER | Renderer::BufferUsage::VERTEX_BUFFER | Renderer::BufferUsage::TRANSFER_DESTINATION; + desc.name = "TerrainCulledInstanceBuffer"; + _culledInstanceBuffer = _renderer->CreateBuffer(_culledInstanceBuffer, desc); - // CulledDrawCallBuffer, one for each view - for (u32 i = 0; i < Renderer::Settings::MAX_VIEWS; i++) - { - desc.name = "TerrainCulledInstanceBuffer" + std::to_string(i); - _culledInstanceBuffer[i] = _renderer->CreateBuffer(_culledInstanceBuffer[i], desc); - - - } - _cullingPassDescriptorSet.Bind("_culledInstances"_h, _culledInstanceBuffer[0]); - _occluderFillPassDescriptorSet.Bind("_culledInstances"_h, _culledInstanceBuffer[0]); + _cullingPassDescriptorSet.Bind("_culledInstances"_h, _culledInstanceBuffer); + _fillPassDescriptorSet.Bind("_culledInstances"_h, _culledInstanceBuffer); } } @@ -862,7 +917,10 @@ void TerrainRenderer::SyncToGPU() { Renderer::BufferDesc desc; desc.name = "TerrainCulledInstanceBitMaskBuffer"; - desc.size = RenderUtils::CalcCullingBitmaskSize(_cellDatas.Size()); + + _culledInstanceBitMaskBufferSizePerView = RenderUtils::CalcCullingBitmaskSize(_cellDatas.Size()); + + desc.size = _culledInstanceBitMaskBufferSizePerView * Renderer::Settings::MAX_VIEWS; desc.usage = Renderer::BufferUsage::STORAGE_BUFFER | Renderer::BufferUsage::TRANSFER_DESTINATION; for (u32 i = 0; i < _culledInstanceBitMaskBuffer.Num; i++) @@ -939,18 +997,14 @@ void TerrainRenderer::Draw(const RenderResources& resources, u8 frameIndex, Rend // Set index buffer commandList.SetIndexBuffer(_cellIndices.GetBuffer(), Renderer::IndexFormat::UInt16); - if (params.shadowPass) + struct PushConstants { - struct PushConstants - { - u32 cascadeIndex; - }; - - PushConstants* constants = graphResources.FrameNew(); + u32 viewIndex; + }; - constants->cascadeIndex = params.shadowCascade; - commandList.PushConstant(constants, 0, sizeof(PushConstants)); - } + PushConstants* constants = graphResources.FrameNew(); + constants->viewIndex = params.viewIndex; + commandList.PushConstant(constants, 0, sizeof(PushConstants)); // Bind descriptors params.drawDescriptorSet.Bind("_instanceDatas"_h, params.instanceBuffer); @@ -962,7 +1016,7 @@ void TerrainRenderer::Draw(const RenderResources& resources, u8 frameIndex, Rend if (params.cullingEnabled) { - commandList.DrawIndexedIndirect(params.argumentBuffer, params.argumentsIndex * sizeof(Renderer::IndexedIndirectDraw), 1); + commandList.DrawIndexedIndirect(params.argumentBuffer, 0, 1); } else { @@ -973,3 +1027,44 @@ void TerrainRenderer::Draw(const RenderResources& resources, u8 frameIndex, Rend commandList.EndPipeline(pipeline); } + +void TerrainRenderer::FillDrawCalls(u8 frameIndex, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList, FillDrawCallsParams& params) +{ + commandList.PushMarker(params.passName + " Fill", Color::White); + + Renderer::ComputePipelineDesc pipelineDesc; + graphResources.InitializePipelineDesc(pipelineDesc); + + Renderer::ComputeShaderDesc shaderDesc; + shaderDesc.path = "Terrain/FillDrawCalls.cs.hlsl"; + pipelineDesc.computeShader = _renderer->LoadShader(shaderDesc); + + Renderer::ComputePipelineID pipeline = _renderer->CreatePipeline(pipelineDesc); + commandList.BeginPipeline(pipeline); + + struct FillDrawCallConstants + { + u32 numTotalInstances; + u32 bitmaskOffset; + u32 diffAgainstPrev; + }; + + FillDrawCallConstants* fillConstants = graphResources.FrameNew(); + fillConstants->numTotalInstances = params.cellCount; + + u32 uintsNeededPerView = (params.cellCount + 31) / 32; + fillConstants->bitmaskOffset = params.viewIndex * uintsNeededPerView; + fillConstants->diffAgainstPrev = params.diffAgainstPrev; + commandList.PushConstant(fillConstants, 0, sizeof(FillDrawCallConstants)); + + params.fillSet.Bind("_culledInstancesBitMask"_h, params.culledInstanceBitMaskBuffer); + params.fillSet.Bind("_prevCulledInstancesBitMask"_h, params.prevCulledInstanceBitMaskBuffer); + + // Bind descriptorset + commandList.BindDescriptorSet(Renderer::DescriptorSetSlot::PER_PASS, params.fillSet, frameIndex); + + commandList.Dispatch((params.cellCount + 31) / 32, 1, 1); + + commandList.EndPipeline(pipeline); + commandList.PopMarker(); +} diff --git a/Source/Game/Game/Rendering/Terrain/TerrainRenderer.h b/Source/Game/Game/Rendering/Terrain/TerrainRenderer.h index e4e3ecb2..7abf17df 100644 --- a/Source/Game/Game/Rendering/Terrain/TerrainRenderer.h +++ b/Source/Game/Game/Rendering/Terrain/TerrainRenderer.h @@ -49,12 +49,12 @@ class TerrainRenderer // Drawcall stats u32 GetNumDrawCalls() { return Terrain::CHUNK_NUM_CELLS * _numChunksLoaded; } - u32 GetNumOccluderDrawCalls() { return _numOccluderDrawCalls; } + u32 GetNumOccluderDrawCalls(u32 viewID) { return _numOccluderDrawCalls[viewID]; } u32 GetNumSurvivingDrawCalls(u32 viewID) { return _numSurvivingDrawCalls[viewID]; } // Triangle stats u32 GetNumTriangles() { return Terrain::CHUNK_NUM_CELLS * _numChunksLoaded * Terrain::CELL_NUM_TRIANGLES; } - u32 GetNumOccluderTriangles() { return _numOccluderDrawCalls * Terrain::CELL_NUM_TRIANGLES; } + u32 GetNumOccluderTriangles(u32 viewID) { return _numOccluderDrawCalls[viewID] * Terrain::CELL_NUM_TRIANGLES; } u32 GetNumSurvivingGeometryTriangles(u32 viewID) { return _numSurvivingDrawCalls[viewID] * Terrain::CELL_NUM_TRIANGLES; } private: @@ -65,7 +65,7 @@ class TerrainRenderer struct DrawParams { bool shadowPass = false; - u32 shadowCascade = 0; + u32 viewIndex = 0; bool cullingEnabled = false; Renderer::ImageMutableResource visibilityBuffer; @@ -81,6 +81,21 @@ class TerrainRenderer }; void Draw(const RenderResources& resources, u8 frameIndex, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList, DrawParams& params); + struct FillDrawCallsParams + { + std::string passName; + + u32 cellCount; + u32 viewIndex; + bool diffAgainstPrev = false; + + Renderer::BufferMutableResource culledInstanceBitMaskBuffer; + Renderer::BufferMutableResource prevCulledInstanceBitMaskBuffer; + + Renderer::DescriptorSetResource fillSet; + }; + void FillDrawCalls(u8 frameIndex, Renderer::RenderGraphResources& graphResources, Renderer::CommandList& commandList, FillDrawCallsParams& params); + private: PRAGMA_NO_PADDING_START struct TerrainVertex @@ -136,7 +151,8 @@ class TerrainRenderer Renderer::BufferID _drawCountReadBackBuffer; FrameResource _culledInstanceBitMaskBuffer; - Renderer::BufferID _culledInstanceBuffer[Renderer::Settings::MAX_VIEWS]; + u32 _culledInstanceBitMaskBufferSizePerView = 0; + Renderer::BufferID _culledInstanceBuffer; Renderer::TextureArrayID _textures; Renderer::TextureArrayID _alphaTextures; @@ -145,7 +161,7 @@ class TerrainRenderer Renderer::SamplerID _alphaSampler; Renderer::SamplerID _occlusionSampler; - Renderer::DescriptorSet _occluderFillPassDescriptorSet; + Renderer::DescriptorSet _fillPassDescriptorSet; Renderer::DescriptorSet _cullingPassDescriptorSet; Renderer::DescriptorSet _geometryPassDescriptorSet; Renderer::DescriptorSet _materialPassDescriptorSet; @@ -155,7 +171,7 @@ class TerrainRenderer std::atomic _numChunksLoaded = 0; - u32 _numOccluderDrawCalls = 0; + u32 _numOccluderDrawCalls[Renderer::Settings::MAX_VIEWS] = { 0 }; u32 _numSurvivingDrawCalls[Renderer::Settings::MAX_VIEWS] = { 0 }; std::shared_mutex _packedChunkCellIDToGlobalCellIDMutex; diff --git a/Source/Shaders/Shaders/Include/Lighting.inc.hlsl b/Source/Shaders/Shaders/Include/Lighting.inc.hlsl index c29c11ce..1f2588a6 100644 --- a/Source/Shaders/Shaders/Include/Lighting.inc.hlsl +++ b/Source/Shaders/Shaders/Include/Lighting.inc.hlsl @@ -1,6 +1,9 @@ #ifndef LIGHTING_INCLUDED #define LIGHTING_INCLUDED +#include "Include/Shadows.inc.hlsl" +#include "Include/VisibilityBuffers.inc.hlsl" + struct DirectionalLight { float4 direction; @@ -21,14 +24,15 @@ DirectionalLight LoadDirectionalLight(uint index) return light; } -float3 ApplyLighting(float3 materialColor, float3 normal, float2 uv, float2 pixelPos, uint4 lightInfo) +float3 ApplyLighting(float2 uv, float3 materialColor, PixelVertexData pixelVertexData, uint4 lightInfo, ShadowSettings shadowSettings) { uint numDirectionalLights = lightInfo.x; + uint numCascades = lightInfo.z; float3 ambientColor = float3(0.0f, 0.0f, 0.0f); float3 directionalColor = float3(0.0f, 0.0f, 0.0f); - float ambientOcclusion = _ambientOcclusion.Load(int3(pixelPos, 0)).r; + float ambientOcclusion = _ambientOcclusion.Load(int3(pixelVertexData.pixelPos, 0)).r; for (uint i = 0; i < numDirectionalLights; i++) { @@ -38,20 +42,32 @@ float3 ApplyLighting(float3 materialColor, float3 normal, float2 uv, float2 pixe light.skyAmbientColor.rgb = float3(0.4f, 0.4f, 0.4f); // Ambient Light - float nDotUp = saturate(dot(normal, float3(0.0f, 1.0f, 0.0f))); // Dot product between normal and up direction + float nDotUp = saturate(dot(pixelVertexData.worldNormal, float3(0.0f, 1.0f, 0.0f))); // Dot product between normal and up direction float4 lightAmbientColor = lerp(light.groundAmbientColor, light.skyAmbientColor, nDotUp); // Ambient color based on normal - ambientColor += lightAmbientColor.rgb * lightAmbientColor.a; // Intensity in alpha channel + lightAmbientColor.rgb *= lightAmbientColor.a; // Intensity in alpha channel // Ambient Occlusion - ambientColor *= ambientOcclusion; + lightAmbientColor.rgb *= ambientOcclusion; + ambientColor += lightAmbientColor.rgb; // Directional Light - float nDotL = saturate(dot(normal, -light.direction.xyz)); // Dot product between normal and light direction + float nDotL = saturate(dot(pixelVertexData.worldNormal, -light.direction.xyz)); // Dot product between normal and light direction float3 lightColor = lerp(light.color.rgb, float3(1.0f, 1.0f, 1.0f), nDotL); // Light color based on normal - directionalColor += lightColor.rgb * light.color.a; // Intensity in alpha channel - + lightColor *= light.color.a; // Intensity in alpha channel + // Directional Light Shadows - // TODO + if (shadowSettings.enableShadows) + { + shadowSettings.cascadeIndex = GetShadowCascadeIndexFromDepth(pixelVertexData.viewPos.z, numCascades); + Camera cascadeCamera = _cameras[shadowSettings.cascadeIndex + 1]; // +1 because the first camera is the main camera + + float4 shadowPosition = mul(float4(pixelVertexData.worldPos, 1.0f), cascadeCamera.worldToClip); + + float shadowFactor = GetShadowFactor(uv, shadowPosition, shadowSettings); + lightColor *= shadowFactor; + } + + directionalColor += lightColor; } // Point Lights diff --git a/Source/Shaders/Shaders/Include/Shadows.inc.hlsl b/Source/Shaders/Shaders/Include/Shadows.inc.hlsl new file mode 100644 index 00000000..5a9892f4 --- /dev/null +++ b/Source/Shaders/Shaders/Include/Shadows.inc.hlsl @@ -0,0 +1,216 @@ +#ifndef SHADOWS_INCLUDED +#define SHADOWS_INCLUDED + +#include "globalData.inc.hlsl" + +#define MAX_SHADOW_CASCADES 8 // Has to be kept in sync with the one in RenderSettings.h + +[[vk::binding(0, SHADOWS)]] SamplerComparisonState _shadowCmpSampler; +[[vk::binding(1, SHADOWS)]] SamplerState _shadowPointClampSampler; +[[vk::binding(2, SHADOWS)]] Texture2D _shadowCascadeRTs[MAX_SHADOW_CASCADES]; + +struct ShadowSettings +{ + bool enableShadows; + float filterSize; + float penumbraFilterSize; + + uint cascadeIndex; // Filled in by ApplyLighting +}; + +float TextureProj(float4 P, float2 offset, uint shadowCascadeIndex) +{ + float shadow = 1.0f; + + float4 shadowCoord = P / P.w; + shadowCoord.xy = shadowCoord.xy * 0.5f + 0.5f; + + if (shadowCoord.z > -1.0f && shadowCoord.z < 1.0f) + { + float3 sc = float3(float2(shadowCoord.x, 1.0f - shadowCoord.y) + offset, shadowCoord.z); + //shadow = _shadowRT.SampleLevel(_shadowSampler, sc.xy, sc.z); + shadow = _shadowCascadeRTs[shadowCascadeIndex].SampleCmpLevelZero(_shadowCmpSampler, sc.xy, sc.z); + } + return shadow; +} + +// 9 imad (+ 6 iops with final shuffle) +uint3 PCG3DHash(uint3 v) +{ + v = v * 1664525u + 1013904223u; + + v.x += v.y * v.z; + v.y += v.z * v.x; + v.z += v.x * v.y; + + v ^= v >> 16u; + + v.x += v.y * v.z; + v.y += v.z * v.x; + v.z += v.x * v.y; + + return v; +} + +// Percentage Closer Filtering +float FilterPCF(float2 screenUV, float4 shadowCoord, ShadowSettings shadowSettings) +{ + float2 texDim; + _shadowCascadeRTs[0].GetDimensions(texDim.x, texDim.y); + + const float scale = 0.5f; + float dx = scale * (1.0f / texDim.x); + float dy = scale * (1.0f / texDim.y); + + // Calculate directions for the filtering + uint4 u = uint4(screenUV, uint(screenUV.x) ^ uint(screenUV.y), uint(screenUV.x) + uint(screenUV.y)); + float3 rand = normalize(PCG3DHash(u.xyz)); + + float2 dirA = normalize(rand.xy); + float2 dirB = normalize(float2(-dirA.y, dirA.x)); + + dirA *= dx; + dirB *= dy; + + // Add together all the filter taps + float shadowFactor = 0.0f; + const int range = 2; + int count = 0; + + [unroll] + for (int x = -range; x <= range; x++) + { + [unroll] + for (int y = -range; y <= range; y++) + { + shadowFactor += TextureProj(shadowCoord, dirA * x + dirB * y, shadowSettings.cascadeIndex); + count++; + } + } + + return shadowFactor / float(count); +} + + +// Percentage Closer Soft Shadows, credits: https://www.gamedev.net/tutorials/programming/graphics/contact-hardening-soft-shadows-made-fast-r4906/ +float InterleavedGradientNoise(float2 screenPos) +{ + float3 magic = float3(0.06711056f, 0.00583715f, 52.9829189f); + return frac(magic.z * frac(dot(screenPos, magic.xy))); +} + +float2 VogelDiskSample(int sampleIndex, int samplesCount, float phi) +{ + float goldenAngle = 2.4f; + + float r = sqrt(sampleIndex + 0.5f) / sqrt(samplesCount); + float theta = sampleIndex * goldenAngle + phi; + + float sine, cosine; + sincos(theta, sine, cosine); + + return float2(r * cosine, r * sine); +} + +// This should be tuned for the visuals we want +float AvgBlockersDepthToPenumbra(float shadowMapViewZ, float avgBlockersDepth) +{ + float penumbra = (shadowMapViewZ - avgBlockersDepth) / avgBlockersDepth; + penumbra *= penumbra; + return saturate(80.0f * penumbra); +} + +float Penumbra(float gradientNoise, float2 shadowMapUV, float shadowMapViewZ, float penumbraFilterSize, int samplesCount, uint shadowCascadeIndex) +{ + float avgBlockersDepth = 0.0f; + float blockersCount = 0.0f; + + for (int i = 0; i < samplesCount; i++) + { + float2 sampleUV = VogelDiskSample(i, samplesCount, gradientNoise); + sampleUV = shadowMapUV + penumbraFilterSize * sampleUV; + + // _shadowCascadeRTs[shadowCascadeIndex].SampleCmpLevelZero(_shadowSampler, sc.xy, sc.z); + float sampleDepth = _shadowCascadeRTs[shadowCascadeIndex].SampleLevel(_shadowPointClampSampler, sampleUV, 0).x; + + if (sampleDepth < shadowMapViewZ) + { + avgBlockersDepth += sampleDepth; + blockersCount += 1.0f; + } + } + + if (blockersCount > 0.0f) + { + avgBlockersDepth /= blockersCount; + return AvgBlockersDepthToPenumbra(shadowMapViewZ, avgBlockersDepth); + } + else + { + return 0.0f; + } +} + +float FilterPCSS(float2 screenUV, float4 P, ShadowSettings shadowSettings) +{ + float2 texDim; + _shadowCascadeRTs[0].GetDimensions(texDim.x, texDim.y); + + float4 shadowCoord = P / P.w; + shadowCoord.xy = shadowCoord.xy * 0.5f + 0.5f; + shadowCoord.y = -shadowCoord.y; + + const float tau = 6.28318; + float gradientNoise = tau * InterleavedGradientNoise(screenUV * texDim); + + float shadow = 0.0f; + //if (shadowCoord.z > -1.0f && shadowCoord.z < 1.0f) + { + float penumbra = 1.0f - Penumbra(gradientNoise, shadowCoord.xy, shadowCoord.z, shadowSettings.penumbraFilterSize, 16, shadowSettings.cascadeIndex); + + for (int i = 0; i < 16; i++) + { + float2 sampleUV = VogelDiskSample(i, 16, gradientNoise); + sampleUV = shadowCoord.xy + sampleUV * penumbra * shadowSettings.filterSize; + + shadow += _shadowCascadeRTs[shadowSettings.cascadeIndex].SampleCmpLevelZero(_shadowCmpSampler, sampleUV, shadowCoord.z); + } + } + shadow /= 16.0f; + + return shadow; +} + +#define SHADOW_FILTER_MODE_OFF 0 +#define SHADOW_FILTER_MODE_PCF 1 // Percentage Closer Filtering +#define SHADOW_FILTER_MODE_PCSS 2 // Percentage Closer Soft Shadows + +#ifndef SHADOW_FILTER_MODE +#define SHADOW_FILTER_MODE SHADOW_FILTER_MODE_OFF +#endif + +float GetShadowFactor(float2 screenUV, float4 shadowCoord, ShadowSettings shadowSettings) +{ +#if SHADOW_FILTER_MODE == SHADOW_FILTER_MODE_PCF + return lerp(0.0f, 1.0f, FilterPCF(screenUV, shadowCoord, shadowSettings)); +#elif SHADOW_FILTER_MODE == SHADOW_FILTER_MODE_PCSS + return saturate(FilterPCSS(screenUV, shadowCoord, shadowSettings)); +#else + return lerp(0.0f, 1.0f, TextureProj(shadowCoord, float2(0, 0), shadowSettings.cascadeIndex)); +#endif +} + +uint GetShadowCascadeIndexFromDepth(float depth, uint numCascades) +{ + uint cascadeIndex = 0; + for (int i = numCascades; i > 0; i--) + { + if (depth > _cameras[i].eyePosition.w) + { + cascadeIndex = i; + break; + } + } + return cascadeIndex; +} +#endif // SHADOWS_INCLUDED \ No newline at end of file diff --git a/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl b/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl index f7f54577..74373c36 100644 --- a/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl +++ b/Source/Shaders/Shaders/Include/VisibilityBuffers.inc.hlsl @@ -1,8 +1,9 @@ #ifndef VISIBILITYBUFFERS_INCLUDED #define VISIBILITYBUFFERS_INCLUDED -#include "Terrain/Shared.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" +#include "globalData.inc.hlsl" #if GEOMETRY_PASS uint4 PackVisibilityBuffer(uint typeID, uint drawID, uint triangleID, float2 barycentrics, float2 ddxBarycentrics, float2 ddyBarycentrics) @@ -242,9 +243,11 @@ struct PixelVertexData float3 color; // Only used for terrain, for models it's hardcoded to white float3 worldNormal; float3 worldPos; + float4 viewPos; + float2 pixelPos; }; -PixelVertexData GetPixelVertexDataTerrain(const uint2 pixelPos, const VisibilityBuffer vBuffer) +PixelVertexData GetPixelVertexDataTerrain(const uint2 pixelPos, const VisibilityBuffer vBuffer, const uint cameraIndex) { InstanceData cellInstance = _instanceDatas[vBuffer.drawID]; uint globalCellID = cellInstance.globalCellID; @@ -279,13 +282,15 @@ PixelVertexData GetPixelVertexDataTerrain(const uint2 pixelPos, const Visibility // Normal result.worldNormal = normalize(InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].normal, vertices[1].normal, vertices[2].normal)); - // World Position + // Position result.worldPos = InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].position, vertices[1].position, vertices[2].position); + result.viewPos = mul(float4(result.worldPos, 1.0f), _cameras[cameraIndex].worldToView); + result.pixelPos = pixelPos; return result; } -PixelVertexData GetPixelVertexDataModel(const uint2 pixelPos, const VisibilityBuffer vBuffer) +PixelVertexData GetPixelVertexDataModel(const uint2 pixelPos, const VisibilityBuffer vBuffer, const uint cameraIndex) { ModelDrawCallData drawCallData = LoadModelDrawCallData(vBuffer.drawID); ModelInstanceData instanceData = _modelInstanceDatas[drawCallData.instanceID]; @@ -332,19 +337,21 @@ PixelVertexData GetPixelVertexDataModel(const uint2 pixelPos, const VisibilityBu // World Position float3 pixelVertexPosition = InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].position, vertices[1].position, vertices[2].position); result.worldPos = mul(float4(pixelVertexPosition, 1.0f), instanceMatrix).xyz; // Convert to world space + result.viewPos = mul(float4(result.worldPos, 1.0f), _cameras[cameraIndex].worldToView); + result.pixelPos = pixelPos; return result; } -PixelVertexData GetPixelVertexData(const uint2 pixelPos, const VisibilityBuffer vBuffer) +PixelVertexData GetPixelVertexData(const uint2 pixelPos, const VisibilityBuffer vBuffer, uint cameraIndex) { if (vBuffer.typeID == ObjectType::Terrain) { - return GetPixelVertexDataTerrain(pixelPos, vBuffer); + return GetPixelVertexDataTerrain(pixelPos, vBuffer, cameraIndex); } else if (vBuffer.typeID == ObjectType::ModelOpaque) { - return GetPixelVertexDataModel(pixelPos, vBuffer); + return GetPixelVertexDataModel(pixelPos, vBuffer, cameraIndex); } PixelVertexData result; @@ -361,6 +368,8 @@ PixelVertexData GetPixelVertexData(const uint2 pixelPos, const VisibilityBuffer result.color = float3(1, 1, 1); result.worldNormal = float3(0, 1, 0); result.worldPos = float3(0, 0, 0); + result.viewPos = float4(0, 0, 0, 1); + result.pixelPos = pixelPos; return result; } @@ -399,4 +408,22 @@ float3 IDToColor3(uint ID) return color; } +float3 CascadeIDToColor(uint cascadeID) +{ + const uint cascadeCount = 8; + static float3 cascadeColors[cascadeCount] = + { + float3(1.0f, 0.0f, 0.0f), // Red + float3(0.0f, 1.0f, 0.0f), // Green + float3(0.0f, 0.0f, 1.0f), // Blue + float3(1.0f, 1.0f, 0.0f), // Yellow + float3(1.0f, 0.0f, 1.0f), // Purple + float3(0.0f, 1.0f, 1.0f), // Cyan + float3(1.0f, 0.5f, 0.0f), // Orange + float3(0.0f, 0.5f, 1.0f) // Light Blue + }; + + return cascadeColors[cascadeID % cascadeCount]; +} + #endif // VISIBILITYBUFFERS_INCLUDED \ No newline at end of file diff --git a/Source/Shaders/Shaders/Liquid/Draw.vs.hlsl b/Source/Shaders/Shaders/Liquid/Draw.vs.hlsl index 94a85d55..14d05fc2 100644 --- a/Source/Shaders/Shaders/Liquid/Draw.vs.hlsl +++ b/Source/Shaders/Shaders/Liquid/Draw.vs.hlsl @@ -1,5 +1,5 @@ #include "globalData.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" struct PackedDrawCallData { diff --git a/Source/Shaders/Shaders/Model/CullInstances.cs.hlsl b/Source/Shaders/Shaders/Model/CullInstances.cs.hlsl index 2aec4d83..68bc7498 100644 --- a/Source/Shaders/Shaders/Model/CullInstances.cs.hlsl +++ b/Source/Shaders/Shaders/Model/CullInstances.cs.hlsl @@ -1,4 +1,4 @@ -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" struct CSInput diff --git a/Source/Shaders/Shaders/Model/Draw.ps.hlsl b/Source/Shaders/Shaders/Model/Draw.ps.hlsl index 84922470..302740b6 100644 --- a/Source/Shaders/Shaders/Model/Draw.ps.hlsl +++ b/Source/Shaders/Shaders/Model/Draw.ps.hlsl @@ -4,7 +4,7 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "common.inc.hlsl" #include "globalData.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" #include "Include/VisibilityBuffers.inc.hlsl" struct PSInput diff --git a/Source/Shaders/Shaders/Model/Draw.vs.hlsl b/Source/Shaders/Shaders/Model/Draw.vs.hlsl index e61ec942..d46c36fe 100644 --- a/Source/Shaders/Shaders/Model/Draw.vs.hlsl +++ b/Source/Shaders/Shaders/Model/Draw.vs.hlsl @@ -5,7 +5,7 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "common.inc.hlsl" #include "globalData.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" /* TODO: Shadows struct Constants diff --git a/Source/Shaders/Shaders/Model/DrawSkybox.vs.hlsl b/Source/Shaders/Shaders/Model/DrawSkybox.vs.hlsl index c077ffca..fb1c729a 100644 --- a/Source/Shaders/Shaders/Model/DrawSkybox.vs.hlsl +++ b/Source/Shaders/Shaders/Model/DrawSkybox.vs.hlsl @@ -1,7 +1,7 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "common.inc.hlsl" #include "globalData.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" struct VSInput { diff --git a/Source/Shaders/Shaders/Model/DrawTransparent.ps.hlsl b/Source/Shaders/Shaders/Model/DrawTransparent.ps.hlsl index f87e3777..dfa3aad6 100644 --- a/Source/Shaders/Shaders/Model/DrawTransparent.ps.hlsl +++ b/Source/Shaders/Shaders/Model/DrawTransparent.ps.hlsl @@ -3,7 +3,7 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "common.inc.hlsl" #include "globalData.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" #include "Include/OIT.inc.hlsl" struct PSInput diff --git a/Source/Shaders/Shaders/Model/DrawTransparent.vs.hlsl b/Source/Shaders/Shaders/Model/DrawTransparent.vs.hlsl index 32f426d0..380f9918 100644 --- a/Source/Shaders/Shaders/Model/DrawTransparent.vs.hlsl +++ b/Source/Shaders/Shaders/Model/DrawTransparent.vs.hlsl @@ -1,7 +1,7 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "common.inc.hlsl" #include "globalData.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" struct VSInput { diff --git a/Source/Shaders/Shaders/Model/ExpandMeshlets.cs.hlsl b/Source/Shaders/Shaders/Model/ExpandMeshlets.cs.hlsl index a8093182..095ad65c 100644 --- a/Source/Shaders/Shaders/Model/ExpandMeshlets.cs.hlsl +++ b/Source/Shaders/Shaders/Model/ExpandMeshlets.cs.hlsl @@ -1,4 +1,4 @@ -#include "Model/Shared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" /*struct PaddedDispatch { diff --git a/Source/Shaders/Shaders/Model/Shared.inc.hlsl b/Source/Shaders/Shaders/Model/ModelShared.inc.hlsl similarity index 100% rename from Source/Shaders/Shaders/Model/Shared.inc.hlsl rename to Source/Shaders/Shaders/Model/ModelShared.inc.hlsl diff --git a/Source/Shaders/Shaders/PreEffectsPass.cs.hlsl b/Source/Shaders/Shaders/PreEffectsPass.cs.hlsl index cc528850..87edf551 100644 --- a/Source/Shaders/Shaders/PreEffectsPass.cs.hlsl +++ b/Source/Shaders/Shaders/PreEffectsPass.cs.hlsl @@ -22,7 +22,7 @@ void main(uint3 dispatchThreadId : SV_DispatchThreadID) uint4 vBufferData = LoadVisibilityBuffer(pixelPos); const VisibilityBuffer vBuffer = UnpackVisibilityBuffer(vBufferData); - PixelVertexData pixelVertexData = GetPixelVertexData(pixelPos, vBuffer); + PixelVertexData pixelVertexData = GetPixelVertexData(pixelPos, vBuffer, 0); float3 normal = pixelVertexData.worldNormal; diff --git a/Source/Shaders/Shaders/Terrain/Culling.cs.hlsl b/Source/Shaders/Shaders/Terrain/Culling.cs.hlsl index e0f1da59..b984b77d 100644 --- a/Source/Shaders/Shaders/Terrain/Culling.cs.hlsl +++ b/Source/Shaders/Shaders/Terrain/Culling.cs.hlsl @@ -3,7 +3,7 @@ #include "Include/PyramidCulling.inc.hlsl" #include "Include/Debug.inc.hlsl" #include "globalData.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" struct Constants { @@ -11,6 +11,7 @@ struct Constants uint viewportSizeY; uint numCascades; uint occlusionCull; + uint bitMaskBufferSizePerView; }; struct HeightRange @@ -79,6 +80,7 @@ struct DrawInput struct BitmaskInput { bool useBitmasks; + uint bitmaskOffset; StructuredBuffer prevCulledInstancesBitMask; RWStructuredBuffer outCulledInstancesBitMask; }; @@ -93,8 +95,7 @@ struct CullOutput void CullForCamera(DrawInput drawInput, Camera camera, - BitmaskInput bitmaskInput, - CullOutput cullOutput) + BitmaskInput bitmaskInput) { bool isVisible = true; @@ -113,7 +114,6 @@ void CullForCamera(DrawInput drawInput, } } - bool shouldRender = isVisible; if (bitmaskInput.useBitmasks) { uint bitMask = WaveActiveBallot(isVisible).x; @@ -121,33 +121,17 @@ void CullForCamera(DrawInput drawInput, // The first thread writes the bitmask if (drawInput.csInput.groupThreadID.x == 0) { - bitmaskInput.outCulledInstancesBitMask[drawInput.csInput.groupID.x] = bitMask; + uint bitMaskIndex = drawInput.csInput.groupID.x + bitmaskInput.bitmaskOffset; + bitmaskInput.outCulledInstancesBitMask[bitMaskIndex] = bitMask; } - - uint occluderBitMask = bitmaskInput.prevCulledInstancesBitMask[drawInput.csInput.groupID.x]; - uint renderBitMask = bitMask & ~occluderBitMask; // This should give us all currently visible objects that were not occluders - - // We only want to render objects that are visible and not occluders since they were already rendered this frame - shouldRender = renderBitMask & (1u << drawInput.csInput.groupThreadID.x); - } - - if (shouldRender) - { - uint argumentByteOffset = cullOutput.argumentIndex * (sizeof(uint) * 5); // VkDrawIndexedIndirectCommand - - uint culledInstanceIndex; - cullOutput.argumentBuffer.InterlockedAdd(argumentByteOffset + 4, 1, culledInstanceIndex); - - uint firstInstanceOffset = cullOutput.argumentBuffer.Load(argumentByteOffset + 16); - WriteCellInstanceToByteAdressBuffer(cullOutput.instanceBuffer, firstInstanceOffset + culledInstanceIndex, drawInput.instance); } // Debug draw AABB boxes - float3 cameraPos = _cameras[0].eyePosition.xyz; + /*float3 cameraPos = _cameras[0].eyePosition.xyz; float3 aabbPos = (drawInput.aabb.min + drawInput.aabb.max) / 2.0f; float distanceToCamera = distance(cameraPos, aabbPos); - /*if (isVisible) + if (isVisible) { DrawAABB3D(drawInput.aabb, DebugColor::GREEN); } @@ -183,16 +167,24 @@ void main(CSInput input) BitmaskInput bitmaskInput; bitmaskInput.useBitmasks = true; + bitmaskInput.bitmaskOffset = 0; bitmaskInput.prevCulledInstancesBitMask = _prevCulledInstancesBitMask; bitmaskInput.outCulledInstancesBitMask = _culledInstancesBitMask; - CullOutput cullOutput; - cullOutput.instanceBuffer = _culledInstances; - cullOutput.argumentIndex = 0; - cullOutput.argumentBuffer = _arguments; - // Main camera view { - CullForCamera(drawInput, _cameras[0], bitmaskInput, cullOutput); + CullForCamera(drawInput, _cameras[0], bitmaskInput); + } + + // Shadow cascades + for (uint i = 1; i < _constants.numCascades + 1; i++) + { + drawInput.shouldOcclusionCull = false; // No occlusion culling for shadow cascades... yet? + + bitmaskInput.bitmaskOffset = _constants.bitMaskBufferSizePerView * i; + + CullForCamera(drawInput, + _cameras[i], + bitmaskInput); } } \ No newline at end of file diff --git a/Source/Shaders/Shaders/Terrain/Draw.ps.hlsl b/Source/Shaders/Shaders/Terrain/Draw.ps.hlsl index 70fb2ab5..5f4458d4 100644 --- a/Source/Shaders/Shaders/Terrain/Draw.ps.hlsl +++ b/Source/Shaders/Shaders/Terrain/Draw.ps.hlsl @@ -3,14 +3,15 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "common.inc.hlsl" #include "globalData.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" #include "Include/VisibilityBuffers.inc.hlsl" struct PSInput { uint triangleID : SV_PrimitiveID; uint instanceID : TEXCOORD0; - float3 worldPosition : TEXCOORD1; + uint culledInstanceID : TEXCOORD1; + float3 worldPosition : TEXCOORD2; }; struct PSOutput @@ -25,7 +26,7 @@ PSOutput main(PSInput input) const uint padding = 0; // Get the vertexIDs of the triangle we're in - InstanceData instanceData = _instanceDatas[input.instanceID]; + InstanceData instanceData = _instanceDatas[input.culledInstanceID]; // Get the cellID and chunkID const uint cellID = instanceData.packedChunkCellID & 0xFFFF; diff --git a/Source/Shaders/Shaders/Terrain/Draw.vs.hlsl b/Source/Shaders/Shaders/Terrain/Draw.vs.hlsl index c133a790..1963a407 100644 --- a/Source/Shaders/Shaders/Terrain/Draw.vs.hlsl +++ b/Source/Shaders/Shaders/Terrain/Draw.vs.hlsl @@ -4,11 +4,11 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #define GEOMETRY_PASS 1 #include "globalData.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" struct Constants { - uint cascadeIndex; + uint viewIndex; }; [[vk::push_constant]] Constants _constants; @@ -16,7 +16,7 @@ struct Constants struct VSInput { uint vertexID : SV_VertexID; - uint instanceID : SV_InstanceID; + uint culledInstanceID : SV_InstanceID; }; struct VSOutput @@ -24,13 +24,14 @@ struct VSOutput float4 position : SV_Position; #if !EDITOR_PASS && !SHADOW_PASS uint instanceID : TEXCOORD0; - float3 worldPosition : TEXCOORD1; + uint culledInstanceID : TEXCOORD1; + float3 worldPosition : TEXCOORD2; #endif }; VSOutput main(VSInput input) { - InstanceData instanceData = _instanceDatas[input.instanceID]; + InstanceData instanceData = _instanceDatas[input.culledInstanceID]; VSOutput output; @@ -48,14 +49,11 @@ VSOutput main(VSInput input) uint vertexBaseOffset = instanceData.globalCellID * NUM_VERTICES_PER_CELL; TerrainVertex vertex = LoadTerrainVertex(chunkID, cellID, vertexBaseOffset, input.vertexID); -#if SHADOW_PASS - output.position = float4(0, 0, 0, 1);// mul(float4(vertex.position, 1.0f), GetShadowViewProjectionMatrix(_constants.cascadeIndex)); -#else - output.position = mul(float4(vertex.position, 1.0f), _cameras[0].worldToClip); -#endif + output.position = mul(float4(vertex.position, 1.0f), _cameras[_constants.viewIndex].worldToClip); #if !EDITOR_PASS && !SHADOW_PASS - output.instanceID = input.instanceID; + output.instanceID = instanceData.globalCellID; + output.culledInstanceID = input.culledInstanceID; output.worldPosition = vertex.position; #endif diff --git a/Source/Shaders/Shaders/Terrain/FillDrawCalls.cs.hlsl b/Source/Shaders/Shaders/Terrain/FillDrawCalls.cs.hlsl index 0f35351d..35fe2ce8 100644 --- a/Source/Shaders/Shaders/Terrain/FillDrawCalls.cs.hlsl +++ b/Source/Shaders/Shaders/Terrain/FillDrawCalls.cs.hlsl @@ -2,20 +2,23 @@ #include "Include/Culling.inc.hlsl" #include "Include/PyramidCulling.inc.hlsl" #include "globalData.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" struct Constants { uint numTotalInstances; + uint bitmaskOffset; + uint diffAgainstPrev; }; [[vk::push_constant]] Constants _constants; [[vk::binding(0, PER_PASS)]] StructuredBuffer _instances; [[vk::binding(1, PER_PASS)]] StructuredBuffer _culledInstancesBitMask; +[[vk::binding(2, PER_PASS)]] StructuredBuffer _prevCulledInstancesBitMask; -[[vk::binding(2, PER_PASS)]] RWStructuredBuffer _culledInstances; -[[vk::binding(3, PER_PASS)]] RWByteAddressBuffer _drawCount; +[[vk::binding(3, PER_PASS)]] RWStructuredBuffer _culledInstances; +[[vk::binding(4, PER_PASS)]] RWByteAddressBuffer _drawCount; struct CSInput { @@ -32,10 +35,16 @@ void main(CSInput input) if (index >= _constants.numTotalInstances) return; - uint bitMask = _culledInstancesBitMask[input.groupID.x]; + uint bitMaskIndex = _constants.bitmaskOffset + input.groupID.x; + uint bitMask = _culledInstancesBitMask[bitMaskIndex]; + uint prevBitMask = _prevCulledInstancesBitMask[bitMaskIndex]; uint bitIndex = input.groupThreadID.x; - if (bitMask & (1u << bitIndex)) + bool isVisible = bitMask & (1u << bitIndex); + bool wasAlreadyDrawn = prevBitMask & (1u << bitIndex); + + bool shouldDraw = isVisible && (!wasAlreadyDrawn || !_constants.diffAgainstPrev); + if (shouldDraw) { uint outIndex; _drawCount.InterlockedAdd(4, 1, outIndex); diff --git a/Source/Shaders/Shaders/Terrain/Terrain.vs.hlsl b/Source/Shaders/Shaders/Terrain/Terrain.vs.hlsl index 530e54bd..8bab5335 100644 --- a/Source/Shaders/Shaders/Terrain/Terrain.vs.hlsl +++ b/Source/Shaders/Shaders/Terrain/Terrain.vs.hlsl @@ -1,5 +1,5 @@ /*#include "globalData.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" struct PackedTerrainVertex { diff --git a/Source/Shaders/Shaders/Terrain/Shared.inc.hlsl b/Source/Shaders/Shaders/Terrain/TerrainShared.inc.hlsl similarity index 100% rename from Source/Shaders/Shaders/Terrain/Shared.inc.hlsl rename to Source/Shaders/Shaders/Terrain/TerrainShared.inc.hlsl diff --git a/Source/Shaders/Shaders/Utils/ObjectQuery.cs.hlsl b/Source/Shaders/Shaders/Utils/ObjectQuery.cs.hlsl index a5e2369e..c52cb7bf 100644 --- a/Source/Shaders/Shaders/Utils/ObjectQuery.cs.hlsl +++ b/Source/Shaders/Shaders/Utils/ObjectQuery.cs.hlsl @@ -1,6 +1,6 @@ permutation SUPPORTS_EXTENDED_TEXTURES = [0, 1]; #include "Include/VisibilityBuffers.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" struct Constants { diff --git a/Source/Shaders/Shaders/Utils/resetIndirectBuffer.cs.hlsl b/Source/Shaders/Shaders/Utils/resetIndirectBuffer.cs.hlsl index 64d88b6b..31670b75 100644 --- a/Source/Shaders/Shaders/Utils/resetIndirectBuffer.cs.hlsl +++ b/Source/Shaders/Shaders/Utils/resetIndirectBuffer.cs.hlsl @@ -9,7 +9,7 @@ struct IndirectArguments struct Constants { - bool moveCountToFirst; + uint moveCountToFirst; }; [[vk::push_constant]] Constants _constants; diff --git a/Source/Shaders/Shaders/materialPass.cs.hlsl b/Source/Shaders/Shaders/materialPass.cs.hlsl index ef5f4926..a000eb22 100644 --- a/Source/Shaders/Shaders/materialPass.cs.hlsl +++ b/Source/Shaders/Shaders/materialPass.cs.hlsl @@ -8,13 +8,13 @@ permutation EDITOR_MODE = [0, 1]; // Off, Terrain #include "Include/VisibilityBuffers.inc.hlsl" #include "Include/Editor.inc.hlsl" #include "Include/Lighting.inc.hlsl" -#include "Terrain/Shared.inc.hlsl" -#include "Model/Shared.inc.hlsl" +#include "Terrain/TerrainShared.inc.hlsl" +#include "Model/ModelShared.inc.hlsl" // Reenable this in C++ as well struct Constants { - uint4 lightInfo; // x = Num Directional Lights, y = Num Point Lights + uint4 lightInfo; // x = Num Directional Lights, y = Num Point Lights, z = Num Cascades, w = Shadows Enabled float4 fogColor; float4 fogSettings; // x = Enabled, y = Begin Fog Blend Dist, z = End Fog Blend Dist, w = UNUSED float4 mouseWorldPos; @@ -36,45 +36,12 @@ struct Constants float4 ShadeTerrain(const uint2 pixelPos, const float2 screenUV, const VisibilityBuffer vBuffer, out float3 outPixelWorldPos) { + // Get the interpolated vertex data from the visibility buffer + PixelVertexData pixelVertexData = GetPixelVertexDataTerrain(pixelPos, vBuffer, 0); + InstanceData cellInstance = _instanceDatas[vBuffer.drawID]; uint globalCellID = cellInstance.globalCellID; - - // Terrain code - uint globalVertexOffset = globalCellID * NUM_VERTICES_PER_CELL; - uint3 localVertexIDs = GetLocalTerrainVertexIDs(vBuffer.triangleID); - const uint cellID = cellInstance.packedChunkCellID & 0xFFFF; - const uint chunkID = cellInstance.packedChunkCellID >> 16; - - // Get vertices - TerrainVertex vertices[3]; - - [unroll] - for (uint i = 0; i < 3; i++) - { - vertices[i] = LoadTerrainVertex(chunkID, cellID, globalVertexOffset, localVertexIDs[i]); - } - - // Interpolate vertex attributes - FullBary2 pixelUV = CalcFullBary2(vBuffer.barycentrics, vertices[0].uv, vertices[1].uv, vertices[2].uv); // [0..8] This is correct for terrain color textures - FullBary3 pixelWorldPosition = CalcFullBary3(vBuffer.barycentrics, vertices[0].position, vertices[1].position, vertices[2].position); - - outPixelWorldPos = pixelWorldPosition.value; - - //Camera mainCamera = _cameras[0]; - //float4 pixelViewPosition = mul(float4(pixelWorldPosition.value, 1.0f), mainCamera.worldToView); - uint shadowCascadeIndex = 0;// GetShadowCascadeIndexFromDepth(pixelViewPosition.z, _constants.numCascades); -#if DEBUG_ID == 4 - return float4(IDToColor3(shadowCascadeIndex + 1), 1.0f); -#endif - //ViewData shadowCascadeViewData = _shadowCascadeViewDatas[shadowCascadeIndex]; - - //float4 pixelShadowPosition = mul(float4(pixelWorldPosition.value, 1.0f), shadowCascadeViewData.viewProjectionMatrix); - float4 pixelShadowPosition = float4(0.0f, 0.0f, 0.0f, 0.0f); - - float3 pixelColor = InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].color, vertices[1].color, vertices[2].color); - float3 pixelNormal = InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].normal, vertices[1].normal, vertices[2].normal); - float3 pixelAlphaUV = float3(saturate(pixelUV.value / 8.0f), float(cellID)); // However the alpha needs to be between 0 and 1, and load from the correct layer // Get CellData and ChunkData const CellData cellData = LoadCellData(globalCellID); @@ -95,6 +62,9 @@ float4 ShadeTerrain(const uint2 pixelPos, const float2 screenUV, const Visibilit uint diffuse3ID = cellData.diffuseIDs.w; uint alphaID = chunkData.alphaID; + FullBary2 pixelUV = pixelVertexData.uv0; + float3 pixelAlphaUV = float3(saturate(pixelUV.value / 8.0f), float(cellID)); // The alpha needs to be between 0 and 1, and load from the correct layer + float3 alpha = _terrainAlphaTextures[NonUniformResourceIndex(alphaID)].SampleGrad(_alphaSampler, pixelAlphaUV, pixelUV.ddx, pixelUV.ddy).rgb; float minusAlphaBlendSum = (1.0 - clamp(alpha.x + alpha.y + alpha.z, 0.0, 1.0)); float4 weightsVector = float4(minusAlphaBlendSum, alpha); @@ -113,20 +83,25 @@ float4 ShadeTerrain(const uint2 pixelPos, const float2 screenUV, const Visibilit float3 diffuse3 = _terrainColorTextures[NonUniformResourceIndex(diffuse3ID)].SampleGrad(_sampler, pixelUV.value, pixelUV.ddx, pixelUV.ddy).xyz * weightsVector.w; color.rgb += diffuse3; - // Apply Vertex Color - color.rgb *= pixelColor; + // Apply vertex color + color.rgb *= pixelVertexData.color; - /*if (_constants.numTextureDecals + _constants.numProceduralDecals > 0) - { - // Apply decals - ApplyDecals(pixelWorldPosition, color, pixelNormal, _constants.numTextureDecals, _constants.numProceduralDecals, _constants.mouseWorldPos.xyz); - }*/ + //if (_constants.numTextureDecals + _constants.numProceduralDecals > 0) + //{ + // // Apply decals + // ApplyDecals(pixelWorldPosition, color, pixelNormal, _constants.numTextureDecals, _constants.numProceduralDecals, _constants.mouseWorldPos.xyz); + //} + + // TODO: Don't hardcode this + ShadowSettings shadowSettings; + shadowSettings.enableShadows = _constants.lightInfo.w == 1; + shadowSettings.filterSize = 3.0f; + shadowSettings.penumbraFilterSize = 3.0f; // Apply lighting - float3 normal = normalize(pixelNormal); - color.rgb = ApplyLighting(color.rgb, pixelNormal, screenUV, pixelPos, _constants.lightInfo); + color.rgb = ApplyLighting(screenUV, color.rgb, pixelVertexData, _constants.lightInfo, shadowSettings); -#if EDITOR_MODE == 1 +/*#if EDITOR_MODE == 1 // Get settings from push constants const float brushHardness = _constants.brushSettings.x; const float brushRadius = _constants.brushSettings.y; @@ -137,7 +112,7 @@ float4 ShadeTerrain(const uint2 pixelPos, const float2 screenUV, const Visibilit const float wireframeFalloffDistance = 100.0f; // Wireframes - float4 pixelClipSpacePosition = mul(float4(pixelWorldPosition.value, 1.0f), _cameras[0].worldToClip); + float4 pixelClipSpacePosition = mul(float4(pixelVertexData.worldPos.value, 1.0f), _cameras[0].worldToClip); pixelClipSpacePosition.xyz /= pixelClipSpacePosition.w; float4 verticesClipSpacePosition[3]; @@ -169,11 +144,11 @@ float4 ShadeTerrain(const uint2 pixelPos, const float2 screenUV, const Visibilit bool isRightChunkEdge = cellID % 16 == 15; bool isTopChunkEdge = cellID < 16; bool isBottomChunkEdge = cellID >= 240; - + bool isChunkEdge = (isLeftChunkEdge && isLeftCellEdge) || - (isRightChunkEdge && isRightCellEdge) || - (isTopChunkEdge && isTopCellEdge) || - (isBottomChunkEdge && isBottomCellEdge); + (isRightChunkEdge && isRightCellEdge) || + (isTopChunkEdge && isTopCellEdge) || + (isBottomChunkEdge && isBottomCellEdge); if (isChunkEdge) { @@ -204,61 +179,18 @@ float4 ShadeTerrain(const uint2 pixelPos, const float2 screenUV, const Visibilit float brush = EditorCircleBrush(_constants.mouseWorldPos.xyz, pixelWorldPosition.value.xyz, brushRadius, brushFalloff, vBuffer.barycentrics); color.rgb = lerp(_constants.brushColor.rgb, color.rgb, brush); -#endif +#endif*/ + outPixelWorldPos = pixelVertexData.worldPos; return saturate(color); } float4 ShadeModel(const uint2 pixelPos, const float2 screenUV, const VisibilityBuffer vBuffer, out float3 outPixelWorldPos) { - ModelDrawCallData drawCallData = LoadModelDrawCallData(vBuffer.drawID); - ModelInstanceData instanceData = _modelInstanceDatas[drawCallData.instanceID]; - float4x4 instanceMatrix = _modelInstanceMatrices[drawCallData.instanceID]; + // Get the interpolated vertex data from the visibility buffer + PixelVertexData pixelVertexData = GetPixelVertexDataModel(pixelPos, vBuffer, 0); - // Get the VertexIDs of the triangle we're in - IndexedDraw draw = _modelDraws[vBuffer.drawID]; - uint3 vertexIDs = GetVertexIDs(vBuffer.triangleID, draw, _modelIndices); - - // Get Vertices - ModelVertex vertices[3]; - - [unroll] - for (uint i = 0; i < 3; i++) - { - vertices[i] = LoadModelVertex(vertexIDs[i]); - - // Animate the vertex normal if we need to - if (instanceData.boneMatrixOffset != 4294967295) - { - // Calculate bone transform matrix - float4x4 boneTransformMatrix = CalcBoneTransformMatrix(instanceData, vertices[i]); - vertices[i].normal = mul(vertices[i].normal, (float3x3)boneTransformMatrix); - } - - // Convert normals to world normals - vertices[i].normal = mul(vertices[i].normal, (float3x3)instanceMatrix); - } - - // Interpolate vertex attributes - FullBary2 pixelUV0 = CalcFullBary2(vBuffer.barycentrics, vertices[0].uv01.xy, vertices[1].uv01.xy, vertices[2].uv01.xy); - FullBary2 pixelUV1 = CalcFullBary2(vBuffer.barycentrics, vertices[0].uv01.zw, vertices[1].uv01.zw, vertices[2].uv01.zw); - - float3 pixelVertexPosition = InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].position, vertices[1].position, vertices[2].position); - float3 pixelWorldPosition = mul(float4(pixelVertexPosition, 1.0f), instanceMatrix).xyz; - - outPixelWorldPos = pixelWorldPosition; - - float4 pixelViewPosition = mul(float4(pixelWorldPosition, 1.0f), _cameras[0].worldToView); - uint shadowCascadeIndex = 0;// GetShadowCascadeIndexFromDepth(pixelViewPosition.z, _constants.numCascades); -#if DEBUG_ID == 4 - return float4(IDToColor3(shadowCascadeIndex + 1), 1.0f); -#endif - //ViewData shadowCascadeViewData = _shadowCascadeViewDatas[shadowCascadeIndex]; - - //float4 pixelShadowPosition = mul(float4(pixelWorldPosition, 1.0f), shadowCascadeViewData.viewProjectionMatrix); - float4 pixelShadowPosition = float4(0, 0, 0, 0); - - float3 pixelNormal = InterpolateVertexAttribute(vBuffer.barycentrics, vertices[0].normal, vertices[1].normal, vertices[2].normal); + ModelDrawCallData drawCallData = LoadModelDrawCallData(vBuffer.drawID); // Shade float4 color = float4(0, 0, 0, 0); @@ -282,13 +214,13 @@ float4 ShadeModel(const uint2 pixelPos, const float2 screenUV, const VisibilityB if (materialType == 0x8000) continue; - float4 texture0Color = _modelTextures[NonUniformResourceIndex(textureUnit.textureIDs[0])].SampleGrad(_samplers[texture0SamplerIndex], pixelUV0.value, pixelUV0.ddx, pixelUV0.ddy); + float4 texture0Color = _modelTextures[NonUniformResourceIndex(textureUnit.textureIDs[0])].SampleGrad(_samplers[texture0SamplerIndex], pixelVertexData.uv0.value, pixelVertexData.uv0.ddx, pixelVertexData.uv0.ddy); float4 texture1Color = float4(0, 0, 0, 0); if (vertexShaderId >= 2) { // ENV uses generated UVCoords based on camera pos + geometry normal in frame space - texture1Color = _modelTextures[NonUniformResourceIndex(textureUnit.textureIDs[1])].SampleGrad(_samplers[texture1SamplerIndex], pixelUV1.value, pixelUV1.ddx, pixelUV1.ddy); + texture1Color = _modelTextures[NonUniformResourceIndex(textureUnit.textureIDs[1])].SampleGrad(_samplers[texture1SamplerIndex], pixelVertexData.uv1.value, pixelVertexData.uv1.ddx, pixelVertexData.uv1.ddy); } isUnlit |= (materialFlags & 0x1); @@ -297,10 +229,16 @@ float4 ShadeModel(const uint2 pixelPos, const float2 screenUV, const VisibilityB color = BlendModel(blendingMode, color, shadedColor); } + // TODO: Don't hardcode this + ShadowSettings shadowSettings; + shadowSettings.enableShadows = _constants.lightInfo.w == 1; + shadowSettings.filterSize = 3.0f; + shadowSettings.penumbraFilterSize = 3.0f; + // Apply lighting - color.rgb = ApplyLighting(color.rgb, pixelNormal, screenUV, pixelPos, _constants.lightInfo); - //color = float4(pixelUV0.value, 0, 1); - + color.rgb = ApplyLighting(screenUV, color.rgb, pixelVertexData, _constants.lightInfo, shadowSettings); + + outPixelWorldPos = pixelVertexData.worldPos; return saturate(color); } @@ -340,6 +278,12 @@ void main(uint3 dispatchThreadId : SV_DispatchThreadID) float3 debugColor = IDToColor3(vBuffer.triangleID); _resolvedColor[pixelPos] = float4(debugColor, 1); return; +#elif DEBUG_ID == 4 // CascadeID + uint numCascades = _constants.lightInfo.z; + PixelVertexData pixelVertexData = GetPixelVertexData(pixelPos, vBuffer, 0); + uint cascadeIndex = GetShadowCascadeIndexFromDepth(pixelVertexData.viewPos.z, numCascades); + _resolvedColor[pixelPos] = float4(CascadeIDToColor(cascadeIndex), 1); + return; #endif float2 pixelUV = pixelPos / dimensions; diff --git a/Submodules/Engine b/Submodules/Engine index 5af2ad41..3f375e35 160000 --- a/Submodules/Engine +++ b/Submodules/Engine @@ -1 +1 @@ -Subproject commit 5af2ad419d0479c41db51558835047e133ad3d0b +Subproject commit 3f375e351317ede786dd42912a5c5b4e7c4ae107