Merge branch 'development' into Atom/jromnoa/ATOM-14767-update-build-config-and-s3-uploader
This commit is contained in:
@@ -274,7 +274,7 @@ namespace AZ
|
||||
{
|
||||
using Callable = AZStd::conditional_t<AZStd::function_traits<Invocable>::value, AZStd::function<typename AZStd::function_traits<Invocable>::function_type>, Invocable>;
|
||||
public:
|
||||
AZ_RTTI((AttributeInvocable<Invocable>, "{60D5804F-9AF4-4EB1-8F5A-62AFB4883F9D}"), AZ::Attribute);
|
||||
AZ_RTTI((AttributeInvocable<Invocable>, "{60D5804F-9AF4-4EB1-8F5A-62AFB4883F9D}", Invocable), AZ::Attribute);
|
||||
AZ_CLASS_ALLOCATOR(AttributeInvocable<Invocable>, SystemAllocator, 0);
|
||||
template<typename CallableType>
|
||||
explicit AttributeInvocable(CallableType&& invocable)
|
||||
|
||||
@@ -2010,6 +2010,28 @@ TEST_F(SerializeBasicTest, BasicTypeTest_Succeed)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This test will dynamic cast (azrtti_cast) between incompatible types, which should always result in nullptr.
|
||||
If this test fails, the RTTI declaration for the relevant type is incorrect.
|
||||
*/
|
||||
TEST_F(Serialization, AttributeRTTI)
|
||||
{
|
||||
{
|
||||
AttributeInvocable<AZStd::function<AZStd::string(AZStd::string)>> fn([](AZStd::string x) { return x + x; });
|
||||
Attribute* fnDownCast = &fn;
|
||||
auto fnUpCast = azrtti_cast<AttributeInvocable<AZStd::function<int(int)>>*>(fnDownCast);
|
||||
EXPECT_EQ(fnUpCast, nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
AttributeFunction<AZStd::string(AZStd::string)> fn([](AZStd::string x) { return x + x; });
|
||||
Attribute* fnDownCast = &fn;
|
||||
auto fnUpCast = azrtti_cast<AttributeFunction<int(int)>*>(fnDownCast);
|
||||
EXPECT_EQ(fnUpCast, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deprecation
|
||||
*/
|
||||
|
||||
@@ -181,7 +181,8 @@ void CViewportTitleDlg::SetupCameraDropdownMenu()
|
||||
auto comboBoxTextChanged = static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::currentTextChanged);
|
||||
|
||||
SetSpeedComboBox(cameraMoveSpeed);
|
||||
m_cameraSpeed->setInsertPolicy(QComboBox::NoInsert);
|
||||
m_cameraSpeed->setInsertPolicy(QComboBox::InsertAtBottom);
|
||||
m_cameraSpeed->setDuplicatesEnabled(false);
|
||||
connect(m_cameraSpeed, comboBoxTextChanged, this, &CViewportTitleDlg::OnUpdateMoveSpeedText);
|
||||
connect(m_cameraSpeed->lineEdit(), &QLineEdit::returnPressed, this, &CViewportTitleDlg::OnSpeedComboBoxEnter);
|
||||
|
||||
|
||||
@@ -117,11 +117,11 @@ protected:
|
||||
// Speed combobox/lineEdit settings
|
||||
double m_minSpeed = 0.01;
|
||||
double m_maxSpeed = 100.0;
|
||||
double m_speedStep = 0.01;
|
||||
double m_speedStep = 0.001;
|
||||
int m_numDecimals = 3;
|
||||
|
||||
// Speed presets
|
||||
float m_speedPresetValues[3] = { 0.1f, 1.0f, 10.0f };
|
||||
float m_speedPresetValues[4] = { 0.01f, 0.1f, 1.0f, 10.0f };
|
||||
|
||||
double m_fieldWidthMultiplier = 1.8;
|
||||
|
||||
|
||||
@@ -109,14 +109,7 @@ namespace ImageProcessingAtom
|
||||
while (!m_process->IsFinished() && !IsJobCancelled())
|
||||
{
|
||||
m_process->UpdateProcess();
|
||||
if (m_isPreview)
|
||||
{
|
||||
m_output->SetProgress(m_process->GetProgress() / static_cast<float>(m_previewProcessStep));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output->SetProgress(m_process->GetProgress());
|
||||
}
|
||||
m_output->SetProgress(m_process->GetProgress() / static_cast<float>(m_previewProcessStep));
|
||||
}
|
||||
|
||||
IImageObjectPtr outputImage = m_process->GetOutputImage();
|
||||
@@ -125,7 +118,7 @@ namespace ImageProcessingAtom
|
||||
m_output->SetOutputImage(outputImage, ImageConvertOutput::Base);
|
||||
m_output->SetOutputImage(outputImageAlpha, ImageConvertOutput::Alpha);
|
||||
|
||||
if (m_isPreview && !IsJobCancelled())
|
||||
if (!IsJobCancelled())
|
||||
{
|
||||
// For preview, combine image output with alpha if any
|
||||
m_output->SetProgress(1.0f / static_cast<float>(m_previewProcessStep));
|
||||
|
||||
@@ -72,7 +72,6 @@ namespace ImageProcessingAtom
|
||||
static const int m_previewProcessStep = 2;
|
||||
|
||||
AZStd::unique_ptr<ImageConvertProcess> m_process;
|
||||
bool m_isPreview;
|
||||
AZStd::atomic_bool m_isCancelled;
|
||||
ImageConvertOutput* m_output;
|
||||
};
|
||||
|
||||
@@ -95,6 +95,8 @@ namespace AZ
|
||||
|
||||
TransformServiceFeatureProcessorInterface::ObjectId m_objectId;
|
||||
|
||||
Aabb m_aabb = Aabb::CreateNull();
|
||||
|
||||
bool m_cullBoundsNeedsUpdate = false;
|
||||
bool m_cullableNeedsRebuild = false;
|
||||
bool m_objectSrgNeedsUpdate = true;
|
||||
@@ -160,6 +162,9 @@ namespace AZ
|
||||
Transform GetTransform(const MeshHandle& meshHandle) override;
|
||||
Vector3 GetNonUniformScale(const MeshHandle& meshHandle) override;
|
||||
|
||||
void SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb) override;
|
||||
AZ::Aabb GetLocalAabb(const MeshHandle& meshHandle) const override;
|
||||
|
||||
void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override;
|
||||
RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override;
|
||||
|
||||
|
||||
+4
@@ -86,6 +86,10 @@ namespace AZ
|
||||
virtual Transform GetTransform(const MeshHandle& meshHandle) = 0;
|
||||
//! Gets the non-uniform scale for a given mesh handle.
|
||||
virtual Vector3 GetNonUniformScale(const MeshHandle& meshHandle) = 0;
|
||||
//! Sets the local space bbox for a given mesh handle. You don't need to call this for static models, only skinned/animated models
|
||||
virtual void SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb) = 0;
|
||||
//! Gets the local space bbox for a given mesh handle. Unless SetLocalAabb has been called before, this will be the bbox of the model asset
|
||||
virtual AZ::Aabb GetLocalAabb(const MeshHandle& meshHandle) const = 0;
|
||||
//! 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.
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace UnitTest
|
||||
MOCK_METHOD2(SetMaterialAssignmentMap, void(const MeshHandle&, const AZ::Render::MaterialAssignmentMap&));
|
||||
MOCK_METHOD1(GetTransform, AZ::Transform(const MeshHandle&));
|
||||
MOCK_METHOD1(GetNonUniformScale, AZ::Vector3(const MeshHandle&));
|
||||
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));
|
||||
|
||||
@@ -304,6 +304,30 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void MeshFeatureProcessor::SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb)
|
||||
{
|
||||
if (meshHandle.IsValid())
|
||||
{
|
||||
MeshDataInstance& meshData = *meshHandle;
|
||||
meshData.m_aabb = localAabb;
|
||||
meshData.m_cullBoundsNeedsUpdate = true;
|
||||
meshData.m_objectSrgNeedsUpdate = true;
|
||||
}
|
||||
};
|
||||
|
||||
AZ::Aabb MeshFeatureProcessor::GetLocalAabb(const MeshHandle& meshHandle) const
|
||||
{
|
||||
if (meshHandle.IsValid())
|
||||
{
|
||||
return meshHandle->m_aabb;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Invalid mesh handle");
|
||||
return Aabb::CreateNull();
|
||||
}
|
||||
}
|
||||
|
||||
Transform MeshFeatureProcessor::GetTransform(const MeshHandle& meshHandle)
|
||||
{
|
||||
if (meshHandle.IsValid())
|
||||
@@ -603,6 +627,8 @@ namespace AZ
|
||||
SetRayTracingData();
|
||||
}
|
||||
|
||||
m_aabb = model->GetModelAsset()->GetAabb();
|
||||
|
||||
m_cullableNeedsRebuild = true;
|
||||
m_cullBoundsNeedsUpdate = true;
|
||||
m_objectSrgNeedsUpdate = true;
|
||||
@@ -996,7 +1022,7 @@ namespace AZ
|
||||
RPI::Cullable::CullData& cullData = m_cullable.m_cullData;
|
||||
RPI::Cullable::LodData& lodData = m_cullable.m_lodData;
|
||||
|
||||
const Aabb& localAabb = m_model->GetAabb();
|
||||
const Aabb& localAabb = m_aabb;
|
||||
lodData.m_lodSelectionRadius = 0.5f*localAabb.GetExtents().GetMaxElement();
|
||||
|
||||
const size_t modelLodCount = m_model->GetLodCount();
|
||||
@@ -1077,7 +1103,7 @@ namespace AZ
|
||||
|
||||
Vector3 center;
|
||||
float radius;
|
||||
Aabb localAabb = m_model->GetAabb();
|
||||
Aabb localAabb = m_aabb;
|
||||
localAabb.MultiplyByScale(nonUniformScale);
|
||||
|
||||
localAabb.GetTransformedAabb(localToWorld).GetAsSphere(center, radius);
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace AZ
|
||||
: public Data::InstanceData
|
||||
{
|
||||
friend class ModelSystem;
|
||||
|
||||
public:
|
||||
AZ_INSTANCE_DATA(Model, "{C30F5522-B381-4B38-BBAF-6E0B1885C8B9}");
|
||||
AZ_CLASS_ALLOCATOR(Model, AZ::SystemAllocator, 0);
|
||||
@@ -53,8 +54,6 @@ namespace AZ
|
||||
//! Returns whether a buffer upload is pending.
|
||||
bool IsUploadPending() const;
|
||||
|
||||
const AZ::Aabb& GetAabb() const;
|
||||
|
||||
const Data::Asset<ModelAsset>& GetModelAsset() const;
|
||||
|
||||
//! Checks a ray for intersection against this model. The ray must be in the same coordinate space as the model.
|
||||
@@ -105,8 +104,6 @@ namespace AZ
|
||||
|
||||
// Tracks whether buffers have all been streamed up to the GPU.
|
||||
bool m_isUploadPending = false;
|
||||
|
||||
AZ::Aabb m_aabb;
|
||||
};
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -62,8 +62,6 @@ namespace AZ
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
|
||||
|
||||
m_aabb = modelAsset.GetAabb();
|
||||
|
||||
m_lods.resize(modelAsset.GetLodAssets().size());
|
||||
|
||||
for (size_t lodIndex = 0; lodIndex < m_lods.size(); ++lodIndex)
|
||||
@@ -127,11 +125,6 @@ namespace AZ
|
||||
return m_isUploadPending;
|
||||
}
|
||||
|
||||
const AZ::Aabb& Model::GetAabb() const
|
||||
{
|
||||
return m_aabb;
|
||||
}
|
||||
|
||||
const Data::Asset<ModelAsset>& Model::GetModelAsset() const
|
||||
{
|
||||
return m_modelAsset;
|
||||
@@ -140,9 +133,16 @@ namespace AZ
|
||||
bool Model::LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
|
||||
|
||||
if (!GetModelAsset())
|
||||
{
|
||||
AZ_Assert(false, "Invalid Model - not created from a ModelAsset?");
|
||||
return false;
|
||||
}
|
||||
|
||||
float start;
|
||||
float end;
|
||||
const int result = Intersect::IntersectRayAABB2(rayStart, rayDir.GetReciprocal(), m_aabb, start, end);
|
||||
const int result = Intersect::IntersectRayAABB2(rayStart, rayDir.GetReciprocal(), GetModelAsset()->GetAabb(), start, end);
|
||||
if (Intersect::ISECT_RAY_AABB_NONE != result)
|
||||
{
|
||||
if (ModelAsset* modelAssetPtr = m_modelAsset.Get())
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace AZ
|
||||
|
||||
With that percentage we can determine which Lod we want to use.
|
||||
*/
|
||||
Aabb modelAabb = model.GetAabb();
|
||||
Aabb modelAabb = model.GetModelAsset()->GetAabb();
|
||||
modelAabb.Translate(position);
|
||||
|
||||
Vector3 center;
|
||||
|
||||
@@ -460,10 +460,10 @@ namespace AZ
|
||||
|
||||
Aabb MeshComponentController::GetLocalBounds()
|
||||
{
|
||||
const Data::Instance<RPI::Model> model = GetModel();
|
||||
if (model)
|
||||
if (m_meshHandle.IsValid() && m_meshFeatureProcessor)
|
||||
{
|
||||
Aabb aabb = model->GetAabb();
|
||||
Aabb aabb = m_meshFeatureProcessor->GetLocalAabb(m_meshHandle);
|
||||
|
||||
aabb.MultiplyByScale(m_cachedNonUniformScale);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
@@ -83,12 +83,20 @@ namespace AZ
|
||||
void AtomActorInstance::UpdateBounds()
|
||||
{
|
||||
// Update RenderActorInstance world bounding box
|
||||
// The bounding box is moving with the actor instance. It is static in the way that it does not change shape.
|
||||
// The bounding box is moving with the actor instance.
|
||||
// The entity and actor transforms are kept in sync already.
|
||||
m_worldAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetAABB().GetMin(), m_actorInstance->GetAABB().GetMax());
|
||||
|
||||
// Update RenderActorInstance local bounding box
|
||||
m_localAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetStaticBasedAABB().GetMin(), m_actorInstance->GetStaticBasedAABB().GetMax());
|
||||
// NB: computing the local bbox from the world bbox makes the local bbox artifically larger than it should be
|
||||
// instead EMFX should support getting the local bbox from the actor instance directly
|
||||
m_localAABB = m_worldAABB.GetTransformedAabb(m_transformInterface->GetWorldTM().GetInverse());
|
||||
|
||||
// Update bbox on mesh instance if it exists
|
||||
if (m_meshFeatureProcessor && m_meshHandle && m_meshHandle->IsValid() && m_skinnedMeshInstance)
|
||||
{
|
||||
m_meshFeatureProcessor->SetLocalAabb(*m_meshHandle, m_localAABB);
|
||||
}
|
||||
|
||||
AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->RefreshEntityLocalBoundsUnion(m_entityId);
|
||||
}
|
||||
|
||||
@@ -57,14 +57,68 @@ namespace EMotionFX
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void ActorComponent::BoundingBoxConfiguration::Set(ActorInstance* actor) const
|
||||
{
|
||||
if (m_autoUpdateBounds)
|
||||
{
|
||||
actor->SetupAutoBoundsUpdate(m_updateTimeFrequency, m_boundsType, m_updateItemFrequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->SetBoundsUpdateType(m_boundsType);
|
||||
actor->SetBoundsUpdateEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ActorComponent::BoundingBoxConfiguration::SetAndUpdate(ActorInstance* actor) const
|
||||
{
|
||||
Set(actor);
|
||||
const AZ::u32 freq = actor->GetBoundsUpdateEnabled() ? actor->GetBoundsUpdateItemFrequency() : 1;
|
||||
actor->UpdateBounds(0, actor->GetBoundsUpdateType(), freq);
|
||||
}
|
||||
|
||||
void ActorComponent::BoundingBoxConfiguration::Reflect(AZ::ReflectContext * context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<BoundingBoxConfiguration>()
|
||||
->Version(2, [](AZ::SerializeContext& sc, AZ::SerializeContext::DataElementNode& node)
|
||||
{
|
||||
if (node.GetVersion() < 2)
|
||||
{
|
||||
// m_boundsType used to be an enum class with `int' underlying type, is now `u8'
|
||||
static const char* m_boundsType_name = "m_boundsType";
|
||||
static AZ::Crc32 m_boundsType_nameCrc(m_boundsType_name);
|
||||
|
||||
int m_boundsType_as_int;
|
||||
if (!node.GetChildData(m_boundsType_nameCrc, m_boundsType_as_int))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!node.RemoveElementByName(m_boundsType_nameCrc)) return false;
|
||||
if (node.AddElementWithData(sc, m_boundsType_name, (AZ::u8)m_boundsType_as_int) == -1) return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
->Field("m_boundsType", &BoundingBoxConfiguration::m_boundsType)
|
||||
->Field("m_autoUpdateBounds", &BoundingBoxConfiguration::m_autoUpdateBounds)
|
||||
->Field("m_updateTimeFrequency", &BoundingBoxConfiguration::m_updateTimeFrequency)
|
||||
->Field("m_updateItemFrequency", &BoundingBoxConfiguration::m_updateItemFrequency)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void ActorComponent::Configuration::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
BoundingBoxConfiguration::Reflect(context);
|
||||
|
||||
auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<Configuration>()
|
||||
->Version(3)
|
||||
->Version(4)
|
||||
->Field("ActorAsset", &Configuration::m_actorAsset)
|
||||
->Field("MaterialPerLOD", &Configuration::m_materialPerLOD)
|
||||
->Field("RenderSkeleton", &Configuration::m_renderSkeleton)
|
||||
@@ -74,6 +128,7 @@ namespace EMotionFX
|
||||
->Field("AttachmentTarget", &Configuration::m_attachmentTarget)
|
||||
->Field("SkinningMethod", &Configuration::m_skinningMethod)
|
||||
->Field("LODLevel", &Configuration::m_lodLevel)
|
||||
->Field("BoundingBoxConfig", &Configuration::m_bboxConfig)
|
||||
->Field("ForceJointsUpdateOOV", &Configuration::m_forceUpdateJointsOOV)
|
||||
;
|
||||
}
|
||||
@@ -349,6 +404,8 @@ namespace EMotionFX
|
||||
AZ::TransformNotificationBus::MultiHandler::BusConnect(GetEntityId());
|
||||
|
||||
m_actorInstance->UpdateWorldTransform();
|
||||
// Set bounds update mode and compute bbox first time
|
||||
m_configuration.m_bboxConfig.SetAndUpdate(m_actorInstance.get());
|
||||
m_actorInstance->UpdateBounds(0, ActorInstance::EBoundsType::BOUNDS_STATIC_BASED);
|
||||
|
||||
// Creating the render actor AFTER both actor asset and mesh asset loaded.
|
||||
|
||||
@@ -49,6 +49,26 @@ namespace EMotionFX
|
||||
AZ_COMPONENT(ActorComponent, "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}");
|
||||
friend class EditorActorComponent;
|
||||
|
||||
struct BoundingBoxConfiguration
|
||||
{
|
||||
AZ_TYPE_INFO(BoundingBoxConfiguration, "{EBCFF975-00A5-4578-85C7-59909F52067C}");
|
||||
|
||||
BoundingBoxConfiguration() = default;
|
||||
|
||||
EMotionFX::ActorInstance::EBoundsType m_boundsType = EMotionFX::ActorInstance::BOUNDS_STATIC_BASED;
|
||||
bool m_autoUpdateBounds = true;
|
||||
float m_updateTimeFrequency = 0.f;
|
||||
AZ::u32 m_updateItemFrequency = 1;
|
||||
|
||||
// Set the bounding box configuration of the given actor instance to the parameters given by `this'. The actor instance must not be null (this is not checked).
|
||||
void Set(ActorInstance* inst) const;
|
||||
|
||||
// Set the bounding box configuration, then update the bounds of the actor instance
|
||||
void SetAndUpdate(ActorInstance* inst) const;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration struct for procedural configuration of Actor Components.
|
||||
*/
|
||||
@@ -71,6 +91,7 @@ namespace EMotionFX
|
||||
// default, joints level update (beside the root joint) on
|
||||
// actor are disabled when the actor is out of view.
|
||||
bool m_forceUpdateJointsOOV = false;
|
||||
BoundingBoxConfiguration m_bboxConfig; ///< Configuration for bounding box type and updates
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
};
|
||||
|
||||
@@ -58,11 +58,49 @@ namespace EMotionFX
|
||||
->Field("SkinningMethod", &EditorActorComponent::m_skinningMethod)
|
||||
->Field("UpdateJointTransformsWhenOutOfView", &EditorActorComponent::m_forceUpdateJointsOOV)
|
||||
->Field("LodLevel", &EditorActorComponent::m_lodLevel)
|
||||
->Field("BBoxConfig", &EditorActorComponent::m_bboxConfig)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<ActorComponent::BoundingBoxConfiguration>("Actor Bounding Box Config", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &ActorComponent::BoundingBoxConfiguration::m_boundsType,
|
||||
"Bounds type",
|
||||
"The method used to compute the Actor bounding box. NOTE: ordered by least expensive to compute to most expensive to compute."
|
||||
)
|
||||
->EnumAttribute(ActorInstance::BOUNDS_STATIC_BASED, "Static bounds (source-asset bounds)")
|
||||
->EnumAttribute(ActorInstance::BOUNDS_NODE_BASED, "Bone position-based")
|
||||
->EnumAttribute(ActorInstance::BOUNDS_NODEOBB_BASED, "Bone local bounding box-based")
|
||||
->EnumAttribute(ActorInstance::BOUNDS_MESH_BASED, "Render mesh vertex position-based (VERY EXPENSIVE)")
|
||||
|
||||
->DataElement(0, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds,
|
||||
"Automatically update bounds?",
|
||||
"If true, bounds are automatically updated based on some frequency. Otherwise bounds are computed only at creation or when triggered manually"
|
||||
)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
|
||||
|
||||
->DataElement(0, &ActorComponent::BoundingBoxConfiguration::m_updateTimeFrequency,
|
||||
"Update frequency",
|
||||
"How often to update bounds automatically"
|
||||
)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " Hz")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.f)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.001f)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds)
|
||||
|
||||
->DataElement(0, &ActorComponent::BoundingBoxConfiguration::m_updateItemFrequency,
|
||||
"Update item skip factor",
|
||||
"How many items (bones or vertices) to skip when automatically updating bounds."
|
||||
" <br> i.e. =1 uses every single item, =2 uses every 2nd item, =3 uses every 3rd item... "
|
||||
)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " items")
|
||||
->Attribute(AZ::Edit::Attributes::Min, (AZ::u32)1)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds)
|
||||
;
|
||||
|
||||
editContext->Class<EditorActorComponent>("Actor", "The Actor component manages an instance of an Actor")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Animation")
|
||||
@@ -118,6 +156,9 @@ namespace EMotionFX
|
||||
->DataElement(0, &EditorActorComponent::m_forceUpdateJointsOOV,
|
||||
"Force update joints", "Force update the joint transforms of actor, even when the character is out of the camera view.")
|
||||
|
||||
->DataElement(0, &EditorActorComponent::m_bboxConfig,
|
||||
"Bounding box configuration", "")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorActorComponent::OnBBoxConfigChanged)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -433,6 +474,14 @@ namespace EMotionFX
|
||||
return refreshLevel;
|
||||
}
|
||||
|
||||
void EditorActorComponent::OnBBoxConfigChanged()
|
||||
{
|
||||
if (m_actorInstance)
|
||||
{
|
||||
m_bboxConfig.SetAndUpdate(m_actorInstance.get());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorActorComponent::LaunchAnimationEditor(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType&)
|
||||
{
|
||||
// call to open must be done before LoadCharacter
|
||||
@@ -571,6 +620,7 @@ namespace EMotionFX
|
||||
cfg.m_attachmentJointIndex = m_attachmentJointIndex;
|
||||
cfg.m_lodLevel = m_lodLevel;
|
||||
cfg.m_skinningMethod = m_skinningMethod;
|
||||
cfg.m_bboxConfig = m_bboxConfig;
|
||||
cfg.m_forceUpdateJointsOOV = m_forceUpdateJointsOOV;
|
||||
|
||||
gameEntity->AddComponent(aznew ActorComponent(&cfg));
|
||||
@@ -846,6 +896,7 @@ namespace EMotionFX
|
||||
|
||||
// Force an update of node transforms so we can get an accurate bounding box.
|
||||
m_actorInstance->UpdateTransformations(0.0f, true, false);
|
||||
OnBBoxConfigChanged(); // Apply BBox config
|
||||
|
||||
// Creating the render actor AFTER both actor asset and mesh asset loaded.
|
||||
RenderBackend* renderBackend = AZ::Interface<RenderBackendManager>::Get()->GetRenderBackend();
|
||||
@@ -898,4 +949,3 @@ namespace EMotionFX
|
||||
}
|
||||
} //namespace Integration
|
||||
} // namespace EMotionFX
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace EMotionFX
|
||||
AZ::Crc32 OnAttachmentTypeChanged();
|
||||
AZ::Crc32 OnAttachmentTargetChanged();
|
||||
AZ::Crc32 OnAttachmentTargetJointSelect();
|
||||
void OnBBoxConfigChanged();
|
||||
bool AttachmentTargetVisibility();
|
||||
bool AttachmentTargetJointVisibility();
|
||||
AZStd::string AttachmentJointButtonText();
|
||||
@@ -163,6 +164,7 @@ namespace EMotionFX
|
||||
AZStd::string m_attachmentJointName; ///< Joint name on target to which to attach (if ActorAttachment).
|
||||
AZ::u32 m_attachmentJointIndex;
|
||||
AZ::u32 m_lodLevel;
|
||||
ActorComponent::BoundingBoxConfiguration m_bboxConfig;
|
||||
bool m_forceUpdateJointsOOV = false;
|
||||
// \todo attachmentTarget node nr
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Gem::Multiplayer.Builders.Static
|
||||
RUNTIME_DEPENDENCIES
|
||||
Gem::Multiplayer.Editor
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
|
||||
Reference in New Issue
Block a user