diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index 1679326bc..679555141 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -337,14 +337,14 @@ void RenderTools::ComputePitch(PixelFormat format, int32 width, int32 height, ui case PixelFormat::ASTC_8x8_UNorm_sRGB: case PixelFormat::ASTC_10x10_UNorm: case PixelFormat::ASTC_10x10_UNorm_sRGB: - { - const int32 blockSize = PixelFormatExtensions::ComputeBlockSize(format); - uint32 nbw = Math::Max(1, Math::DivideAndRoundUp(width, blockSize)); - uint32 nbh = Math::Max(1, Math::DivideAndRoundUp(height, blockSize)); - rowPitch = nbw * 16; // All ASTC blocks use 128 bits - slicePitch = rowPitch * nbh; - } - break; + { + const int32 blockSize = PixelFormatExtensions::ComputeBlockSize(format); + uint32 nbw = Math::Max(1, Math::DivideAndRoundUp(width, blockSize)); + uint32 nbh = Math::Max(1, Math::DivideAndRoundUp(height, blockSize)); + rowPitch = nbw * 16; // All ASTC blocks use 128 bits + slicePitch = rowPitch * nbh; + } + break; case PixelFormat::R8G8_B8G8_UNorm: case PixelFormat::G8R8_G8B8_UNorm: ASSERT(PixelFormatExtensions::IsPacked(format)); @@ -590,7 +590,7 @@ void RenderTools::CalculateTangentFrame(FloatR10G10B10A2& resultNormal, FloatR10 void RenderTools::ComputeSphereModelDrawMatrix(const RenderView& view, const Float3& position, float radius, Matrix& resultWorld, bool& resultIsViewInside) { // Construct world matrix - constexpr float sphereModelScale = 0.0202f; // Manually tweaked for 'Engine/Models/Sphere' + constexpr float sphereModelScale = 0.0205f; // Manually tweaked for 'Engine/Models/Sphere' with some slack const float scaling = radius * sphereModelScale; resultWorld = Matrix::Identity; resultWorld.M11 = scaling; @@ -601,10 +601,7 @@ void RenderTools::ComputeSphereModelDrawMatrix(const RenderView& view, const Flo resultWorld.M43 = position.Z; // Check if view is inside the sphere - float viewToCenter = Float3::Distance(view.Position, position); - //if (radius + viewToCenter > view.Far) - // radius = view.Far - viewToCenter; // Clamp radius - resultIsViewInside = viewToCenter - radius < 5.0f; // Manually tweaked bias + resultIsViewInside = Float3::DistanceSquared(view.Position, position) < Math::Square(radius * 1.1f); // Manually tweaked bias } int32 MipLevelsCount(int32 width, bool useMipLevels) diff --git a/Source/Engine/Renderer/LightPass.cpp b/Source/Engine/Renderer/LightPass.cpp index 72fcc5a0c..93ad7a4a1 100644 --- a/Source/Engine/Renderer/LightPass.cpp +++ b/Source/Engine/Renderer/LightPass.cpp @@ -31,20 +31,18 @@ bool LightPass::Init() { // Create pipeline states _psLightDir.CreatePipelineStates(); - _psLightPointNormal.CreatePipelineStates(); - _psLightPointInverted.CreatePipelineStates(); - _psLightSpotNormal.CreatePipelineStates(); - _psLightSpotInverted.CreatePipelineStates(); - _psLightSkyNormal = GPUDevice::Instance->CreatePipelineState(); - _psLightSkyInverted = GPUDevice::Instance->CreatePipelineState(); + _psLightPoint.CreatePipelineStates(); + _psLightPointInside.CreatePipelineStates(); + _psLightSpot.CreatePipelineStates(); + _psLightSpotInside.CreatePipelineStates(); + _psLightSky = GPUDevice::Instance->CreatePipelineState(); + _psLightSkyInside = GPUDevice::Instance->CreatePipelineState(); // Load assets _shader = Content::LoadAsyncInternal(TEXT("Shaders/Lights")); _sphereModel = Content::LoadAsyncInternal(TEXT("Engine/Models/Sphere")); if (_shader == nullptr || _sphereModel == nullptr) - { return true; - } #if COMPILE_WITH_DEV_ENV _shader.Get()->OnReloading.Bind(this); @@ -90,46 +88,50 @@ bool LightPass::setupResources() if (_psLightDir.Create(psDesc, shader, "PS_Directional")) return true; } - if (!_psLightPointNormal.IsValid() || !_psLightPointInverted.IsValid()) + if (!_psLightPoint.IsValid()) { psDesc = GPUPipelineState::Description::DefaultNoDepth; psDesc.BlendMode = BlendingMode::Add; psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB; psDesc.VS = shader->GetVS("VS_Model"); - psDesc.CullMode = CullMode::TwoSided; - if (_psLightPointInverted.Create(psDesc, shader, "PS_Point")) - return true; - psDesc.CullMode = CullMode::Normal; psDesc.DepthEnable = true; - if (_psLightPointNormal.Create(psDesc, shader, "PS_Point")) + psDesc.CullMode = CullMode::Normal; + if (_psLightPoint.Create(psDesc, shader, "PS_Point")) + return true; + psDesc.DepthFunc = ComparisonFunc::Greater; + psDesc.CullMode = CullMode::Inverted; + if (_psLightPointInside.Create(psDesc, shader, "PS_Point")) return true; } - if (!_psLightSpotNormal.IsValid() || !_psLightSpotInverted.IsValid()) + if (!_psLightSpot.IsValid()) { psDesc = GPUPipelineState::Description::DefaultNoDepth; psDesc.BlendMode = BlendingMode::Add; psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB; psDesc.VS = shader->GetVS("VS_Model"); - psDesc.CullMode = CullMode::TwoSided; - if (_psLightSpotInverted.Create(psDesc, shader, "PS_Spot")) - return true; - psDesc.CullMode = CullMode::Normal; psDesc.DepthEnable = true; - if (_psLightSpotNormal.Create(psDesc, shader, "PS_Spot")) + psDesc.CullMode = CullMode::Normal; + if (_psLightSpot.Create(psDesc, shader, "PS_Spot")) + return true; + psDesc.DepthFunc = ComparisonFunc::Greater; + psDesc.CullMode = CullMode::Inverted; + if (_psLightSpotInside.Create(psDesc, shader, "PS_Spot")) return true; } - if (!_psLightSkyNormal->IsValid() || !_psLightSkyInverted->IsValid()) + if (!_psLightSky->IsValid()) { psDesc = GPUPipelineState::Description::DefaultNoDepth; psDesc.BlendMode = BlendingMode::Add; psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB; - psDesc.CullMode = CullMode::Normal; psDesc.VS = shader->GetVS("VS_Model"); psDesc.PS = shader->GetPS("PS_Sky"); - if (_psLightSkyNormal->Init(psDesc)) + psDesc.DepthEnable = true; + psDesc.CullMode = CullMode::Normal; + if (_psLightSky->Init(psDesc)) return true; - psDesc.CullMode = CullMode::TwoSided; - if (_psLightSkyInverted->Init(psDesc)) + psDesc.DepthFunc = ComparisonFunc::Greater; + psDesc.CullMode = CullMode::Inverted; + if (_psLightSkyInside->Init(psDesc)) return true; } @@ -143,12 +145,12 @@ void LightPass::Dispose() // Cleanup _psLightDir.Delete(); - _psLightPointNormal.Delete(); - _psLightPointInverted.Delete(); - _psLightSpotNormal.Delete(); - _psLightSpotInverted.Delete(); - SAFE_DELETE_GPU_RESOURCE(_psLightSkyNormal); - SAFE_DELETE_GPU_RESOURCE(_psLightSkyInverted); + _psLightPoint.Delete(); + _psLightPointInside.Delete(); + _psLightSpot.Delete(); + _psLightSpotInside.Delete(); + SAFE_DELETE_GPU_RESOURCE(_psLightSky); + SAFE_DELETE_GPU_RESOURCE(_psLightSkyInside); SAFE_DELETE_GPU_RESOURCE(_psClearDiffuse); _sphereModel = nullptr; } @@ -298,7 +300,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV context->BindCB(0, cb0); context->BindCB(1, cb1); int32 permutationIndex = (disableSpecular ? 1 : 0) + (useIES ? 2 : 0); - context->SetState((isViewInside ? _psLightPointInverted : _psLightPointNormal).Get(permutationIndex)); + context->SetState((isViewInside ? _psLightPointInside : _psLightPoint).Get(permutationIndex)); sphereMesh.Render(context); } @@ -341,7 +343,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV context->BindCB(0, cb0); context->BindCB(1, cb1); int32 permutationIndex = (disableSpecular ? 1 : 0) + (useIES ? 2 : 0); - context->SetState((isViewInside ? _psLightSpotInverted : _psLightSpotNormal).Get(permutationIndex)); + context->SetState((isViewInside ? _psLightSpotInside : _psLightSpot).Get(permutationIndex)); sphereMesh.Render(context); } @@ -400,7 +402,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV context->UpdateCB(cb0, &perLight); context->BindCB(0, cb0); context->BindCB(1, cb1); - context->SetState(isViewInside ? _psLightSkyInverted : _psLightSkyNormal); + context->SetState(isViewInside ? _psLightSkyInside : _psLightSky); sphereMesh.Render(context); } diff --git a/Source/Engine/Renderer/LightPass.h b/Source/Engine/Renderer/LightPass.h index a399c7bfd..935052497 100644 --- a/Source/Engine/Renderer/LightPass.h +++ b/Source/Engine/Renderer/LightPass.h @@ -16,12 +16,12 @@ class LightPass : public RendererPass private: AssetReference _shader; GPUPipelineStatePermutationsPs<2> _psLightDir; - GPUPipelineStatePermutationsPs<4> _psLightPointNormal; - GPUPipelineStatePermutationsPs<4> _psLightPointInverted; - GPUPipelineStatePermutationsPs<4> _psLightSpotNormal; - GPUPipelineStatePermutationsPs<4> _psLightSpotInverted; - GPUPipelineState* _psLightSkyNormal = nullptr; - GPUPipelineState* _psLightSkyInverted = nullptr; + GPUPipelineStatePermutationsPs<4> _psLightPoint; + GPUPipelineStatePermutationsPs<4> _psLightPointInside; + GPUPipelineStatePermutationsPs<4> _psLightSpot; + GPUPipelineStatePermutationsPs<4> _psLightSpotInside; + GPUPipelineState* _psLightSky = nullptr; + GPUPipelineState* _psLightSkyInside = nullptr; GPUPipelineState* _psClearDiffuse = nullptr; AssetReference _sphereModel; PixelFormat _shadowMaskFormat; @@ -44,12 +44,12 @@ private: void OnShaderReloading(Asset* obj) { _psLightDir.Release(); - _psLightPointNormal.Release(); - _psLightPointInverted.Release(); - _psLightSpotNormal.Release(); - _psLightSpotInverted.Release(); - _psLightSkyNormal->ReleaseGPU(); - _psLightSkyInverted->ReleaseGPU(); + _psLightPoint.Release(); + _psLightPointInside.Release(); + _psLightSpot.Release(); + _psLightSpotInside.Release(); + _psLightSky->ReleaseGPU(); + _psLightSkyInside->ReleaseGPU(); invalidateResources(); } #endif diff --git a/Source/Engine/Renderer/ReflectionsPass.cpp b/Source/Engine/Renderer/ReflectionsPass.cpp index 3a548f8ab..4f362392f 100644 --- a/Source/Engine/Renderer/ReflectionsPass.cpp +++ b/Source/Engine/Renderer/ReflectionsPass.cpp @@ -13,6 +13,12 @@ #include "Engine/Graphics/RenderTargetPool.h" #include "Engine/Level/Actors/EnvironmentProbe.h" +PACK_STRUCT(struct Data { + ShaderEnvProbeData PData; + Matrix WVP; + ShaderGBufferData GBuffer; + }); + #if GENERATE_GF_CACHE // This code below (PreIntegratedGF namespace) is based on many Siggraph presentations about BRDF shading: @@ -239,13 +245,6 @@ namespace PreIntegratedGF class Model; -ReflectionsPass::ReflectionsPass() - : _psProbeNormal(nullptr) - , _psProbeInverted(nullptr) - , _psCombinePass(nullptr) -{ -} - String ReflectionsPass::ToString() const { return TEXT("ReflectionsPass"); @@ -254,15 +253,13 @@ String ReflectionsPass::ToString() const bool ReflectionsPass::Init() { #if GENERATE_GF_CACHE - // Generate cache PreIntegratedGF::Generate(); - #endif // Create pipeline states - _psProbeNormal = GPUDevice::Instance->CreatePipelineState(); - _psProbeInverted = GPUDevice::Instance->CreatePipelineState(); + _psProbe = GPUDevice::Instance->CreatePipelineState(); + _psProbeInside = GPUDevice::Instance->CreatePipelineState(); _psCombinePass = GPUDevice::Instance->CreatePipelineState(); // Load assets @@ -294,17 +291,19 @@ bool ReflectionsPass::setupResources() // Create pipeline stages GPUPipelineState::Description psDesc; - if (!_psProbeNormal->IsValid() || !_psProbeInverted->IsValid()) + if (!_psProbe->IsValid()) { psDesc = GPUPipelineState::Description::DefaultNoDepth; psDesc.BlendMode = BlendingMode::AlphaBlend; - psDesc.CullMode = CullMode::Normal; psDesc.VS = shader->GetVS("VS_Model"); psDesc.PS = shader->GetPS("PS_EnvProbe"); - if (_psProbeNormal->Init(psDesc)) + psDesc.CullMode = CullMode::Normal; + psDesc.DepthEnable = true; + if (_psProbe->Init(psDesc)) return true; - psDesc.CullMode = CullMode::TwoSided; - if (_psProbeInverted->Init(psDesc)) + psDesc.DepthFunc = ComparisonFunc::Greater; + psDesc.CullMode = CullMode::Inverted; + if (_psProbeInside->Init(psDesc)) return true; } psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle; @@ -326,8 +325,8 @@ void ReflectionsPass::Dispose() RendererPass::Dispose(); // Cleanup - SAFE_DELETE_GPU_RESOURCE(_psProbeNormal); - SAFE_DELETE_GPU_RESOURCE(_psProbeInverted); + SAFE_DELETE_GPU_RESOURCE(_psProbe); + SAFE_DELETE_GPU_RESOURCE(_psProbeInside); SAFE_DELETE_GPU_RESOURCE(_psCombinePass); _shader = nullptr; _sphereModel = nullptr; @@ -416,7 +415,7 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light context->UpdateCB(cb, &data); context->BindCB(0, cb); context->BindSR(4, probe.Texture); - context->SetState(isViewInside ? _psProbeInverted : _psProbeNormal); + context->SetState(isViewInside ? _psProbeInside : _psProbe); sphereMesh.Render(context); } diff --git a/Source/Engine/Renderer/ReflectionsPass.h b/Source/Engine/Renderer/ReflectionsPass.h index a88a4eec4..d41b83d49 100644 --- a/Source/Engine/Renderer/ReflectionsPass.h +++ b/Source/Engine/Renderer/ReflectionsPass.h @@ -16,30 +16,15 @@ class ReflectionsPass : public RendererPass { private: - - PACK_STRUCT(struct Data { - ShaderEnvProbeData PData; - Matrix WVP; - ShaderGBufferData GBuffer; - }); - AssetReference _shader; - GPUPipelineState* _psProbeNormal; - GPUPipelineState* _psProbeInverted; - GPUPipelineState* _psCombinePass; + GPUPipelineState* _psProbe = nullptr; + GPUPipelineState* _psProbeInside = nullptr; + GPUPipelineState* _psCombinePass = nullptr; AssetReference _sphereModel; AssetReference _preIntegratedGF; public: - - /// - /// Init - /// - ReflectionsPass(); - -public: - /// /// Perform reflections pass rendering for the input task. /// @@ -48,7 +33,6 @@ public: void Render(RenderContext& renderContext, GPUTextureView* lightBuffer); public: - // [RendererPass] String ToString() const override; bool Init() override; @@ -56,15 +40,14 @@ public: #if COMPILE_WITH_DEV_ENV void OnShaderReloading(Asset* obj) { - _psProbeNormal->ReleaseGPU(); - _psProbeInverted->ReleaseGPU(); + _psProbe->ReleaseGPU(); + _psProbeInside->ReleaseGPU(); _psCombinePass->ReleaseGPU(); invalidateResources(); } #endif protected: - // [RendererPass] bool setupResources() override; }; diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index e2c1c1f42..205f3301c 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -446,7 +446,9 @@ bool ShadowsPass::Init() // Create pipeline states _psShadowDir.CreatePipelineStates(); _psShadowPoint.CreatePipelineStates(); + _psShadowPointInside.CreatePipelineStates(); _psShadowSpot.CreatePipelineStates(); + _psShadowSpotInside.CreatePipelineStates(); // Load assets _shader = Content::LoadAsyncInternal(TEXT("Shaders/Shadows")); @@ -496,27 +498,40 @@ bool ShadowsPass::setupResources() // Create pipeline stages GPUPipelineState::Description psDesc; - if (!_psShadowPoint.IsValid()) - { - psDesc = GPUPipelineState::Description::DefaultNoDepth; - psDesc.CullMode = CullMode::TwoSided; - psDesc.VS = shader->GetVS("VS_Model"); - if (_psShadowPoint.Create(psDesc, shader, "PS_PointLight")) - return true; - } if (!_psShadowDir.IsValid()) { psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle; + psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RG; if (_psShadowDir.Create(psDesc, shader, "PS_DirLight")) return true; } + if (!_psShadowPoint.IsValid()) + { + psDesc = GPUPipelineState::Description::DefaultNoDepth; + psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RG; + psDesc.VS = shader->GetVS("VS_Model"); + psDesc.DepthEnable = true; + psDesc.CullMode = CullMode::Normal; + if (_psShadowPoint.Create(psDesc, shader, "PS_PointLight")) + return true; + psDesc.DepthFunc = ComparisonFunc::Greater; + psDesc.CullMode = CullMode::Inverted; + if (_psShadowPointInside.Create(psDesc, shader, "PS_PointLight")) + return true; + } if (!_psShadowSpot.IsValid()) { psDesc = GPUPipelineState::Description::DefaultNoDepth; - psDesc.CullMode = CullMode::TwoSided; + psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RG; psDesc.VS = shader->GetVS("VS_Model"); + psDesc.DepthEnable = true; + psDesc.CullMode = CullMode::Normal; if (_psShadowSpot.Create(psDesc, shader, "PS_SpotLight")) return true; + psDesc.DepthFunc = ComparisonFunc::Greater; + psDesc.CullMode = CullMode::Inverted; + if (_psShadowSpotInside.Create(psDesc, shader, "PS_SpotLight")) + return true; } if (_psDepthClear == nullptr) { @@ -994,7 +1009,9 @@ void ShadowsPass::Dispose() // Cleanup _psShadowDir.Delete(); _psShadowPoint.Delete(); + _psShadowPointInside.Delete(); _psShadowSpot.Delete(); + _psShadowSpotInside.Delete(); _shader = nullptr; _sphereModel = nullptr; SAFE_DELETE_GPU_RESOURCE(_psDepthClear); @@ -1072,7 +1089,6 @@ void ShadowsPass::SetupShadows(RenderContext& renderContext, RenderContextBatch& } if (shadows.StaticAtlasTiles && (float)shadows.StaticAtlasPixelsUsed / (shadows.StaticAtlasTiles->Width * shadows.StaticAtlasTiles->Height) < SHADOWS_MAX_STATIC_ATLAS_CAPACITY_TO_DEFRAG) { - float app = (float)shadows.StaticAtlasPixelsUsed / (shadows.StaticAtlasTiles->Width * shadows.StaticAtlasTiles->Height); // Defragment static shadow atlas if it failed to insert any light but it's still should have space bool anyStaticFailed = false; for (auto& e : shadows.Lights) @@ -1478,12 +1494,12 @@ void ShadowsPass::RenderShadowMask(RenderContextBatch& renderContextBatch, Rende sperLight.TemporalTime = renderContext.List->Setup.UseTemporalAAJitter ? RenderTools::ComputeTemporalTime() : 0.0f; sperLight.ContactShadowsDistance = light.ShadowsDistance; sperLight.ContactShadowsLength = EnumHasAnyFlags(view.Flags, ViewFlags::ContactShadows) ? light.ContactShadowsLength : 0.0f; + bool isViewInside; if (isLocalLight) { // Calculate world view projection matrix for the light sphere Matrix world, wvp; - bool isInside; - RenderTools::ComputeSphereModelDrawMatrix(renderContext.View, light.Position, ((RenderLocalLightData&)light).Radius, world, isInside); + RenderTools::ComputeSphereModelDrawMatrix(renderContext.View, light.Position, ((RenderLocalLightData&)light).Radius, world, isViewInside); Matrix::Multiply(world, view.ViewProjection(), wvp); Matrix::Transpose(wvp, sperLight.WVP); } @@ -1498,12 +1514,12 @@ void ShadowsPass::RenderShadowMask(RenderContextBatch& renderContextBatch, Rende context->SetRenderTarget(shadowMask); if (light.IsPointLight) { - context->SetState(_psShadowPoint.Get(permutationIndex)); + context->SetState((isViewInside ? _psShadowPointInside : _psShadowPoint).Get(permutationIndex)); _sphereModel->LODs.Get()[0].Meshes.Get()[0].Render(context); } else if (light.IsSpotLight) { - context->SetState(_psShadowSpot.Get(permutationIndex)); + context->SetState((isViewInside ? _psShadowSpotInside : _psShadowSpot).Get(permutationIndex)); _sphereModel->LODs.Get()[0].Meshes.Get()[0].Render(context); } else //if (light.IsDirectionalLight) diff --git a/Source/Engine/Renderer/ShadowsPass.h b/Source/Engine/Renderer/ShadowsPass.h index df647aac6..551b3a504 100644 --- a/Source/Engine/Renderer/ShadowsPass.h +++ b/Source/Engine/Renderer/ShadowsPass.h @@ -21,7 +21,9 @@ private: GPUPipelineState* _psDepthCopy = nullptr; GPUPipelineStatePermutationsPs(Quality::MAX) * 2> _psShadowDir; GPUPipelineStatePermutationsPs(Quality::MAX) * 2> _psShadowPoint; + GPUPipelineStatePermutationsPs(Quality::MAX) * 2> _psShadowPointInside; GPUPipelineStatePermutationsPs(Quality::MAX) * 2> _psShadowSpot; + GPUPipelineStatePermutationsPs(Quality::MAX) * 2> _psShadowSpotInside; PixelFormat _shadowMapFormat; // Cached on initialization public: