Files
UnrealEngine/Engine/Plugins/Experimental/ChaosFlesh/Source/ChaosFleshDeprecatedNodes/Private/Dataflow/ChaosFleshKinematicTetrahedralConstraintNode.cpp
2025-05-18 13:04:45 +08:00

123 lines
5.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Dataflow/ChaosFleshKinematicTetrahedralConstraintNode.h"
#include "ChaosFlesh/TetrahedralCollection.h"
#include "Engine/SkeletalMesh.h"
#include "GeometryCollection/Facades/CollectionKinematicBindingFacade.h"
#include "GeometryCollection/Facades/CollectionVertexBoneWeightsFacade.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(ChaosFleshKinematicTetrahedralConstraintNode)
void FKinematicTetrahedralBindingsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<DataType>(&Collection))
{
DataType InCollection = GetValue<DataType>(Context, &Collection);
TManagedArray<FIntVector4>* Tetrahedron = InCollection.FindAttribute<FIntVector4>(FTetrahedralCollection::TetrahedronAttribute, FTetrahedralCollection::TetrahedralGroup);
TManagedArray<FVector3f>* Vertex = InCollection.FindAttribute<FVector3f>("Vertex", "Vertices");
TObjectPtr<USkeletalMesh> SkeletalMesh = GetValue<TObjectPtr<USkeletalMesh>>(Context, &SkeletalMeshIn);
if (SkeletalMesh && Tetrahedron && Vertex)
{
//parse exclusion list to find bones to skip
TArray<FString> StrArray;
ExclusionList.ParseIntoArray(StrArray, *FString(" "));
int32 NumTets = Tetrahedron->Num();
TArray<FTransform> ComponentPose;
UE::Dataflow::Animation::GlobalTransforms(SkeletalMesh->GetRefSkeleton(), ComponentPose);
TArray<bool> VertAdded;
VertAdded.Init(false, Vertex->Num());
auto DoSkipBoneIndex = [&StrArray, &SkeletalMesh](int32 BoneIndex)
{
bool Skip = false;
FString BoneName = SkeletalMesh->GetRefSkeleton().GetBoneName(BoneIndex).ToString();
for (FString Elem : StrArray)
{
if (BoneName.Contains(Elem))
{
Skip = true;
break;
}
}
return Skip;
};
for (int32 b = 0; b < SkeletalMesh->GetRefSkeleton().GetNum(); ++b)
{
FVector3f BonePosition(ComponentPose[b].GetTranslation());
int32 ParentIndex=SkeletalMesh->GetRefSkeleton().GetParentIndex(b);
if (!(ParentIndex == INDEX_NONE || DoSkipBoneIndex(b) || DoSkipBoneIndex(ParentIndex)))
{
FVector3f ParentPosition(ComponentPose[ParentIndex].GetTranslation());
FVector3f RayDir = ParentPosition - BonePosition;
Chaos::FReal Length = RayDir.Length();
RayDir.Normalize();
if (Length > Chaos::FReal(1e-8))
{
TSet<int32> BoneVertSet;
for (int32 t = 0; t < NumTets; t++)
{
int32 i = (*Tetrahedron)[t][0];
int32 j = (*Tetrahedron)[t][1];
int32 k = (*Tetrahedron)[t][2];
int32 l = (*Tetrahedron)[t][3];
TArray<Chaos::TVec3<Chaos::FRealSingle>> InVertices;
InVertices.SetNum(4);
InVertices[0][0] = (*Vertex)[i].X; InVertices[0][1] = (*Vertex)[i].Y; InVertices[0][2] = (*Vertex)[i].Z;
InVertices[1][0] = (*Vertex)[j].X; InVertices[1][1] = (*Vertex)[j].Y; InVertices[1][2] = (*Vertex)[j].Z;
InVertices[2][0] = (*Vertex)[k].X; InVertices[2][1] = (*Vertex)[k].Y; InVertices[2][2] = (*Vertex)[k].Z;
InVertices[3][0] = (*Vertex)[l].X; InVertices[3][1] = (*Vertex)[l].Y; InVertices[3][2] = (*Vertex)[l].Z;
Chaos::FConvex ConvexTet(InVertices, Chaos::FReal(0));
Chaos::FReal OutTime;
Chaos::FVec3 OutPosition, OutNormal;
int32 OutFaceIndex;
bool KeepTet = ConvexTet.Raycast(BonePosition, RayDir, Length, Chaos::FReal(0), OutTime, OutPosition, OutNormal, OutFaceIndex);
if (KeepTet)
{
for (int32 c = 0; c < 4; ++c)
{
if (!VertAdded[(*Tetrahedron)[t][c]])
{
VertAdded[(*Tetrahedron)[t][c]] = true;
BoneVertSet.Add((*Tetrahedron)[t][c]);
}
}
}
}
TArray<int32> BoundVerts = BoneVertSet.Array();
TArray<float> BoundWeights;
BoundWeights.Init(float(1), BoundVerts.Num());
if (BoundVerts.Num())
{
//get local coords of bound verts
typedef GeometryCollection::Facades::FKinematicBindingFacade FKinematics;
FKinematics Kinematics(InCollection); Kinematics.DefineSchema();
if (Kinematics.IsValid())
{
FKinematics::FBindingKey Binding = Kinematics.SetBoneBindings(ParentIndex, BoundVerts, BoundWeights);
TManagedArray<TArray<FVector3f>>& LocalPos = InCollection.AddAttribute<TArray<FVector3f>>("LocalPosition", Binding.GroupName);
Kinematics.AddKinematicBinding(Binding);
auto DoubleVert = [](FVector3f V) { return FVector3d(V.X, V.Y, V.Z); };
auto FloatVert = [](FVector3d V) { return FVector3f(V.X, V.Y, V.Z); };
LocalPos[Binding.Index].SetNum(BoundVerts.Num());
for (int32 i = 0; i < BoundVerts.Num(); i++)
{
FVector3f Temp = (*Vertex)[BoundVerts[i]];
LocalPos[Binding.Index][i] = FloatVert(ComponentPose[ParentIndex].InverseTransformPosition(DoubleVert(Temp)));
}
}
}
}
}
}
GeometryCollection::Facades::FVertexBoneWeightsFacade(InCollection).AddBoneWeightsFromKinematicBindings();
}
SetValue(Context, MoveTemp(InCollection), &Collection);
}
}