/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include namespace AZ { namespace Render { uint32_t DepthOfFieldReadBackFocusDepthPass::s_bufferInstance = 0; RPI::Ptr DepthOfFieldReadBackFocusDepthPass::Create(const RPI::PassDescriptor& descriptor) { RPI::Ptr pass = aznew DepthOfFieldReadBackFocusDepthPass(descriptor); return pass; } DepthOfFieldReadBackFocusDepthPass::DepthOfFieldReadBackFocusDepthPass(const RPI::PassDescriptor& descriptor) : ParentPass(descriptor) { // Create buffer for read back focus depth. We append static counter to avoid name conflicts. RPI::CommonBufferDescriptor desc; desc.m_bufferName = "DepthOfFieldReadBackAutoFocusDepthBuffer"; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; desc.m_byteCount = sizeof(float); desc.m_elementSize = aznumeric_cast(desc.m_byteCount); desc.m_bufferData = nullptr; desc.m_elementFormat = RHI::Format::R32_FLOAT; m_buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); } DepthOfFieldReadBackFocusDepthPass::~DepthOfFieldReadBackFocusDepthPass() { m_buffer = nullptr; m_getDepthPass = nullptr; m_readbackPass = nullptr; } float DepthOfFieldReadBackFocusDepthPass::GetFocusDepth() { return m_readbackPass->GetFocusDepth(); } float DepthOfFieldReadBackFocusDepthPass::GetNormalizedFocusDistanceForAutoFocus() const { return m_normalizedFocusDistanceForAutoFocus; } void DepthOfFieldReadBackFocusDepthPass::SetScreenPosition(const AZ::Vector2& screenPosition) { if(m_getDepthPass) { m_getDepthPass->SetScreenPosition(screenPosition); } } void DepthOfFieldReadBackFocusDepthPass::CreateChildPassesInternal() { RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); // Create read back pass m_readbackPass = passSystem->CreatePass(AZ::Name("DepthOfFieldReadBackPass")); AZ_Assert(m_readbackPass, "DepthOfFieldReadBackFocusDepthPass : read back pass is invalid"); AddChild(m_readbackPass); // Find GetDepth pass on template auto pass = FindChildPass(Name("DepthOfFieldWriteFocusDepthFromGpu")); m_getDepthPass = static_cast(pass.get()); m_getDepthPass->SetBufferRef(m_buffer); m_readbackPass->SetBufferRef(m_buffer); } void DepthOfFieldReadBackFocusDepthPass::FrameBeginInternal(FramePrepareParams params) { RPI::Scene* scene = GetScene(); PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor(); AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); if (fp) { PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view); if (postProcessSettings) { DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings(); if (dofSettings) { SetScreenPosition(dofSettings->m_autoFocusScreenPosition); UpdateAutoFocus(*dofSettings); } } } RPI::ParentPass::FrameBeginInternal(params); } void DepthOfFieldReadBackFocusDepthPass::UpdateAutoFocus(DepthOfFieldSettings& dofSettings) { float viewNear = dofSettings.m_viewNear; float viewFar = dofSettings.m_viewFar; if (dofSettings.m_enableAutoFocus) { float deltaTime = dofSettings.m_deltaTime; float depthForAutoFocus = GetFocusDepth(); // Convert depth to linear. // This value is in the range [0.0, 1.0], where 0.0 is view near and 1.0 is view far. float div1 = viewNear * depthForAutoFocus - viewFar * depthForAutoFocus + viewFar; float viewZ = div1 > 0.001f ? viewFar * viewNear / div1 : viewFar; float div2 = viewFar - viewNear; float targetLinearDepth = div2 > 0.001f ? (viewZ - viewNear) / div2 : 0.0f; targetLinearDepth = GetClamp(targetLinearDepth, 0.0f, 1.0f); // Response distance when m_autoFocusSensitivity is 0.0. // As a standard, the distance from near to far is 1.0. constexpr float FocusStartingDistanceMax = 0.5f; // The greater m_autoFocusSensitivity, the easier the response. // If m_autoFocusSensitivity is 1.0, always re-focus. float focusStartingDistance = (1.0f - dofSettings.m_autoFocusSensitivity) * FocusStartingDistanceMax; float targetDistance = targetLinearDepth - m_normalizedFocusDistanceForAutoFocus; if (!m_isMovingFocus && focusStartingDistance < GetAbs(targetDistance)) { m_isMovingFocus = true; m_delayTimer = 0.0f; } if (m_isMovingFocus) { if (m_delayTimer < dofSettings.m_autoFocusDelay) { m_delayTimer += deltaTime; } else { // Start focus after m_delayTimer[s] exceeds m_autoFocusDelay[s]. float speed = dofSettings.m_autoFocusSpeed * deltaTime; if (GetAbs(targetDistance) < speed) { // Arrive at the focus target. m_normalizedFocusDistanceForAutoFocus = targetLinearDepth; m_isMovingFocus = false; } else { m_normalizedFocusDistanceForAutoFocus += speed * GetSign(targetDistance); } } } } else { m_isMovingFocus = false; // Always update distance for auto focus. // Process to prevent a sudden change of focus when changing the auto focus from disabled to enabled. // convert from to [Near, Far] to [0, 1] float focusDistance = GetClamp(dofSettings.m_focusDistance, viewNear, viewFar); m_normalizedFocusDistanceForAutoFocus = (focusDistance - viewNear) / (viewFar - viewNear); } } } // namespace Render } // namespace AZ