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

497 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Dataflow/GeometryCollectionTransferVertexScalarAttributeDepNode.h"
#include "Chaos/Triangle.h"
#include "Chaos/TriangleMesh.h"
#include "Chaos/HierarchicalSpatialHash.h"
#include "Chaos/TriangleCollisionPoint.h"
#include "Dataflow/DataflowInputOutput.h"
#include "GeometryCollection/GeometryCollectionAlgo.h"
#include "GeometryCollection/ManagedArrayAccessor.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionTransferVertexScalarAttributeDepNode)
#define LOCTEXT_NAMESPACE "FGeometryCollectionTransferVertexScalarAttributeDepNode"
namespace UE::Private {
class FTransferFacade
{
const FManagedArrayCollection& ConstCollection;
FManagedArrayCollection* Collection = nullptr;
public:
FTransferFacade(FManagedArrayCollection& InCollection)
: ConstCollection(InCollection)
, Collection(&InCollection)
, BoneMap(InCollection, FName("BoneMap"), FName("Vertices"))
, Vertex(InCollection, FName("Vertex"), FName("Vertices"))
, Indices(InCollection, FName("Indices"), FName("Faces"))
, Transform(InCollection, FTransformCollection::TransformAttribute, FTransformCollection::TransformGroup)
, Parent(InCollection, FTransformCollection::ParentAttribute, FTransformCollection::TransformGroup)
, VertexStart(InCollection, "VertexStart", FGeometryCollection::GeometryGroup)
, VertexCount(InCollection, "VertexCount", FGeometryCollection::GeometryGroup)
, FaceStart(InCollection, "FaceStart", FGeometryCollection::GeometryGroup)
, FaceCount(InCollection, "FaceCount", FGeometryCollection::GeometryGroup)
{}
FTransferFacade(const FManagedArrayCollection& InCollection)
: ConstCollection(InCollection)
, Collection(nullptr)
, BoneMap(InCollection, FName("BoneMap"), FName("Vertices"))
, Vertex(InCollection, FName("Vertex"), FName("Vertices"))
, Indices(InCollection, FName("Indices"), FName("Faces"))
, Transform(InCollection, FTransformCollection::TransformAttribute, FTransformCollection::TransformGroup)
, Parent(InCollection, FTransformCollection::ParentAttribute, FTransformCollection::TransformGroup)
, VertexStart(InCollection, "VertexStart", FGeometryCollection::GeometryGroup)
, VertexCount(InCollection, "VertexCount", FGeometryCollection::GeometryGroup)
, FaceStart(InCollection, "FaceStart", FGeometryCollection::GeometryGroup)
, FaceCount(InCollection, "FaceCount", FGeometryCollection::GeometryGroup)
{}
bool IsValid() const {
return BoneMap.IsValid() && Vertex.IsValid() && Indices.IsValid() && Transform.IsValid() && Parent.IsValid() && VertexStart.IsValid() &&
VertexCount.IsValid() && FaceStart.IsValid() && FaceCount.IsValid();
}
const TManagedArray<float>* GetFloatArray(FString AttributeName, FString Group) const
{
return ConstCollection.FindAttribute<float>(FName(AttributeName), FName(Group));
}
TManagedArray<float>* GetFloatArray(FString AttributeName, FString Group)
{
TManagedArray<float>* TargetFloatArray = nullptr;
if (!Collection->HasAttribute(FName(AttributeName), FName(Group)))
{
Collection->AddAttribute<float>(FName(AttributeName), FName(Group));
}
return Collection->FindAttribute<float>(FName(AttributeName), FName(Group));
}
TManagedArrayAccessor<int32> BoneMap;
TManagedArrayAccessor<FVector3f> Vertex;
TManagedArrayAccessor<FIntVector3> Indices;
TManagedArrayAccessor<FTransform3f> Transform;
TManagedArrayAccessor<int32> Parent;
TManagedArrayAccessor<int32> VertexStart;
TManagedArrayAccessor<int32> VertexCount;
TManagedArrayAccessor<int32> FaceStart;
TManagedArrayAccessor<int32> FaceCount;
};
}
void FGeometryCollectionTransferVertexScalarAttributeNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
typedef TPair<FName, FName> NamePair;
FCollectionAttributeKey Key = GetValue(Context, &AttributeKey, AttributeKey);
if (Out->IsA(&Collection))
{
FManagedArrayCollection TargetCollection = GetValue(Context, &Collection);
const FManagedArrayCollection& SampleCollection = GetValue(Context, &FromCollection);
UE::Private::FTransferFacade Target(TargetCollection);
const UE::Private::FTransferFacade Sample(SampleCollection);
if (Target.IsValid() && Sample.IsValid())
{
if (TManagedArray<float>* TargetFloatArray = Target.GetFloatArray(Key.Attribute, Key.Group))
{
TargetFloatArray->Fill(0.f);
TArray<FIntVector2> AlignedGeometry = FindSourceToTargetGeometryMap(SampleCollection, TargetCollection);
if (AlignedGeometry.Num() == TargetCollection.NumElements(FGeometryCollection::GeometryGroup))
{
PairedGeometryTransfer(Key, AlignedGeometry, Sample, Target, TargetFloatArray);
}
else
{
NearestVertexTransfer(Key, Sample, Target, TargetFloatArray);
}
}
}
SetValue(Context, MoveTemp(TargetCollection), &Collection);
}
else if (Out->IsA(&AttributeKey))
{
SetValue(Context, MoveTemp(Key), &AttributeKey);
}
}
TArray<FIntVector2> FGeometryCollectionTransferVertexScalarAttributeNode::FindSourceToTargetGeometryMap(const FManagedArrayCollection& AttributeCollectionVal, const FManagedArrayCollection& CollectionVal) const
{
TArray<FIntVector2> Mapping;
const TManagedArray<FString>* SourceName = AttributeCollectionVal.FindAttribute<FString>(FName("BoneName"), FTransformCollection::TransformGroup);
const TManagedArray<int32>* SourceGeometryGroup = AttributeCollectionVal.FindAttribute<int32>(FName("TransformToGeometryIndex"), FTransformCollection::TransformGroup);
const TManagedArray<FString>* TargetName = CollectionVal.FindAttribute<FString>(FName("BoneName"), FTransformCollection::TransformGroup);
const TManagedArray<int32>* TargetGeometryGroup = CollectionVal.FindAttribute<int32>(FName("TransformToGeometryIndex"), FTransformCollection::TransformGroup);
if (SourceName && SourceGeometryGroup && TargetName && TargetGeometryGroup)
{
for (int i = 0; i < SourceName->Num(); i++)
{
for (int j = 0; j < TargetName->Num(); j++)
{
FString TestName = FString::Printf(TEXT("%s_Tet"), *(*SourceName)[i]);
if ((*TargetName)[j].StartsWith(TestName))
{
Mapping.Add(FIntVector2((*SourceGeometryGroup)[i], (*TargetGeometryGroup)[j]));
break;
}
}
}
}
return Mapping;
}
void FGeometryCollectionTransferVertexScalarAttributeNode::PairedGeometryTransfer(FCollectionAttributeKey Key, const TArray<FIntVector2>& PairedGeometry,
const UE::Private::FTransferFacade& Sample, UE::Private::FTransferFacade& Target, TManagedArray<float>* TargetFloatArray) const
{
if (const TManagedArray<float>* FloatArray = Sample.GetFloatArray(Key.Attribute, Key.Group))
{
Chaos::FReal SphereFullRadius;
if (SampleScale == EDataflowTransferNodeSampleScale::Dataflow_Transfer_Asset_Edge || SampleScale == EDataflowTransferNodeSampleScale::Dataflow_Transfer_Asset_Bound)
{
// Build component space vertices for TargetCollection
TArray<FVector> ComponentSpaceFullTargetVertices; // size of num vertices of the geometry entry.
BuildComponentSpaceVertices(&Target.Transform.Get(), &Target.Parent.Get(), &Target.BoneMap.Get(), &Target.Vertex.Get(),
0, Target.Vertex.Num(), ComponentSpaceFullTargetVertices);
// Build component space vertices for TargetCollection
TArray<FVector> ComponentSpaceFullVertices; // size of num vertices of the geometry entry
BuildComponentSpaceVertices(&Sample.Transform.Get(), &Sample.Parent.Get(), &Sample.BoneMap.Get(), &Sample.Vertex.Get(),
0, Sample.Vertex.Num(), ComponentSpaceFullVertices);
if (SampleScale == EDataflowTransferNodeSampleScale::Dataflow_Transfer_Asset_Edge)
{
SphereFullRadius = Chaos::FReal(EdgeMultiplier * FMath::Max(
MaxEdgeLength(ComponentSpaceFullTargetVertices, Target.Indices.Get(), 0, 0, Target.Indices.Num()),
MaxEdgeLength(ComponentSpaceFullVertices, Sample.Indices.Get(), 0, 0, Sample.Indices.Num())));
}
else if (SampleScale == EDataflowTransferNodeSampleScale::Dataflow_Transfer_Asset_Bound)
{
Chaos::TVec3<float> CoordMaxs(-FLT_MAX);
Chaos::TVec3<float> CoordMins(FLT_MAX);
for (int32 i = 0; i < ComponentSpaceFullVertices.Num(); i++)
{
for (int32 j = 0; j < 3; j++)
{
if (ComponentSpaceFullVertices[i][j] > CoordMaxs[j])
{
CoordMaxs[j] = ComponentSpaceFullVertices[i][j];
}
if (ComponentSpaceFullVertices[i][j] < CoordMins[j])
{
CoordMins[j] = ComponentSpaceFullVertices[i][j];
}
}
}
Chaos::TVec3<float> CoordDiff = (CoordMaxs - CoordMins) * BoundMultiplier;
SphereFullRadius = Chaos::FReal(FGenericPlatformMath::Min(CoordDiff[0], FGenericPlatformMath::Min(CoordDiff[1], CoordDiff[2])));
}
}
ParallelFor(PairedGeometry.Num(), [&](int32 Pdx)
{
int32 AttributeGeometryIndex = PairedGeometry[Pdx][0];
int32 TargetGeometryIndex = PairedGeometry[Pdx][1];
if (ensure(0 <= AttributeGeometryIndex && AttributeGeometryIndex < Sample.VertexStart.Num()))
{
if (ensure(0 <= TargetGeometryIndex && TargetGeometryIndex < Target.VertexStart.Num()))
{
// Build component space vertices for TargetCollection
TArray<FVector> ComponentSpaceTargetVertices; // size of num vertices of the geometry entry.
BuildComponentSpaceVertices(&Target.Transform.Get(), &Target.Parent.Get(), &Target.BoneMap.Get(), &Target.Vertex.Get(),
Target.VertexStart[TargetGeometryIndex], Target.VertexCount[TargetGeometryIndex], ComponentSpaceTargetVertices);
// Build component space vertices for SampleCollection
TArray<FVector> ComponentSpaceVertices; // size of num vertices of the geometry entry
BuildComponentSpaceVertices(&Sample.Transform.Get(), &Sample.Parent.Get(), &Sample.BoneMap.Get(), &Sample.Vertex.Get(),
Sample.VertexStart[AttributeGeometryIndex], Sample.VertexCount[AttributeGeometryIndex], ComponentSpaceVertices);
// build Sphere based BVH
Chaos::FReal SphereRadius = SphereFullRadius;
if (SampleScale == EDataflowTransferNodeSampleScale::Dataflow_Transfer_Component_Edge)
{
SphereRadius = Chaos::FReal(EdgeMultiplier * FMath::Max(
MaxEdgeLength(ComponentSpaceTargetVertices, Target.Indices.Get(), Target.VertexStart[TargetGeometryIndex], Target.FaceStart[TargetGeometryIndex], Target.FaceCount[TargetGeometryIndex]),
MaxEdgeLength(ComponentSpaceVertices, Sample.Indices.Get(), Sample.VertexStart[AttributeGeometryIndex], Sample.FaceStart[AttributeGeometryIndex], Sample.FaceCount[AttributeGeometryIndex])));
}
int32 TargetVertexStartVal = Target.VertexStart[TargetGeometryIndex];
int32 TargetVertexCountVal = Target.VertexCount[TargetGeometryIndex];
int32 VertexStartVal = Sample.VertexStart[AttributeGeometryIndex];
int32 FaceStartVal = Sample.FaceStart[AttributeGeometryIndex];
int32 FaceCountVal = Sample.FaceCount[AttributeGeometryIndex];
if (BoundingVolumeType == EDataflowTransferNodeBoundingVolume::Dataflow_Transfer_Triangle)
{
TArray<Chaos::TVec3<Chaos::FReal>> ComponentSpaceVerticesTVec3;
ComponentSpaceVerticesTVec3.SetNum(ComponentSpaceVertices.Num());
for (int32 SourceIndex = 0; SourceIndex < ComponentSpaceVerticesTVec3.Num(); SourceIndex++)
{
ComponentSpaceVerticesTVec3[SourceIndex] = Chaos::TVec3<Chaos::FReal>(ComponentSpaceVertices[SourceIndex]);
}
TConstArrayView<Chaos::TVec3<Chaos::FReal>> ConstComponentSpaceVertices(ComponentSpaceVerticesTVec3);
Chaos::FTriangleMesh TriangleMesh;
TArray<Chaos::TVec3<int32>> SourceElements;
SourceElements.SetNum(FaceCountVal);
for (int32 ElementIndex = 0; ElementIndex < FaceCountVal; ++ElementIndex)
{
FIntVector3 Element = Sample.Indices[FaceStartVal + ElementIndex];
SourceElements[ElementIndex] = Chaos::TVec3<int32>(Element[0]-VertexStartVal, Element[1]-VertexStartVal, Element[2]-VertexStartVal);
}
TriangleMesh.Init(SourceElements);
Chaos::FTriangleMesh::TSpatialHashType<Chaos::FReal> SpatialHash;
TriangleMesh.BuildSpatialHash(ConstComponentSpaceVertices, SpatialHash, SphereRadius);
for (int32 TargetIndex = 0; TargetIndex < TargetVertexCountVal; TargetIndex++)
{
TArray<Chaos::TTriangleCollisionPoint<Chaos::FReal>> Result;
if (TriangleMesh.PointClosestTriangleQuery(SpatialHash, ConstComponentSpaceVertices,
TargetIndex, Chaos::TVec3<Chaos::FReal>(ComponentSpaceTargetVertices[TargetIndex]), SphereRadius / 2.f, SphereRadius / 2.f,
[](const int32 PointIndex, const int32 TriangleIndex)->bool {return true; }, Result))
{
for (const Chaos::TTriangleCollisionPoint<Chaos::FReal>& CollisionPoint : Result)
{
Chaos::FRealSingle CurrentDistance = abs(CollisionPoint.Phi);
float TriRadius = FalloffThreshold * MaxEdgeLength(ComponentSpaceVertices, Sample.Indices.Get(), VertexStartVal, FaceStartVal+CollisionPoint.Indices[1], 1);
float FalloffScale = CalculateFalloffScale(Falloff, TriRadius, CurrentDistance);
if (!FMath::IsNearlyZero(FalloffScale))
{
int32 TargetCandidateIndex = CollisionPoint.Indices[0]+ TargetVertexStartVal;
if (ensure(0 <= TargetCandidateIndex && TargetCandidateIndex < TargetFloatArray->Num()))
{
float Value = 0.f;
for (int32 k = 0; k < 3; k++)
{
Value += FalloffScale * (CollisionPoint.Bary[k] * (*FloatArray)[Sample.Indices[FaceStartVal+CollisionPoint.Indices[1]][k]]);
}
(*TargetFloatArray)[TargetCandidateIndex] = FMath::Max((*TargetFloatArray)[TargetCandidateIndex], Value);
}
}
}
}
}
}
else if (BoundingVolumeType == EDataflowTransferNodeBoundingVolume::Dataflow_Transfer_Vertex)
{
TUniquePtr<UE::Private::BVH> VertexBVH(BuildParticleSphereBVH(ComponentSpaceTargetVertices, SphereRadius));
for (int32 i = 0; i < FaceCountVal; i++)
{
FIntVector3 ComponentTriangle = Sample.Indices[FaceStartVal + i] - FIntVector3(VertexStartVal);
if (TriangleHasWeightsToTransfer(Sample.Indices[FaceStartVal + i], *FloatArray))
{
TArray<int32> TargetVertexIntersection({});
TriangleToVertexIntersections(*VertexBVH, ComponentSpaceVertices, ComponentTriangle, TargetVertexIntersection);
for (int32 j = 0; j < TargetVertexIntersection.Num(); j++)
{
Chaos::TVector<float, 3> Bary,
TriPos0(ComponentSpaceVertices[ComponentTriangle[0]]),
TriPos1(ComponentSpaceVertices[ComponentTriangle[1]]),
TriPos2(ComponentSpaceVertices[ComponentTriangle[2]]),
ParticlePos(ComponentSpaceTargetVertices[TargetVertexIntersection[j]]);
Chaos::TVector<Chaos::FRealSingle, 3> ClosestPoint = Chaos::FindClosestPointAndBaryOnTriangle(TriPos0, TriPos1, TriPos2, ParticlePos, Bary);
Chaos::FRealSingle CurrentDistance = (ParticlePos - ClosestPoint).Size();
float TriRadius = FalloffThreshold * MaxEdgeLength(ComponentSpaceVertices, Sample.Indices.Get(), VertexStartVal, FaceStartVal+i, 1);
float FalloffScale = CalculateFalloffScale(Falloff, TriRadius, CurrentDistance);
if (!FMath::IsNearlyZero(FalloffScale))
{
int32 TargetIndex = TargetVertexIntersection[j] + TargetVertexStartVal;
if (ensure(0 <= TargetIndex && TargetIndex < TargetFloatArray->Num()))
{
float Value = 0.f;
for (int32 k = 0; k < 3; k++)
{
Value += FalloffScale * (Bary[k] * (*FloatArray)[ComponentTriangle[k] + VertexStartVal]);
}
(*TargetFloatArray)[TargetIndex] = FMath::Max((*TargetFloatArray)[TargetIndex], Value);
}
}
}
}
}
}
}
}
});
}
}
void FGeometryCollectionTransferVertexScalarAttributeNode::NearestVertexTransfer(FCollectionAttributeKey Key, const UE::Private::FTransferFacade& Sample, UE::Private::FTransferFacade& Target, TManagedArray<float>* TargetFloatArray) const
{
if (const TManagedArray<float>* FloatArray = Sample.GetFloatArray(Key.Attribute, Key.Group))
{
// Build component space vertices for TargetCollection
TArray<FVector> ComponentSpaceTargetVertices;
BuildComponentSpaceVertices(&Target.Transform.Get(), &Target.Parent.Get(), &Target.BoneMap.Get(), &Target.Vertex.Get(), 0, Target.Vertex.Num(), ComponentSpaceTargetVertices);
// Build component space vertices for SourceCollection
TArray<FVector> ComponentSpaceVertices;
BuildComponentSpaceVertices(&Sample.Transform.Get(), &Sample.Parent.Get(), &Sample.BoneMap.Get(), &Sample.Vertex.Get(), 0, Sample.Vertex.Num(), ComponentSpaceVertices);
// build Sphere based BVH
Chaos::FReal SphereRadius = Chaos::FReal(EdgeMultiplier * FMath::Max(
MaxEdgeLength(ComponentSpaceTargetVertices, Target.Indices.Get(), 0, 0, Target.Indices.Num()),
MaxEdgeLength(ComponentSpaceVertices, Sample.Indices.Get(), 0, 0, Sample.Indices.Num())));
TUniquePtr<UE::Private::BVH> VertexBVH(BuildParticleSphereBVH(ComponentSpaceTargetVertices, SphereRadius));
for (int32 i = 0; i < Sample.Indices.Num(); i++)
{
FIntVector3 Triangle = Sample.Indices[i];
if (TriangleHasWeightsToTransfer(Triangle, *FloatArray))
{
TArray<int32> TargetVertexIntersection({});
TriangleToVertexIntersections(*VertexBVH, ComponentSpaceVertices, Triangle, TargetVertexIntersection);
for (int32 j = 0; j < TargetVertexIntersection.Num(); j++)
{
Chaos::TVector<float, 3> Bary,
TriPos0(ComponentSpaceVertices[Sample.Indices[i][0]]),
TriPos1(ComponentSpaceVertices[Sample.Indices[i][1]]),
TriPos2(ComponentSpaceVertices[Sample.Indices[i][2]]),
ParticlePos(ComponentSpaceTargetVertices[TargetVertexIntersection[j]]);
Chaos::TVector<Chaos::FRealSingle, 3> ClosestPoint = Chaos::FindClosestPointAndBaryOnTriangle(TriPos0, TriPos1, TriPos2, ParticlePos, Bary);
Chaos::FRealSingle CurrentDistance = (ParticlePos - ClosestPoint).Size();
float TriRadius = FalloffThreshold * MaxEdgeLength(ComponentSpaceVertices, Sample.Indices.Get(), 0, i, 1);
float FalloffScale = CalculateFalloffScale(Falloff, TriRadius, CurrentDistance);
if (!FMath::IsNearlyZero(FalloffScale))
{
int32 TargetIndex = TargetVertexIntersection[j];
if (ensure(0 <= TargetIndex && TargetIndex < TargetFloatArray->Num()))
{
float Value = 0.f;
for (int32 k = 0; k < 3; k++)
{
Value += FalloffScale * (Bary[k] * (*FloatArray)[Sample.Indices[i][k]]);
}
(*TargetFloatArray)[TargetIndex] = FMath::Max((*TargetFloatArray)[TargetIndex], Value);
}
}
}
}
}
}
}
float FGeometryCollectionTransferVertexScalarAttributeNode::MaxEdgeLength(TArray<FVector>& Vert, const TManagedArray<FIntVector3>& Tri, int VertexOffset, int TriStart, int TriCount)
{
auto TriInRange = [](const FIntVector3& T, int Max) {
for (int k = 0; k < 3; k++)
{
if (ensure(0 <= T[k] && T[k] < Max))
{
return true;
}
}
return false;
};
float Max = 0;
int TriStop = TriStart + TriCount;
for (int i = TriStart; i < TriStop; i++)
{
if (TriInRange(Tri[i] - FIntVector3(VertexOffset), Vert.Num()))
{
Max = FMath::Max(Max, FVector3f(Vert[Tri[i][0] - VertexOffset] - Vert[Tri[i][1] - VertexOffset]).SquaredLength());
Max = FMath::Max(Max, FVector3f(Vert[Tri[i][0] - VertexOffset] - Vert[Tri[i][2] - VertexOffset]).SquaredLength());
Max = FMath::Max(Max, FVector3f(Vert[Tri[i][1] - VertexOffset] - Vert[Tri[i][2] - VertexOffset]).SquaredLength());
}
}
return FMath::Sqrt(Max);
}
void FGeometryCollectionTransferVertexScalarAttributeNode::BuildComponentSpaceVertices(const TManagedArray<FTransform3f>* LocalSpaceTransform, const TManagedArray<int32>* Parent, const TManagedArray<int32>* BoneMapArray,
const TManagedArray<FVector3f>* VertexArray, int32 Start, int32 Count, TArray<FVector>& ComponentSpaceVertices)
{
TArray<FTransform> ComponentTransform;
GeometryCollectionAlgo::GlobalMatrices(*LocalSpaceTransform, *Parent, ComponentTransform);
ComponentSpaceVertices.SetNumUninitialized(Count);
for (int i = 0; i < Count; i++)
{
int j = i + Start;
if (0 < (*BoneMapArray)[i] && (*BoneMapArray)[i] < ComponentTransform.Num())
{
ComponentSpaceVertices[i] = ComponentTransform[(*BoneMapArray)[j]].TransformPosition(FVector((*VertexArray)[j]));
}
else
{
ComponentSpaceVertices[i] = FVector((*VertexArray)[j]);
}
}
}
UE::Private::BVH* FGeometryCollectionTransferVertexScalarAttributeNode::BuildParticleSphereBVH(const TArray<FVector>& Vertices, float Radius)
{
TArray<Chaos::FSphere*> VertexSpherePtrs;
TArray<Chaos::FSphere> VertexSpheres;
VertexSpheres.Init(Chaos::FSphere(Chaos::TVec3<Chaos::FReal>(0), Radius), Vertices.Num());
VertexSpherePtrs.SetNum(Vertices.Num());
for (int32 i = 0; i < Vertices.Num(); i++)
{
Chaos::TVec3<Chaos::FReal> SphereCenter(Vertices[i]);
Chaos::FSphere VertexSphere(SphereCenter, Radius);
VertexSpheres[i] = Chaos::FSphere(SphereCenter, Radius);
VertexSpherePtrs[i] = &VertexSpheres[i];
}
return new UE::Private::BVH(VertexSpherePtrs);
}
bool FGeometryCollectionTransferVertexScalarAttributeNode::TriangleHasWeightsToTransfer(const FIntVector3& T, const TManagedArray<float>& F)
{
return !FMath::IsNearlyZero((F[T[0]] + F[T[1]] + F[T[2]]));
}
void FGeometryCollectionTransferVertexScalarAttributeNode::TriangleToVertexIntersections(
UE::Private::BVH& VertexBVH, const TArray<FVector>& ComponentSpaceVertices, const FIntVector3& Triangle, TArray<int32>& OutTargetVertexIntersection)
{
OutTargetVertexIntersection.Empty();
TArray<int32> TargetVertexIntersection0 = VertexBVH.FindAllIntersections(ComponentSpaceVertices[Triangle[0]]);
TArray<int32> TargetVertexIntersection1 = VertexBVH.FindAllIntersections(ComponentSpaceVertices[Triangle[1]]);
TArray<int32> TargetVertexIntersection2 = VertexBVH.FindAllIntersections(ComponentSpaceVertices[Triangle[2]]);
TargetVertexIntersection0.Sort();
TargetVertexIntersection1.Sort();
TargetVertexIntersection2.Sort();
for (int32 k = 0; k < TargetVertexIntersection0.Num(); k++)
{
if (TargetVertexIntersection1.Contains(TargetVertexIntersection0[k])
&& TargetVertexIntersection2.Contains(TargetVertexIntersection0[k]))
{
OutTargetVertexIntersection.Emplace(TargetVertexIntersection0[k]);
}
}
}
float FGeometryCollectionTransferVertexScalarAttributeNode::CalculateFalloffScale(EDataflowTransferNodeFalloff FalloffSetting, float Threshold, float Distance)
{
float Denominator = 1.0;
if (Distance > Threshold && !FMath::IsNearlyZero(Threshold))
{
Denominator = Distance / Threshold;
}
switch (FalloffSetting)
{
case EDataflowTransferNodeFalloff::Dataflow_Transfer_Linear:
return 1. / Denominator;
case EDataflowTransferNodeFalloff::Dataflow_Transfer_Squared:
return 1. / FMath::Square(Denominator);
}
return 1.0;
}
#undef LOCTEXT_NAMESPACE