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.
o3de/Gems/Vegetation/Code/Source/Components/DescriptorWeightSelectorCom...

203 lines
8.4 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "DescriptorWeightSelectorComponent.h"
#include <AzCore/Component/Entity.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <AzCore/Debug/Profiler.h>
namespace Vegetation
{
void DescriptorWeightSelectorConfig::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<DescriptorWeightSelectorConfig, AZ::ComponentConfig>()
->Version(0)
->Field("SortBehavior", &DescriptorWeightSelectorConfig::m_sortBehavior)
->Field("Gradient", &DescriptorWeightSelectorConfig::m_gradientSampler)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<DescriptorWeightSelectorConfig>(
"Vegetation Asset Weight Selector", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &DescriptorWeightSelectorConfig::m_sortBehavior, "Sort By Weight", "Defines how descriptors will be sorted before gradient is used for selection")
->EnumAttribute(SortBehavior::Unsorted, "Unsorted")
->EnumAttribute(SortBehavior::Ascending, "Ascending (lowest first)")
->EnumAttribute(SortBehavior::Descending, "Descending (highest first)")
->DataElement(0, &DescriptorWeightSelectorConfig::m_gradientSampler, "Gradient", "Gradient mapped to range between 0 and total combined weight of all descriptors.")
;
}
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<DescriptorWeightSelectorConfig>()
->Attribute(AZ::Script::Attributes::Category, "Vegetation")
->Constructor()
->Property("noiseType",
[](DescriptorWeightSelectorConfig* config) { return (AZ::u8&)(config->m_sortBehavior); },
[](DescriptorWeightSelectorConfig* config, const AZ::u8& i) { config->m_sortBehavior = (SortBehavior)i; })
->Property("gradientSampler", BehaviorValueProperty(&DescriptorWeightSelectorConfig::m_gradientSampler))
;
}
}
void DescriptorWeightSelectorComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("VegetationDescriptorSelectorService", 0xe684eeec));
}
void DescriptorWeightSelectorComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("VegetationDescriptorSelectorService", 0xe684eeec));
}
void DescriptorWeightSelectorComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& services)
{
}
void DescriptorWeightSelectorComponent::Reflect(AZ::ReflectContext* context)
{
DescriptorWeightSelectorConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<DescriptorWeightSelectorComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &DescriptorWeightSelectorComponent::m_configuration)
;
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Constant("DescriptorWeightSelectorComponentTypeId", BehaviorConstant(DescriptorWeightSelectorComponentTypeId));
behaviorContext->Class<DescriptorWeightSelectorComponent>()->RequestBus("DescriptorWeightSelectorRequestBus");
behaviorContext->EBus<DescriptorWeightSelectorRequestBus>("DescriptorWeightSelectorRequestBus")
->Attribute(AZ::Script::Attributes::Category, "Vegetation")
->Event("GetSortBehavior", &DescriptorWeightSelectorRequestBus::Events::GetSortBehavior)
->Event("SetSortBehavior", &DescriptorWeightSelectorRequestBus::Events::SetSortBehavior)
->VirtualProperty("SortBehavior", "GetSortBehavior", "SetSortBehavior")
->Event("GetGradientSampler", &DescriptorWeightSelectorRequestBus::Events::GetGradientSampler)
;
}
}
DescriptorWeightSelectorComponent::DescriptorWeightSelectorComponent(const DescriptorWeightSelectorConfig& configuration)
: m_configuration(configuration)
{
}
void DescriptorWeightSelectorComponent::Activate()
{
m_dependencyMonitor.Reset();
m_dependencyMonitor.ConnectOwner(GetEntityId());
m_dependencyMonitor.ConnectDependencies({ m_configuration.m_gradientSampler.m_gradientId });
DescriptorSelectorRequestBus::Handler::BusConnect(GetEntityId());
DescriptorWeightSelectorRequestBus::Handler::BusConnect(GetEntityId());
}
void DescriptorWeightSelectorComponent::Deactivate()
{
m_dependencyMonitor.Reset();
DescriptorSelectorRequestBus::Handler::BusDisconnect();
DescriptorWeightSelectorRequestBus::Handler::BusDisconnect();
}
bool DescriptorWeightSelectorComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const DescriptorWeightSelectorConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool DescriptorWeightSelectorComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<DescriptorWeightSelectorConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
void DescriptorWeightSelectorComponent::SelectDescriptors(const DescriptorSelectorParams& params, DescriptorPtrVec& descriptors) const
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
switch (m_configuration.m_sortBehavior)
{
default:
case SortBehavior::Unsorted:
//defaulting to no sorting as an optimization since descriptors can be presorted
break;
case SortBehavior::Ascending:
std::sort(descriptors.begin(), descriptors.end(), [](const auto& lhs, const auto& rhs) { return lhs->m_weight < rhs->m_weight; });
break;
case SortBehavior::Descending:
std::sort(descriptors.begin(), descriptors.end(), [](const auto& lhs, const auto& rhs) { return lhs->m_weight > rhs->m_weight; });
break;
}
float totalWeight = 0.0f;
for (const auto& descriptor : descriptors)
{
totalWeight += descriptor->m_weight;
}
int count = 0;
const GradientSignal::GradientSampleParams sampleParams(params.m_position);
float minimumWeight = m_configuration.m_gradientSampler.GetValue(sampleParams) * totalWeight;
float currentWeight = 0.0f;
for (const auto& descriptor : descriptors)
{
currentWeight += descriptor->m_weight;
if (currentWeight < minimumWeight)
{
++count;
}
}
if (count > 0)
{
descriptors.erase(descriptors.begin(), descriptors.begin() + count);
}
}
SortBehavior DescriptorWeightSelectorComponent::GetSortBehavior() const
{
return m_configuration.m_sortBehavior;
}
void DescriptorWeightSelectorComponent::SetSortBehavior(SortBehavior behavior)
{
m_configuration.m_sortBehavior = behavior;
LmbrCentral::DependencyNotificationBus::Event(GetEntityId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
}
GradientSignal::GradientSampler& DescriptorWeightSelectorComponent::GetGradientSampler()
{
return m_configuration.m_gradientSampler;
}
}