You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
6.9 KiB
C++
177 lines
6.9 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <AzCore/Math/MathUtils.h>
|
|
|
|
#include <PostProcess/PostProcessFeatureProcessor.h>
|
|
#include <PostProcess/DepthOfField/DepthOfFieldSettings.h>
|
|
#include <PostProcessing/NewDepthOfFieldPasses.h>
|
|
|
|
#include <Atom/RPI.Public/RenderPipeline.h>
|
|
#include <Atom/RPI.Public/Scene.h>
|
|
#include <Atom/RPI.Public/View.h>
|
|
|
|
namespace AZ
|
|
{
|
|
namespace Render
|
|
{
|
|
|
|
// Must match the struct in NewDepthOfFieldCommon.azsli
|
|
struct NewDepthOfFieldConstants
|
|
{
|
|
static constexpr uint32_t numberOfLoops = 3;
|
|
static constexpr float loopCounts[] = { 8.0f, 16.0f, 24.0f };
|
|
|
|
AZStd::array<float[4], 60> m_samplePositions; // XY are sample positions (normalized so max lenght is 1)
|
|
// Z is the length of XY (0 - 1)
|
|
// W is unused
|
|
};
|
|
|
|
// --- Depth of Field Parent Pass ---
|
|
|
|
RPI::Ptr<NewDepthOfFieldParentPass> NewDepthOfFieldParentPass::Create(const RPI::PassDescriptor& descriptor)
|
|
{
|
|
RPI::Ptr<NewDepthOfFieldParentPass> pass = aznew NewDepthOfFieldParentPass(descriptor);
|
|
return AZStd::move(pass);
|
|
}
|
|
|
|
NewDepthOfFieldParentPass::NewDepthOfFieldParentPass(const RPI::PassDescriptor& descriptor)
|
|
: RPI::ParentPass(descriptor)
|
|
{ }
|
|
|
|
bool NewDepthOfFieldParentPass::IsEnabled() const
|
|
{
|
|
if (!ParentPass::IsEnabled())
|
|
{
|
|
return false;
|
|
}
|
|
RPI::Scene* scene = GetScene();
|
|
if (!scene)
|
|
{
|
|
return false;
|
|
}
|
|
PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor<PostProcessFeatureProcessor>();
|
|
AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView();
|
|
if (!fp)
|
|
{
|
|
return false;
|
|
}
|
|
PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view);
|
|
if (!postProcessSettings)
|
|
{
|
|
return false;
|
|
}
|
|
DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings();
|
|
return (dofSettings != nullptr) && dofSettings->GetEnabled();
|
|
}
|
|
|
|
void NewDepthOfFieldParentPass::FrameBeginInternal(FramePrepareParams params)
|
|
{
|
|
RPI::Scene* scene = GetScene();
|
|
PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor<PostProcessFeatureProcessor>();
|
|
AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView();
|
|
if (fp)
|
|
{
|
|
PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view);
|
|
if (postProcessSettings)
|
|
{
|
|
DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings();
|
|
if (dofSettings)
|
|
{
|
|
dofSettings->SetValuesToViewSrg(view->GetShaderResourceGroup());
|
|
}
|
|
}
|
|
}
|
|
|
|
ParentPass::FrameBeginInternal(params);
|
|
}
|
|
|
|
// --- Tile Reduce Pass ---
|
|
|
|
RPI::Ptr<NewDepthOfFieldTileReducePass> NewDepthOfFieldTileReducePass::Create(const RPI::PassDescriptor& descriptor)
|
|
{
|
|
RPI::Ptr<NewDepthOfFieldTileReducePass> pass = aznew NewDepthOfFieldTileReducePass(descriptor);
|
|
return AZStd::move(pass);
|
|
}
|
|
|
|
NewDepthOfFieldTileReducePass::NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor)
|
|
: RPI::ComputePass(descriptor)
|
|
{
|
|
// Though this is a fullscreen pass, the shader computes 16x16 tiles with groups of 8x8 threads,
|
|
// each thread outputting to a single pixel in the tiled min/max texture
|
|
m_isFullscreenPass = false;
|
|
}
|
|
|
|
void NewDepthOfFieldTileReducePass::FrameBeginInternal(FramePrepareParams params)
|
|
{
|
|
AZ_Assert(GetOutputCount() > 0, "NewDepthOfFieldTileReducePass: No output bindings!");
|
|
RPI::PassAttachment* outputAttachment = GetOutputBinding(0).m_attachment.get();
|
|
|
|
AZ_Assert(outputAttachment != nullptr, "NewDepthOfFieldTileReducePass: Output binding has no attachment!");
|
|
RHI::Size outputSize = outputAttachment->m_descriptor.m_image.m_size;
|
|
|
|
// The algorithm outputs the min/max CoC values from a 16x16 region using 8x8 threads
|
|
u32 targetThreadCountX = outputSize.m_width * 8;
|
|
u32 targetThreadCountY = outputSize.m_height * 8;
|
|
SetTargetThreadCounts(targetThreadCountX, targetThreadCountY, 1);
|
|
|
|
RPI::ComputePass::FrameBeginInternal(params);
|
|
}
|
|
|
|
// --- Filter Pass ---
|
|
|
|
RPI::Ptr<NewDepthOfFieldFilterPass> NewDepthOfFieldFilterPass::Create(const RPI::PassDescriptor& descriptor)
|
|
{
|
|
RPI::Ptr<NewDepthOfFieldFilterPass> pass = aznew NewDepthOfFieldFilterPass(descriptor);
|
|
return AZStd::move(pass);
|
|
}
|
|
|
|
NewDepthOfFieldFilterPass::NewDepthOfFieldFilterPass(const RPI::PassDescriptor& descriptor)
|
|
: RPI::FullscreenTrianglePass(descriptor)
|
|
{ }
|
|
|
|
void NewDepthOfFieldFilterPass::FrameBeginInternal(FramePrepareParams params)
|
|
{
|
|
NewDepthOfFieldConstants dofConstants;
|
|
|
|
uint32_t sampleIndex = 0;
|
|
|
|
// Calculate all the offset positions
|
|
for (uint32_t loop = 0; loop < NewDepthOfFieldConstants::numberOfLoops; ++loop)
|
|
{
|
|
float radius = (loop + 1.0f) / float(NewDepthOfFieldConstants::numberOfLoops);
|
|
float loopCount = NewDepthOfFieldConstants::loopCounts[loop];
|
|
|
|
float angleStep = Constants::TwoPi / loopCount;
|
|
|
|
// Every other loop slightly rotate sample ring so they don't line up
|
|
float angle = (loop & 1) ? (angleStep * 0.5f) : 0;
|
|
|
|
for (float i = 0.0f; i < loopCount; ++i)
|
|
{
|
|
Vector2 pos = Vector2::CreateFromAngle(angle);
|
|
pos = pos * radius;
|
|
|
|
dofConstants.m_samplePositions[sampleIndex][0] = pos.GetX();
|
|
dofConstants.m_samplePositions[sampleIndex][1] = pos.GetY();
|
|
dofConstants.m_samplePositions[sampleIndex][2] = radius;
|
|
dofConstants.m_samplePositions[sampleIndex][3] = 0.0f;
|
|
|
|
++sampleIndex;
|
|
angle += angleStep;
|
|
}
|
|
}
|
|
|
|
m_shaderResourceGroup->SetConstant(m_constantsIndex, dofConstants);
|
|
|
|
RPI::FullscreenTrianglePass::FrameBeginInternal(params);
|
|
}
|
|
|
|
} // namespace Render
|
|
} // namespace AZ
|