1877 lines
67 KiB
C++
1877 lines
67 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Dataflow/GeometryCollectionNodes.h"
|
|
#include "Dataflow/DataflowCore.h"
|
|
|
|
#include "Engine/Engine.h"
|
|
#include "Engine/StaticMesh.h"
|
|
#include "GeometryCollection/Facades/CollectionMeshFacade.h"
|
|
#include "GeometryCollection/GeometryCollectionObject.h"
|
|
#include "GeometryCollection/ManagedArrayCollection.h"
|
|
#include "GeometryCollection/GeometryCollection.h"
|
|
#include "GeometryCollection/GeometryCollectionEngineUtility.h"
|
|
#include "GeometryCollection/GeometryCollectionEngineRemoval.h"
|
|
#include "GeometryCollection/GeometryCollectionEngineConversion.h"
|
|
#include "Logging/LogMacros.h"
|
|
#include "Templates/SharedPointer.h"
|
|
#include "UObject/UnrealTypePrivate.h"
|
|
#include "DynamicMeshToMeshDescription.h"
|
|
#include "MeshDescriptionToDynamicMesh.h"
|
|
#include "StaticMeshAttributes.h"
|
|
#include "DynamicMeshEditor.h"
|
|
#include "Operations/MeshBoolean.h"
|
|
#include "Materials/Material.h"
|
|
|
|
#include "EngineGlobals.h"
|
|
#include "GeometryCollection/GeometryCollectionAlgo.h"
|
|
#include "GeometryCollection/GeometryCollectionClusteringUtility.h"
|
|
#include "GeometryCollection/GeometryCollectionConvexUtility.h"
|
|
#include "Voronoi/Voronoi.h"
|
|
#include "PlanarCut.h"
|
|
#include "GeometryCollection/GeometryCollectionProximityUtility.h"
|
|
#include "FractureEngineClustering.h"
|
|
#include "FractureEngineSelection.h"
|
|
#include "GeometryCollection/Facades/CollectionBoundsFacade.h"
|
|
#include "GeometryCollection/Facades/CollectionAnchoringFacade.h"
|
|
#include "GeometryCollection/Facades/CollectionRemoveOnBreakFacade.h"
|
|
#include "GeometryCollection/Facades/CollectionTransformFacade.h"
|
|
#include "GeometryCollection/Facades/CollectionHierarchyFacade.h"
|
|
#include "DynamicMesh/MeshTransforms.h"
|
|
#include "DynamicMesh/DynamicMesh3.h"
|
|
#include "Dataflow/DataflowDebugDrawInterface.h"
|
|
#include "Dataflow/DataflowDebugDraw.h"
|
|
#if WITH_EDITOR
|
|
#include "Dataflow/DataflowRenderingViewMode.h"
|
|
#endif
|
|
#include "Dataflow/GeometryCollectionUtils.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionNodes)
|
|
|
|
namespace UE::Dataflow
|
|
{
|
|
void GeometryCollectionEngineNodes()
|
|
{
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetCollectionFromAssetDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FAppendCollectionAssetsDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FPrintStringDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FLogStringDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBoundingBoxDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FExpandBoundingBoxDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetBoxLengthsDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FExpandVectorDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FStringAppendDataflowNode_v2);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FHashStringDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FHashVectorDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetBoundingBoxesFromCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetRootIndexFromCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetCentroidsFromCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FTransformCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBakeTransformsInCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FTransformMeshDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCompareIntDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCompareFloatDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBooleanOperationDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBranchMeshDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBranchCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetSchemaDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRemoveOnBreakDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSetAnchorStateDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSetDynamicStateDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FProximityDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionSetPivotDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FAddCustomCollectionAttributeDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetNumElementsInCollectionGroupDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetCollectionAttributeDataTypedDataflowNode);
|
|
// Commented out until AnyType outputs can properly change types
|
|
// DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetCollectionAttributeDataTypedDataflowNode_v2);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSetCollectionAttributeDataTypedDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMultiplyTransformDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FInvertTransformDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSelectionToVertexListDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBranchFloatDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBranchIntDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBoundingSphereDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FExpandBoundingSphereDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FVisualizeTetrahedronsDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FPointsToCollectionDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionToPointsDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSpheresToPointsDataflowNode);
|
|
|
|
// Deprecated
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FStringAppendDataflowNode);
|
|
}
|
|
}
|
|
|
|
void FGetCollectionFromAssetDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
if (CollectionAsset)
|
|
{
|
|
if (const TSharedPtr<FGeometryCollection, ESPMode::ThreadSafe> AssetCollection = CollectionAsset->GetGeometryCollection())
|
|
{
|
|
SetValue(Context, (const FManagedArrayCollection&)(*AssetCollection), &Collection);
|
|
}
|
|
else
|
|
{
|
|
SetValue(Context, FManagedArrayCollection(), &Collection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetValue(Context, FManagedArrayCollection(), &Collection);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FAppendCollectionAssetsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<DataType>(&Collection1))
|
|
{
|
|
FManagedArrayCollection InCollection1 = GetValue<DataType>(Context, &Collection1);
|
|
const FManagedArrayCollection& InCollection2 = GetValue<DataType>(Context, &Collection2);
|
|
TArray<FString> GeometryGroupGuidsLocal1, GeometryGroupGuidsLocal2;
|
|
if (const TManagedArray<FString>* GuidArray1 = InCollection1.FindAttribute<FString>("Guid", FGeometryCollection::GeometryGroup))
|
|
{
|
|
GeometryGroupGuidsLocal1 = GuidArray1->GetConstArray();
|
|
}
|
|
InCollection1.Append(InCollection2);
|
|
|
|
//Manually update indices in TransformToGeometryIndex, Parent and Children attributes, since they do not have group dependencies set to automatically manage this
|
|
// TODO: Can we set up dependencies s.t. these indices are updated automatically, and then remove this manual fixup?
|
|
{
|
|
const int32 GeometryOffset = InCollection2.NumElements(FGeometryCollection::GeometryGroup);
|
|
const int32 OtherSize = InCollection2.NumElements(FGeometryCollection::TransformGroup);
|
|
const int32 Size = InCollection1.NumElements(FGeometryCollection::TransformGroup);
|
|
if (TManagedArray<int32>* TransformToGeometryIndex = InCollection1.ModifyAttributeTyped<int32>("TransformToGeometryIndex", FGeometryCollection::TransformGroup))
|
|
{
|
|
for (int32 Idx = OtherSize; Idx < Size; ++Idx)
|
|
{
|
|
if ((*TransformToGeometryIndex)[Idx] != INDEX_NONE)
|
|
{
|
|
(*TransformToGeometryIndex)[Idx] += GeometryOffset;
|
|
}
|
|
}
|
|
}
|
|
if (TManagedArray<int32>* Parent = InCollection1.ModifyAttributeTyped<int32>("Parent", FGeometryCollection::TransformGroup))
|
|
{
|
|
for (int32 Idx = OtherSize; Idx < Size; ++Idx)
|
|
{
|
|
if ((*Parent)[Idx] != INDEX_NONE)
|
|
{
|
|
(*Parent)[Idx] += OtherSize;
|
|
}
|
|
}
|
|
}
|
|
if (TManagedArray<TSet<int32>>* Children = InCollection1.ModifyAttributeTyped<TSet<int32>>("Children", FGeometryCollection::TransformGroup))
|
|
{
|
|
for (int32 Idx = OtherSize; Idx < Size; ++Idx)
|
|
{
|
|
for (int32& Child : (*Children)[Idx])
|
|
{
|
|
if (Child != INDEX_NONE)
|
|
{
|
|
Child += OtherSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
SetValue(Context, MoveTemp(InCollection1), &Collection1);
|
|
if (const TManagedArray<FString>* GuidArray2 = InCollection2.FindAttribute<FString>("Guid", FGeometryCollection::GeometryGroup))
|
|
{
|
|
GeometryGroupGuidsLocal2 = GuidArray2->GetConstArray();
|
|
}
|
|
SetValue(Context, MoveTemp(GeometryGroupGuidsLocal1), &GeometryGroupGuidsOut1);
|
|
SetValue(Context, MoveTemp(GeometryGroupGuidsLocal2), &GeometryGroupGuidsOut2);
|
|
}
|
|
}
|
|
|
|
|
|
void FPrintStringDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
FString Value = GetValue<FString>(Context, &String);
|
|
|
|
if (bPrintToScreen)
|
|
{
|
|
GEngine->AddOnScreenDebugMessage(-1, Duration, Color, Value);
|
|
}
|
|
if (bPrintToLog)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("Text, %s"), *Value);
|
|
}
|
|
}
|
|
|
|
void FLogStringDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (bPrintToLog)
|
|
{
|
|
FString Value = GetValue<FString>(Context, &String);
|
|
UE_LOG(LogTemp, Warning, TEXT("[Dataflow Log] %s"), *Value);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void FBoundingBoxDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FBox>(&BoundingBox))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
GeometryCollection::Facades::FBoundsFacade BoundsFacade(InCollection);
|
|
const FBox& BoundingBoxInCollectionSpace = BoundsFacade.GetBoundingBoxInCollectionSpace();
|
|
|
|
SetValue(Context, BoundingBoxInCollectionSpace, &BoundingBox);
|
|
}
|
|
}
|
|
|
|
void FGetBoxLengthsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Lengths))
|
|
{
|
|
const TArray<FBox>& InBoxes = GetValue(Context, &Boxes);
|
|
|
|
TArray<float> OutLengths;
|
|
OutLengths.SetNumUninitialized(InBoxes.Num());
|
|
for (int32 Idx = 0; Idx < InBoxes.Num(); ++Idx)
|
|
{
|
|
const FBox& Box = InBoxes[Idx];
|
|
OutLengths[Idx] = BoxToMeasurement(Box);
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(OutLengths), &Lengths);
|
|
}
|
|
}
|
|
|
|
|
|
void FExpandBoundingBoxDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
FBox BBox = GetValue<FBox>(Context, &BoundingBox);
|
|
|
|
if (Out->IsA<FVector>(&Min))
|
|
{
|
|
SetValue(Context, BBox.Min, &Min);
|
|
}
|
|
else if (Out->IsA<FVector>(&Max))
|
|
{
|
|
SetValue(Context, BBox.Max, &Max);
|
|
}
|
|
else if (Out->IsA<FVector>(&Center))
|
|
{
|
|
SetValue(Context, BBox.GetCenter(), &Center);
|
|
}
|
|
else if (Out->IsA<FVector>(&HalfExtents))
|
|
{
|
|
SetValue(Context, BBox.GetExtent(), &HalfExtents);
|
|
}
|
|
else if (Out->IsA<float>(&Volume))
|
|
{
|
|
SetValue(Context, (float)BBox.GetVolume(), &Volume);
|
|
}
|
|
}
|
|
|
|
|
|
void FExpandVectorDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
FVector VectorVal = GetValue<FVector>(Context, &Vector);
|
|
|
|
if (Out->IsA<float>(&X))
|
|
{
|
|
SetValue(Context, (float)VectorVal.X, &X);
|
|
}
|
|
else if (Out->IsA<float>(&Y))
|
|
{
|
|
SetValue(Context, (float)VectorVal.Y, &Y);
|
|
}
|
|
else if (Out->IsA<float>(&Z))
|
|
{
|
|
SetValue(Context, (float)VectorVal.Z, &Z);
|
|
}
|
|
}
|
|
|
|
void FStringAppendDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FString>(&String))
|
|
{
|
|
FString StringOut = GetValue<FString>(Context, &String1) + GetValue<FString>(Context, &String2);
|
|
SetValue(Context, MoveTemp(StringOut), &String);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
|
|
FStringAppendDataflowNode_v2::FStringAppendDataflowNode_v2(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
|
|
: FDataflowNode(InParam, InGuid)
|
|
{
|
|
RegisterOutputConnection(&String);
|
|
|
|
// Add initial variable inputs
|
|
for (int32 Index = 0; Index < NumInitialVariableInputs; ++Index)
|
|
{
|
|
AddPins();
|
|
}
|
|
}
|
|
|
|
void FStringAppendDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&String))
|
|
{
|
|
FString ResultStr;
|
|
|
|
for (int32 Idx = 0; Idx < Inputs.Num(); ++Idx)
|
|
{
|
|
const FString InputValue = GetValue(Context, GetConnectionReference(Idx));
|
|
|
|
ResultStr = ResultStr + InputValue;
|
|
}
|
|
|
|
SetValue(Context, ResultStr, &String);
|
|
}
|
|
}
|
|
|
|
bool FStringAppendDataflowNode_v2::CanAddPin() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool FStringAppendDataflowNode_v2::CanRemovePin() const
|
|
{
|
|
return Inputs.Num() > 0;
|
|
}
|
|
|
|
UE::Dataflow::TConnectionReference<FDataflowStringConvertibleTypes> FStringAppendDataflowNode_v2::GetConnectionReference(int32 Index) const
|
|
{
|
|
return { &Inputs[Index], Index, &Inputs };
|
|
}
|
|
|
|
TArray<UE::Dataflow::FPin> FStringAppendDataflowNode_v2::AddPins()
|
|
{
|
|
const int32 Index = Inputs.AddDefaulted();
|
|
const FDataflowInput& Input = RegisterInputArrayConnection(GetConnectionReference(Index));
|
|
return { { UE::Dataflow::FPin::EDirection::INPUT, Input.GetType(), Input.GetName() } };
|
|
}
|
|
|
|
TArray<UE::Dataflow::FPin> FStringAppendDataflowNode_v2::GetPinsToRemove() const
|
|
{
|
|
const int32 Index = (Inputs.Num() - 1);
|
|
check(Inputs.IsValidIndex(Index));
|
|
if (const FDataflowInput* const Input = FindInput(GetConnectionReference(Index)))
|
|
{
|
|
return { { UE::Dataflow::FPin::EDirection::INPUT, Input->GetType(), Input->GetName() } };
|
|
}
|
|
return Super::GetPinsToRemove();
|
|
}
|
|
|
|
void FStringAppendDataflowNode_v2::OnPinRemoved(const UE::Dataflow::FPin& Pin)
|
|
{
|
|
const int32 Index = Inputs.Num() - 1;
|
|
check(Inputs.IsValidIndex(Index));
|
|
#if DO_CHECK
|
|
const FDataflowInput* const Input = FindInput(GetConnectionReference(Index));
|
|
check(Input);
|
|
check(Input->GetName() == Pin.Name);
|
|
check(Input->GetType() == Pin.Type);
|
|
#endif
|
|
Inputs.SetNum(Index);
|
|
|
|
return Super::OnPinRemoved(Pin);
|
|
}
|
|
|
|
void FStringAppendDataflowNode_v2::PostSerialize(const FArchive& Ar)
|
|
{
|
|
if (Ar.IsLoading())
|
|
{
|
|
check(Inputs.Num() >= 0);
|
|
// register new elements from the array as inputs
|
|
for (int32 Index = 0; Index < Inputs.Num(); ++Index)
|
|
{
|
|
FindOrRegisterInputArrayConnection(GetConnectionReference(Index));
|
|
}
|
|
if (Ar.IsTransacting())
|
|
{
|
|
// if we have more inputs than materials then we need to unregister the inputs
|
|
const int32 NumVariableInputs = (GetNumInputs() - NumOtherInputs);
|
|
const int32 NumInputs = Inputs.Num();
|
|
if (NumVariableInputs > NumInputs)
|
|
{
|
|
// Inputs have been removed.
|
|
// Temporarily expand Collections so we can get connection references.
|
|
Inputs.SetNum(NumVariableInputs);
|
|
for (int32 Index = NumInputs; Index < Inputs.Num(); ++Index)
|
|
{
|
|
UnregisterInputConnection(GetConnectionReference(Index));
|
|
}
|
|
Inputs.SetNum(NumInputs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ensureAlways(Inputs.Num() + NumOtherInputs == GetNumInputs());
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
|
|
void FHashStringDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<int32>(&Hash))
|
|
{
|
|
SetValue(Context, (int32)GetTypeHash(GetValue<FString>(Context, &String)), &Hash);
|
|
}
|
|
}
|
|
|
|
void FHashVectorDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<int32>(&Hash))
|
|
{
|
|
SetValue(Context, (int32)GetTypeHash(GetValue<FVector>(Context, &Vector)), &Hash);
|
|
}
|
|
}
|
|
|
|
|
|
void FGetBoundingBoxesFromCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TArray<FBox>>(&BoundingBoxes))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
const FDataflowTransformSelection& InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
|
|
|
|
GeometryCollection::Facades::FBoundsFacade BoundsFacade(InCollection);
|
|
const TManagedArray<FBox>& InBoundingBoxes = BoundsFacade.GetBoundingBoxes();
|
|
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
|
|
TArray<FBox> BoundingBoxesArr;
|
|
for (int32 Idx = 0; Idx < InBoundingBoxes.Num(); ++Idx)
|
|
{
|
|
const FBox BoundingBoxInBoneSpace = InBoundingBoxes[Idx];
|
|
|
|
// Transform from BoneSpace to CollectionSpace
|
|
const FTransform CollectionSpaceTransform = TransformFacade.ComputeCollectionSpaceTransform(Idx);
|
|
const FBox BoundingBoxInCollectionSpace = BoundingBoxInBoneSpace.TransformBy(CollectionSpaceTransform);
|
|
|
|
if (IsConnected<FDataflowTransformSelection>(&TransformSelection))
|
|
{
|
|
if (InTransformSelection.IsSelected(Idx))
|
|
{
|
|
BoundingBoxesArr.Add(BoundingBoxInCollectionSpace);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BoundingBoxesArr.Add(BoundingBoxInCollectionSpace);
|
|
}
|
|
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(BoundingBoxesArr), &BoundingBoxes);
|
|
}
|
|
}
|
|
|
|
void FGetRootIndexFromCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&RootIndex))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
Chaos::Facades::FCollectionHierarchyFacade HierarchyFacade(InCollection);
|
|
SetValue(Context, HierarchyFacade.GetRootIndex(), &RootIndex);
|
|
}
|
|
}
|
|
|
|
void FGetCentroidsFromCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TArray<FVector>>(&Centroids))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
const FDataflowTransformSelection& InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
|
|
|
|
GeometryCollection::Facades::FBoundsFacade BoundsFacade(InCollection);
|
|
const TArray<FVector>& InCentroids = BoundsFacade.GetCentroids();
|
|
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
|
|
TArray<FVector> CentroidsArr;
|
|
for (int32 Idx = 0; Idx < InCentroids.Num(); ++Idx)
|
|
{
|
|
const FVector PositionInBoneSpace(InCentroids[Idx]);
|
|
|
|
// Transform from BoneSpace to CollectionSpace
|
|
const FTransform CollectionSpaceTransform = TransformFacade.ComputeCollectionSpaceTransform(Idx);
|
|
const FVector PositionInCollectionSpace = CollectionSpaceTransform.TransformPosition(PositionInBoneSpace);
|
|
|
|
if (IsConnected<FDataflowTransformSelection>(&TransformSelection))
|
|
{
|
|
if (InTransformSelection.IsSelected(Idx))
|
|
{
|
|
CentroidsArr.Add(PositionInCollectionSpace);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CentroidsArr.Add(PositionInCollectionSpace);
|
|
}
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(CentroidsArr), &Centroids);
|
|
}
|
|
}
|
|
|
|
|
|
void FTransformCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
const FVector InTranslate = GetValue(Context, &Translate);
|
|
const FVector InRotate = GetValue(Context, &Rotate);
|
|
const FVector InScale = GetValue(Context, &Scale);
|
|
|
|
FTransform NewTransform = GeometryCollection::Facades::FCollectionTransformFacade::BuildTransform(
|
|
InTranslate,
|
|
(uint8)RotationOrder,
|
|
InRotate,
|
|
InScale,
|
|
UniformScale,
|
|
RotatePivot,
|
|
ScalePivot,
|
|
bInvertTransformation);
|
|
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
|
|
if (!IsConnected(&TransformSelection))
|
|
{
|
|
TransformFacade.Transform(NewTransform);
|
|
}
|
|
else
|
|
{
|
|
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
|
|
|
|
TransformFacade.Transform(NewTransform, InTransformSelection.AsArray());
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
}
|
|
}
|
|
|
|
|
|
void FBakeTransformsInCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
const TArray<FTransform>& CollectionSpaceTransforms = TransformFacade.ComputeCollectionSpaceTransforms();
|
|
|
|
GeometryCollection::Facades::FCollectionMeshFacade MeshFacade(InCollection);
|
|
|
|
const int32 NumTransforms = InCollection.NumElements(FGeometryCollection::TransformGroup);
|
|
|
|
for (int32 TransformIdx = 0; TransformIdx < NumTransforms; ++TransformIdx)
|
|
{
|
|
MeshFacade.BakeTransform(TransformIdx, CollectionSpaceTransforms[TransformIdx]);
|
|
TransformFacade.SetBoneTransformToIdentity(TransformIdx);
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
}
|
|
}
|
|
|
|
|
|
void FTransformMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TObjectPtr<UDynamicMesh>>(&Mesh))
|
|
{
|
|
if (TObjectPtr<const UDynamicMesh> InMesh = GetValue<TObjectPtr<UDynamicMesh>>(Context, &Mesh))
|
|
{
|
|
// Creating a new mesh object from InMesh
|
|
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
|
|
NewMesh->SetMesh(InMesh->GetMeshRef());
|
|
|
|
const FVector& InTranslate = GetValue(Context, &Translate);
|
|
const FVector& InRotate = GetValue(Context, &Rotate);
|
|
const FVector& InScale = GetValue(Context, &Scale);
|
|
const float InUniformScale = GetValue(Context, &UniformScale);
|
|
const FVector& InRotatePivot = GetValue(Context, &RotatePivot);
|
|
const FVector& InScalePivot = GetValue(Context, &ScalePivot);
|
|
const bool InbInvertTransformation = GetValue(Context, &bInvertTransformation);
|
|
|
|
FTransform NewTransform = GeometryCollection::Facades::FCollectionTransformFacade::BuildTransform(
|
|
InTranslate,
|
|
(uint8)RotationOrder,
|
|
InRotate,
|
|
InScale,
|
|
InUniformScale,
|
|
InRotatePivot,
|
|
InScalePivot,
|
|
InbInvertTransformation);
|
|
|
|
UE::Geometry::FDynamicMesh3& DynamicMesh = NewMesh->GetMeshRef();
|
|
|
|
MeshTransforms::ApplyTransform(DynamicMesh, UE::Geometry::FTransformSRT3d(NewTransform), true);
|
|
|
|
SetValue(Context, NewMesh, &Mesh);
|
|
}
|
|
else
|
|
{
|
|
SetValue(Context, TObjectPtr<UDynamicMesh>(NewObject<UDynamicMesh>()), &Mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
// helper to apply an ECompareOperationEnum operation to various numeric types
|
|
template <typename T>
|
|
static bool ApplyDataflowOperationComparison(T A, T B, ECompareOperationEnum Operation)
|
|
{
|
|
switch (Operation)
|
|
{
|
|
case ECompareOperationEnum::Dataflow_Compare_Equal:
|
|
return A == B;
|
|
case ECompareOperationEnum::Dataflow_Compare_Smaller:
|
|
return A < B;
|
|
case ECompareOperationEnum::Dataflow_Compare_SmallerOrEqual:
|
|
return A <= B;
|
|
case ECompareOperationEnum::Dataflow_Compare_Greater:
|
|
return A > B;
|
|
case ECompareOperationEnum::Dataflow_Compare_GreaterOrEqual:
|
|
return A >= B;
|
|
case ECompareOperationEnum::Dataflow_Compare_NotEqual:
|
|
return A != B;
|
|
default:
|
|
ensureMsgf(false, TEXT("Invalid ECompareOperationEnum value: %u"), (uint8)Operation);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void FCompareIntDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<bool>(&Result))
|
|
{
|
|
const int32 IntAValue = GetValue<int32>(Context, &IntA);
|
|
const int32 IntBValue = GetValue<int32>(Context, &IntB);
|
|
const bool ResultValue = ApplyDataflowOperationComparison(IntAValue, IntBValue, Operation);
|
|
|
|
SetValue(Context, ResultValue, &Result);
|
|
}
|
|
}
|
|
|
|
|
|
void FCompareFloatDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Result))
|
|
{
|
|
const float AValue = GetValue(Context, &FloatA);
|
|
const float BValue = GetValue(Context, &FloatB);
|
|
const bool ResultValue = ApplyDataflowOperationComparison(AValue, BValue, Operation);
|
|
|
|
SetValue(Context, ResultValue, &Result);
|
|
}
|
|
}
|
|
|
|
|
|
void FBooleanOperationDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&bResult))
|
|
{
|
|
bool bResultValue = false;
|
|
switch (Operation)
|
|
{
|
|
case EBooleanOperationEnum::Dataflow_And:
|
|
bResultValue = GetValue(Context, &bBoolA) && GetValue(Context, &bBoolB);
|
|
break;
|
|
case EBooleanOperationEnum::Dataflow_Or:
|
|
bResultValue = GetValue(Context, &bBoolA) || GetValue(Context, &bBoolB);
|
|
break;
|
|
case EBooleanOperationEnum::Dataflow_Not:
|
|
bResultValue = !GetValue(Context, &bBoolA);
|
|
break;
|
|
default:
|
|
ensureMsgf(false, TEXT("Invalid EBooleanOperationEnum value: %u"), (uint8)Operation);
|
|
}
|
|
|
|
SetValue(Context, bResultValue, &bResult);
|
|
}
|
|
}
|
|
|
|
|
|
void FBranchMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TObjectPtr<UDynamicMesh>>(&Mesh))
|
|
{
|
|
bool InCondition = GetValue<bool>(Context, &bCondition);
|
|
|
|
if (InCondition)
|
|
{
|
|
if (TObjectPtr<UDynamicMesh> InMeshA = GetValue<TObjectPtr<UDynamicMesh>>(Context, &MeshA))
|
|
{
|
|
SetValue(Context, InMeshA, &Mesh);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TObjectPtr<UDynamicMesh> InMeshB = GetValue<TObjectPtr<UDynamicMesh>>(Context, &MeshB))
|
|
{
|
|
SetValue(Context, InMeshB, &Mesh);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
SetValue(Context, TObjectPtr<UDynamicMesh>(NewObject<UDynamicMesh>()), &Mesh);
|
|
}
|
|
}
|
|
|
|
|
|
void FBranchCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&ChosenCollection))
|
|
{
|
|
bool InCondition = GetValue<bool>(Context, &bCondition);
|
|
|
|
if (InCondition)
|
|
{
|
|
if (IsConnected(&TrueCollection))
|
|
{
|
|
const FManagedArrayCollection& InTrueCollection = GetValue(Context, &TrueCollection);
|
|
SetValue(Context, InTrueCollection, &ChosenCollection);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsConnected(&FalseCollection))
|
|
{
|
|
const FManagedArrayCollection& InFalseCollection = GetValue(Context, &FalseCollection);
|
|
SetValue(Context, InFalseCollection, &ChosenCollection);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// default empty collection
|
|
SetValue(Context, FManagedArrayCollection(), &ChosenCollection);
|
|
}
|
|
}
|
|
|
|
|
|
namespace {
|
|
inline FName GetArrayTypeString(FManagedArrayCollection::EArrayType ArrayType)
|
|
{
|
|
switch (ArrayType)
|
|
{
|
|
#define MANAGED_ARRAY_TYPE(a,A) case EManagedArrayType::F##A##Type:\
|
|
return FName(#A);
|
|
#include "GeometryCollection/ManagedArrayTypeValues.inl"
|
|
#undef MANAGED_ARRAY_TYPE
|
|
}
|
|
return FName();
|
|
}
|
|
}
|
|
|
|
void FGetSchemaDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FString>(&String))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
FString OutputStr;
|
|
OutputStr.Appendf(TEXT("\n----------------------------------------\n"));
|
|
for (auto& Group : InCollection.GroupNames())
|
|
{
|
|
if (InCollection.HasGroup(Group))
|
|
{
|
|
int32 NumElems = InCollection.NumElements(Group);
|
|
|
|
OutputStr.Appendf(TEXT("Group: %s Number of Elements: %d\n"), *Group.ToString(), NumElems);
|
|
OutputStr.Appendf(TEXT("Attributes:\n"));
|
|
|
|
for (auto& Attr : InCollection.AttributeNames(Group))
|
|
{
|
|
if (InCollection.HasAttribute(Attr, Group))
|
|
{
|
|
FString TypeStr = GetArrayTypeString(InCollection.GetAttributeType(Attr, Group)).ToString();
|
|
OutputStr.Appendf(TEXT("\t%s\t[%s]\n"), *Attr.ToString(), *TypeStr);
|
|
}
|
|
}
|
|
|
|
OutputStr.Appendf(TEXT("\n--------------------\n"));
|
|
}
|
|
}
|
|
OutputStr.Appendf(TEXT("----------------------------------------\n"));
|
|
|
|
SetValue(Context, MoveTemp(OutputStr), &String);
|
|
}
|
|
}
|
|
|
|
|
|
void FRemoveOnBreakDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
const bool& InEnableRemoval = GetValue(Context, &bEnabledRemoval, true);
|
|
const FVector2f& InPostBreakTimer = GetValue(Context, &PostBreakTimer);
|
|
const FVector2f& InRemovalTimer = GetValue(Context, &RemovalTimer);
|
|
const bool& InClusterCrumbling = GetValue(Context, &bClusterCrumbling);
|
|
|
|
// we are making a copy of the collection because we are modifying it
|
|
FManagedArrayCollection InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
GeometryCollection::Facades::FCollectionRemoveOnBreakFacade RemoveOnBreakFacade(InCollection);
|
|
RemoveOnBreakFacade.DefineSchema();
|
|
|
|
GeometryCollection::Facades::FRemoveOnBreakData Data;
|
|
Data.SetBreakTimer(InPostBreakTimer.X, InPostBreakTimer.Y);
|
|
Data.SetRemovalTimer(InRemovalTimer.X, InRemovalTimer.Y);
|
|
Data.SetEnabled(InEnableRemoval);
|
|
Data.SetClusterCrumbling(InClusterCrumbling);
|
|
|
|
// selection is optional
|
|
if (IsConnected<FDataflowTransformSelection>(&TransformSelection))
|
|
{
|
|
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
|
|
TArray<int32> TransformIndices;
|
|
InTransformSelection.AsArrayValidated(TransformIndices, InCollection);
|
|
RemoveOnBreakFacade.SetFromIndexArray(TransformIndices, Data);
|
|
}
|
|
else
|
|
{
|
|
RemoveOnBreakFacade.SetToAll(Data);
|
|
}
|
|
|
|
// move the collection to the output to avoid making another copy
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FSetAnchorStateDataflowNode::FSetAnchorStateDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid )
|
|
: FDataflowNode(InParam, InGuid)
|
|
{
|
|
RegisterInputConnection(&Collection);
|
|
RegisterInputConnection(&TransformSelection);
|
|
RegisterOutputConnection(&Collection, &Collection);
|
|
}
|
|
|
|
void FSetAnchorStateDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Collection))
|
|
{
|
|
FManagedArrayCollection OutCollection = GetValue(Context, &Collection);
|
|
if (IsConnected(&Collection))
|
|
{
|
|
FDataflowTransformSelection InTransformSelection = GetValue(Context, &TransformSelection);
|
|
|
|
Chaos::Facades::FCollectionAnchoringFacade AnchoringFacade(OutCollection);
|
|
if (!AnchoringFacade.HasAnchoredAttribute())
|
|
{
|
|
AnchoringFacade.AddAnchoredAttribute();
|
|
}
|
|
|
|
const bool bAnchored = (AnchorState == EAnchorStateEnum::Dataflow_AnchorState_Anchored) ? true : false;
|
|
TArray<int32> BoneIndices;
|
|
InTransformSelection.AsArrayValidated(BoneIndices, OutCollection);
|
|
AnchoringFacade.SetAnchored(BoneIndices, bAnchored);
|
|
|
|
if (bSetNotSelectedBonesToOppositeState)
|
|
{
|
|
InTransformSelection.Invert();
|
|
InTransformSelection.AsArrayValidated(BoneIndices, OutCollection);
|
|
AnchoringFacade.SetAnchored(BoneIndices, !bAnchored);
|
|
}
|
|
}
|
|
SetValue(Context, OutCollection, &Collection);
|
|
}
|
|
}
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
bool FSetAnchorStateDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
|
|
{
|
|
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
|
|
}
|
|
|
|
void FSetAnchorStateDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
|
|
{
|
|
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
|
|
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
|
|
|
|
GeometryCollection::Facades::FBoundsFacade BoundsFacade(InCollection);
|
|
const TArray<FVector> Centroids = BoundsFacade.GetCentroids();
|
|
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
|
|
DataflowRenderingInterface.SetColor(FLinearColor::Blue);
|
|
DataflowRenderingInterface.SetPointSize(5.f);
|
|
DataflowRenderingInterface.ReservePoints(InTransformSelection.NumSelected());
|
|
DataflowRenderingInterface.SetForegroundPriority();
|
|
|
|
const int32 NumCentroids = Centroids.Num();
|
|
for (int32 TransformIdx = 0; TransformIdx < InTransformSelection.Num(); TransformIdx++)
|
|
{
|
|
if (TransformIdx < NumCentroids && InTransformSelection.IsSelected(TransformIdx))
|
|
{
|
|
const FTransform CollectionSpaceTransform = TransformFacade.ComputeCollectionSpaceTransform(TransformIdx);
|
|
const FVector Point = CollectionSpaceTransform.TransformPosition(Centroids[TransformIdx]);
|
|
DataflowRenderingInterface.DrawPoint(Point);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FSetDynamicStateDataflowNode::FSetDynamicStateDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
|
|
: FDataflowNode(InParam, InGuid)
|
|
{
|
|
RegisterInputConnection(&Collection);
|
|
RegisterInputConnection(&TransformSelection);
|
|
RegisterOutputConnection(&Collection, &Collection);
|
|
}
|
|
|
|
void FSetDynamicStateDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Collection))
|
|
{
|
|
FManagedArrayCollection OutCollection = GetValue(Context, &Collection);
|
|
if (IsConnected(&Collection))
|
|
{
|
|
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
|
|
|
|
const TArray<int32> BoneIndices = InTransformSelection.AsArrayValidated(OutCollection);
|
|
|
|
Chaos::Facades::FCollectionAnchoringFacade AnchoringFacade(OutCollection);
|
|
if (AnchoringFacade.HasInitialDynamicStateAttribute())
|
|
{
|
|
const Chaos::EObjectStateType ObjectState = [this]()
|
|
{
|
|
switch (DynamicState)
|
|
{
|
|
case EDataflowGeometryCollectionDynamicState::None: return Chaos::EObjectStateType::Uninitialized;
|
|
case EDataflowGeometryCollectionDynamicState::Dynamic: return Chaos::EObjectStateType::Dynamic;
|
|
case EDataflowGeometryCollectionDynamicState::Kinematic:return Chaos::EObjectStateType::Kinematic;
|
|
case EDataflowGeometryCollectionDynamicState::Static: return Chaos::EObjectStateType::Static;
|
|
}
|
|
return Chaos::EObjectStateType::Dynamic;
|
|
}();
|
|
|
|
|
|
AnchoringFacade.SetInitialDynamicState(BoneIndices, ObjectState);
|
|
}
|
|
}
|
|
SetValue(Context, OutCollection, &Collection);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/* ---------------------------------------------------------------------------------------------------------------------------------*/
|
|
|
|
void FProximityDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
if (TUniquePtr<FGeometryCollection> GeomCollection = TUniquePtr<FGeometryCollection>(InCollection.NewCopy<FGeometryCollection>()))
|
|
{
|
|
FGeometryCollectionProximityPropertiesInterface::FProximityProperties Properties = GeomCollection->GetProximityProperties();
|
|
|
|
Properties.Method = (EProximityMethod)ProximityMethod;
|
|
Properties.ContactMethod = (EProximityContactMethod)FilterContactMethod;
|
|
Properties.DistanceThreshold = GetValue(Context, &DistanceThreshold);
|
|
Properties.bUseAsConnectionGraph = bUseAsConnectionGraph;
|
|
Properties.ContactAreaMethod = (EConnectionContactMethod)ContactAreaMethod;
|
|
Properties.RequireContactAmount = GetValue(Context, &ContactThreshold);
|
|
|
|
GeomCollection->SetProximityProperties(Properties);
|
|
|
|
UE::GeometryCollectionConvexUtility::FConvexHulls TransformedExistingHulls;
|
|
bool bUseExistingHulls = false;
|
|
if (!bRecomputeConvexHulls)
|
|
{
|
|
bUseExistingHulls = UE::GeometryCollectionConvexUtility::GetExistingConvexHullsInSharedSpace(GeomCollection.Get(), TransformedExistingHulls, true);
|
|
}
|
|
|
|
// Invalidate proximity
|
|
FGeometryCollectionProximityUtility ProximityUtility(GeomCollection.Get());
|
|
ProximityUtility.InvalidateProximity();
|
|
ProximityUtility.UpdateProximity(bUseExistingHulls ? &TransformedExistingHulls : nullptr);
|
|
|
|
SetValue<const FManagedArrayCollection&>(Context, *GeomCollection, &Collection);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
bool FProximityDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
|
|
{
|
|
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
|
|
}
|
|
|
|
void FProximityDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
|
|
{
|
|
using namespace UE::Geometry;
|
|
|
|
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
|
|
{
|
|
if (const FDataflowOutput* Output = FindOutput(&Collection))
|
|
{
|
|
const FManagedArrayCollection& OutCollection = Output->GetValue(Context, Collection);
|
|
|
|
UE::Dataflow::Utils::DebugDrawProximity(DataflowRenderingInterface,
|
|
OutCollection,
|
|
Color,
|
|
LineWidthMultiplier,
|
|
CenterSize,
|
|
CenterColor,
|
|
bRandomizeColor,
|
|
ColorRandomSeed);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------------------------------------------------------------------*/
|
|
|
|
void FCollectionSetPivotDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
const FTransform& InTransform = GetValue<FTransform>(Context, &Transform);
|
|
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
TransformFacade.SetPivot(InTransform);
|
|
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
}
|
|
}
|
|
|
|
|
|
static FName GetGroupName(const EStandardGroupNameEnum& InGroupName)
|
|
{
|
|
FName GroupNameToUse;
|
|
if (InGroupName == EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Transform)
|
|
{
|
|
GroupNameToUse = FGeometryCollection::TransformGroup;
|
|
}
|
|
else if (InGroupName == EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Geometry)
|
|
{
|
|
GroupNameToUse = FGeometryCollection::GeometryGroup;
|
|
}
|
|
else if (InGroupName == EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Faces)
|
|
{
|
|
GroupNameToUse = FGeometryCollection::FacesGroup;
|
|
}
|
|
else if (InGroupName == EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Vertices)
|
|
{
|
|
GroupNameToUse = FGeometryCollection::VerticesGroup;
|
|
}
|
|
else if (InGroupName == EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Material)
|
|
{
|
|
GroupNameToUse = FGeometryCollection::MaterialGroup;
|
|
}
|
|
else if (InGroupName == EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Breaking)
|
|
{
|
|
GroupNameToUse = FGeometryCollection::BreakingGroup;
|
|
}
|
|
|
|
return GroupNameToUse;
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
static void AddAndFillAttribute(FManagedArrayCollection& InCollection, FName AttributeName, FName GroupName, const T& DefaultValue)
|
|
{
|
|
TManagedArrayAccessor<T> CustomAttribute(InCollection, AttributeName, GroupName);
|
|
CustomAttribute.AddAndFill(DefaultValue);
|
|
}
|
|
|
|
void FAddCustomCollectionAttributeDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
const int32 InNumElements = GetValue<int32>(Context, &NumElements);
|
|
|
|
FName GroupNameToUse;
|
|
if (GroupName != EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Custom)
|
|
{
|
|
GroupNameToUse = GetGroupName(GroupName);
|
|
}
|
|
else
|
|
{
|
|
GroupNameToUse = FName(*CustomGroupName);
|
|
}
|
|
|
|
if (GroupNameToUse.GetStringLength() > 0 && AttrName.Len() > 0)
|
|
{
|
|
// If the group already exists don't change the number of elements
|
|
if (!InCollection.HasGroup(GroupNameToUse))
|
|
{
|
|
InCollection.AddGroup(GroupNameToUse);
|
|
InCollection.AddElements(InNumElements, GroupNameToUse);
|
|
}
|
|
|
|
FName AttributeNameToUse = FName(*AttrName);
|
|
|
|
switch (CustomAttributeType)
|
|
{
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_UInt8:
|
|
AddAndFillAttribute<uint8>(InCollection, AttributeNameToUse, GroupNameToUse, uint8(0));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Int32:
|
|
AddAndFillAttribute<int32>(InCollection, AttributeNameToUse, GroupNameToUse, 0);
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Float:
|
|
AddAndFillAttribute<float>(InCollection, AttributeNameToUse, GroupNameToUse, float(0.0));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Double:
|
|
AddAndFillAttribute<double>(InCollection, AttributeNameToUse, GroupNameToUse, double(0.0));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Bool:
|
|
AddAndFillAttribute<bool>(InCollection, AttributeNameToUse, GroupNameToUse, false);
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_String:
|
|
AddAndFillAttribute<FString>(InCollection, AttributeNameToUse, GroupNameToUse, FString());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Vector2f:
|
|
AddAndFillAttribute<FVector2f>(InCollection, AttributeNameToUse, GroupNameToUse, FVector2f(EForceInit::ForceInitToZero));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Vector3f:
|
|
AddAndFillAttribute<FVector3f>(InCollection, AttributeNameToUse, GroupNameToUse, FVector3f(EForceInit::ForceInitToZero));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Vector3d:
|
|
AddAndFillAttribute<FVector3d>(InCollection, AttributeNameToUse, GroupNameToUse, FVector3d(EForceInit::ForceInitToZero));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Vector4f:
|
|
AddAndFillAttribute<FVector4f>(InCollection, AttributeNameToUse, GroupNameToUse, FVector4f(EForceInit::ForceInitToZero));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_LinearColor:
|
|
AddAndFillAttribute<FLinearColor>(InCollection, AttributeNameToUse, GroupNameToUse, FLinearColor(0.f, 0.f, 0.f, 1.f));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Transform:
|
|
AddAndFillAttribute<FTransform>(InCollection, AttributeNameToUse, GroupNameToUse, FTransform(FTransform::Identity));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Quat4f:
|
|
AddAndFillAttribute<FQuat4f>(InCollection, AttributeNameToUse, GroupNameToUse, FQuat4f(ForceInitToZero));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Box:
|
|
AddAndFillAttribute<FBox>(InCollection, AttributeNameToUse, GroupNameToUse, FBox(ForceInit));
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Guid:
|
|
AddAndFillAttribute<FGuid>(InCollection, AttributeNameToUse, GroupNameToUse, FGuid());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Int32Set:
|
|
AddAndFillAttribute<TSet<int32>>(InCollection, AttributeNameToUse, GroupNameToUse, TSet<int32>());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Int32Array:
|
|
AddAndFillAttribute<TArray<int32>>(InCollection, AttributeNameToUse, GroupNameToUse, TArray<int32>());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_IntVector:
|
|
AddAndFillAttribute<FIntVector>(InCollection, AttributeNameToUse, GroupNameToUse, FIntVector());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_IntVector2:
|
|
AddAndFillAttribute<FIntVector2>(InCollection, AttributeNameToUse, GroupNameToUse, FIntVector2());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_IntVector4:
|
|
AddAndFillAttribute<FIntVector4>(InCollection, AttributeNameToUse, GroupNameToUse, FIntVector4());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_IntVector2Array:
|
|
AddAndFillAttribute<TArray<FIntVector2>>(InCollection, AttributeNameToUse, GroupNameToUse, TArray<FIntVector2>());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_FloatArray:
|
|
AddAndFillAttribute<TArray<float>>(InCollection, AttributeNameToUse, GroupNameToUse, TArray<float>());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_Vector2fArray:
|
|
AddAndFillAttribute<TArray<FVector2f>>(InCollection, AttributeNameToUse, GroupNameToUse, TArray<FVector2f>());
|
|
break;
|
|
case ECustomAttributeTypeEnum::Dataflow_CustomAttributeType_FVector3fArray:
|
|
AddAndFillAttribute<TArray<FVector3f>>(InCollection, AttributeNameToUse, GroupNameToUse, TArray<FVector3f>());
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
}
|
|
}
|
|
|
|
|
|
void FGetNumElementsInCollectionGroupDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<int32>(&NumElements))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
int32 OutNumElements = 0;
|
|
|
|
FName GroupNameToUse;
|
|
if (GroupName != EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Custom)
|
|
{
|
|
GroupNameToUse = GetGroupName(GroupName);
|
|
}
|
|
else
|
|
{
|
|
GroupNameToUse = FName(*CustomGroupName);
|
|
}
|
|
|
|
if (GroupNameToUse.GetStringLength() > 0)
|
|
{
|
|
if (InCollection.HasGroup(GroupNameToUse))
|
|
{
|
|
OutNumElements = InCollection.NumElements(GroupNameToUse);
|
|
}
|
|
}
|
|
|
|
SetValue(Context, OutNumElements, &NumElements);
|
|
}
|
|
}
|
|
|
|
void FGetCollectionAttributeDataTypedDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TArray<bool>>(&BoolAttributeData) ||
|
|
Out->IsA<TArray<float>>(&FloatAttributeData) ||
|
|
Out->IsA<TArray<double>>(&DoubleAttributeData) ||
|
|
Out->IsA<TArray<int32>>(&Int32AttributeData) ||
|
|
Out->IsA<TArray<FString>>(&StringAttributeData) ||
|
|
Out->IsA<TArray<FVector3f>>(&Vector3fAttributeData) ||
|
|
Out->IsA<TArray<FVector3d>>(&Vector3dAttributeData))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
FName InputGroupName;
|
|
if (GroupName != EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Custom)
|
|
{
|
|
InputGroupName = GetGroupName(GroupName);
|
|
}
|
|
else
|
|
{
|
|
InputGroupName = FName(*CustomGroupName);
|
|
}
|
|
|
|
SetValue(Context, TArray<bool>(), &BoolAttributeData);
|
|
SetValue(Context, TArray<float>(), &FloatAttributeData);
|
|
SetValue(Context, TArray<double>(), &DoubleAttributeData);
|
|
SetValue(Context, TArray<int32>(), &Int32AttributeData);
|
|
SetValue(Context, TArray<FString>(), &StringAttributeData);
|
|
SetValue(Context, TArray<FVector3f>(), &Vector3fAttributeData);
|
|
SetValue(Context, TArray<FVector3d>(), &Vector3dAttributeData);
|
|
|
|
FCollectionAttributeKey DefaultAttributeKey(AttrName, InputGroupName.ToString());
|
|
FCollectionAttributeKey AttributeKeyVal = GetValue(Context, &AttributeKey, DefaultAttributeKey);
|
|
FName GroupNameVal = FName(AttributeKeyVal.Group);
|
|
FName AttributeNameVal = FName(AttributeKeyVal.Attribute);
|
|
|
|
if (GroupNameVal.GetStringLength() > 0 && AttributeNameVal.GetStringLength() > 0)
|
|
{
|
|
if (InCollection.HasGroup(GroupNameVal))
|
|
{
|
|
if (InCollection.HasAttribute(AttributeNameVal, GroupNameVal))
|
|
{
|
|
FString TypeStr = GetArrayTypeString(InCollection.GetAttributeType(AttributeNameVal, GroupNameVal)).ToString();
|
|
|
|
if (TypeStr == FString("Bool"))
|
|
{
|
|
if (const TManagedArray<bool>* AttributeArr = InCollection.FindAttribute<bool>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<bool> BoolArray = AttributeArr->GetAsBoolArray();
|
|
SetValue(Context, MoveTemp(BoolArray), &BoolAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Float"))
|
|
{
|
|
if (const TManagedArray<float>* AttributeArr = InCollection.FindAttribute<float>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &FloatAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Double"))
|
|
{
|
|
if (const TManagedArray<double>* AttributeArr = InCollection.FindAttribute<double>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &DoubleAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Int32"))
|
|
{
|
|
if (const TManagedArray<int32>* AttributeArr = InCollection.FindAttribute<int32>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &Int32AttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("String"))
|
|
{
|
|
if (const TManagedArray<FString>* AttributeArr = InCollection.FindAttribute<FString>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &StringAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Vector"))
|
|
{
|
|
if (const TManagedArray<FVector3f>* AttributeArr = InCollection.FindAttribute<FVector3f>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &Vector3fAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Vector3d"))
|
|
{
|
|
if (const TManagedArray<FVector3d>* AttributeArr = InCollection.FindAttribute<FVector3d>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &Vector3dAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("LinearColor"))
|
|
{
|
|
if (const TManagedArray<FLinearColor>* AttributeArr = InCollection.FindAttribute<FLinearColor>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &LinearColorAttributeData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FGetCollectionAttributeDataTypedDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Collection))
|
|
{
|
|
SafeForwardInput(Context, &Collection, &Collection);
|
|
}
|
|
else if (Out->IsA(&BoolAttributeData) ||
|
|
Out->IsA(&NumericArray) ||
|
|
Out->IsA(&VectorArray) ||
|
|
Out->IsA(&StringArray))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
FName InputGroupName;
|
|
if (GroupName != EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Custom)
|
|
{
|
|
InputGroupName = GetGroupName(GroupName);
|
|
}
|
|
else
|
|
{
|
|
InputGroupName = FName(*CustomGroupName);
|
|
}
|
|
|
|
SetValue(Context, TArray<bool>(), &BoolAttributeData);
|
|
SetValue(Context, TArray<double>(), &NumericArray);
|
|
SetValue(Context, TArray<FVector4>(), &VectorArray);
|
|
SetValue(Context, TArray<FString>(), &StringArray);
|
|
|
|
FCollectionAttributeKey DefaultAttributeKey(AttrName, InputGroupName.ToString());
|
|
FCollectionAttributeKey AttributeKeyVal = GetValue(Context, &AttributeKey, DefaultAttributeKey);
|
|
FName GroupNameVal = FName(AttributeKeyVal.Group);
|
|
FName AttributeNameVal = FName(AttributeKeyVal.Attribute);
|
|
|
|
if (GroupNameVal.GetStringLength() > 0 && AttributeNameVal.GetStringLength() > 0)
|
|
{
|
|
if (InCollection.HasGroup(GroupNameVal))
|
|
{
|
|
if (InCollection.HasAttribute(AttributeNameVal, GroupNameVal))
|
|
{
|
|
FString TypeStr = GetArrayTypeString(InCollection.GetAttributeType(AttributeNameVal, GroupNameVal)).ToString();
|
|
|
|
if (TypeStr == FString("Bool"))
|
|
{
|
|
if (const TManagedArray<bool>* AttributeArr = InCollection.FindAttribute<bool>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<bool> BoolArray = AttributeArr->GetAsBoolArray();
|
|
SetValue(Context, MoveTemp(BoolArray), &BoolAttributeData);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Float"))
|
|
{
|
|
if (const TManagedArray<float>* AttributeArr = InCollection.FindAttribute<float>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<double> Arr; Arr.Reserve(AttributeArr->Num());
|
|
Algo::Copy(AttributeArr->GetConstArray(), Arr);
|
|
|
|
SetValue(Context, MoveTemp(Arr), &NumericArray);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Double"))
|
|
{
|
|
if (const TManagedArray<double>* AttributeArr = InCollection.FindAttribute<double>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &NumericArray);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Int32"))
|
|
{
|
|
if (const TManagedArray<int32>* AttributeArr = InCollection.FindAttribute<int32>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<double> Arr; Arr.Reserve(AttributeArr->Num());
|
|
Algo::Copy(AttributeArr->GetConstArray(), Arr);
|
|
|
|
SetValue(Context, MoveTemp(Arr), &NumericArray);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("String"))
|
|
{
|
|
if (const TManagedArray<FString>* AttributeArr = InCollection.FindAttribute<FString>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
SetValue(Context, AttributeArr->GetConstArray(), &StringArray);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Vector"))
|
|
{
|
|
if (const TManagedArray<FVector3f>* AttributeArr = InCollection.FindAttribute<FVector3f>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<FVector4> Arr; Arr.Reserve(AttributeArr->Num());
|
|
for (int32 Idx = 0; Idx < AttributeArr->Num(); ++Idx)
|
|
{
|
|
const FVector3f Vec = AttributeArr->GetConstArray()[Idx];
|
|
Arr[Idx] = FVector4(Vec.X, Vec.Y, Vec.Z, 0.0);
|
|
}
|
|
SetValue(Context, MoveTemp(Arr), &VectorArray);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("Vector3d"))
|
|
{
|
|
if (const TManagedArray<FVector3d>* AttributeArr = InCollection.FindAttribute<FVector3d>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<FVector4> Arr; Arr.Reserve(AttributeArr->Num());
|
|
for (int32 Idx = 0; Idx < AttributeArr->Num(); ++Idx)
|
|
{
|
|
const FVector3d Vec = AttributeArr->GetConstArray()[Idx];
|
|
Arr[Idx] = FVector4(Vec.X, Vec.Y, Vec.Z, 0.0);
|
|
}
|
|
SetValue(Context, MoveTemp(Arr), &VectorArray);
|
|
}
|
|
}
|
|
else if (TypeStr == FString("LinearColor"))
|
|
{
|
|
if (const TManagedArray<FLinearColor>* AttributeArr = InCollection.FindAttribute<FLinearColor>(AttributeNameVal, GroupNameVal))
|
|
{
|
|
TArray<FVector4> Arr; Arr.Reserve(AttributeArr->Num());
|
|
for (int32 Idx = 0; Idx < AttributeArr->Num(); ++Idx)
|
|
{
|
|
const FLinearColor Vec = AttributeArr->GetConstArray()[Idx];
|
|
Arr[Idx] = FVector4(Vec.R, Vec.G, Vec.B, Vec.A);
|
|
}
|
|
SetValue(Context, MoveTemp(Arr), &VectorArray);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
static void SetAttributeData(const FDataflowNode* DataflowNode, UE::Dataflow::FContext& Context, FManagedArrayCollection& InCollection, const TArray<T>& Property, FName AttributeName, FName GroupName)
|
|
{
|
|
if (DataflowNode && DataflowNode->IsConnected<TArray<T>>(&Property))
|
|
{
|
|
const TArray<T> & AttributeData = DataflowNode->GetValue<TArray<T>>(Context, &Property);
|
|
if (InCollection.FindAttributeTyped<T>(AttributeName, GroupName))
|
|
{
|
|
TManagedArray<T>& AttributeArray = InCollection.ModifyAttribute<T>(AttributeName, GroupName);
|
|
|
|
if (AttributeData.Num() == AttributeArray.Num())
|
|
{
|
|
for (int32 Idx = 0; Idx < AttributeArray.Num(); ++Idx)
|
|
{
|
|
AttributeArray[Idx] = AttributeData[Idx];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSetCollectionAttributeDataTypedDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
FName InputGroupName;
|
|
if (GroupName != EStandardGroupNameEnum::Dataflow_EStandardGroupNameEnum_Custom)
|
|
{
|
|
InputGroupName = GetGroupName(GroupName);
|
|
}
|
|
else
|
|
{
|
|
InputGroupName = FName(*CustomGroupName);
|
|
}
|
|
|
|
FCollectionAttributeKey DefaultAttributeKey(AttrName, InputGroupName.ToString());
|
|
FCollectionAttributeKey AttributeKeyVal = GetValue(Context, &AttributeKey, DefaultAttributeKey);
|
|
FName GroupNameVal = FName(AttributeKeyVal.Group);
|
|
FName AttributeNameVal = FName(AttributeKeyVal.Attribute);
|
|
|
|
if (GroupNameVal.GetStringLength() && AttributeNameVal.GetStringLength() )
|
|
{
|
|
if (InCollection.HasGroup(GroupNameVal))
|
|
{
|
|
if (InCollection.HasAttribute(AttributeNameVal, GroupNameVal))
|
|
{
|
|
FString TypeStr = GetArrayTypeString(InCollection.GetAttributeType(AttributeNameVal, GroupNameVal)).ToString();
|
|
|
|
if (TypeStr == FString("Bool"))
|
|
{
|
|
SetAttributeData<bool>(this, Context, InCollection, BoolAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("Float"))
|
|
{
|
|
SetAttributeData<float>(this, Context, InCollection, FloatAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("Double"))
|
|
{
|
|
SetAttributeData<double>(this, Context, InCollection, DoubleAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("Int32"))
|
|
{
|
|
SetAttributeData<int32>(this, Context, InCollection, Int32AttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("String"))
|
|
{
|
|
SetAttributeData<FString>(this, Context, InCollection, StringAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("Vector"))
|
|
{
|
|
SetAttributeData<FVector3f>(this, Context, InCollection, Vector3fAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("Vector3d"))
|
|
{
|
|
SetAttributeData<FVector3d>(this, Context, InCollection, Vector3dAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
else if (TypeStr == FString("LinearColor"))
|
|
{
|
|
SetAttributeData<FLinearColor>(this, Context, InCollection, LinearColorAttributeData, AttributeNameVal, GroupNameVal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
}
|
|
}
|
|
|
|
void FSelectionToVertexListDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
const FDataflowVertexSelection& InVertexSelection = GetValue<FDataflowVertexSelection>(Context, &VertexSelection);
|
|
SetValue(Context, InVertexSelection.AsArray(), &VertexList);
|
|
}
|
|
|
|
void FMultiplyTransformDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FTransform>(&OutTransform))
|
|
{
|
|
SetValue(Context,
|
|
GetValue<FTransform>(Context, &InLeftTransform, FTransform::Identity)
|
|
*GetValue<FTransform>(Context, &InRightTransform, FTransform::Identity)
|
|
, &OutTransform);
|
|
}
|
|
}
|
|
|
|
void FInvertTransformDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FTransform>(&OutTransform))
|
|
{
|
|
const FTransform InXf = GetValue<FTransform>(Context, &InTransform, FTransform::Identity);
|
|
const FTransform OutXf = InXf.Inverse();
|
|
SetValue(Context, OutXf, &OutTransform);
|
|
}
|
|
}
|
|
|
|
void FBranchFloatDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<float>(&ReturnValue))
|
|
{
|
|
bool InCondition = GetValue<bool>(Context, &bCondition);
|
|
|
|
if (InCondition)
|
|
{
|
|
const float InA = GetValue<float>(Context, &A, A);
|
|
|
|
SetValue(Context, InA, &ReturnValue);
|
|
}
|
|
else
|
|
{
|
|
const float InB = GetValue<float>(Context, &B, B);
|
|
|
|
SetValue(Context, InB, &ReturnValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FBranchIntDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<int32>(&ReturnValue))
|
|
{
|
|
bool InCondition = GetValue<bool>(Context, &bCondition);
|
|
|
|
if (InCondition)
|
|
{
|
|
const int32 InA = GetValue<int32>(Context, &A, A);
|
|
|
|
SetValue(Context, InA, &ReturnValue);
|
|
}
|
|
else
|
|
{
|
|
const int32 InB = GetValue<int32>(Context, &B, B);
|
|
|
|
SetValue(Context, InB, &ReturnValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FBoundingSphereDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&BoundingSphere))
|
|
{
|
|
if (IsConnected(&Collection))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
|
|
GeometryCollection::Facades::FBoundsFacade BoundsFacade(InCollection);
|
|
const FSphere& BoundingSphereInCollectionSpace = BoundsFacade.GetBoundingSphereInCollectionSpace();
|
|
|
|
SetValue(Context, BoundingSphereInCollectionSpace, &BoundingSphere);
|
|
return;
|
|
}
|
|
|
|
SetValue(Context, FSphere(), &BoundingSphere);
|
|
}
|
|
}
|
|
|
|
void FExpandBoundingSphereDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
FSphere InSphere = GetValue(Context, &BoundingSphere);
|
|
|
|
if (Out->IsA(&Center))
|
|
{
|
|
SetValue(Context, InSphere.Center, &Center);
|
|
}
|
|
else if (Out->IsA(&Radius))
|
|
{
|
|
SetValue(Context, (float)InSphere.W, &Radius);
|
|
}
|
|
else if (Out->IsA(&Volume))
|
|
{
|
|
SetValue(Context, (float)InSphere.GetVolume(), &Volume);
|
|
}
|
|
}
|
|
|
|
void FVisualizeTetrahedronsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Collection))
|
|
{
|
|
SafeForwardInput(Context, &Collection, &Collection);
|
|
}
|
|
else if (Out->IsA(&Vertices))
|
|
{
|
|
if (IsConnected(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue(Context, &Collection);
|
|
|
|
if (InCollection.HasAttribute("Vertex", FGeometryCollection::VerticesGroup) &&
|
|
InCollection.HasAttribute("TransformToGeometryIndex", FGeometryCollection::TransformGroup) &&
|
|
InCollection.HasAttribute("VertexStart", FGeometryCollection::GeometryGroup) &&
|
|
InCollection.HasAttribute("VertexCount", FGeometryCollection::GeometryGroup))
|
|
{
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
if (TransformFacade.IsValid())
|
|
{
|
|
TArray<FTransform> CollectionSpaceTransforms = TransformFacade.ComputeCollectionSpaceTransforms();
|
|
|
|
const TManagedArray<FVector3f>& Vertex = InCollection.GetAttribute<FVector3f>("Vertex", FGeometryCollection::VerticesGroup);
|
|
const TManagedArray<int32>& TransformToGeometryIndex = InCollection.GetAttribute<int32>("TransformToGeometryIndex", FGeometryCollection::TransformGroup);
|
|
const TManagedArray<int32>& VertexStartArr = InCollection.GetAttribute<int32>("VertexStart", FGeometryCollection::GeometryGroup);
|
|
const TManagedArray<int32>& VertexCountArr = InCollection.GetAttribute<int32>("VertexCount", FGeometryCollection::GeometryGroup);
|
|
|
|
TArray<FVector> VerticesInCollectionSpace;
|
|
VerticesInCollectionSpace.AddUninitialized(Vertex.Num());
|
|
|
|
for (int32 TransformIndex = 0; TransformIndex < CollectionSpaceTransforms.Num(); ++TransformIndex)
|
|
{
|
|
const FTransform CollectionSpaceTransform = CollectionSpaceTransforms[TransformIndex];
|
|
const int32 GeoIndex = TransformToGeometryIndex[TransformIndex];
|
|
const int32 VertexStart = VertexStartArr[GeoIndex];
|
|
const int32 VertexCount = VertexCountArr[GeoIndex];
|
|
|
|
for (int32 VertexIdx = VertexStart; VertexIdx < VertexStart + VertexCount; ++VertexIdx)
|
|
{
|
|
VerticesInCollectionSpace[VertexIdx] = CollectionSpaceTransform.TransformPosition((FVector)Vertex[VertexIdx]);
|
|
}
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(VerticesInCollectionSpace), &Vertices);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetValue(Context, TArray<FVector>(), &Vertices);
|
|
}
|
|
}
|
|
|
|
void FPointsToCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Collection))
|
|
{
|
|
if (IsConnected(&Collection) && IsConnected(&Points))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue(Context, &Collection);
|
|
const TArray<FVector> InPoints = GetValue(Context, &Points);
|
|
|
|
const int32 NumTransforms = InCollection.NumElements(FGeometryCollection::TransformGroup);
|
|
const int32 NumGeoms = InCollection.NumElements(FGeometryCollection::GeometryGroup);
|
|
const int32 NumVertices = InCollection.NumElements(FGeometryCollection::VerticesGroup);
|
|
|
|
// Add new element to groups
|
|
InCollection.AddElements(1, FGeometryCollection::TransformGroup);
|
|
InCollection.AddElements(1, FGeometryCollection::GeometryGroup);
|
|
InCollection.AddElements(InPoints.Num(), FGeometryCollection::VerticesGroup);
|
|
|
|
TManagedArray<FTransform>& Transform = InCollection.AddAttribute<FTransform>("Transform", FGeometryCollection::TransformGroup);
|
|
TManagedArray<FString>& BoneName = InCollection.AddAttribute<FString>("BoneName", FGeometryCollection::TransformGroup);
|
|
TManagedArray<FLinearColor>& BoneColor = InCollection.AddAttribute<FLinearColor>("BoneColor", FGeometryCollection::TransformGroup);
|
|
TManagedArray<int32>& Parent = InCollection.AddAttribute<int32>("Parent", FGeometryCollection::TransformGroup);
|
|
TManagedArray<TSet<int32>>& Children = InCollection.AddAttribute<TSet<int32>>("Children", FGeometryCollection::TransformGroup);
|
|
TManagedArray<int32>& TransformToGeometryIndex = InCollection.AddAttribute<int32>("TransformToGeometryIndex", FGeometryCollection::TransformGroup);
|
|
TManagedArray<FVector3f>& Vertex = InCollection.AddAttribute<FVector3f>("Vertex", FGeometryCollection::VerticesGroup);
|
|
TManagedArray<int32>& BoneMap = InCollection.AddAttribute<int32>("BoneMap", FGeometryCollection::VerticesGroup);
|
|
TManagedArray<int32>& TransformIndex = InCollection.AddAttribute<int32>("TransformIndex", FGeometryCollection::GeometryGroup);
|
|
TManagedArray<FBox>& BoundingBox = InCollection.AddAttribute<FBox>("BoundingBox", FGeometryCollection::GeometryGroup);
|
|
TManagedArray<int32>& VertexStart = InCollection.AddAttribute<int32>("VertexStart", FGeometryCollection::GeometryGroup);
|
|
TManagedArray<int32>& VertexCount = InCollection.AddAttribute<int32>("VertexCount", FGeometryCollection::GeometryGroup);
|
|
|
|
Transform[NumTransforms] = FTransform::Identity;
|
|
BoneName[NumTransforms] = FString(TEXT("Points"));
|
|
BoneColor[NumTransforms] = FLinearColor(0.02f, 0.01f, 0.1f, 1.0f);
|
|
Parent[NumTransforms] = -1;
|
|
Children[NumTransforms] = TSet<int32>();
|
|
TransformToGeometryIndex[NumTransforms] = NumGeoms;
|
|
|
|
for (int32 VertexIdx = 0; VertexIdx < InPoints.Num(); ++VertexIdx)
|
|
{
|
|
Vertex[NumVertices + VertexIdx] = (FVector3f)InPoints[VertexIdx];
|
|
}
|
|
|
|
TransformIndex[NumGeoms] = NumTransforms;
|
|
VertexStart[NumGeoms] = NumVertices;
|
|
VertexCount[NumGeoms] = InPoints.Num();
|
|
|
|
|
|
GeometryCollection::Facades::FBoundsFacade BoundsFacade(InCollection);
|
|
const FBox& BoundingBoxOfPoints = BoundsFacade.ComputeBoundingBox(InPoints);
|
|
|
|
BoundingBox[NumGeoms] = BoundingBoxOfPoints;
|
|
|
|
SetValue(Context, MoveTemp(InCollection), &Collection);
|
|
return;
|
|
}
|
|
|
|
SetValue(Context, FManagedArrayCollection(), &Collection);
|
|
}
|
|
}
|
|
|
|
void FCollectionToPointsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Collection))
|
|
{
|
|
SafeForwardInput(Context, &Collection, &Collection);
|
|
}
|
|
else if (Out->IsA(&Points))
|
|
{
|
|
if (IsConnected(&Collection))
|
|
{
|
|
FManagedArrayCollection InCollection = GetValue(Context, &Collection);
|
|
|
|
if (InCollection.HasAttribute("Vertex", FGeometryCollection::VerticesGroup) &&
|
|
InCollection.HasAttribute("TransformToGeometryIndex", FGeometryCollection::TransformGroup) &&
|
|
InCollection.HasAttribute("VertexStart", FGeometryCollection::GeometryGroup) &&
|
|
InCollection.HasAttribute("VertexCount", FGeometryCollection::GeometryGroup))
|
|
{
|
|
GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(InCollection);
|
|
if (TransformFacade.IsValid())
|
|
{
|
|
TArray<FTransform> CollectionSpaceTransforms = TransformFacade.ComputeCollectionSpaceTransforms();
|
|
|
|
const TManagedArray<FVector3f>& Vertex = InCollection.GetAttribute<FVector3f>("Vertex", FGeometryCollection::VerticesGroup);
|
|
const TManagedArray<int32>& TransformToGeometryIndex = InCollection.GetAttribute<int32>("TransformToGeometryIndex", FGeometryCollection::TransformGroup);
|
|
const TManagedArray<int32>& VertexStartArr = InCollection.GetAttribute<int32>("VertexStart", FGeometryCollection::GeometryGroup);
|
|
const TManagedArray<int32>& VertexCountArr = InCollection.GetAttribute<int32>("VertexCount", FGeometryCollection::GeometryGroup);
|
|
|
|
TArray<FVector> VerticesInCollectionSpace;
|
|
VerticesInCollectionSpace.AddUninitialized(Vertex.Num());
|
|
|
|
for (int32 TransformIndex = 0; TransformIndex < CollectionSpaceTransforms.Num(); ++TransformIndex)
|
|
{
|
|
const FTransform CollectionSpaceTransform = CollectionSpaceTransforms[TransformIndex];
|
|
const int32 GeoIndex = TransformToGeometryIndex[TransformIndex];
|
|
const int32 VertexStart = VertexStartArr[GeoIndex];
|
|
const int32 VertexCount = VertexCountArr[GeoIndex];
|
|
|
|
for (int32 VertexIdx = VertexStart; VertexIdx < VertexStart + VertexCount; ++VertexIdx)
|
|
{
|
|
VerticesInCollectionSpace[VertexIdx] = CollectionSpaceTransform.TransformPosition((FVector)Vertex[VertexIdx]);
|
|
}
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(VerticesInCollectionSpace), &Points);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetValue(Context, TArray<FVector>(), &Points);
|
|
}
|
|
}
|
|
|
|
void FSpheresToPointsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA(&Points) ||
|
|
Out->IsA(&Radii))
|
|
{
|
|
if (IsConnected(&Spheres))
|
|
{
|
|
const TArray<FSphere>& InSpheres = GetValue(Context, &Spheres);
|
|
|
|
const int32 NumSpheres = InSpheres.Num();
|
|
|
|
if (NumSpheres > 0)
|
|
{
|
|
TArray<FVector> OutPoints; OutPoints.AddUninitialized(NumSpheres);
|
|
TArray<float> OutRadii; OutRadii.AddUninitialized(NumSpheres);
|
|
|
|
for (int32 Idx = 0; Idx < NumSpheres; ++Idx)
|
|
{
|
|
OutPoints[Idx] = InSpheres[Idx].Center;
|
|
OutRadii[Idx] = InSpheres[Idx].W;
|
|
}
|
|
|
|
SetValue(Context, MoveTemp(OutPoints), &Points);
|
|
SetValue(Context, MoveTemp(OutRadii), &Radii);
|
|
return;
|
|
}
|
|
}
|
|
|
|
SetValue(Context, TArray<FVector>(), &Points);
|
|
SetValue(Context, TArray<float>(), &Radii);
|
|
}
|
|
} |