diff --git a/res/shaders/BasePass.slang b/res/shaders/BasePass.slang index 28e36e1..1bc4038 100644 --- a/res/shaders/BasePass.slang +++ b/res/shaders/BasePass.slang @@ -3,6 +3,18 @@ import LightEnv; import MaterialParameter; import MATERIAL_FILE_NAME; +const static uint64_t NUM_CASCADES = 4; + +/*struct ShadowMappingData +{ + Texture2DArray shadowMaps[NUM_CASCADES]; + + ConstantBuffer lightSpaceMatrices[NUM_CASCADES]; + + ConstantBuffer cascadeSplits; +}; +ParameterBlock pShadowMapping; +*/ struct LightCullingData { RWStructuredBuffer lightIndexList; @@ -30,7 +42,13 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target float3 result = float3(0, 0, 0); for(int i = 0; i < pLightEnv.numDirectionalLights; ++i) { - float4 lightSpacePos = mul(biasMat, mul(pLightEnv.directionalLights[i].lightSpaceMatrix, float4(params.position_WS, 1))); + /*uint cascadeIndex = 0; + for (uint c = 0; c < NUM_CASCADES - 1; ++c) { + if (params.position_VS.z < pShadowMapping.cascadeSplits[c]) { + cascadeIndex = c + 1; + } + } + float4 lightSpacePos = mul(biasMat, mul(pShadowMapping.lightSpaceMatrices[i], float4(params.position_WS, 1))); float4 shadowCoord = lightSpacePos / lightSpacePos.w; int2 texDim; pLightEnv.shadowMap.GetDimensions(texDim.x, texDim.y); @@ -55,9 +73,9 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target shadowFactor += shadow; count++; } - } + }*/ - result += (shadowFactor / count) * pLightEnv.directionalLights[i].illuminate(lightingParams, brdf); + result += /*(shadowFactor / count) **/ pLightEnv.directionalLights[i].illuminate(lightingParams, brdf); } for (uint i = 0; i < pLightEnv.numPointLights; ++i) { diff --git a/res/shaders/lib/LightEnv.slang b/res/shaders/lib/LightEnv.slang index b664c3b..c05bcb7 100644 --- a/res/shaders/lib/LightEnv.slang +++ b/res/shaders/lib/LightEnv.slang @@ -10,7 +10,6 @@ struct DirectionalLight : ILightEnv { float4 color; float4 direction; - float4x4 lightSpaceMatrix; float3 illuminate(LightingParameter params, B brdf) { @@ -369,4 +368,3 @@ struct CookTorrance : IBRDF } [mutating] void setNormal(float3 n) { normal = n; } }; - diff --git a/res/shaders/lib/MaterialParameter.slang b/res/shaders/lib/MaterialParameter.slang index 6d201a9..7794d55 100644 --- a/res/shaders/lib/MaterialParameter.slang +++ b/res/shaders/lib/MaterialParameter.slang @@ -63,7 +63,8 @@ struct FragmentParameter float3 normal_WS : NORMALWS; float3 tangent_WS : TANGENTWS; float3 biTangent_WS : BITANGENTWS; - float3 position_WS : POSITIONWS; + float3 position_WS : POSITIONWS; + float3 position_VS : POSITIONVS; float3 vertexColor : COLOR; float4 texCoords0 : TEXCOORDS0; float4 texCoords1 : TEXCOORDS1; @@ -109,7 +110,8 @@ struct FragmentParameter result.normal_WS = f0.normal_WS * barycentricCoords.x + f1.normal_WS * barycentricCoords.y + f2.normal_WS * barycentricCoords.z; result.tangent_WS = f0.tangent_WS * barycentricCoords.x + f1.tangent_WS * barycentricCoords.y + f2.tangent_WS * barycentricCoords.z; result.biTangent_WS = f0.biTangent_WS * barycentricCoords.x + f1.biTangent_WS * barycentricCoords.y + f2.biTangent_WS * barycentricCoords.z; - result.position_WS = f0.position_WS * barycentricCoords.x + f1.position_WS * barycentricCoords.y + f2.position_WS * barycentricCoords.z; + result.position_WS = f0.position_WS * barycentricCoords.x + f1.position_WS * barycentricCoords.y + f2.position_WS * barycentricCoords.z; + result.position_VS = f0.position_VS * barycentricCoords.x + f1.position_VS * barycentricCoords.y + f2.position_VS * barycentricCoords.z; result.vertexColor = f0.vertexColor * barycentricCoords.x + f1.vertexColor * barycentricCoords.y + f2.vertexColor * barycentricCoords.z; result.texCoords0 = f0.texCoords0 * barycentricCoords.x + f1.texCoords0 * barycentricCoords.y + f2.texCoords0 * barycentricCoords.z; result.texCoords1 = f0.texCoords1 * barycentricCoords.x + f1.texCoords1 * barycentricCoords.y + f2.texCoords1 * barycentricCoords.z; @@ -135,7 +137,8 @@ struct VertexAttributes FragmentParameter getParameter(float4x4 transformMatrix, float4x4 inverseTransformMatrix) { float4 modelPos = float4(position_MS, 1); - float4 worldPos = mul(transformMatrix, modelPos); + float4 worldPos = mul(transformMatrix, modelPos); + float4 viewPos = mul(pViewParams.viewMatrix, worldPos); float4 clipPos = mul(pViewParams.viewProjectionMatrix, worldPos); FragmentParameter result; result.position_CS = clipPos; @@ -145,7 +148,8 @@ struct VertexAttributes result.biTangent_WS = mul(transformMatrix, float4(biTangent_MS, 0)).xyz; result.normal_WS = mul(transformMatrix, float4(normal_MS, 0)).xyz; result.vertexColor = vertexColor; - result.position_WS = worldPos.xyz; + result.position_WS = worldPos.xyz; + result.position_VS = viewPos.xyz; result.texCoords0 = float4(texCoords[0], texCoords[1]); result.texCoords1 = float4(texCoords[2], texCoords[3]); result.texCoords2 = float4(texCoords[4], texCoords[5]); diff --git a/src/Engine/Containers/Array.h b/src/Engine/Containers/Array.h index 1ddc0c5..49c55c7 100644 --- a/src/Engine/Containers/Array.h +++ b/src/Engine/Containers/Array.h @@ -535,8 +535,11 @@ template struct StaticArray { } } } + constexpr StaticArray(const StaticArray& other) = default; + constexpr StaticArray(StaticArray&& other) = default; constexpr ~StaticArray() {} - + constexpr StaticArray& operator=(const StaticArray& other) = default; + constexpr StaticArray& operator=(StaticArray&& other) = default; constexpr size_type size() const { return N; } constexpr pointer data() { return _data; } constexpr const_pointer data() const { return _data; } diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 3fce329..8aa66c2 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -84,7 +84,8 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics) BasePass::~BasePass() {} void BasePass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); cameraPos = transform.getPosition(); cameraForward = transform.getForward(); diff --git a/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp b/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp index 5b8245c..915f384 100644 --- a/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp +++ b/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp @@ -42,7 +42,8 @@ CachedDepthPass::CachedDepthPass(Gfx::PGraphics graphics, PScene scene) : Render CachedDepthPass::~CachedDepthPass() {} void CachedDepthPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); } void CachedDepthPass::render() { diff --git a/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp b/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp index 43f0b63..ba1a3ff 100644 --- a/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp @@ -66,7 +66,8 @@ DepthCullingPass::DepthCullingPass(Gfx::PGraphics graphics, PScene scene) : Rend DepthCullingPass::~DepthCullingPass() {} void DepthCullingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); } void DepthCullingPass::render() { diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp index 8aab9ec..853cf89 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp @@ -1,6 +1,7 @@ #include "LightCullingPass.h" #include "Actor/CameraActor.h" #include "Component/Camera.h" +#include "Component/Transform.h" #include "Graphics/Command.h" #include "Graphics/Graphics.h" #include "Graphics/Pipeline.h" @@ -15,7 +16,8 @@ LightCullingPass::LightCullingPass(Gfx::PGraphics graphics, PScene scene) : Rend LightCullingPass::~LightCullingPass() {} void LightCullingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); oLightIndexCounter->pipelineBarrier(Gfx::SE_ACCESS_MEMORY_WRITE_BIT | Gfx::SE_ACCESS_MEMORY_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_MEMORY_WRITE_BIT, @@ -232,7 +234,8 @@ void LightCullingPass::setupFrustums() { numThreads = glm::ceil(glm::vec4(viewportWidth / (float)BLOCK_SIZE, viewportHeight / (float)BLOCK_SIZE, 1, 0)); numThreadGroups = glm::ceil(glm::vec4(numThreads.x / (float)BLOCK_SIZE, numThreads.y / (float)BLOCK_SIZE, 1, 0)); - viewParamsSet = createViewParamsSet(Component::Camera(), Component::Transform()); + updateViewParameters(Component::Camera(), Component::Transform()); + viewParamsSet = createViewParamsSet(); dispatchParamsLayout = graphics->createDescriptorLayout("pDispatchParams"); dispatchParamsLayout->addDescriptorBinding(Gfx::DescriptorBinding{ diff --git a/src/Engine/Graphics/RenderPass/RayTracingPass.cpp b/src/Engine/Graphics/RenderPass/RayTracingPass.cpp index 8c8d615..2a5301b 100644 --- a/src/Engine/Graphics/RenderPass/RayTracingPass.cpp +++ b/src/Engine/Graphics/RenderPass/RayTracingPass.cpp @@ -65,8 +65,8 @@ RayTracingPass::RayTracingPass(Gfx::PGraphics graphics, PScene scene) : RenderPa static uint32 pass = 0; static Component::Transform lastCam; void RayTracingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); - if (lastCam.getPosition() != transform.getPosition() || lastCam.getForward() != transform.getForward()) { + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); if (lastCam.getPosition() != transform.getPosition() || lastCam.getForward() != transform.getForward()) { lastCam = transform; pass = 0; } diff --git a/src/Engine/Graphics/RenderPass/RenderPass.cpp b/src/Engine/Graphics/RenderPass/RenderPass.cpp index 6bf9480..afeccf2 100644 --- a/src/Engine/Graphics/RenderPass/RenderPass.cpp +++ b/src/Engine/Graphics/RenderPass/RenderPass.cpp @@ -27,8 +27,7 @@ void RenderPass::setResources(PRenderGraphResources _resources) { resources = _r void RenderPass::setViewport(Gfx::PViewport _viewport) { viewport = _viewport; } -Gfx::PDescriptorSet RenderPass::createViewParamsSet(const Component::Camera& cam, const Component::Transform& transform) -{ +void RenderPass::updateViewParameters(const Component::Camera& cam, const Component::Transform& transform) { auto screenDim = Vector2(static_cast(viewport->getWidth()), static_cast(viewport->getHeight())); Vector eyePos = transform.getPosition(); Vector lookAt = eyePos + transform.getForward(); @@ -48,24 +47,27 @@ Gfx::PDescriptorSet RenderPass::createViewParamsSet(const Component::Camera& cam .frameIndex = Gfx::getCurrentFrameIndex(), .time = static_cast(Gfx::getCurrentFrameTime()), }; +} +Gfx::PDescriptorSet RenderPass::createViewParamsSet() +{ // screen space - StaticArray corners = { - Vector4(0, 0, -1, 1), - Vector4(screenDim.x, 0, -1, 1), - Vector4(screenDim.y, 0, -1, 1), - Vector4(screenDim.x, screenDim.y, -1, 1), - }; - - for (uint32 i = 0; i < corners.size(); ++i) { - Vector2 texCoord = Vector2(corners[i].x, corners[i].y) / screenDim; - - Vector4 clip = Vector4(Vector2(texCoord.x, 1 - texCoord.y) * 2.0f - 1.0f, corners[i].z, corners[i].w); - - Vector4 world = viewParams.inverseViewProjectionMatrix * clip; - - corners[i] = world / world.w; - } + //StaticArray corners = { + // Vector4(0, 0, -1, 1), + // Vector4(screenDim.x, 0, -1, 1), + // Vector4(screenDim.y, 0, -1, 1), + // Vector4(screenDim.x, screenDim.y, -1, 1), + //}; + // + //for (uint32 i = 0; i < corners.size(); ++i) { + // Vector2 texCoord = Vector2(corners[i].x, corners[i].y) / screenDim; + // + // Vector4 clip = Vector4(Vector2(texCoord.x, 1 - texCoord.y) * 2.0f - 1.0f, corners[i].z, corners[i].w); + // + // Vector4 world = viewParams.inverseViewProjectionMatrix * clip; + // + // corners[i] = world / world.w; + //} // extract_planes_from_view_projection_matrix(viewParams.viewProjectionMatrix, viewParams.viewFrustum); diff --git a/src/Engine/Graphics/RenderPass/RenderPass.h b/src/Engine/Graphics/RenderPass/RenderPass.h index e873189..92c1ad0 100644 --- a/src/Engine/Graphics/RenderPass/RenderPass.h +++ b/src/Engine/Graphics/RenderPass/RenderPass.h @@ -27,7 +27,8 @@ class RenderPass { void setViewport(Gfx::PViewport _viewport); protected: - Gfx::PDescriptorSet createViewParamsSet(const Component::Camera& cam, const Component::Transform& transform); + void updateViewParameters(const Component::Camera& cam, const Component::Transform& transform); + Gfx::PDescriptorSet createViewParamsSet(); struct Plane { Vector n; float d; diff --git a/src/Engine/Graphics/RenderPass/ShadowPass.cpp b/src/Engine/Graphics/RenderPass/ShadowPass.cpp index 7e9bb1d..c1d2d3c 100644 --- a/src/Engine/Graphics/RenderPass/ShadowPass.cpp +++ b/src/Engine/Graphics/RenderPass/ShadowPass.cpp @@ -1,6 +1,10 @@ #include "ShadowPass.h" +#include "Graphics/Enums.h" #include "Graphics/Graphics.h" +#include "Graphics/Initializer.h" #include "Graphics/Shader.h" +#include +#include using namespace Seele; @@ -39,126 +43,214 @@ ShadowPass::ShadowPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graph ShadowPass::~ShadowPass() {} -void ShadowPass::beginFrame(const Component::Camera&, const Component::Transform&) {} +void ShadowPass::beginFrame(const Component::Camera& camera, const Component::Transform& transform) { + uint32 cascadeDim = SHADOW_MAP_SIZE; + float cascadeSplits[NUM_CASCADES]; + + float nearClip = camera.nearPlane; + float farClip = camera.farPlane; + float clipRange = farClip - nearClip; + + float minZ = nearClip; + float maxZ = nearClip + clipRange; + + float range = maxZ - minZ; + float ratio = maxZ / minZ; + constexpr float cascadeSplitLambda = 0.95f; + for (uint32 i = 0; i < NUM_CASCADES; ++i) { + cascades[i].shadowMaps = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_D32_SFLOAT, + .width = cascadeDim, + .height = cascadeDim, + .elements = (uint32)scene->getLightEnvironment()->getNumDirectionalLights(), + .usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, + .name = "ShadowMapCascade", + }); + cascades[i].views.clear(); + for (uint32 j = 0; j < cascades[i].shadowMaps->getNumLayers(); ++j) { + cascades[i].views.add(cascades[i].shadowMaps->createTextureView(0, 1, j, 1)); + } + cascadeDim /= 2; + float p = (i + 1) / static_cast(NUM_CASCADES); + float log = minZ * std::pow(ratio, p); + float uniform = minZ + range * p; + float d = cascadeSplitLambda * (log - uniform) + uniform; + cascadeSplits[i] = (d - nearClip) / clipRange; + } + + // call this to update view params member, ignore descriptor set + updateViewParameters(camera, transform); + Array frustumCorners = { + Vector(-1.0f, 1.0f, 0.0f), Vector(1.0f, 1.0f, 0.0f), Vector(1.0f, -1.0f, 0.0f), Vector(-1.0f, -1.0f, 0.0f), + Vector(-1.0f, 1.0f, 1.0f), Vector(1.0f, 1.0f, 1.0f), Vector(1.0f, -1.0f, 1.0f), Vector(-1.0f, -1.0f, 1.0f), + }; + + for (auto& c : frustumCorners) { + Vector4 invCorner = viewParams.inverseViewProjectionMatrix * Vector4(c, 1); + c = invCorner / invCorner.w; + } + for (uint32 s = 0; s < scene->getLightEnvironment()->getNumDirectionalLights(); ++s) { + float lastSplitDist = 0.0; + for (uint32 i = 0; i < NUM_CASCADES; ++i) { + float splitDist = cascadeSplits[i]; + + Array cascadeCorners(8); + for (uint32 j = 0; j < 4; j++) { + Vector dist = frustumCorners[j + 4] - frustumCorners[j]; + cascadeCorners[j + 4] = frustumCorners[j] + (dist * splitDist); + cascadeCorners[j] = frustumCorners[j] + (dist * lastSplitDist); + } + + Vector frustumCenter = Vector(0); + for (uint32 j = 0; j < 8; j++) { + frustumCenter += cascadeCorners[j]; + } + frustumCenter /= 8.0f; + + float radius = 0.0f; + for (uint j = 0; j < 8; j++) { + float distance = glm::length(cascadeCorners[j] - frustumCenter); + radius = glm::max(radius, distance); + } + radius = std::ceil(radius * 16.0f) / 16.0f; + + Vector maxExtents = Vector(radius); + Vector minExtents = -maxExtents; + + Vector lightDir = glm::normalize(scene->getLightEnvironment()->getDirectionalLight(s).direction); + Matrix4 viewMatrix = glm::lookAt(frustumCenter - lightDir * -minExtents.z, frustumCenter, Vector(0, 1, 0)); + Matrix4 projectionMatrix = + glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, 0.0f, maxExtents.z - minExtents.z); + Matrix4 viewProjectionMatrix = projectionMatrix * viewMatrix; + viewParams.viewMatrix = viewMatrix; + viewParams.inverseViewMatrix = glm::inverse(viewMatrix); + viewParams.projectionMatrix = projectionMatrix; + viewParams.inverseProjection = glm::inverse(projectionMatrix); + viewParams.viewProjectionMatrix = viewProjectionMatrix; + viewParams.inverseViewProjectionMatrix = glm::inverse(viewProjectionMatrix); + viewParams.screenDimensions = Vector2(maxExtents.x - minExtents.x, maxExtents.y - minExtents.y); + viewParams.invScreenDimensions = 1.0f / viewParams.screenDimensions; + cascades[i].viewParams.add(createViewParamsSet()); + } + } +} void ShadowPass::render() { graphics->beginDebugRegion("ShadowPass"); Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("ShadowPass"); permutation.setDepthCulling(true); permutation.setPositionOnly(true); - const auto& shadowMaps = scene->getLightEnvironment()->getShadowMaps(); - for (uint32 shadowIndex = 0; shadowIndex < scene->getLightEnvironment()->getNumDirectionalLights(); ++shadowIndex) { - Array commands; - renderPass = graphics->createRenderPass( - Gfx::RenderTargetLayout{ - .depthAttachment = Gfx::RenderTargetAttachment(shadowMaps[shadowIndex]->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED, - Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE), + for (uint32 c = 0; c < NUM_CASCADES; ++c) { + graphics->beginDebugRegion("Cascade"); + for (uint32 shadowIndex = 0; shadowIndex < cascades[c].shadowMaps->getNumLayers(); ++shadowIndex) { + Array commands; + renderPass = graphics->createRenderPass( + Gfx::RenderTargetLayout{ + .depthAttachment = Gfx::RenderTargetAttachment( + cascades[c].views[shadowIndex], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, + Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE), - }, - { - Gfx::SubPassDependency{ - .srcSubpass = ~0U, - .dstSubpass = 0, - .srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - .dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, }, - Gfx::SubPassDependency{ - .srcSubpass = 0, - .dstSubpass = ~0U, - .srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - .srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - .dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + { + Gfx::SubPassDependency{ + .srcSubpass = ~0U, + .dstSubpass = 0, + .srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + }, + Gfx::SubPassDependency{ + .srcSubpass = 0, + .dstSubpass = ~0U, + .srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + .srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + }, }, - }, - { - .size = {shadowMaps[shadowIndex]->getWidth(), shadowMaps[shadowIndex]->getHeight()}, - .offset = {0, 0}, - }, - "Shadow"); - Component::Camera lightCamera = Component::Camera{ - .nearPlane = -100.f, - .farPlane = 100.0f, - }; - Gfx::PDescriptorSet viewParamsSet = createViewParamsSet(lightCamera, scene->getLightEnvironment()->getDirectionalTransform(shadowIndex)); - graphics->beginRenderPass(renderPass); - for (VertexData* vertexData : VertexData::getList()) { - permutation.setVertexData(vertexData->getTypeName()); - Gfx::PermutationId id(permutation); + { + .size = {cascades[c].shadowMaps->getWidth(), cascades[c].shadowMaps->getHeight()}, + .offset = {0, 0}, + }, + "Shadow"); + graphics->beginRenderPass(renderPass); + for (VertexData* vertexData : VertexData::getList()) { + permutation.setVertexData(vertexData->getTypeName()); + Gfx::PermutationId id(permutation); - Gfx::ORenderCommand command = graphics->createRenderCommand("ShadowRender"); - command->setViewport(shadowViewport); + Gfx::ORenderCommand command = graphics->createRenderCommand("ShadowRender"); + command->setViewport(shadowViewport); - const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); - constexpr float depthBiasConstant = -1.25f; - constexpr float depthBiasSlope = -1.75f; - if (graphics->supportMeshShading()) { - Gfx::MeshPipelineCreateInfo pipelineInfo = { - .taskShader = collection->taskShader, - .meshShader = collection->meshShader, - .fragmentShader = collection->fragmentShader, - .renderPass = renderPass, - .pipelineLayout = collection->pipelineLayout, - .rasterizationState = - { - .cullMode = Gfx::SE_CULL_MODE_FRONT_BIT, - .depthBiasEnable = true, - .depthBiasConstantFactor = depthBiasConstant, - .depthBiasSlopeFactor = depthBiasSlope, - }, + const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); + constexpr float depthBiasConstant = -1.25f; + constexpr float depthBiasSlope = -1.75f; + if (graphics->supportMeshShading()) { + Gfx::MeshPipelineCreateInfo pipelineInfo = { + .taskShader = collection->taskShader, + .meshShader = collection->meshShader, + .fragmentShader = collection->fragmentShader, + .renderPass = renderPass, + .pipelineLayout = collection->pipelineLayout, + .rasterizationState = + { + .cullMode = Gfx::SE_CULL_MODE_FRONT_BIT, + .depthBiasEnable = true, + .depthBiasConstantFactor = depthBiasConstant, + .depthBiasSlopeFactor = depthBiasSlope, + }, + }; + Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); + command->bindPipeline(pipeline); + } else { + Gfx::LegacyPipelineCreateInfo pipelineInfo = { + .vertexShader = collection->vertexShader, + .fragmentShader = collection->fragmentShader, + .renderPass = renderPass, + .pipelineLayout = collection->pipelineLayout, + .rasterizationState = + { + .cullMode = Gfx::SE_CULL_MODE_FRONT_BIT, + .depthBiasEnable = true, + .depthBiasConstantFactor = depthBiasConstant, + .depthBiasSlopeFactor = depthBiasSlope, + }, + }; + Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); + command->bindPipeline(pipeline); + } + command->bindDescriptor({cascades[c].viewParams[shadowIndex], vertexData->getVertexDataSet(), vertexData->getInstanceDataSet()}); + VertexData::DrawCallOffsets offsets = { + .instanceOffset = 0, }; - Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); - command->bindPipeline(pipeline); - } else { - Gfx::LegacyPipelineCreateInfo pipelineInfo = { - .vertexShader = collection->vertexShader, - .fragmentShader = collection->fragmentShader, - .renderPass = renderPass, - .pipelineLayout = collection->pipelineLayout, - .rasterizationState = - { - .cullMode = Gfx::SE_CULL_MODE_FRONT_BIT, - .depthBiasEnable = true, - .depthBiasConstantFactor = depthBiasConstant, - .depthBiasSlopeFactor = depthBiasSlope, - }, - }; - Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); - command->bindPipeline(pipeline); - } - command->bindDescriptor({viewParamsSet, vertexData->getVertexDataSet(), vertexData->getInstanceDataSet()}); - VertexData::DrawCallOffsets offsets = { - .instanceOffset = 0, - }; - command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, - sizeof(VertexData::DrawCallOffsets), &offsets); - if (graphics->supportMeshShading()) { - command->drawMesh((uint32)vertexData->getNumInstances(), 1, 1); - } else { - const auto& materials = vertexData->getMaterialData(); - for (const auto& materialData : materials) { - // material not used for any active meshes, skip - if (materialData.instances.size() == 0) - continue; - for (const auto& drawCall : materialData.instances) { - command->bindIndexBuffer(vertexData->getIndexBuffer()); - uint32 inst = drawCall.offsets.instanceOffset; - for (const auto& meshData : drawCall.instanceMeshData) { - // all meshlets of a mesh share the same indices offset - command->drawIndexed(meshData.indicesRange.size, 1, meshData.indicesRange.offset, - vertexData->getIndicesOffset(meshData.meshletRange.offset), inst++); + command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, + sizeof(VertexData::DrawCallOffsets), &offsets); + if (graphics->supportMeshShading()) { + command->drawMesh((uint32)vertexData->getNumInstances(), 1, 1); + } else { + const auto& materials = vertexData->getMaterialData(); + for (const auto& materialData : materials) { + // material not used for any active meshes, skip + if (materialData.instances.size() == 0) + continue; + for (const auto& drawCall : materialData.instances) { + command->bindIndexBuffer(vertexData->getIndexBuffer()); + uint32 inst = drawCall.offsets.instanceOffset; + for (const auto& meshData : drawCall.instanceMeshData) { + // all meshlets of a mesh share the same indices offset + command->drawIndexed(meshData.indicesRange.size, 1, meshData.indicesRange.offset, + vertexData->getIndicesOffset(meshData.meshletRange.offset), inst++); + } } } } + commands.add(std::move(command)); } - commands.add(std::move(command)); + graphics->executeCommands(std::move(commands)); + graphics->endRenderPass(); + graphics->waitDeviceIdle(); } - graphics->executeCommands(std::move(commands)); - graphics->endRenderPass(); - graphics->waitDeviceIdle(); + graphics->endDebugRegion(); } graphics->endDebugRegion(); } @@ -168,7 +260,7 @@ void ShadowPass::endFrame() {} void ShadowPass::publishOutputs() { shadowViewport = graphics->createViewport(nullptr, ViewportCreateInfo{.dimensions = { - .size = {8192, 8192}, + .size = {SHADOW_MAP_SIZE, SHADOW_MAP_SIZE}, .offset = {0, 0}, }, .fieldOfView = 0, diff --git a/src/Engine/Graphics/RenderPass/ShadowPass.h b/src/Engine/Graphics/RenderPass/ShadowPass.h index 14b8e28..e40e437 100644 --- a/src/Engine/Graphics/RenderPass/ShadowPass.h +++ b/src/Engine/Graphics/RenderPass/ShadowPass.h @@ -1,7 +1,12 @@ #pragma once +#include "Graphics/Buffer.h" +#include "Graphics/Descriptor.h" #include "RenderPass.h" namespace Seele { + +static constexpr uint64 SHADOW_MAP_SIZE = 8192; + class ShadowPass : public RenderPass { public: ShadowPass(Gfx::PGraphics graphics, PScene scene); @@ -15,6 +20,13 @@ class ShadowPass : public RenderPass { virtual void createRenderPass() override; private: AABB cameraFrustumBox; + static constexpr uint64 NUM_CASCADES = 4; + struct Cascade { + Gfx::OTexture2D shadowMaps; + Array views; + Array viewParams; + }; + StaticArray cascades; Gfx::OPipelineLayout shadowLayout; Gfx::PShaderBuffer cullingBuffer; Gfx::OViewport shadowViewport; diff --git a/src/Engine/Graphics/RenderPass/ToneMappingPass.cpp b/src/Engine/Graphics/RenderPass/ToneMappingPass.cpp index c1a74aa..19f704c 100644 --- a/src/Engine/Graphics/RenderPass/ToneMappingPass.cpp +++ b/src/Engine/Graphics/RenderPass/ToneMappingPass.cpp @@ -124,7 +124,8 @@ ToneMappingPass::ToneMappingPass(Gfx::PGraphics graphics) : RenderPass(graphics) ToneMappingPass::~ToneMappingPass() {} void ToneMappingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); } void ToneMappingPass::render() { diff --git a/src/Engine/Graphics/RenderPass/UIPass.cpp b/src/Engine/Graphics/RenderPass/UIPass.cpp index 2f34c5c..b2e7271 100644 --- a/src/Engine/Graphics/RenderPass/UIPass.cpp +++ b/src/Engine/Graphics/RenderPass/UIPass.cpp @@ -54,7 +54,8 @@ UIPass::UIPass(Gfx::PGraphics graphics, UI::PSystem system) : RenderPass(graphic UIPass::~UIPass() {} void UIPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); glyphs.clear(); usedTextures.clear(); elements.clear(); diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp index 4c3c032..e98721f 100644 --- a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp @@ -8,7 +8,8 @@ VisibilityPass::VisibilityPass(Gfx::PGraphics graphics) : RenderPass(graphics) { VisibilityPass::~VisibilityPass() {} void VisibilityPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { - viewParamsSet = createViewParamsSet(cam, transform); + updateViewParameters(cam, transform); + viewParamsSet = createViewParamsSet(); cullingBuffer->rotateBuffer(VertexData::getMeshletCount() * sizeof(VertexData::MeshletCullingInfo), true); } diff --git a/src/Engine/Scene/LightEnvironment.cpp b/src/Engine/Scene/LightEnvironment.cpp index 784f10f..b7bc208 100644 --- a/src/Engine/Scene/LightEnvironment.cpp +++ b/src/Engine/Scene/LightEnvironment.cpp @@ -82,34 +82,11 @@ void LightEnvironment::reset() { } void LightEnvironment::addDirectionalLight(const Component::DirectionalLight& dirLight, const Component::Transform& transform) { - Vector eyePos = transform.getPosition(); - Vector lookAt = eyePos + transform.getForward(); - Matrix4 cameraMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0)); - Matrix4 correctionMatrix = Matrix4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 / 2.f, 0, 0, 0, 1 / 2.f, 1); dirs.add(ShaderDirectionalLight{ .color = Vector4(dirLight.color, dirLight.intensity), .direction = Vector4(transform.getForward(), 0), - .lightSpaceMatrix = correctionMatrix * glm::ortho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f) * cameraMatrix, }); directionalTransforms.add(transform); - if (shadowMaps.size() < dirs.size()) { - shadowMaps.add(graphics->createTexture2D(TextureCreateInfo{ - .format = Gfx::SE_FORMAT_D32_SFLOAT, - .width = 8192, - .height = 8192, - .elements = (uint32)dirs.size(), - .usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, - .name = "ShadowMap", - })); - shadowMaps.back()->changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); - shadowSamplers.add(graphics->createSampler(SamplerCreateInfo{ - .addressModeU = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - .addressModeV = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - .addressModeW = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - .name = "ShadowSampler", - })); - } } void LightEnvironment::addPointLight(const Component::PointLight& pointLight, const Component::Transform& transform) { @@ -136,8 +113,6 @@ void LightEnvironment::commit() { uint32 numDirectionalLights = (uint32)dirs.size(); set->updateConstants("numDirectionalLights", 0, &numDirectionalLights); set->updateBuffer("directionalLights", 0, directionalLights); - set->updateTexture("shadowMap", 0, shadowMaps[0]->getDefaultView()); - set->updateSampler("shadowSampler", 0, Gfx::PSampler(shadowSamplers[0])); set->updateConstants("numPointLights", 0, &numPointLights); set->updateBuffer("pointLights", 0, pointLights); set->updateTexture("irradianceMap", 0, environment->getIrradianceMap()->getDefaultView()); diff --git a/src/Engine/Scene/LightEnvironment.h b/src/Engine/Scene/LightEnvironment.h index 31de620..4546063 100644 --- a/src/Engine/Scene/LightEnvironment.h +++ b/src/Engine/Scene/LightEnvironment.h @@ -4,7 +4,6 @@ #include "Component/Transform.h" #include "Graphics/Buffer.h" #include "Graphics/Descriptor.h" -#include "Graphics/Texture.h" namespace Seele { DECLARE_REF(EnvironmentMapAsset) @@ -13,7 +12,6 @@ class LightEnvironment { struct ShaderDirectionalLight { Vector4 color; Vector4 direction; - Matrix4 lightSpaceMatrix; }; struct ShaderPointLight { Vector4 position_WS; @@ -31,12 +29,10 @@ class LightEnvironment { Gfx::PDescriptorSet getDescriptorSet(); PEnvironmentMapAsset getEnvironmentMap() { return environment; } uint64 getNumDirectionalLights() const { return dirs.size(); } - const Array& getShadowMaps() const { return shadowMaps; } private: Gfx::PGraphics graphics; Gfx::OShaderBuffer directionalLights; - Array shadowMaps; Array shadowSamplers; Gfx::OShaderBuffer pointLights; Array dirs;