Skip to content

Commit

Permalink
Merge pull request #2752 from greenrazer/ExposeLodControls
Browse files Browse the repository at this point in the history
Expose lod controls
  • Loading branch information
gadams3 committed Aug 24, 2021
2 parents 660caf6 + dfc5baa commit 701e36f
Show file tree
Hide file tree
Showing 13 changed files with 313 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ namespace AZ
void BuildDrawPacketList(size_t modelLodIndex);
void SetRayTracingData();
void SetSortKey(RHI::DrawItemSortKey sortKey);
RHI::DrawItemSortKey GetSortKey();
void SetLodOverride(RPI::Cullable::LodOverride lodOverride);
RPI::Cullable::LodOverride GetLodOverride();
RHI::DrawItemSortKey GetSortKey() const;
void SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig);
RPI::Cullable::LodConfiguration GetMeshLodConfiguration() const;
void UpdateDrawPackets(bool forceUpdate = false);
void BuildCullable();
void UpdateCullBounds(const TransformServiceFeatureProcessor* transformService);
Expand Down Expand Up @@ -153,10 +153,10 @@ namespace AZ
AZ::Aabb GetLocalAabb(const MeshHandle& meshHandle) const override;

void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override;
RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override;
RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) const override;

void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) override;
RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) override;
void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig) override;
RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const override;

void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) override;
void SetRayTracingEnabled(const MeshHandle& meshHandle, bool rayTracingEnabled) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ namespace AZ
//! Sets the sort key for a given mesh handle.
virtual void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) = 0;
//! Gets the sort key for a given mesh handle.
virtual RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) = 0;
//! Sets an LOD override for a given mesh handle. This LOD will always be rendered instead being automatically determined.
virtual void SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride) = 0;
//! Gets the LOD override for a given mesh handle.
virtual RPI::Cullable::LodOverride GetLodOverride(const MeshHandle& meshHandle) = 0;
virtual RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) const = 0;
//! Sets LOD mesh configurations to be used in the Mesh Feature Processor
virtual void SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig) = 0;
//! Gets the LOD mesh configurations being used in the Mesh Feature Processor
virtual RPI::Cullable::LodConfiguration GetMeshLodConfiguration(const MeshHandle& meshHandle) const = 0;
//! Sets the option to exclude this mesh from baked reflection probe cubemaps
virtual void SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps) = 0;
//! Sets the option to exclude this mesh from raytracing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ namespace UnitTest
MOCK_METHOD2(SetLocalAabb, void(const MeshHandle&, const AZ::Aabb&));
MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&));
MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey));
MOCK_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&));
MOCK_METHOD2(SetLodOverride, void(const MeshHandle&, AZ::RPI::Cullable::LodOverride));
MOCK_METHOD1(GetLodOverride, AZ::RPI::Cullable::LodOverride(const MeshHandle&));
MOCK_CONST_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&));
MOCK_METHOD2(SetMeshLodConfiguration, void(const MeshHandle&, const AZ::RPI::Cullable::LodConfiguration&));
MOCK_CONST_METHOD1(GetMeshLodConfiguration, AZ::RPI::Cullable::LodConfiguration(const MeshHandle&));
MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&));
MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance<AZ::RPI::Material>&));
MOCK_METHOD2(SetRayTracingEnabled, void (const MeshHandle&, bool));
Expand Down
32 changes: 15 additions & 17 deletions Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ namespace AZ
}
}

RHI::DrawItemSortKey MeshFeatureProcessor::GetSortKey(const MeshHandle& meshHandle)
RHI::DrawItemSortKey MeshFeatureProcessor::GetSortKey(const MeshHandle& meshHandle) const
{
if (meshHandle.IsValid())
{
Expand All @@ -359,24 +359,24 @@ namespace AZ
}
}

void MeshFeatureProcessor::SetLodOverride(const MeshHandle& meshHandle, RPI::Cullable::LodOverride lodOverride)
void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig)
{
if (meshHandle.IsValid())
{
meshHandle->SetLodOverride(lodOverride);
meshHandle->SetMeshLodConfiguration(meshLodConfig);
}
}

RPI::Cullable::LodOverride MeshFeatureProcessor::GetLodOverride(const MeshHandle& meshHandle)
RPI::Cullable::LodConfiguration MeshFeatureProcessor::GetMeshLodConfiguration(const MeshHandle& meshHandle) const
{
if (meshHandle.IsValid())
{
return meshHandle->GetLodOverride();
return meshHandle->GetMeshLodConfiguration();
}
else
{
AZ_Assert(false, "Invalid mesh handle");
return 0;
return {RPI::Cullable::LodType::Default, 0, 0.0f, 0.0f };
}
}

Expand Down Expand Up @@ -968,19 +968,19 @@ namespace AZ
}
}

RHI::DrawItemSortKey MeshDataInstance::GetSortKey()
RHI::DrawItemSortKey MeshDataInstance::GetSortKey() const
{
return m_sortKey;
}

void MeshDataInstance::SetLodOverride(RPI::Cullable::LodOverride lodOverride)
void MeshDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
{
m_cullable.m_lodData.m_lodOverride = lodOverride;
m_cullable.m_lodData.m_lodConfiguration = meshLodConfig;
}

RPI::Cullable::LodOverride MeshDataInstance::GetLodOverride()
RPI::Cullable::LodConfiguration MeshDataInstance::GetMeshLodConfiguration() const
{
return m_cullable.m_lodData.m_lodOverride;
return m_cullable.m_lodData.m_lodConfiguration;
}

void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
Expand Down Expand Up @@ -1022,9 +1022,6 @@ namespace AZ
{
//initialize the lod
RPI::Cullable::LodData::Lod& lod = lodData.m_lods[lodIndex];
//[GFX TODO][ATOM-5562] - Level of detail: override lod distances and add global lod multiplier(s)
static const float MinimumScreenCoverage = 1.0f/1080.0f; //mesh should cover at least a screen pixel at 1080p to be drawn
static const float ReductionFactor = 0.5f;
if (lodIndex == 0)
{
//first lod
Expand All @@ -1033,17 +1030,18 @@ namespace AZ
else
{
//every other lod: use the previous lod's min
lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex-1].m_screenCoverageMin, MinimumScreenCoverage);
lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex - 1].m_screenCoverageMin, lodData.m_lodConfiguration.m_minimumScreenCoverage);
}

if (lodIndex < lodAssets.size() - 1)
{
//first and middle lods: compute a stepdown value for the min
lod.m_screenCoverageMin = AZStd::GetMax(ReductionFactor * lod.m_screenCoverageMax, MinimumScreenCoverage);
lod.m_screenCoverageMin = AZStd::GetMax(lodData.m_lodConfiguration.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_lodConfiguration.m_minimumScreenCoverage);
}
else
{
//last lod: use MinimumScreenCoverage for the min
lod.m_screenCoverageMin = MinimumScreenCoverage;
lod.m_screenCoverageMin = lodData.m_lodConfiguration.m_minimumScreenCoverage;
}

lod.m_drawPackets.clear();
Expand Down
19 changes: 17 additions & 2 deletions Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,23 @@ namespace AZ
};
CullData m_cullData;

enum LodType : uint8_t
{
Default = 0,
ScreenCoverage,
SpecificLod,
};
using LodOverride = uint8_t;
static constexpr uint8_t NoLodOverride = AZStd::numeric_limits<LodOverride>::max();

struct LodConfiguration
{
LodType m_lodType = LodType::Default;
LodOverride m_lodOverride = 0;
// the minimum possibe area a sphere enclosing a mesh projected onto the screen should have before it is culled.
float m_minimumScreenCoverage = 1.0f / 1080.0f; // For default, mesh should cover at least a screen pixel at 1080p to be drawn;
// The screen area decay between 0 and 1, i.e. closer to 1 -> lose quality immediately, closer to 0 -> never lose quality
float m_qualityDecayRate = 0.5f;
};

struct LodData
{
Expand All @@ -88,7 +103,7 @@ namespace AZ
//! Suggest setting to: 0.5f*localAabb.GetExtents().GetMaxElement()
float m_lodSelectionRadius = 1.0f;

LodOverride m_lodOverride = NoLodOverride;
LodConfiguration m_lodConfiguration;
};
LodData m_lodData;

Expand Down
27 changes: 16 additions & 11 deletions Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,20 +672,25 @@ namespace AZ
}
};

if (lodData.m_lodOverride == Cullable::NoLodOverride)
switch (lodData.m_lodConfiguration.m_lodType)
{
for (const Cullable::LodData::Lod& lod : lodData.m_lods)
{
//Note that this supports overlapping lod ranges (to suport cross-fading lods, for example)
if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax)
case Cullable::LodType::SpecificLod:
if (lodData.m_lodConfiguration.m_lodOverride < lodData.m_lods.size())
{
addLodToDrawPacket(lod);
addLodToDrawPacket(lodData.m_lods.at(lodData.m_lodConfiguration.m_lodOverride));
}
}
}
else if(lodData.m_lodOverride < lodData.m_lods.size())
{
addLodToDrawPacket(lodData.m_lods.at(lodData.m_lodOverride));
break;
case Cullable::LodType::ScreenCoverage:
default:
for (const Cullable::LodData::Lod& lod : lodData.m_lods)
{
// Note that this supports overlapping lod ranges (to suport cross-fading lods, for example)
if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax)
{
addLodToDrawPacket(lod);
}
}
break;
}

return numVisibleDrawPackets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,18 @@ namespace AZ
virtual void SetSortKey(RHI::DrawItemSortKey sortKey) = 0;
virtual RHI::DrawItemSortKey GetSortKey() const = 0;

virtual void SetLodType(RPI::Cullable::LodType lodType) = 0;
virtual RPI::Cullable::LodType GetLodType() const = 0;

virtual void SetLodOverride(RPI::Cullable::LodOverride lodOverride) = 0;
virtual RPI::Cullable::LodOverride GetLodOverride() const = 0;

virtual void SetMinimumScreenCoverage(float minimumScreenCoverage) = 0;
virtual float GetMinimumScreenCoverage() const = 0;

virtual void SetQualityDecayRate(float qualityDecayRate) = 0;
virtual float GetQualityDecayRate() const = 0;

virtual void SetVisibility(bool visible) = 0;
virtual bool GetVisibility() const = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,36 @@ namespace AZ
"MeshComponentConfig", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_modelAsset, "Mesh Asset", "Mesh asset reference")
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_sortKey, "Sort Key", "Transparent meshes are drawn by sort key then depth. Used this to force certain transparent meshes to draw before or after others.")
->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.")
->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet)
->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_excludeFromReflectionCubeMaps, "Exclude from reflection cubemaps", "Mesh will not be visible in baked reflection probe cubemaps")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_useForwardPassIblSpecular, "Use Forward Pass IBL Specular",
"Renders IBL specular reflections in the forward pass, using only the most influential probe (based on the position of the entity) and the global IBL cubemap. Can reduce rendering costs, but only recommended for static objects that are affected by at most one reflection probe.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_modelAsset, "Mesh Asset", "Mesh asset reference")
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentConfig::m_sortKey, "Sort Key", "Transparent meshes are drawn by sort key then depth. Used this to force certain transparent meshes to draw before or after others.")
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet)
->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_excludeFromReflectionCubeMaps, "Exclude from reflection cubemaps", "Mesh will not be visible in baked reflection probe cubemaps")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::CheckBox, &MeshComponentConfig::m_useForwardPassIblSpecular, "Use Forward Pass IBL Specular",
"Renders IBL specular reflections in the forward pass, using only the most influential probe (based on the position of the entity) and the global IBL cubemap. Can reduce rendering costs, but only recommended for static objects that are affected by at most one reflection probe.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodType, "Lod Type", "Lod Method.")
->EnumAttribute(RPI::Cullable::LodType::Default, "Default")
->EnumAttribute(RPI::Cullable::LodType::ScreenCoverage, "Screen Coverage")
->EnumAttribute(RPI::Cullable::LodType::SpecificLod, "Specific Lod")
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::IsAssetSet)
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::EntireTree)
->ClassElement(AZ::Edit::ClassElements::Group, "Lod Configuration")
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::ShowLodConfig)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshComponentConfig::m_lodOverride, "Lod Override", "Allows the rendered LOD to be overridden instead of being calculated automatically.")
->Attribute(AZ::Edit::Attributes::EnumValues, &MeshComponentConfig::GetLodOverrideValues)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::LodTypeIsSpecificLOD)
->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_minimumScreenCoverage, "Minimum Screen Coverage", "Minimum proportion of screen area an entitiy takes up, after that the entitiy is culled.")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, 1.f)
->Attribute(AZ::Edit::Attributes::Suffix, " percent")
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::LodTypeIsScreenCoverage)
->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentConfig::m_qualityDecayRate, "Quality Decay Rate",
"Rate at which mesh quality decays (0 -> always stay highest quality, 1 -> quality falls off to lowest quality immediately).")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, 1.f)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentConfig::LodTypeIsScreenCoverage)
;
}
}
Expand Down

0 comments on commit 701e36f

Please sign in to comment.