Files
UnrealEngine/Engine/Plugins/Experimental/GeometryCollectionPlugin/Source/GeometryCollectionNodes/Private/Dataflow/GeometryCollectionFieldNodes.cpp
2025-05-18 13:04:45 +08:00

2488 lines
81 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Dataflow/GeometryCollectionFieldNodes.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 "DynamicMesh/MeshTransforms.h"
#include "DynamicMesh/DynamicMesh3.h"
#include "Field/FieldSystem.h"
#include "Field/FieldSystemNodes.h"
#include "GeometryCollection/Facades/CollectionMeshFacade.h"
#include "GeometryCollection/Facades/CollectionTransformFacade.h"
//#include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionFieldNodes)
namespace UE::Dataflow
{
void GeometryCollectionFieldNodes()
{
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRadialFalloffFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBoxFalloffFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FPlaneFalloffFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRadialIntMaskFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FUniformScalarFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FUniformVectorFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRadialVectorFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRandomVectorFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FNoiseFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FUniformIntegerFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FWaveScalarFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSumScalarFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSumVectorFieldDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FFieldMakeDenseFloatArrayDataflowNode);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void FieldComputeRemap(const TArray<FVector3f>& InSamplePositions,
const FDataflowVertexSelection& InSampleIndices,
TArray<FVector3f>& OutNewSamplePositions,
TArray<int32>& OutRemapArray)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
//
// Build the SamplePositions array with only the selected indices
// and build the remap array
//
OutNewSamplePositions.Init(FVector3f(0.f), NumInSamplePositions);
OutRemapArray.Init(0, NumInSamplePositions);
int32 NewIdx = 0;
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
if (InSampleIndices.IsSelected(Idx))
{
OutNewSamplePositions[NewIdx] = InSamplePositions[Idx];
OutRemapArray[NewIdx] = Idx;
NewIdx++;
}
}
OutNewSamplePositions.SetNum(NewIdx, EAllowShrinking::Yes);
OutRemapArray.SetNum(NewIdx, EAllowShrinking::Yes);
}
// --------------------------------------------------------------------------------------------------------------------
static void RadialFalloffFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const FSphere& InSphere,
const FVector& InTranslation,
const float InMagnitude,
const float InMinRange,
const float InMaxRange,
const float InDefault,
const EDataflowFieldFalloffType InFalloffType,
TFieldArrayView<float>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FRadialFalloff RadialFalloffField(InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InSphere.W,
InSphere.Center + InTranslation,
(EFieldFalloffType)InFalloffType);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
RadialFalloffField.Evaluate(FieldContext, OutResultsView);
}
static void RadialFalloffFieldProcess(const TArray<FVector3f>& InSamplePositions,
const FSphere& InSphere,
const FVector& InTranslation,
const float InMagnitude,
const float InMinRange,
const float InMaxRange,
const float InDefault,
const EDataflowFieldFalloffType InFalloffType,
FDataflowVertexSelection& OutFieldSelectionMask,
TArray<float>& OutFieldFloatOutput)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
TArray<float> ResultsArray;
ResultsArray.Init(false, NumInSamplePositions);
TFieldArrayView<float> ResultsViewTest(ResultsArray, 0, ResultsArray.Num());
//
// Get the samples which effected by the field by evaluating the field with a default
// value outside of the (MinRange, MaxRange)
//
const float NewDefault = InMinRange - 1000.f;
RadialFalloffFieldEvaluate(InSamplePositions,
InSphere,
InTranslation,
InMagnitude,
InMinRange,
InMaxRange,
NewDefault,
InFalloffType,
ResultsViewTest);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
if (ResultsViewTest[Idx] != NewDefault)
{
OutFieldSelectionMask.SetSelected(Idx);
}
}
// Compute the field
ResultsArray.Init(false, NumInSamplePositions);
TFieldArrayView<float> ResultsView(ResultsArray, 0, ResultsArray.Num());
RadialFalloffFieldEvaluate(InSamplePositions,
InSphere,
InTranslation,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InFalloffType,
ResultsView);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatOutput[Idx] = ResultsView[Idx];
}
}
void FRadialFalloffFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<FDataflowVertexSelection>(&FieldSelectionMask) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const FSphere& InSphere = GetValue<FSphere>(Context, &Sphere);
const FVector& InTranslation = GetValue<FVector>(Context, &Translation);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
const float InMinRange = GetValue<float>(Context, &MinRange);
const float InMaxRange = GetValue<float>(Context, &MaxRange);
const float InDefault = GetValue<float>(Context, &Default);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemap output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
const int32 NumInSamplePositions = InSamplePositions.Num();
//
// Process the field
//
FDataflowVertexSelection NewFieldSelectionMask;
NewFieldSelectionMask.Initialize(NumInSamplePositions, false);
TArray<float> NewFieldFloatResult;
NewFieldFloatResult.Init(false, NumInSamplePositions);
RadialFalloffFieldProcess(InSamplePositions,
InSphere,
InTranslation,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
FalloffType,
NewFieldSelectionMask,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, MoveTemp(NewFieldSelectionMask), &FieldSelectionMask);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemap output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
const int32 NumNewSamplePositions = NewSamplePositions.Num();
//
// Process the field
//
FDataflowVertexSelection NewFieldSelectionMask;
NewFieldSelectionMask.Initialize(NumNewSamplePositions, false);
TArray<float> NewFieldFloatResult;
NewFieldFloatResult.Init(false, NumNewSamplePositions);
RadialFalloffFieldProcess(NewSamplePositions,
InSphere,
InTranslation,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
FalloffType,
NewFieldSelectionMask,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, MoveTemp(NewFieldSelectionMask), &FieldSelectionMask);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
// Set the outputs
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, FDataflowVertexSelection(), &FieldSelectionMask);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void BoxFalloffFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const FBox& InBox,
FTransform InTransform,
const float InMagnitude,
const float InMinRange,
const float InMaxRange,
const float InDefault,
const EDataflowFieldFalloffType InFalloffType,
TFieldArrayView<float>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
//
// Translation and Scale needs to be adjusted based on the InBox
//
FVector Center = InBox.GetCenter();
FVector Translation = InTransform.GetTranslation();
Translation -= Center;
InTransform.SetTranslation(Translation);
FVector Extent(InBox.Max - InBox.Min);
FVector Scale = InTransform.GetScale3D();
Scale.X *= 100.f / Extent.X;
Scale.Y *= 100.f / Extent.Y;
Scale.Z *= 100.f / Extent.Z;
InTransform.SetScale3D(Scale);
FBoxFalloff BoxFalloffField(InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InTransform,
(EFieldFalloffType)InFalloffType);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
BoxFalloffField.Evaluate(FieldContext, OutResultsView);
}
static void BoxFalloffFieldProcess(const TArray<FVector3f>& InSamplePositions,
const FBox& InBox,
const FTransform& InTransform,
const float InMagnitude,
const float InMinRange,
const float InMaxRange,
const float InDefault,
const EDataflowFieldFalloffType InFalloffType,
FDataflowVertexSelection& OutFieldSelectionMask,
TArray<float>& OutFieldFloatOutput)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
TArray<float> ResultsArray;
ResultsArray.Init(false, NumInSamplePositions);
TFieldArrayView<float> ResultsViewTest(ResultsArray, 0, ResultsArray.Num());
//
// Get the samples which effected by the field by evaluating the field with a default
// value outside of the (MinRange, MaxRange)
//
const float NewDefault = InMinRange - 1000.f;
BoxFalloffFieldEvaluate(InSamplePositions,
InBox,
InTransform,
InMagnitude,
InMinRange,
InMaxRange,
NewDefault,
InFalloffType,
ResultsViewTest);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
if (ResultsViewTest[Idx] != NewDefault)
{
OutFieldSelectionMask.SetSelected(Idx);
}
}
// Compute the field
ResultsArray.Init(false, NumInSamplePositions);
TFieldArrayView<float> ResultsView(ResultsArray, 0, ResultsArray.Num());
BoxFalloffFieldEvaluate(InSamplePositions,
InBox,
InTransform,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InFalloffType,
ResultsView);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatOutput[Idx] = ResultsView[Idx];
}
}
void FBoxFalloffFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<FDataflowVertexSelection>(&FieldSelectionMask) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const FBox& InBox = GetValue<FBox>(Context, &Box);
const FTransform& InTransform = GetValue<FTransform>(Context, &Transform);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
const float InMinRange = GetValue<float>(Context, &MinRange);
const float InMaxRange = GetValue<float>(Context, &MaxRange);
const float InDefault = GetValue<float>(Context, &Default);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemap output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
const int32 NumInSamplePositions = InSamplePositions.Num();
//
// Process the field
//
FDataflowVertexSelection NewFieldSelectionMask;
NewFieldSelectionMask.Initialize(NumInSamplePositions, false);
TArray<float> NewFieldFloatResult;
NewFieldFloatResult.Init(false, NumInSamplePositions);
BoxFalloffFieldProcess(InSamplePositions,
InBox,
InTransform,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
FalloffType,
NewFieldSelectionMask,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, MoveTemp(NewFieldSelectionMask), &FieldSelectionMask);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemap output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
const int32 NumNewSamplePositions = NewSamplePositions.Num();
//
// Process the field
//
FDataflowVertexSelection NewFieldSelectionMask;
NewFieldSelectionMask.Initialize(NumNewSamplePositions, false);
TArray<float> NewFieldFloatResult;
NewFieldFloatResult.Init(false, NumNewSamplePositions);
BoxFalloffFieldProcess(NewSamplePositions,
InBox,
InTransform,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
FalloffType,
NewFieldSelectionMask,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, MoveTemp(NewFieldSelectionMask), &FieldSelectionMask);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
// Set the outputs
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, FDataflowVertexSelection(), &FieldSelectionMask);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void PlaneFalloffFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const float InMagnitude,
const float InMinRange,
const float InMaxRange,
const float InDefault,
const float InDistance,
const FVector& InPosition,
const FVector& InNormal,
const EDataflowFieldFalloffType InFalloffType,
TFieldArrayView<float>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FPlaneFalloff PlaneFalloffField(InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InDistance,
InPosition,
InNormal,
(EFieldFalloffType)InFalloffType);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
PlaneFalloffField.Evaluate(FieldContext, OutResultsView);
}
static void PlaneFalloffFieldProcess(const TArray<FVector3f>& InSamplePositions,
const float InMagnitude,
const float InMinRange,
const float InMaxRange,
const float InDefault,
const float InDistance,
const FVector& InPosition,
const FVector& InTranslation,
const FVector& InNormal,
const EDataflowFieldFalloffType InFalloffType,
FDataflowVertexSelection& OutFieldSelectionMask,
TArray<float>& OutFieldFloatOutput)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
TArray<float> ResultsArray;
ResultsArray.Init(false, NumInSamplePositions);
TFieldArrayView<float> ResultsViewTest(ResultsArray, 0, ResultsArray.Num());
//
// Get the samples which effected by the field by evaluating the field with a default
// value outside of the (MinRange, MaxRange)
//
const float NewDefault = InMinRange - 1000.f;
PlaneFalloffFieldEvaluate(InSamplePositions,
InMagnitude,
InMinRange,
InMaxRange,
NewDefault,
InDistance,
InPosition + InTranslation,
InNormal,
InFalloffType,
ResultsViewTest);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
if (ResultsViewTest[Idx] != NewDefault)
{
OutFieldSelectionMask.SetSelected(Idx);
}
}
// Compute the field
ResultsArray.Init(false, NumInSamplePositions);
TFieldArrayView<float> ResultsView(ResultsArray, 0, ResultsArray.Num());
PlaneFalloffFieldEvaluate(InSamplePositions,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InDistance,
InPosition + InTranslation,
InNormal,
InFalloffType,
ResultsViewTest);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatOutput[Idx] = ResultsView[Idx];
}
}
void FPlaneFalloffFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<FDataflowVertexSelection>(&FieldSelectionMask) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const FVector& InPosition = GetValue<FVector>(Context, &Position);
const FVector& InNormal = GetValue<FVector>(Context, &Normal);
const float InDistance = GetValue<float>(Context, &Distance);
const FVector& InTranslation = GetValue<FVector>(Context, &Translation);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
const float InMinRange = GetValue<float>(Context, &MinRange);
const float InMaxRange = GetValue<float>(Context, &MaxRange);
const float InDefault = GetValue<float>(Context, &Default);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemap output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
const int32 NumInSamplePositions = InSamplePositions.Num();
//
// Process the field
//
FDataflowVertexSelection NewFieldSelectionMask;
NewFieldSelectionMask.Initialize(NumInSamplePositions, false);
TArray<float> NewFieldFloatResult;
NewFieldFloatResult.Init(false, NumInSamplePositions);
PlaneFalloffFieldProcess(InSamplePositions,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InDistance,
InPosition,
InTranslation,
InNormal,
FalloffType,
NewFieldSelectionMask,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, MoveTemp(NewFieldSelectionMask), &FieldSelectionMask);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemap output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
const int32 NumNewSamplePositions = NewSamplePositions.Num();
//
// Process the field
//
FDataflowVertexSelection NewFieldSelectionMask;
NewFieldSelectionMask.Initialize(NumNewSamplePositions, false);
TArray<float> NewFieldFloatResult;
NewFieldFloatResult.Init(false, NumNewSamplePositions);
PlaneFalloffFieldProcess(NewSamplePositions,
InMagnitude,
InMinRange,
InMaxRange,
InDefault,
InDistance,
InPosition,
InTranslation,
InNormal,
FalloffType,
NewFieldSelectionMask,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, MoveTemp(NewFieldSelectionMask), &FieldSelectionMask);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
// Set the outputs
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<FDataflowVertexSelection>(Context, FDataflowVertexSelection(), &FieldSelectionMask);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void RadialIntMaskFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
float InRadius,
const FVector InPosition,
int32 InInteriorValue,
int32 InExteriorValue,
EDataflowSetMaskConditionType InSetMaskConditionType,
TFieldArrayView<int32>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FRadialIntMask RadialIntMaskField(InRadius, InPosition, InInteriorValue, InExteriorValue, (ESetMaskConditionType)InSetMaskConditionType);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
RadialIntMaskField.Evaluate(FieldContext, OutResultsView);
}
static void RadialIntMaskFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InRadius,
const FVector InPosition,
const FVector InTranslation,
int32 InInteriorValue,
int32 InExteriorValue,
EDataflowSetMaskConditionType InSetMaskConditionType,
TArray<int32>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<int32> ResultsArray;
ResultsArray.Init(0, NumInSamplePositions);
TFieldArrayView<int32> ResultsView(ResultsArray, 0, ResultsArray.Num());
RadialIntMaskFieldEvaluate(InSamplePositions,
InRadius,
InPosition + InTranslation,
InInteriorValue,
InExteriorValue,
InSetMaskConditionType,
ResultsView);
// Set the outputs
OutFieldFloatResult.Init(0, NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FRadialIntMaskFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<int32>>(&FieldIntResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const FSphere& InSphere = GetValue<FSphere>(Context, &Sphere);
const FVector InTranslation = GetValue<FVector>(Context, &Translation);
const int32 InInteriorValue = GetValue<int32>(Context, &InteriorValue);
const int32 InExteriorValue = GetValue<int32>(Context, &ExteriorValue);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<int32> NewFieldIntResult;
RadialIntMaskFieldProcess(InSamplePositions,
InSphere.W,
InSphere.Center,
InTranslation,
InInteriorValue,
InExteriorValue,
SetMaskConditionType,
NewFieldIntResult);
// Set the outputs
SetValue<TArray<int32>>(Context, MoveTemp(NewFieldIntResult), &FieldIntResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<int32> NewFieldIntResult;
RadialIntMaskFieldProcess(NewSamplePositions,
InSphere.W,
InSphere.Center,
InTranslation,
InInteriorValue,
InExteriorValue,
SetMaskConditionType,
NewFieldIntResult);
// Set the outputs
SetValue<TArray<int32>>(Context, MoveTemp(NewFieldIntResult), &FieldIntResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldIntResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void UniformScalarFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
TFieldArrayView<float>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FUniformScalar UniformScalarField(InMagnitude);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
UniformScalarField.Evaluate(FieldContext, OutResultsView);
}
static void UniformScalarFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
TArray<float>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<float> ResultsArray;
ResultsArray.Init(0.f, NumInSamplePositions);
TFieldArrayView<float> ResultsView(ResultsArray, 0, ResultsArray.Num());
UniformScalarFieldEvaluate(InSamplePositions, InMagnitude, ResultsView);
// Set the outputs
OutFieldFloatResult.Init(0.f, NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FUniformScalarFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<float> NewFieldFloatResult;
UniformScalarFieldProcess(InSamplePositions, InMagnitude, NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<float> NewFieldFloatResult;
UniformScalarFieldProcess(NewSamplePositions, InMagnitude, NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void UniformVectorFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const float InMagnitude,
const FVector InDirection,
TFieldArrayView<FVector>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FUniformVector UniformVectorField(InMagnitude, InDirection);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
UniformVectorField.Evaluate(FieldContext, OutResultsView);
}
static void UniformVectorFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
const FVector InDirection,
TArray<FVector>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<FVector> ResultsArray;
ResultsArray.Init(FVector(0.f), NumInSamplePositions);
TFieldArrayView<FVector> ResultsView(ResultsArray, 0, ResultsArray.Num());
UniformVectorFieldEvaluate(InSamplePositions, InMagnitude, InDirection, ResultsView);
// Set the outputs
OutFieldFloatResult.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FUniformVectorFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<FVector>>(&FieldVectorResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
const FVector InDirection = GetValue<FVector>(Context, &Direction);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<FVector> NewFieldVectorResult;
UniformVectorFieldProcess(InSamplePositions, InMagnitude, InDirection, NewFieldVectorResult);
// Set the outputs
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<FVector> NewFieldVectorResult;
UniformVectorFieldProcess(NewSamplePositions, InMagnitude, InDirection, NewFieldVectorResult);
// Set the outputs
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<FVector>>(Context, TArray<FVector>(), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void RadialVectorFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const float InMagnitude,
const FVector InPosition,
TFieldArrayView<FVector>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FRadialVector RadialVectorField(InMagnitude, InPosition);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
RadialVectorField.Evaluate(FieldContext, OutResultsView);
}
static void RadialVectorFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
const FVector InPosition,
TArray<FVector>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<FVector> ResultsArray;
ResultsArray.Init(FVector(0.f), NumInSamplePositions);
TFieldArrayView<FVector> ResultsView(ResultsArray, 0, ResultsArray.Num());
RadialVectorFieldEvaluate(InSamplePositions, InMagnitude, InPosition, ResultsView);
// Set the outputs
OutFieldFloatResult.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FRadialVectorFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<FVector>>(&FieldVectorResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
const FVector InPosition = GetValue<FVector>(Context, &Position);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<FVector> NewFieldVectorResult;
RadialVectorFieldProcess(InSamplePositions, InMagnitude, InPosition, NewFieldVectorResult);
// Set the outputs
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<FVector> NewFieldVectorResult;
RadialVectorFieldProcess(NewSamplePositions, InMagnitude, InPosition, NewFieldVectorResult);
// Set the outputs
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<FVector>>(Context, TArray<FVector>(), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void RandomVectorFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const float InMagnitude,
TFieldArrayView<FVector>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FRandomVector RandomVectorField(InMagnitude);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
RandomVectorField.Evaluate(FieldContext, OutResultsView);
}
static void RandomVectorFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
TArray<FVector>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<FVector> ResultsArray;
ResultsArray.Init(FVector(0.f), NumInSamplePositions);
TFieldArrayView<FVector> ResultsView(ResultsArray, 0, ResultsArray.Num());
RandomVectorFieldEvaluate(InSamplePositions, InMagnitude, ResultsView);
// Set the outputs
OutFieldFloatResult.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FRandomVectorFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<FVector>>(&FieldVectorResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<FVector> NewFieldVectorResult;
RandomVectorFieldProcess(InSamplePositions, InMagnitude, NewFieldVectorResult);
// Set the outputs
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<FVector> NewFieldVectorResult;
RandomVectorFieldProcess(NewSamplePositions, InMagnitude, NewFieldVectorResult);
// Set the outputs
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<FVector>>(Context, TArray<FVector>(), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void NoiseFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
float InMinRange,
float InMaxRange,
const FTransform& InTransform,
TFieldArrayView<float>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FNoiseField NoiseField(InMinRange, InMaxRange, InTransform);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
NoiseField.Evaluate(FieldContext, OutResultsView);
}
static void NoiseFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InMinRange,
float InMaxRange,
const FTransform& InTransform,
TArray<float>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<float> ResultsArray;
ResultsArray.Init(0.f, NumInSamplePositions);
TFieldArrayView<float> ResultsView(ResultsArray, 0, ResultsArray.Num());
NoiseFieldEvaluate(InSamplePositions, InMinRange, InMaxRange, InTransform, ResultsView);
// Set the outputs
OutFieldFloatResult.Init(0.f, NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FNoiseFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const float InMinRange = GetValue<float>(Context, &MinRange);
const float InMaxRange = GetValue<float>(Context, &MaxRange);
const FTransform InTransform = GetValue<FTransform>(Context, &Transform);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<float> NewFieldFloatResult;
NoiseFieldProcess(InSamplePositions, InMinRange, InMaxRange, InTransform, NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<float> NewFieldFloatResult;
NoiseFieldProcess(NewSamplePositions, InMinRange, InMaxRange, InTransform, NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void UniformIntegerFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
const int32 InMagnitude,
TFieldArrayView<int32>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FUniformInteger UniformIntegerField(InMagnitude);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
UniformIntegerField.Evaluate(FieldContext, OutResultsView);
}
static void UniformIntegerFieldProcess(const TArray<FVector3f>& InSamplePositions,
int32 InMagnitude,
TArray<int32>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<int32> ResultsArray;
ResultsArray.Init(0, NumInSamplePositions);
TFieldArrayView<int32> ResultsView(ResultsArray, 0, ResultsArray.Num());
UniformIntegerFieldEvaluate(InSamplePositions, InMagnitude, ResultsView);
// Set the outputs
OutFieldFloatResult.Init(0, NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FUniformIntegerFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<int32>>(&FieldIntResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const int32 InMagnitude = GetValue<int32>(Context, &Magnitude);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<int32> NewFieldIntResult;
UniformIntegerFieldProcess(InSamplePositions, InMagnitude, NewFieldIntResult);
// Set the outputs
SetValue<TArray<int32>>(Context, MoveTemp(NewFieldIntResult), &FieldIntResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<int32> NewFieldIntResult;
UniformIntegerFieldProcess(NewSamplePositions, InMagnitude, NewFieldIntResult);
// Set the outputs
SetValue<TArray<int32>>(Context, MoveTemp(NewFieldIntResult), &FieldIntResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldIntResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void WaveScalarFieldEvaluate(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
const FVector InPosition,
float InWavelength,
float InPeriod,
const EDataflowWaveFunctionType InFunctionType,
const EDataflowFieldFalloffType InFalloffType,
TFieldArrayView<float>& OutResultsView)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Setup the data for the field
FFieldExecutionDatas ExecutionDatas;
FFieldContextIndex::ContiguousIndices(ExecutionDatas.SampleIndices, NumInSamplePositions);
ExecutionDatas.SamplePositions.Init(FVector(0.f), NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; Idx++)
{
ExecutionDatas.SamplePositions[Idx] = (FVector)InSamplePositions[Idx];
}
FWaveScalar WaveScalarField(InMagnitude, InPosition, InWavelength, InPeriod, (EWaveFunctionType)InFunctionType, (EFieldFalloffType)InFalloffType);
FFieldContext FieldContext{
ExecutionDatas,
FFieldContext::UniquePointerMap(),
0.0
};
// Evalute the field
WaveScalarField.Evaluate(FieldContext, OutResultsView);
}
static void WaveScalarFieldProcess(const TArray<FVector3f>& InSamplePositions,
float InMagnitude,
const FVector InPosition,
const FVector InTranslation,
float InWavelength,
float InPeriod,
const EDataflowWaveFunctionType InFunctionType,
const EDataflowFieldFalloffType InFalloffType,
TArray<float>& OutFieldFloatResult)
{
const int32 NumInSamplePositions = InSamplePositions.Num();
// Compute the field
TArray<float> ResultsArray;
ResultsArray.Init(0.f, NumInSamplePositions);
TFieldArrayView<float> ResultsView(ResultsArray, 0, ResultsArray.Num());
WaveScalarFieldEvaluate(InSamplePositions,
InMagnitude,
InPosition + InTranslation,
InWavelength,
InPeriod,
InFunctionType,
InFalloffType,
ResultsView);
// Set the outputs
OutFieldFloatResult.Init(0.f, NumInSamplePositions);
for (int32 Idx = 0; Idx < NumInSamplePositions; ++Idx)
{
OutFieldFloatResult[Idx] = ResultsView[Idx];
}
}
void FWaveScalarFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap) ||
Out->IsA<int32>(&NumSamplePositions))
{
const TArray<FVector3f>& InSamplePositions = GetValue<TArray<FVector3f>>(Context, &SamplePositions);
const FDataflowVertexSelection& InSampleIndices = GetValue<FDataflowVertexSelection>(Context, &SampleIndices);
const float InMagnitude = GetValue<float>(Context, &Magnitude);
const FVector InPosition = GetValue<FVector>(Context, &Position);
const FVector InTranslation = GetValue<FVector>(Context, &Translation);
const float InWavelength = GetValue<float>(Context, &Wavelength);
const float InPeriod = GetValue<float>(Context, &Period);
//
// SampleIndices input not connected, all the elements from SamplePositions array
// will be processed and FieldRemapOutput output will be set empty
//
if (!IsConnected<FDataflowVertexSelection>(&SampleIndices))
{
// Compute the field
TArray<float> NewFieldFloatResult;
WaveScalarFieldProcess(InSamplePositions,
InMagnitude,
InPosition,
InTranslation,
InWavelength,
InPeriod,
FunctionType,
FalloffType,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
//
// SampleIndices input connected, the selected elements from SamplePositions array
// will be processed and FieldRemapOutput output will contain the remap info
// IMPORTANT: Number of elements in SamplePositions and SampleIndices must be the same
//
else
{
if (InSamplePositions.Num() == InSampleIndices.Num())
{
TArray<FVector3f> NewSamplePositions;
TArray<int32> NewRemapArray;
FieldComputeRemap(InSamplePositions, InSampleIndices, NewSamplePositions, NewRemapArray);
// Compute the field
TArray<float> NewFieldFloatResult;
WaveScalarFieldProcess(NewSamplePositions,
InMagnitude,
InPosition,
InTranslation,
InWavelength,
InPeriod,
FunctionType,
FalloffType,
NewFieldFloatResult);
// Set the outputs
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatResult), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
SetValue<int32>(Context, InSamplePositions.Num(), &NumSamplePositions);
return;
}
}
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
SetValue<int32>(Context, 0, &NumSamplePositions);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void SumScalarEvaluate(const TArray<float>& InFieldFloatLeft,
const TArray<float>& InFieldFloatRight,
TArray<float>& OutNewFieldFloatOutput,
const int32 InNumSamplePositions,
const EDataflowFloatFieldOperationType InOperation,
const float InMagnitude,
const bool bInSwapInputs)
{
switch (InOperation)
{
case EDataflowFloatFieldOperationType::Dataflow_FloatFieldOperationType_Multiply:
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] = InFieldFloatLeft[Idx] * InFieldFloatRight[Idx];
}
break;
case EDataflowFloatFieldOperationType::Dataflow_FloatFieldFalloffType_Divide:
if (!bInSwapInputs)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
if (!FMath::IsNearlyZero(InFieldFloatRight[Idx]))
{
OutNewFieldFloatOutput[Idx] = InFieldFloatLeft[Idx] / InFieldFloatRight[Idx];
}
}
}
else
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
if (!FMath::IsNearlyZero(InFieldFloatLeft[Idx]))
{
OutNewFieldFloatOutput[Idx] = InFieldFloatRight[Idx] / InFieldFloatLeft[Idx];
}
}
}
break;
case EDataflowFloatFieldOperationType::Dataflow_FloatFieldFalloffType_Add:
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] = InFieldFloatLeft[Idx] + InFieldFloatRight[Idx];
}
break;
case EDataflowFloatFieldOperationType::Dataflow_FloatFieldFalloffType_Substract:
if (!bInSwapInputs)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] = InFieldFloatLeft[Idx] - InFieldFloatRight[Idx];
}
}
else
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] = InFieldFloatRight[Idx] - InFieldFloatLeft[Idx];
}
}
break;
case EDataflowFloatFieldOperationType::Dataflow_FloatFieldFalloffType_Min:
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] = FMath::Min(InFieldFloatLeft[Idx], InFieldFloatRight[Idx]);
}
break;
case EDataflowFloatFieldOperationType::Dataflow_FloatFieldFalloffType_Max:
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] = FMath::Max(InFieldFloatLeft[Idx], InFieldFloatRight[Idx]);
}
break;
}
if (InMagnitude != 1.0)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldFloatOutput[Idx] *= InMagnitude;
}
}
}
void FSumScalarFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult) ||
Out->IsA<TArray<int32>>(&FieldRemap))
{
const TArray<float>& InFieldFloatLeft = GetValue<TArray<float>>(Context, &FieldFloatLeft);
const TArray<int32>& InFieldRemapLeft = GetValue<TArray<int32>>(Context, &FieldRemapLeft);
const TArray<float>& InFieldFloatRight = GetValue<TArray<float>>(Context, &FieldFloatRight);
const TArray<int32>& InFieldRemapRight = GetValue<TArray<int32>>(Context, &FieldRemapRight);
const int32 NumFieldFloatLeft = InFieldFloatLeft.Num();
const int32 NumFieldRemapLeft = InFieldRemapLeft.Num();
const int32 NumFieldFloatRight = InFieldFloatRight.Num();
const int32 NumFieldRemapRight = InFieldRemapRight.Num();
const bool IsFieldRemapLeftConnected = IsConnected<TArray<int32>>(&FieldRemapLeft);
const bool IsFieldRemapRightConnected = IsConnected<TArray<int32>>(&FieldRemapRight);
TArray<float> NewFieldFloatOutput;
// Both Remap inputs are connected but they can be different sizes
// Process the two FloatArray inputs and generate a new output remap
if (IsFieldRemapLeftConnected && IsFieldRemapRightConnected)
{
if (NumFieldFloatLeft == NumFieldRemapLeft &&
NumFieldFloatRight == NumFieldRemapRight)
{
int32 NewArraySize = FMath::Max(NumFieldFloatLeft, NumFieldFloatRight);
NewFieldFloatOutput.Init(false, NewArraySize);
TArray<int32> NewRemapArray;
NewRemapArray.Init(false, NewArraySize);
TArray<float> NewFloatArrayLeft, NewFloatArrayRight;
NewFloatArrayLeft.Init(false, NewArraySize);
NewFloatArrayRight.Init(false, NewArraySize);
int32 NewSampleCount = 0;
for (int32 IndexLeft = 0; IndexLeft < NumFieldFloatLeft; ++IndexLeft)
{
int32 SampleIndex = InFieldRemapLeft[IndexLeft];
if (InFieldRemapRight.Contains(SampleIndex))
{
int32 IndexRight = InFieldRemapRight.Find(SampleIndex);
NewRemapArray[NewSampleCount] = SampleIndex;
NewFloatArrayLeft[NewSampleCount] = InFieldFloatLeft[IndexLeft];
NewFloatArrayRight[NewSampleCount] = InFieldFloatRight[IndexRight];
NewSampleCount++;
}
}
NewRemapArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFloatArrayLeft.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFloatArrayRight.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFieldFloatOutput.SetNum(NewSampleCount, EAllowShrinking::Yes);
SumScalarEvaluate(NewFloatArrayLeft,
NewFloatArrayRight,
NewFieldFloatOutput,
NewSampleCount,
Operation,
Magnitude,
bSwapInputs);
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatOutput), &FieldFloatResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
return;
}
}
// At least one of the Remap inputs are not connected
// There is no remap information, just process the two FloatArray inputs
// but they have to be the same size
else
{
if (NumFieldFloatLeft == NumFieldFloatRight)
{
const int32 NumSamplePositions = NumFieldFloatLeft;
NewFieldFloatOutput.Init(false, NumSamplePositions);
SumScalarEvaluate(InFieldFloatLeft,
InFieldFloatRight,
NewFieldFloatOutput,
NumSamplePositions,
Operation,
Magnitude,
bSwapInputs);
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatOutput), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
return;
}
}
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
}
}
// --------------------------------------------------------------------------------------------------------------------
static void SumVectorEvaluate(const TArray<float>* InFieldFloat,
const TArray<FVector>* InFieldVectorLeft,
const TArray<FVector>* InFieldVectorRight,
TArray<FVector>& OutNewFieldVectorResult,
const int32 InNumSamplePositions,
const EDataflowVectorFieldOperationType InOperation,
const float InMagnitude,
const bool bSwapVectorInputs)
{
if (InFieldVectorLeft != nullptr && InFieldVectorRight != nullptr)
{
switch (InOperation)
{
case EDataflowVectorFieldOperationType::Dataflow_VectorFieldOperationType_Multiply:
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorLeft)[Idx] * (*InFieldVectorRight)[Idx];
}
break;
case EDataflowVectorFieldOperationType::Dataflow_VectorFieldFalloffType_Divide:
if (!bSwapVectorInputs)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
if (!FMath::IsNearlyZero((*InFieldVectorRight)[Idx].X) &&
!FMath::IsNearlyZero((*InFieldVectorRight)[Idx].Y) &&
!FMath::IsNearlyZero((*InFieldVectorRight)[Idx].Z))
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorLeft)[Idx] / (*InFieldVectorRight)[Idx];
}
}
}
else
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
if (!FMath::IsNearlyZero((*InFieldVectorLeft)[Idx].X) &&
!FMath::IsNearlyZero((*InFieldVectorLeft)[Idx].Y) &&
!FMath::IsNearlyZero((*InFieldVectorLeft)[Idx].Z))
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorRight)[Idx] / (*InFieldVectorLeft)[Idx];
}
}
}
break;
case EDataflowVectorFieldOperationType::Dataflow_VectorFieldFalloffType_Add:
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorLeft)[Idx] + (*InFieldVectorRight)[Idx];
}
break;
case EDataflowVectorFieldOperationType::Dataflow_VectorFieldFalloffType_Substract:
if (!bSwapVectorInputs)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorLeft)[Idx] - (*InFieldVectorRight)[Idx];
}
}
else
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorRight)[Idx] - (*InFieldVectorLeft)[Idx];
}
}
break;
case EDataflowVectorFieldOperationType::Dataflow_VectorFieldFalloffType_CrossProduct:
if (!bSwapVectorInputs)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorLeft)[Idx] ^ (*InFieldVectorRight)[Idx];
}
}
else
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorRight)[Idx] ^ (*InFieldVectorLeft)[Idx];
}
}
break;
}
}
else if (InFieldVectorLeft != nullptr)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorLeft)[Idx];
}
}
else if (InFieldVectorRight != nullptr)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] = (*InFieldVectorRight)[Idx];
}
}
if (InFieldFloat != nullptr)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] *= (*InFieldFloat)[Idx];
}
}
if (InMagnitude != 1.0)
{
for (int32 Idx = 0; Idx < InNumSamplePositions; ++Idx)
{
OutNewFieldVectorResult[Idx] *= InMagnitude;
}
}
}
void FSumVectorFieldDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<FVector>>(&FieldVectorResult) ||
Out->IsA<TArray<int32>>(&FieldRemap))
{
const TArray<float>& InFieldFloat = GetValue<TArray<float>>(Context, &FieldFloat);
const TArray<int32>& InFieldFloatRemap = GetValue<TArray<int32>>(Context, &FieldFloatRemap);
const TArray<FVector>& InFieldVectorLeft = GetValue<TArray<FVector>>(Context, &FieldVectorLeft);
const TArray<int32>& InFieldRemapLeft = GetValue<TArray<int32>>(Context, &FieldRemapLeft);
const TArray<FVector>& InFieldVectorRight = GetValue<TArray<FVector>>(Context, &FieldVectorRight);
const TArray<int32>& InFieldRemapRight = GetValue<TArray<int32>>(Context, &FieldRemapRight);
const int32 NumFieldFloat = InFieldFloat.Num();
const int32 NumFieldFloatRemap = InFieldFloatRemap.Num();
const int32 NumFieldVectorLeft = InFieldVectorLeft.Num();
const int32 NumFieldRemapLeft = InFieldRemapLeft.Num();
const int32 NumFieldVectorRight = InFieldVectorRight.Num();
const int32 NumFieldRemapRight = InFieldRemapRight.Num();
const bool IsFieldFloatConnected = IsConnected<TArray<float>>(&FieldFloat);
const bool IsFieldFloatRemapConnected = IsConnected<TArray<int32>>(&FieldFloatRemap);
const bool IsFieldVectorLeftConnected = IsConnected<TArray<FVector>>(&FieldVectorLeft);
const bool IsFieldRemapLeftConnected = IsConnected<TArray<int32>>(&FieldRemapLeft);
const bool IsFieldVectorRightConnected = IsConnected<TArray<FVector>>(&FieldVectorRight);
const bool IsFieldRemapRightConnected = IsConnected<TArray<int32>>(&FieldRemapRight);
TArray<FVector> NewFieldVectorResult;
if (IsFieldFloatConnected && IsFieldVectorLeftConnected && !IsFieldVectorRightConnected)
{
// Both Remap inputs are connected but they can be different sizes
// Process the two array inputs and generate a new output remap
if (IsFieldFloatRemapConnected && IsFieldRemapLeftConnected)
{
if (NumFieldFloat == NumFieldFloatRemap &&
NumFieldVectorLeft == NumFieldRemapLeft)
{
int32 NewArraySize = FMath::Max(NumFieldFloat, NumFieldVectorLeft);
NewFieldVectorResult.Init(FVector(0.f), NewArraySize);
TArray<int32> NewRemapArray;
NewRemapArray.Init(false, NewArraySize);
TArray<float> NewFloatArray;
TArray<FVector> NewVectorArrayLeft;
NewFloatArray.Init(false, NewArraySize);
NewVectorArrayLeft.Init(FVector(0.f), NewArraySize);
int32 NewSampleCount = 0;
for (int32 IndexLeft = 0; IndexLeft < NumFieldFloat; ++IndexLeft)
{
int32 SampleIndex = InFieldFloatRemap[IndexLeft];
if (InFieldRemapLeft.Contains(SampleIndex))
{
int32 IndexRight = InFieldRemapLeft.Find(SampleIndex);
NewRemapArray[NewSampleCount] = SampleIndex;
NewFloatArray[NewSampleCount] = InFieldFloat[IndexLeft];
NewVectorArrayLeft[NewSampleCount] = InFieldVectorLeft[IndexRight];
NewSampleCount++;
}
}
NewRemapArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFloatArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewVectorArrayLeft.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFieldVectorResult.SetNum(NewSampleCount, EAllowShrinking::Yes);
SumVectorEvaluate(&NewFloatArray,
&NewVectorArrayLeft,
nullptr,
NewFieldVectorResult,
NewSampleCount,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
return;
}
}
// At least one of the Remap inputs are not connected
// There is no remap information, just process the two FloatArray inputs
// but they have to be the same size
else
{
if (NumFieldFloat == NumFieldVectorLeft)
{
const int32 NumSamplePositions = NumFieldFloat;
NewFieldVectorResult.Init(FVector(0.f), NumSamplePositions);
SumVectorEvaluate(&InFieldFloat,
&InFieldVectorLeft,
nullptr,
NewFieldVectorResult,
NumSamplePositions,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
return;
}
}
}
else if (IsFieldFloatConnected && !IsFieldVectorLeftConnected && IsFieldVectorRightConnected)
{
// Both Remap inputs are connected but they can be different sizes
// Process the two array inputs and generate a new output remap
if (IsFieldFloatRemapConnected && IsFieldRemapRightConnected)
{
if (NumFieldFloat == NumFieldFloatRemap &&
NumFieldVectorRight == NumFieldRemapRight)
{
int32 NewArraySize = FMath::Max(NumFieldFloat, NumFieldVectorRight);
NewFieldVectorResult.Init(FVector(0.f), NewArraySize);
TArray<int32> NewRemapArray;
NewRemapArray.Init(false, NewArraySize);
TArray<float> NewFloatArray;
TArray<FVector> NewVectorArrayRight;
NewFloatArray.Init(false, NewArraySize);
NewVectorArrayRight.Init(FVector(0.f), NewArraySize);
int32 NewSampleCount = 0;
for (int32 IndexLeft = 0; IndexLeft < NumFieldFloat; ++IndexLeft)
{
int32 SampleIndex = InFieldFloatRemap[IndexLeft];
if (InFieldRemapRight.Contains(SampleIndex))
{
int32 IndexRight = InFieldRemapRight.Find(SampleIndex);
NewRemapArray[NewSampleCount] = SampleIndex;
NewFloatArray[NewSampleCount] = InFieldFloat[IndexLeft];
NewVectorArrayRight[NewSampleCount] = InFieldVectorRight[IndexRight];
NewSampleCount++;
}
}
NewRemapArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFloatArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewVectorArrayRight.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFieldVectorResult.SetNum(NewSampleCount, EAllowShrinking::Yes);
SumVectorEvaluate(&NewFloatArray,
nullptr,
&NewVectorArrayRight,
NewFieldVectorResult,
NewSampleCount,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
return;
}
}
// At least one of the Remap inputs are not connected
// There is no remap information, just process the two FloatArray inputs
// but they have to be the same size
else
{
if (NumFieldFloat == NumFieldVectorRight)
{
const int32 NumSamplePositions = NumFieldFloat;
NewFieldVectorResult.Init(FVector(0.f), NumSamplePositions);
SumVectorEvaluate(&InFieldFloat,
nullptr,
&InFieldVectorRight,
NewFieldVectorResult,
NumSamplePositions,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
return;
}
}
}
else if (!IsFieldFloatConnected && IsFieldVectorLeftConnected && IsFieldVectorRightConnected)
{
// Both Remap inputs are connected but they can be different sizes
// Process the two array inputs and generate a new output remap
if (IsFieldRemapLeftConnected && IsFieldRemapRightConnected)
{
if (NumFieldVectorLeft == NumFieldRemapLeft &&
NumFieldVectorRight == NumFieldRemapRight)
{
int32 NewArraySize = FMath::Max(NumFieldVectorLeft, NumFieldVectorRight);
NewFieldVectorResult.Init(FVector(0.f), NewArraySize);
TArray<int32> NewRemapArray;
NewRemapArray.Init(false, NewArraySize);
TArray<FVector> NewVectorArrayLeft, NewVectorArrayRight;
NewVectorArrayLeft.Init(FVector(0.f), NewArraySize);
NewVectorArrayLeft.Init(FVector(0.f), NewArraySize);
int32 NewSampleCount = 0;
for (int32 IndexLeft = 0; IndexLeft < NumFieldVectorLeft; ++IndexLeft)
{
int32 SampleIndex = InFieldRemapLeft[IndexLeft];
if (InFieldRemapRight.Contains(SampleIndex))
{
int32 IndexRight = InFieldRemapRight.Find(SampleIndex);
NewRemapArray[NewSampleCount] = SampleIndex;
NewVectorArrayLeft[NewSampleCount] = InFieldVectorLeft[IndexLeft];
NewVectorArrayRight[NewSampleCount] = InFieldVectorRight[IndexRight];
NewSampleCount++;
}
}
NewRemapArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewVectorArrayLeft.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewVectorArrayRight.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFieldVectorResult.SetNum(NewSampleCount, EAllowShrinking::Yes);
SumVectorEvaluate(nullptr,
&NewVectorArrayLeft,
&NewVectorArrayRight,
NewFieldVectorResult,
NewSampleCount,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
return;
}
}
// At least one of the Remap inputs are not connected
// There is no remap information, just process the two FloatArray inputs
// but they have to be the same size
else
{
if (NumFieldVectorLeft == NumFieldVectorRight)
{
const int32 NumSamplePositions = NumFieldVectorLeft;
NewFieldVectorResult.Init(FVector(0.f), NumSamplePositions);
SumVectorEvaluate(nullptr,
&InFieldVectorLeft,
&InFieldVectorRight,
NewFieldVectorResult,
NumSamplePositions,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
return;
}
}
}
else if (IsFieldFloatConnected && IsFieldVectorLeftConnected && IsFieldVectorRightConnected)
{
// All 3 Remap inputs are connected but they can be different sizes
// Process the 3 array inputs and generate a new output remap
if (IsFieldFloatRemapConnected && IsFieldRemapLeftConnected && IsFieldRemapRightConnected)
{
if (NumFieldFloat == NumFieldFloatRemap &&
NumFieldVectorLeft == NumFieldRemapLeft &&
NumFieldVectorRight == NumFieldRemapRight)
{
int32 NewArraySize = FMath::Max3(NumFieldFloat, NumFieldVectorLeft, NumFieldVectorRight);
NewFieldVectorResult.Init(FVector(0.f), NewArraySize);
TArray<int32> NewRemapArray;
NewRemapArray.Init(false, NewArraySize);
TArray<float> NewFloatArray;
TArray<FVector> NewVectorArrayLeft, NewVectorArrayRight;
NewFloatArray.Init(false, NewArraySize);
NewVectorArrayLeft.Init(FVector(0.f), NewArraySize);
NewVectorArrayRight.Init(FVector(0.f), NewArraySize);
int32 NewSampleCount = 0;
for (int32 IndexLeft = 0; IndexLeft < NumFieldFloat; ++IndexLeft)
{
int32 SampleIndex = InFieldFloatRemap[IndexLeft];
if (InFieldRemapLeft.Contains(SampleIndex) &&
InFieldRemapRight.Contains(SampleIndex))
{
int32 IndexRight1 = InFieldRemapLeft.Find(SampleIndex);
int32 IndexRight2 = InFieldRemapRight.Find(SampleIndex);
NewRemapArray[NewSampleCount] = SampleIndex;
NewFloatArray[NewSampleCount] = InFieldFloat[IndexLeft];
NewVectorArrayLeft[NewSampleCount] = InFieldVectorLeft[IndexRight1];
NewVectorArrayRight[NewSampleCount] = InFieldVectorRight[IndexRight2];
NewSampleCount++;
}
}
NewRemapArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFloatArray.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewVectorArrayLeft.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewVectorArrayRight.SetNum(NewSampleCount, EAllowShrinking::Yes);
NewFieldVectorResult.SetNum(NewSampleCount, EAllowShrinking::Yes);
SumVectorEvaluate(&NewFloatArray,
&NewVectorArrayLeft,
&NewVectorArrayRight,
NewFieldVectorResult,
NewSampleCount,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, MoveTemp(NewRemapArray), &FieldRemap);
return;
}
}
// At least one of the Remap inputs are not connected
// There is no remap information, just process the two FloatArray inputs
// but they have to be the same size
else
{
if (NumFieldFloat == NumFieldVectorLeft &&
NumFieldFloat == NumFieldVectorRight)
{
const int32 NumSamplePositions = NumFieldFloat;
NewFieldVectorResult.Init(FVector(0.f), NumSamplePositions);
SumVectorEvaluate(&InFieldFloat,
&InFieldVectorLeft,
&InFieldVectorRight,
NewFieldVectorResult,
NumSamplePositions,
Operation,
Magnitude,
bSwapVectorInputs);
SetValue<TArray<FVector>>(Context, MoveTemp(NewFieldVectorResult), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
return;
}
}
}
SetValue<TArray<FVector>>(Context, TArray<FVector>(), &FieldVectorResult);
SetValue<TArray<int32>>(Context, TArray<int32>(), &FieldRemap);
}
}
// ----------------------------------------------------------------------------
void FFieldMakeDenseFloatArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<float>>(&FieldFloatResult))
{
const TArray<float>& InFieldFloatInput = GetValue<TArray<float>>(Context, &FieldFloatInput);
const TArray<int32>& InFieldRemap = GetValue<TArray<int32>>(Context, &FieldRemap);
const int32 InNumSamplePositions = GetValue<int32>(Context, &NumSamplePositions);
if (InFieldFloatInput.Num() == InFieldRemap.Num() && InNumSamplePositions > 0)
{
TArray<float> NewFieldFloatOutput;
NewFieldFloatOutput.Init(Default, InNumSamplePositions);
for (int32 Idx = 0; Idx < InFieldRemap.Num(); ++Idx)
{
int32 RemapIdx = InFieldRemap[Idx];
if (RemapIdx < InNumSamplePositions)
{
NewFieldFloatOutput[InFieldRemap[Idx]] = InFieldFloatInput[Idx];
}
}
SetValue<TArray<float>>(Context, MoveTemp(NewFieldFloatOutput), &FieldFloatResult);
return;
}
SetValue<TArray<float>>(Context, TArray<float>(), &FieldFloatResult);
}
}