diff --git a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp index da86e88a..38f9478a 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -62,13 +62,14 @@ void VkSceneRenderer::Init() void VkSceneRenderer::BeginScene(RenderContext inContext) { + GPUResources::Get().ClearCameras(); + Context.CommandBuffer = inContext.CommandBuffer; Context.CurrentScene = inContext.CurrentScene; Context.CameraID = inContext.CameraID; // Collect all global transform of things we will render - BuildMatrixBuffer(); - UpdateTransformBuffer(); + auto& cmd = Context.CommandBuffer; auto& scene = Context.CurrentScene; @@ -115,6 +116,7 @@ void VkSceneRenderer::BeginScene(RenderContext inContext) } // Build light view list + { auto view = scene->m_Registry.view(); for (auto e : view) @@ -136,13 +138,21 @@ void VkSceneRenderer::BeginScene(RenderContext inContext) } } } + + BuildMatrixBuffer(); + UpdateTransformBuffer(); + { auto view = scene->m_Registry.view(); for (auto e : view) { auto [transform, light] = view.get(e); auto cam = GPUResources::Get().GetCamera(inContext.CameraID); - light.CalculateViewProjection(cam.View, cam.Projection); + + if (light.Type == LightType::Directional) + { + light.CalculateViewProjection(cam.View, cam.Projection); + } } } @@ -154,6 +164,7 @@ void VkSceneRenderer::BeginScene(RenderContext inContext) passCtx.commandBuffer = inContext.CommandBuffer; passCtx.resolution = Context.Size; + auto view = scene->m_Registry.view(); for (auto e : view) { @@ -166,10 +177,13 @@ void VkSceneRenderer::BeginScene(RenderContext inContext) passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(light.m_LightViews[0].CameraID); ShadowPipeline.Execute(passCtx); + + light.LightMapID = ShadowPipeline.GetRenderPass("Shadow").GetDepthAttachment().Image->GetID(); + //passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(light.m_LightViews[0].CameraID); for (int i = 0; i < CSM_AMOUNT; i++) { - + //ShadowPipeline.Execute(passCtx); } } @@ -192,11 +206,12 @@ void VkSceneRenderer::EndScene() auto& selectedOutput = shading; selectedOutput.Image->TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); vk.DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + shadow.Image->TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VulkanUtil::CopyImageToImage(cmd, selectedOutput.Image->GetImage(), vk.GetDrawImage()->GetImage(), selectedOutput.Image->GetSize(), vk.DrawImage->GetSize()); vk.DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); selectedOutput.Image->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); - GPUResources::Get().ClearCameras(); + } void VkSceneRenderer::CreateBuffers() @@ -835,6 +850,9 @@ void VkSceneRenderer::BuildMatrixBuffer() light.type = lightComp.Type; light.color = Vector4(lightComp.Color * lightComp.Strength, 1.0); light.castShadow = lightComp.CastShadows; + light.transformId = GPUResources::Get().GetBindlessCameraID(lightComp.m_LightViews[0].CameraID); + light.shadowMapTextureId = GPUResources::Get().GetBindlessTextureID(lightComp.LightMapID); + allLights[currentIndex] = light; currentIndex++; diff --git a/Nuake/src/Scene/Components/LightComponent.h b/Nuake/src/Scene/Components/LightComponent.h index 045fc17a..3c3b4c73 100644 --- a/Nuake/src/Scene/Components/LightComponent.h +++ b/Nuake/src/Scene/Components/LightComponent.h @@ -51,9 +51,11 @@ namespace Nuake float mCascadeSplits[CSM_AMOUNT]; public: + LightComponent(); ~LightComponent() = default; + UUID LightMapID; void SetCastShadows(bool toggle); Matrix4 GetProjection(); @@ -62,13 +64,18 @@ namespace Nuake void CalculateViewProjection(glm::mat4& view, const glm::mat4& projection) { Matrix4 normalProj = projection; + + // Convert to normal Z + //normalProj[2][2] = -normalProj[2][2]; // Restore the sign + //normalProj[2][3] = -normalProj[2][3]; // Restore the far depth term sign + //normalProj *= -1.0f; glm::mat4 viewProjection = normalProj * view; glm::mat4 inverseViewProjection = glm::inverse(viewProjection); // TODO: Automate this const float nearClip = 0.01f; - const float farClip = 800.0f; + const float farClip = 200.0f; const float clipRange = farClip - nearClip; const float mCascadeNearPlaneOffset = -100.0f; @@ -100,16 +107,16 @@ namespace Nuake glm::vec4 frustumCorners[8] = { //Near face - { 1.0f, 1.0f, -1.0f, 1.0f }, - { -1.0f, 1.0f, -1.0f, 1.0f }, - { 1.0f, -1.0f, -1.0f, 1.0f }, - { -1.0f, -1.0f, -1.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 1.0f }, + { -1.0f, -1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 1.0f }, - //Far face - { 1.0f, 1.0f, 1.0f, 1.0f }, - { -1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, -1.0f, 1.0f, 1.0f }, - { -1.0f, -1.0f, 1.0f, 1.0f }, + // Far face (z = 0.0) + { 1.0f, -1.0f, 0.0f, 1.0f }, + { -1.0f, -1.0f, 0.0f, 1.0f }, + { 1.0f, 1.0f, 0.0f, 1.0f }, + { -1.0f, 1.0f, 0.0f, 1.0f }, }; // Project frustum corners into world space from clip space @@ -144,19 +151,41 @@ namespace Nuake // Calculate the view and projection matrix glm::vec3 lightDir = -this->Direction; - glm::mat4 lightViewMatrix = glm::lookAt(frustumCenter - lightDir * -minExtents.z, frustumCenter, glm::vec3(0.0f, 0.0f, 1.0f)); + lightDir.y *= -1.0f; + lightDir.x *= -1.0f; + lightDir.z *= -1.0f; + glm::mat4 lightViewMatrix = glm::lookAt(frustumCenter - lightDir * -minExtents.z, frustumCenter, glm::vec3(0.0f, 1.0, 0.0f)); glm::mat4 lightProjectionMatrix = glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, 0.0f + mCascadeNearPlaneOffset, maxExtents.z - minExtents.z + mCascadeFarPlaneOffset); - + + //lightDir.y *= -1.0f; + // + //glm::mat4 lightViewMatrix = glm::lookAt( + // frustumCenter + lightDir * -minExtents.z, + // frustumCenter, + // glm::vec3(0.0f, 1.0f, 0.0f) + //); + //glm::mat4 lightProjectionMatrix = glm::ortho( + // minExtents.x, maxExtents.x, + // minExtents.y, maxExtents.y, // Y-flip for Vulkan + // 0.0f + mCascadeNearPlaneOffset, + // maxExtents.z - minExtents.z + mCascadeFarPlaneOffset + //); + //lightProjectionMatrix = glm::ortho(-25.0f, 25.0f, -25.0f, 25.0f, 100.0f, -100.0f); // Offset to texel space to avoid shimmering ->(https://stackoverflow.com/questions/33499053/cascaded-shadow-map-shimmering) glm::mat4 shadowMatrix = lightProjectionMatrix * lightViewMatrix; - const float ShadowMapResolution = 4096; - glm::vec4 shadowOrigin = (shadowMatrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) * ShadowMapResolution / 2.0f; - glm::vec4 roundedOrigin = glm::round(shadowOrigin); - glm::vec4 roundOffset = roundedOrigin - shadowOrigin; - roundOffset = roundOffset * 2.0f / ShadowMapResolution; - roundOffset.z = 0.0f; - roundOffset.w = 0.0f; - lightProjectionMatrix[3] += roundOffset; + //const float ShadowMapResolution = 4096; + //glm::vec4 shadowOrigin = (shadowMatrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) * ShadowMapResolution / 2.0f; + //glm::vec4 roundedOrigin = glm::round(shadowOrigin); + //glm::vec4 roundOffset = roundedOrigin - shadowOrigin; + //roundOffset = roundOffset * 2.0f / ShadowMapResolution; + //roundOffset.z = 0.0f; + //roundOffset.w = 0.0f; + //lightProjectionMatrix[3] += roundOffset; + float near_plane = 0.01f, far_plane = 100.0f; + //glm::mat4 lightProjection = glm::ortho(-25.0f, 25.0f, -25.0f, 25.0f, 25.0f, -25.0f); + + //lightProjectionMatrix[2][2] = -lightProjectionMatrix[2][2]; // Flip the sign + //lightProjectionMatrix[2][3] = -lightProjectionMatrix[2][3]; // Flip the sign of the far depth term m_LightViews[cascade].View = lightViewMatrix; m_LightViews[cascade].Proj = lightProjectionMatrix; @@ -166,6 +195,8 @@ namespace Nuake mViewProjections[cascade] = shadowMatrix; lastSplitDist = mCascadeSplits[cascade]; + + // -----------------------Debug only----------------------- // RendererDebug::BeginScene(viewProjection); // RendererDebug::SubmitCameraFrustum(frustumCorners, glm::mat4(1.0f), GetColor(cascade)); // Draws the divided camera frustums diff --git a/Resources/Shaders/Vulkan/shading.frag b/Resources/Shaders/Vulkan/shading.frag index 74a3904b..427ef4ff 100644 --- a/Resources/Shaders/Vulkan/shading.frag +++ b/Resources/Shaders/Vulkan/shading.frag @@ -150,6 +150,32 @@ float3 fresnelSchlickRoughness(float cosTheta, float3 F0, float roughness) return F0 + (max(float3(roughnessTerm, roughnessTerm, roughnessTerm), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0); } +float linearDepth(float z, float near, float far) { + return near * far / (far - z * (far - near)); +} + +float ShadowCalculation(Light light, float3 fragPos, float3 normal) +{ + CameraView camView = cameras[pushConstants.CameraID]; + float depth = length(fragPos - camView.Position); + + CameraView lightView = cameras[light.transformId]; + int shadowMap = light.shadowMapTextureId; + float4 fragLightSpace = mul(lightView.Projection, mul(lightView.View, float4(fragPos, 1.0))); + float3 projCoords = fragLightSpace.xyz / fragLightSpace.w; + projCoords.xy = projCoords.xy * 0.5 + 0.5; + + if (projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) { + return 1.0; + } + + //projCoords.y = 1.0 - projCoords.y; + float currentDepth = projCoords.z; + float bias = max(0.005 * (1.0 - dot(normal, light.direction)), 0.0005); + float shadowMapDepth = textures[light.shadowMapTextureId].Sample(mySampler, projCoords.xy).r; + + return (currentDepth > shadowMapDepth);//> 0.0 ? 1.0 : 0.0; +} PSOutput main(PSInput input) { PSOutput output; @@ -193,6 +219,13 @@ PSOutput main(PSInput input) const float PI = 3.141592653589793f; float3 Lo = float3(0.0, 0.0, 0.0); + float shadow = 1.0f; + + if(foundDirectional == false) + { + shadow = 1.0f; + } + //Directional if(foundDirectional) { @@ -200,6 +233,13 @@ PSOutput main(PSInput input) float3 L = normalize(light.direction); float attenuation = 1.0f; + if(light.castShadow == true) + { + shadow *= ShadowCalculation(light, worldPos, N); + //output.oColor0 = float4(albedo * 0.1 + float3(shadow, shadow, shadow), 1); + //return output; + } + // TODO: Shadow float3 radiance = light.color.rgb * attenuation; float3 H = normalize(V + L); @@ -216,7 +256,7 @@ PSOutput main(PSInput input) kD *= 1.0 - metallic; float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; + Lo += (kD * albedo / PI + specular) * radiance * NdotL * shadow; } // other lights diff --git a/Resources/Shaders/Vulkan/shadow.vert b/Resources/Shaders/Vulkan/shadow.vert index de8c15d8..8acae92c 100644 --- a/Resources/Shaders/Vulkan/shadow.vert +++ b/Resources/Shaders/Vulkan/shadow.vert @@ -73,6 +73,20 @@ struct VSOutput { float4 Position : SV_Position; }; +float LinearizeDepth(float depth, float nearPlane, float farPlane, bool reverseDepth) +{ + if (reverseDepth) + { + // Reverse depth (near plane = 1.0, far plane = 0.0) + return nearPlane * farPlane / lerp(farPlane, nearPlane, depth); + } + else + { + // Standard depth (near plane = 0.0, far plane = 1.0) + return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane)); + } +} + // Main vertex shader VSOutput main(uint vertexIndex : SV_VertexID) { @@ -89,5 +103,6 @@ VSOutput main(uint vertexIndex : SV_VertexID) // Output the position of each vertex output.Position = mul(camView.Projection, mul(camView.View,mul(modelData.model, float4(v.position, 1.0f)))); + //output.Position.z = LinearizeDepth(output.Position.z, camView.Near, camView.Far, false); return output; } \ No newline at end of file