Files
2025-05-18 13:04:45 +08:00

167 lines
5.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PoseSearch/Chooser/PoseSearchChooserColumn.h"
#include "ChooserIndexArray.h"
#include "ChooserPropertyAccess.h"
#include "IChooserParameterBool.h"
#include "IChooserParameterFloat.h"
#include "ChooserTrace.h"
#include "PoseSearch/PoseSearchLibrary.h"
#include "PoseSearch/PoseSearchDatabase.h"
#if WITH_EDITOR
#include "StructUtils/PropertyBag.h"
#endif
bool FPoseHistoryContextProperty::GetValue(FChooserEvaluationContext& Context, FPoseHistoryReference& OutResult) const
{
const FPoseHistoryReference* Reference;
if (Binding.GetValuePtr(Context, Reference))
{
OutResult = *Reference;
return true;
}
return false;
}
FPoseSearchColumn::FPoseSearchColumn()
{
}
#if WITH_EDITOR
void FPoseSearchColumn::AutoPopulate(int32 RowIndex, UObject* OutputObject)
{
if (RowValues.IsValidIndex(RowIndex))
{
RowValues[RowIndex].ResultAsset = Cast<UAnimationAsset>(OutputObject);
}
}
bool FPoseSearchColumn::EditorTestFilter(int32 RowIndex) const
{
// todo: not sure how to do editor display for pose search weights (might need to make a copy of the pose history struct)
return true;
}
float FPoseSearchColumn::EditorTestCost(int32 RowIndex) const
{
// todo: not sure how to do editor display for pose search weights (might need to make a copy of the pose history struct)
return 0.0f;
}
#endif
bool FPoseSearchColumn::HasFilters() const
{
return true;
}
void FPoseSearchColumn::Filter(FChooserEvaluationContext& Context, const FChooserIndexArray& IndexListIn, FChooserIndexArray& IndexListOut) const
{
TArray<const UObject*, TInlineAllocator<128>> AssetsToSearch;
for (const FChooserIndexArray::FIndexData& IndexData : IndexListIn)
{
AssetsToSearch.Add(RowValues[IndexData.Index].ResultAsset);
}
FPoseHistoryReference PoseHistoryReference;
if (const FChooserParameterPoseHistoryBase* PoseHistoryParameter = InputValue.GetPtr<FChooserParameterPoseHistoryBase>())
{
if (PoseHistoryParameter->GetValue(Context, PoseHistoryReference))
{
if (const UE::PoseSearch::IPoseHistory* PoseHistory = PoseHistoryReference.PoseHistory.Get())
{
FPoseSearchContinuingProperties ContinuingProperties;
FPoseSearchFutureProperties Future;
const UE::PoseSearch::FSearchResult SearchResult = UPoseSearchLibrary::MotionMatch(
MakeArrayView(&Context, 1),
MakeArrayView(&UE::PoseSearch::DefaultRole, 1),
MakeArrayView(&PoseHistory, 1),
AssetsToSearch,
ContinuingProperties,
Future,
FPoseSearchEvent());
if (const UE::PoseSearch::FSearchIndexAsset* SearchIndexAsset = SearchResult.GetSearchIndexAsset())
{
const UPoseSearchDatabase* Database = SearchResult.Database.Get();
if (const FPoseSearchDatabaseAnimationAssetBase* DatabaseAnimationAssetBase = Database->GetDatabaseAnimationAsset<FPoseSearchDatabaseAnimationAssetBase>(*SearchIndexAsset))
{
const UObject* Result = DatabaseAnimationAssetBase->GetAnimationAsset();
int Index;
if (AssetsToSearch.Find(Result, Index))
{
IndexListOut.Push(IndexListIn[Index]);
if (const FChooserParameterFloatBase* StartTime = OutputStartTime.GetPtr<FChooserParameterFloatBase>())
{
StartTime->SetValue(Context, SearchResult.AssetTime);
}
if (const FChooserParameterFloatBase* Cost = OutputCost.GetPtr<FChooserParameterFloatBase>())
{
Cost->SetValue(Context, SearchResult.PoseCost);
}
if (const FChooserParameterBoolBase* Mirror = OutputMirror.GetPtr<FChooserParameterBoolBase>())
{
Mirror->SetValue(Context, SearchIndexAsset->IsMirrored());
}
}
}
}
}
}
}
if (IndexListOut.IsEmpty())
{
// if nothing passed the pose match, or if PoseHistory was not found, then ignore pose matching and just pass through everything
IndexListOut = IndexListIn;
// set some reasonable defaults for our other outputs in the passthrough case
if (const FChooserParameterFloatBase* StartTime = OutputStartTime.GetPtr<FChooserParameterFloatBase>())
{
StartTime->SetValue(Context, 0.0);
}
if (const FChooserParameterFloatBase* Cost = OutputCost.GetPtr<FChooserParameterFloatBase>())
{
// set an arbitrary "high" cost value so that cost threshold implementations can still wait for the pose search to find a good match
Cost->SetValue(Context, 100.0);
}
if (const FChooserParameterBoolBase* Mirror = OutputMirror.GetPtr<FChooserParameterBoolBase>())
{
Mirror->SetValue(Context, false);
}
}
}
#if WITH_EDITOR
void FPoseSearchColumn::AddToDetails(FInstancedPropertyBag& PropertyBag, int32 ColumnIndex, int32 RowIndex)
{
FText DisplayName = NSLOCTEXT("PoseSearchColumn","Pose Search", "Pose Search");
FName PropertyName("RowData", ColumnIndex);
FPropertyBagPropertyDesc PropertyDesc(PropertyName, EPropertyBagPropertyType::Struct, FChooserPoseSearchRowData::StaticStruct());
PropertyDesc.MetaData.Add(FPropertyBagPropertyDescMetaData("DisplayName", DisplayName.ToString()));
PropertyBag.AddProperties({PropertyDesc});
PropertyBag.SetValueStruct(PropertyName, RowValues[RowIndex]);
}
void FPoseSearchColumn::SetFromDetails(FInstancedPropertyBag& PropertyBag, int32 ColumnIndex, int32 RowIndex)
{
FName PropertyName("RowData", ColumnIndex);
TValueOrError<FStructView, EPropertyBagResult> Result = PropertyBag.GetValueStruct(PropertyName, FChooserPoseSearchRowData::StaticStruct());
if (FStructView* StructView = Result.TryGetValue())
{
RowValues[RowIndex] = StructView->Get<FChooserPoseSearchRowData>();
}
}
#endif