[new] ATOM-17253 Using AtomTressFX gem as an example to inject hair passes to main pipeline at run-time (#7661)

* Change AtomTressFX passes to write to exsiting DepthLinear buffer instead of creating a new one as output.

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>

* Added new api in RPI to apply render pipeline changes from FP

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>

* Update AtomTressFX gem to create hair parent pass at runtime

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>

* Change Scene::ApplyRenderPipelineChange() to TryApplyRenderPIpelineChanges().
Have TryApplyRenderPIpelineChanges() called automatically when a render pipeline is added to a Scene.
Re-apply the render pipeline change when RenderPipeline got recreated (Pass hot-reloading support)
Add AddPassBefore() and AddPassAfter() function to RenderPIpeline class.

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>
monroegm-disable-blank-issue-2
Qing Tao 4 years ago committed by GitHub
parent ca3018155e
commit 846e2736a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -215,99 +215,6 @@
}
]
},
{
// NOTE: HairParentPass does not write into Depth MSAA from Opaque Pass. If new passes downstream
// of HairParentPass will need to use Depth MSAA, HairParentPass will need to be updated to use Depth MSAA
// instead of regular Depth as DepthStencil. Specifically, HairResolvePPLL.pass and the associated
// .azsl file will need to be updated.
"Name": "HairParentPass",
// Note: The following two lines represent the choice of rendering pipeline for the hair.
// You can either choose to use PPLL or ShortCut and accordingly change the flag
// 'm_usePPLLRenderTechnique' in the class 'HairFeatureProcessor.cpp'
// "TemplateName": "HairParentPassTemplate",
"TemplateName": "HairParentShortCutPassTemplate",
"Enabled": true,
"Connections": [
// Critical to keep DepthLinear as input - used to set the size of the Head PPLL image buffer.
// If DepthLinear is not available - connect to another viewport (non MSAA) image.
{
"LocalSlot": "DepthLinearInput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "Depth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "RenderTargetInputOutput",
"AttachmentRef": {
"Pass": "OpaquePass",
"Attachment": "Output"
}
},
{
"LocalSlot": "RenderTargetInputOnly",
"AttachmentRef": {
"Pass": "OpaquePass",
"Attachment": "Output"
}
},
// Shadows resources
{
"LocalSlot": "DirectionalShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "DirectionalESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ProjectedESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedESM"
}
},
// Lighting Resources
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "LightListRemapped"
}
}
]
},
{
"Name": "TransparentPass",
"TemplateName": "TransparentParentTemplate",
@ -357,22 +264,22 @@
{
"LocalSlot": "InputLinearDepth",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "DepthStencil",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "HairParentPass",
"Attachment": "RenderTargetInputOutput"
"Pass": "OpaquePass",
"Attachment": "Output"
}
}
]
@ -385,22 +292,22 @@
{
"LocalSlot": "InputLinearDepth",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "InputDepthStencil",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "RenderTargetInputOutput",
"AttachmentRef": {
"Pass": "HairParentPass",
"Attachment": "RenderTargetInputOutput"
"Pass": "TransparentPass",
"Attachment": "InputOutput"
}
}
],
@ -440,7 +347,7 @@
{
"LocalSlot": "Depth",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
@ -502,7 +409,7 @@
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
@ -561,7 +468,7 @@
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
@ -574,14 +481,14 @@
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "LyShinePass",
"Attachment": "ColorInputOutput"
"Pass": "DebugOverlayPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "HairParentPass",
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}

@ -1340,6 +1340,8 @@ void CCryEditApp::CompileCriticalAssets() const
}
assetsInQueueNotifcation.BusDisconnect();
AZ_TracePrintf("Editor", "CriticalAssetsCompiled\n");
// Signal the "CriticalAssetsCompiled" lifecycle event
// Also reload the "assetcatalog.xml" if it exists
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
@ -1411,11 +1413,13 @@ bool CCryEditApp::ConnectToAssetProcessor() const
if (connectedToAssetProcessor)
{
AZ_TracePrintf("Editor", "Connected to Asset Processor\n");
CCryEditApp::OutputStartupMessage(QString("Connected to Asset Processor"));
CompileCriticalAssets();
return true;
}
AZ_TracePrintf("Editor", "Failed to connect to Asset Processor\n");
CCryEditApp::OutputStartupMessage(QString("Failed to connect to Asset Processor"));
return false;
}

@ -6,6 +6,7 @@
"Name": "MainPipeline",
"MainViewTag": "MainCamera",
"RootPassTemplate": "MainPipeline",
"AllowModification": true,
"RenderSettings": {
"MultisampleState": {
"samples": 4

@ -30,6 +30,8 @@ namespace AZ
namespace RPI
{
class RenderPipeline;
//! @class FeatureProcessor
//! @brief Interface that FeatureProcessors should derive from
//! @detail FeatureProcceors will record simulation state from the simulation job graph into a buffer that is isolated from the asynchronous rendering graph.
@ -87,6 +89,9 @@ namespace AZ
//! Perform any necessary deactivation.
virtual void Deactivate() {}
//! Apply changes and add additional render passes to the render pipeline from the feature processors
virtual void ApplyRenderPipelineChange(RenderPipeline* ) {}
//! Allows the feature processor to expose supporting views based on
//! the main views passed in. Main views (persistent views) are views that must be
//! rendered and impacts the presentation of the application. Support

@ -66,6 +66,7 @@ namespace AZ
//! Inserts a pass at specified position
//! If the position is invalid, the child pass won't be added, and the function returns false
bool InsertChild(const Ptr<Pass>& child, ChildPassIndex position);
bool InsertChild(const Ptr<Pass>& child, uint32_t index);
//! Searches for a child pass with the given name. Returns the child's index if found, null index otherwise
ChildPassIndex FindChildPassIndex(const Name& passName) const;

@ -184,6 +184,23 @@ namespace AZ
//! Get draw filter mask
RHI::DrawFilterMask GetDrawFilterMask() const;
//! Get the RenderPipelineDescriptor which was used to create this RenderPipeline
const RenderPipelineDescriptor& GetDescriptor() const;
// Helper functions to modify the passes of this render pipeline
//! Find a reference pass's location and add the new pass before the reference pass
//! After the new pass was inserted, the new pass and the reference pass are siblings
bool AddPassBefore(Ptr<Pass> newPass, const AZ::Name& referencePassName);
//! Find a reference pass's location and add the new pass after the reference pass
//! After the new pass was inserted, the new pass and the reference pass are siblings
bool AddPassAfter(Ptr<Pass> newPass, const AZ::Name& referencePassName);
//! Find the first pass with matching name in the render pipeline
//! Note: to find all the passes with matching name in this render pipeline,
//! use RPI::PassSystemInterface::Get()->ForEachPass() function instead.
Ptr<Pass> FindFirstPass(const AZ::Name& passName);
private:
RenderPipeline() = default;
@ -238,8 +255,8 @@ namespace AZ
PipelineViewTag m_mainViewTag;
// Whether the pipeline should be removed after one execution
bool m_executeOnce = false;
// Was the pipeline modified by Scene's feature processor
bool m_wasModifiedByScene = false;
// The window handle associated with this render pipeline if it's created for a window
AzFramework::NativeWindowHandle m_windowHandle = nullptr;
@ -247,15 +264,15 @@ namespace AZ
// Render settings that can be queried by passes to setup things like render target resolution
PipelineRenderSettings m_activeRenderSettings;
// Original settings from RenderPipelineDescriptor, used to revert active render settings to original settings from RenderPipelineDescriptor
PipelineRenderSettings m_originalRenderSettings;
// A tag to filter draw items submitted by passes of this render pipeline.
// This tag is allocated when it's added to a scene. It's set to invalid when it's removed to the scene.
RHI::DrawFilterTag m_drawFilterTag;
// A mask to filter draw items submitted by passes of this render pipeline.
// This mask is created from the value of m_drawFilterTag.
RHI::DrawFilterMask m_drawFilterMask = 0;
RHI::DrawFilterMask m_drawFilterMask = 0;
// The descriptor used to created this render pipeline
RenderPipelineDescriptor m_descriptor;
};
} // namespace RPI

@ -169,6 +169,9 @@ namespace AZ
//! This function is called every time scene's render pipelines change.
//! User may call this function explicitly if render pipelines were changed
void RebuildPipelineStatesLookup();
//! Try apply render pipeline changes from each feature processors if the pipeline allows modification and wasn't modified.
void TryApplyRenderPipelineChanges(RenderPipeline* pipeline);
protected:
// SceneFinder overrides...
@ -192,6 +195,7 @@ namespace AZ
// This is called after PassSystem's FramePrepare so passes can still modify view srgs in its FramePrepareIntenal function before they are submitted to command list
void UpdateSrgs();
private:
Scene();

@ -41,6 +41,9 @@ namespace AZ
//! Flag indicating if this pipeline should execute one time and then be removed.
bool m_executeOnce = false;
//! Flag indicating if this pipeline can accept modifications from scene's feature processors
bool m_allowModification = false;
};
} // namespace RPI

@ -76,6 +76,16 @@ namespace AZ
}
bool ParentPass::InsertChild(const Ptr<Pass>& child, ChildPassIndex position)
{
if (!position.IsValid())
{
AZ_Assert(false, "Can't insert a child pass with invalid position");
return false;
}
return InsertChild(child, position.GetIndex());
}
bool ParentPass::InsertChild(const Ptr<Pass>& child, uint32_t index)
{
if (child->m_parent != nullptr)
{
@ -83,13 +93,13 @@ namespace AZ
return false;
}
if (!position.IsValid() || position.GetIndex() > m_children.size())
if (index > m_children.size())
{
AZ_Assert(false, "Can't insert a child pass with invalid position");
return false;
}
auto insertPos = m_children.cbegin() + position.GetIndex();
auto insertPos = m_children.cbegin() + index;
m_children.insert(insertPos, child);
child->m_parent = this;

@ -294,7 +294,7 @@ namespace AZ
void PassLibrary::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
// Handle pass asset reload
Data::Asset<PassAsset> passAsset = Data::static_pointer_cast<PassAsset>(asset);
Data::Asset<PassAsset> passAsset = { asset.GetAs<PassAsset>() , AZ::Data::AssetLoadBehavior::PreLoad};
if (passAsset && passAsset->GetPassTemplate())
{
LoadPassAsset(passAsset->GetPassTemplate()->m_name, passAsset, true);

@ -370,6 +370,7 @@ namespace AZ
m_commonShaderAssetForSrgs = AssetUtils::LoadCriticalAsset<ShaderAsset>( m_descriptor.m_commonSrgsShaderAssetPath.c_str());
if (!m_commonShaderAssetForSrgs.IsReady())
{
AZ_Error("RPI system", false, "Failed to load RPI system asset %s", m_descriptor.m_commonSrgsShaderAssetPath.c_str());
return;
}
m_sceneSrgLayout = m_commonShaderAssetForSrgs->FindShaderResourceGroupLayout(SrgBindingSlot::Scene);
@ -395,6 +396,7 @@ namespace AZ
m_passSystem.InitPassTemplates();
m_systemAssetsInitialized = true;
AZ_TracePrintf("RPI system", "System assets initialized\n");
}
bool RPISystem::IsInitialized() const

@ -9,6 +9,7 @@
#include <Atom/RHI/DrawListTagRegistry.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassSystem.h>
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
#include <Atom/RPI.Public/RenderPipeline.h>
@ -97,10 +98,9 @@ namespace AZ
void RenderPipeline::InitializeRenderPipeline(RenderPipeline* pipeline, const RenderPipelineDescriptor& desc)
{
pipeline->m_descriptor = desc;
pipeline->m_mainViewTag = Name(desc.m_mainViewTagName);
pipeline->m_nameId = desc.m_name.data();
pipeline->m_executeOnce = desc.m_executeOnce;
pipeline->m_originalRenderSettings = desc.m_renderSettings;
pipeline->m_activeRenderSettings = desc.m_renderSettings;
pipeline->m_rootPass->SetRenderPipeline(pipeline);
pipeline->m_rootPass->m_flags.m_isPipelineRoot = true;
@ -337,6 +337,10 @@ namespace AZ
m_rootPass = newRoot;
passSystem->GetRootPass()->AddChild(m_rootPass);
// Re-Apply render pipeline change
m_wasModifiedByScene = false;
m_scene->TryApplyRenderPipelineChanges(this);
m_wasPassModified = true;
}
else
@ -366,7 +370,7 @@ namespace AZ
bool RenderPipeline::IsExecuteOnce()
{
return m_executeOnce;
return m_descriptor.m_executeOnce;
}
void RenderPipeline::RemoveFromScene()
@ -477,7 +481,7 @@ namespace AZ
void RenderPipeline::RevertRenderSettings()
{
m_activeRenderSettings = m_originalRenderSettings;
m_activeRenderSettings = m_descriptor.m_renderSettings;
}
void RenderPipeline::AddToRenderTickOnce()
@ -527,5 +531,60 @@ namespace AZ
m_drawFilterMask = 0;
}
}
const RenderPipelineDescriptor& RenderPipeline::GetDescriptor() const
{
return m_descriptor;
}
bool RenderPipeline::AddPassBefore(Ptr<Pass> newPass, const AZ::Name& referencePassName)
{
auto foundPass = FindFirstPass(referencePassName);
if (!foundPass)
{
AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
referencePassName.GetCStr(), GetId().GetCStr());
return false;
}
// insert the pass
auto parentPass = foundPass->GetParent();
auto passIndex = parentPass->FindChildPassIndex(referencePassName);
// Note: no need to check if passIndex is valid since the pass was already found
return parentPass->InsertChild(newPass, passIndex.GetIndex());
}
bool RenderPipeline::AddPassAfter(Ptr<Pass> newPass, const AZ::Name& referencePassName)
{
auto foundPass = FindFirstPass(referencePassName);
if (!foundPass)
{
AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
referencePassName.GetCStr(), GetId().GetCStr());
return false;
}
// insert the pass
auto parentPass = foundPass->GetParent();
auto passIndex = parentPass->FindChildPassIndex(referencePassName);
// Note: no need to check if passIndex is valid since the pass was already found
return parentPass->InsertChild(newPass, passIndex.GetIndex()+1);
}
Ptr<Pass> RenderPipeline::FindFirstPass(const AZ::Name& passName)
{
auto passFilter = RPI::PassFilter::CreateWithPassHierarchy({passName});
passFilter.SetOwnerRenderPipeline(this);
RPI::Ptr<RPI::Pass> foundPass = nullptr;
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundPass](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
foundPass = pass;
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
});
return foundPass;
}
}
}

@ -285,6 +285,22 @@ namespace AZ
return foundFP == AZStd::end(m_featureProcessors) ? nullptr : (*foundFP).get();
}
void Scene::TryApplyRenderPipelineChanges(RenderPipeline* pipeline)
{
// return directly if the pipeline doesn't allow modification or it was already modifed by scene
if (!pipeline->m_descriptor.m_allowModification || pipeline->m_wasModifiedByScene)
{
return;
}
pipeline->m_wasModifiedByScene = true;
for (auto& fp : m_featureProcessors)
{
fp->ApplyRenderPipelineChange(pipeline);
}
AZ::RPI::PassSystemInterface::Get()->ProcessQueuedChanges();
}
void Scene::AddRenderPipeline(RenderPipelinePtr pipeline)
{
if (pipeline->m_scene != nullptr)
@ -311,6 +327,9 @@ namespace AZ
}
pipeline->OnAddedToScene(this);
TryApplyRenderPipelineChanges(pipeline.get());
PassSystemInterface::Get()->ProcessQueuedChanges();
pipeline->BuildPipelineViews();

@ -25,6 +25,7 @@ namespace AZ
->Field("RootPassTemplate", &RenderPipelineDescriptor::m_rootPassTemplate)
->Field("ExecuteOnce", &RenderPipelineDescriptor::m_executeOnce)
->Field("RenderSettings", &RenderPipelineDescriptor::m_renderSettings)
->Field("AllowModification", &RenderPipelineDescriptor::m_allowModification)
;
}
}

@ -0,0 +1,96 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassRequest",
"ClassData": {
// NOTE: HairParentPass does not write into Depth MSAA from Opaque Pass. If new passes downstream
// of HairParentPass will need to use Depth MSAA, HairParentPass will need to be updated to use Depth MSAA
// instead of regular Depth as DepthStencil. Specifically, HairResolvePPLL.pass and the associated
// .azsl file will need to be updated.
"Name": "HairParentPass",
// Note: The following two lines represent the choice of rendering pipeline for the hair.
// You can either choose to use PPLL or ShortCut by changing TemplateName to HairParentPassTemplate (for PPLL)
// or HairParentShortCutPassTemplate (for Shortcut)
// "TemplateName": "HairParentPassTemplate",
"TemplateName": "HairParentShortCutPassTemplate",
"Enabled": true,
"Connections": [
// Critical to keep DepthLinear as input - used to set the size of the Head PPLL image buffer.
// If DepthLinear is not available - connect to another viewport (non MSAA) image.
{
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "Depth",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "RenderTargetInputOutput",
"AttachmentRef": {
"Pass": "OpaquePass",
"Attachment": "Output"
}
},
{
"LocalSlot": "RenderTargetInputOnly",
"AttachmentRef": {
"Pass": "OpaquePass",
"Attachment": "Output"
}
},
// Shadows resources
{
"LocalSlot": "DirectionalShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "DirectionalESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ProjectedESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedESM"
}
},
// Lighting Resources
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "LightListRemapped"
}
}
]
}
}

@ -62,6 +62,10 @@
{
"Name": "HairShortCutResolveColorPassTemplate",
"Path": "Passes/HairShortCutResolveColor.pass"
},
{
"Name": "HairDepthToLinearTemplate",
"Path": "Passes/HairDepthToLinear.pass"
}
]
}

@ -0,0 +1,38 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "HairDepthToLinearTemplate",
"PassClass": "FullScreenTriangle",
"Slots": [
{
"Name": "Input",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"AspectFlags": [
"Depth"
]
}
},
{
"Name": "Output",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"LoadAction": "DontCare"
}
}
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"ShaderAsset": {
"FilePath": "Shaders/PostProcessing/DepthToLinearDepth.shader"
},
"PipelineViewTag": "MainCamera"
}
}
}
}

@ -25,17 +25,11 @@
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "DepthStencil"
},
// Keep DepthLinear as input - used to set the size of the Head PPLL image buffer.
// If DepthLinear is not availbale - connect to another viewport (non MSAA) image.
{
"Name": "DepthLinearInput",
"SlotType": "Input"
},
// used to set the size of the Head PPLL image buffer.
{
"Name": "DepthLinear",
"SlotType": "Output"
"SlotType": "InputOutput"
},
// Lights & Shadows resources
{
"Name": "DirectionalShadowmap",
@ -62,21 +56,6 @@
"SlotType": "Input"
}
],
"Connections": [
{
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "DepthToDepthLinearPass",
"Attachment": "Output"
}
}
],
"FallbackConnections": [
{
"Input": "DepthLinearInput",
"Output": "DepthLinear"
}
],
"PassRequests": [
{
"Name": "HairGlobalShapeConstraintsComputePass",
@ -172,7 +151,7 @@
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DepthLinearInput"
"Attachment": "DepthLinear"
}
},
{
@ -260,7 +239,7 @@
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DepthLinearInput"
"Attachment": "DepthLinear"
}
},
@ -334,7 +313,7 @@
// buffer pixels that were touched by HairPPLLResolvePass hence preventing depth update unless
// it is hair.
"Name": "DepthToDepthLinearPass",
"TemplateName": "DepthToLinearTemplate",
"TemplateName": "HairDepthToLinearTemplate",
"Enabled": true,
"Connections": [
{
@ -343,6 +322,13 @@
"Pass": "HairPPLLResolvePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DepthLinear"
}
}
]
}

@ -26,15 +26,10 @@
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "DepthStencil"
},
// Keep DepthLinear as input - used to set the size of the Head PPLL image buffer.
// If DepthLinear is not availbale - connect to another viewport (non MSAA) image.
{
"Name": "DepthLinearInput",
"SlotType": "Input"
},
// Used to set the size of the Head PPLL image buffer.
{
"Name": "DepthLinear",
"SlotType": "Output"
"SlotType": "InputOutput"
},
// Lights & Shadows resources
@ -63,21 +58,6 @@
"SlotType": "Input"
}
],
"Connections": [
{
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "DepthToDepthLinearPass",
"Attachment": "Output"
}
}
],
"FallbackConnections": [
{
"Input": "DepthLinearInput",
"Output": "DepthLinear"
}
],
"PassRequests": [
{
"Name": "HairGlobalShapeConstraintsComputePass",
@ -277,7 +257,7 @@
"LocalSlot": "DepthLinear",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DepthLinearInput"
"Attachment": "DepthLinear"
}
},
{
@ -387,7 +367,7 @@
// buffer pixels that were touched by HairPPLLResolvePass hence preventing depth update unless
// it is hair.
"Name": "DepthToDepthLinearPass",
"TemplateName": "DepthToLinearTemplate",
"TemplateName": "HairDepthToLinearTemplate",
"Enabled": true,
"Connections": [
{
@ -396,6 +376,13 @@
"Pass": "HairShortCutResolveDepthPass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DepthLinear"
}
}
]
}

@ -139,6 +139,7 @@
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"PipelineViewTag": "MainCamera",
"ShaderAsset": {
// Looking for it in the Shaders directory relative to the Assets directory
"FilePath": "Shaders/HairRenderingResolvePPLL.shader"

@ -5,7 +5,7 @@
<Class name="AZ::Uuid" field="guid" value="{A10B5BBC-8C5B-5CFA-BD2C-0FD712737F82}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="defaultwhite.png.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
@ -13,7 +13,7 @@
<Class name="AZ::Uuid" field="guid" value="{0847ECF0-FBC6-557E-BCFC-58784C2ED459}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/atomtressfx_passtemplates.azasset" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
@ -21,80 +21,16 @@
<Class name="AZ::Uuid" field="guid" value="{259539B9-DEB6-52F7-9BEC-CFEC0773566C}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="shaders/hairrenderingfillppll.azshader" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{E8301497-7A8B-559E-9CE1-2884592AE667}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="AZ::Uuid" field="guid" value="{902FE8CB-B6FC-599C-8986-9E44BF67E15E}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairparentpass.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{7E9E13B4-BEFB-581A-AEBB-0BA3B71F7B5A}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairglobalshapeconstraintscompute.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{A97D5FFA-F0CB-5A65-B080-9B9387FD1EA4}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/haircalculatestrandleveldatacompute.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{3F874810-7999-5573-80E7-6134631D431F}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairvelocityshockpropagationcompute.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{E4F74482-CB83-5BC2-A50E-60A5882C9193}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairlocalshapeconstraintscompute.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{0DD4BCEB-3FEE-5575-A20C-4B0D343EE78D}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairlengthconstraintswindandcollisioncompute.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{67B559EE-1445-5A2C-8E01-78CF06460D7E}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairupdatefollowhaircompute.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{2B332B34-23CE-588E-9BCA-73BFEE29AEEE}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairfillppll.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{184ED1B4-118F-5506-8E61-91A4D5DFFEA5}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/hairresolveppll.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/atomtressfx_passrequest.azasset" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</Class>
</ObjectStream>

@ -69,12 +69,6 @@ namespace AZ
HairShortCutResolveColorPassName = Name{ "HairShortCutResolveColorPass" };
++s_instanceCount;
if (!CreatePerPassResources())
{ // this might not be an error - if the pass system is still empty / minimal
// and these passes are not part of the minimal pipeline, they will not be created.
AZ_Error("Hair Gem", false, "Failed to create the hair shared buffer resource");
}
}
HairFeatureProcessor::~HairFeatureProcessor()
@ -106,11 +100,17 @@ namespace AZ
void HairFeatureProcessor::Deactivate()
{
m_hairPassRequestAsset.Reset();
DisableSceneNotification();
TickBus::Handler::BusDisconnect();
HairGlobalSettingsRequestBus::Handler::BusDisconnect();
}
void HairFeatureProcessor::ApplyRenderPipelineChange(RPI::RenderPipeline* renderPipeline)
{
AddHairParentPass(renderPipeline);
}
void HairFeatureProcessor::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
const float MAX_SIMULATION_TIME_STEP = 0.033f; // Assuming minimal of 30 fps
@ -268,6 +268,12 @@ namespace AZ
return;
}
// Skip adding draw or dispath items if there it no hair render objects
if (m_hairRenderObjects.size() == 0)
{
return;
}
// [To Do] - no culling scheme applied yet.
// Possibly setup the hair culling work group to be re-used for each view.
// See SkinnedMeshFeatureProcessor::Render for more details
@ -316,6 +322,53 @@ namespace AZ
return pass ? true : false;
}
bool HairFeatureProcessor::AddHairParentPass(RPI::RenderPipeline* renderPipeline)
{
if (HasHairParentPass(renderPipeline))
{
CreatePerPassResources();
return true;
}
const char* passRequestAssetFilePath = "Passes/AtomTressFX_PassRequest.azasset";
m_hairPassRequestAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(
passRequestAssetFilePath, AZ::RPI::AssetUtils::TraceLevel::Warning);
const AZ::RPI::PassRequest* passRequest = nullptr;
if (m_hairPassRequestAsset->IsReady())
{
passRequest = m_hairPassRequestAsset->GetDataAs<AZ::RPI::PassRequest>();
}
if (!passRequest)
{
AZ_Error("AtomTressFx", false, "Failed to add hair parent pass. Can't load PassRequest from %s", passRequestAssetFilePath);
return false;
}
m_usePPLLRenderTechnique = passRequest->m_templateName == AZ::Name("HairParentPassTemplate");
// Create the pass
RPI::Ptr<RPI::Pass> hairParentPass = RPI::PassSystemInterface::Get()->CreatePassFromRequest(passRequest);
if (!hairParentPass)
{
AZ_Error("AtomTressFx", false, "Create hair parent pass from pass request failed",
renderPipeline->GetId().GetCStr());
return false;
}
// Add the pass to render pipeline
bool success = renderPipeline->AddPassAfter(hairParentPass, Name("OpaquePass"));
// only create pass resources if it was success
if (success)
{
CreatePerPassResources();
}
else
{
AZ_Error("AtomTressFx", false, "Add the hair parent pass to render pipeline [%s] failed",
renderPipeline->GetId().GetCStr());
}
return success;
}
void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline)
{
// Proceed only if this is the main pipeline that contains the parent pass
@ -405,15 +458,11 @@ namespace AZ
bool HairFeatureProcessor::CreatePerPassResources()
{
if (m_sharedResourcesCreated)
{
return true;
}
SrgBufferDescriptor descriptor;
AZStd::string instanceNumber = AZStd::to_string(s_instanceCount);
// Shared buffer - this is a persistent buffer that needs to be created manually.
if (!m_sharedDynamicBuffer)
{
AZStd::vector<SrgBufferDescriptor> hairDynamicDescriptors;
DynamicHairData::PrepareSrgDescriptors(hairDynamicDescriptors, 1, 1);
@ -426,7 +475,7 @@ namespace AZ
}
// PPLL nodes buffer - created only if the PPLL technique is used
if (m_usePPLLRenderTechnique)
if (m_usePPLLRenderTechnique && !m_linkedListNodesBuffer)
{
descriptor = SrgBufferDescriptor(
RPI::CommonBufferPoolType::ReadWrite, RHI::Format::Unknown,
@ -441,7 +490,6 @@ namespace AZ
}
}
m_sharedResourcesCreated = true;
return true;
}

@ -113,6 +113,7 @@ namespace AZ
// FeatureProcessor overrides ...
void Activate() override;
void Deactivate() override;
void ApplyRenderPipelineChange(RPI::RenderPipeline* renderPipeline) override;
void Simulate(const FeatureProcessor::SimulatePacket& packet) override;
void Render(const FeatureProcessor::RenderPacket& packet) override;
@ -167,6 +168,8 @@ namespace AZ
bool HasHairParentPass(RPI::RenderPipeline* renderPipeline);
bool AddHairParentPass(RPI::RenderPipeline* renderPipeline);
//! The following will serve to register the FP in the Thumbnail system
AZStd::vector<AZStd::string> m_hairFeatureProcessorRegistryName;
@ -193,6 +196,9 @@ namespace AZ
Data::Instance<HairShortCutGeometryDepthAlphaPass> m_hairShortCutGeometryDepthAlphaPass = nullptr;
Data::Instance<HairShortCutGeometryShadingPass> m_hairShortCutGeometryShadingPass = nullptr;
// Cache the pass request data for creating a hair parent pass
AZ::Data::Asset<AZ::RPI::AnyAsset> m_hairPassRequestAsset;
//--------------------------------------------------------------
// Per Pass Resources
//--------------------------------------------------------------
@ -211,7 +217,6 @@ namespace AZ
float m_currentDeltaTime = 0.02f;
//! flag to disable/enable feature processor adding dispatch calls to compute passes.
bool m_addDispatchEnabled = true;
bool m_sharedResourcesCreated = false;
//! reload / pipeline changes force build dispatches and render items
bool m_forceRebuildRenderData = false;
bool m_forceClearRenderData = false;

Loading…
Cancel
Save