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

840 lines
28 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Dataflow/GeometryCollectionMakeNodes.h"
#include "Dataflow/DataflowCore.h"
#if WITH_EDITOR
#include "Dataflow/DataflowRenderingViewMode.h"
#endif
#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 "Dataflow/DataflowDebugDraw.h"
#include "Dataflow/DataflowSimpleDebugDrawMesh.h"
#include "DynamicMesh/DynamicMesh3.h"
#include "Generators/SphereGenerator.h"
#include "Generators/BoxSphereGenerator.h"
#include "Generators/CapsuleGenerator.h"
#include "Generators/SweepGenerator.h"
#include "Generators/GridBoxMeshGenerator.h"
#include "Generators/DiscMeshGenerator.h"
#include "Generators/StairGenerator.h"
#include "Generators/RectangleMeshGenerator.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionMakeNodes)
namespace UE::Dataflow
{
void GeometryCollectionMakeNodes()
{
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralStringDataflowNode_v2);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakePointsDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeBoxDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeSphereDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralFloatDataflowNode_v2);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralDoubleDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralIntDataflowNode_v2);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralBoolDataflowNode_v2);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralVectorDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeQuaternionDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeFloatArrayDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeCollectionDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeRotatorDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBreakTransformDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralStringDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralFloatDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralIntDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeLiteralBoolDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeSphereMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeCapsuleMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeCylinderMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeBoxMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakePlaneDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeDiscMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeStairMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeRectangleMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeTorusMeshDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeTransformDataflowNode);
// Deprecated
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeTransformDataflowNode_v2);
}
}
void FMakeLiteralStringDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FString>(&String))
{
SetValue(Context, Value, &String);
}
}
void FMakeLiteralStringDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FString>(&String))
{
SetValue(Context, String, &String);
}
}
/*--------------------------------------------------------------------------------------------------------*/
#if WITH_EDITOR
bool FMakePointsDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
{
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
}
void FMakePointsDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
{
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
{
FVector Min(UE_BIG_NUMBER);
FVector Max(-UE_BIG_NUMBER);
// Compute (Min, Max) of BoundingBox
for (const FVector& Pt : Point)
{
Min = FVector::Min(Pt, Min);
Max = FVector::Max(Pt, Max);
}
DataflowRenderingInterface.SetLineWidth(1.0);
DataflowRenderingInterface.SetWireframe(true);
DataflowRenderingInterface.SetWorldPriority();
DataflowRenderingInterface.SetColor(FLinearColor::Gray);
DataflowRenderingInterface.DrawBox(0.5 * FVector(Max - Min), FQuat::Identity, 0.5 * FVector(Min + Max), 1.0);
}
}
#endif
void FMakePointsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<TArray<FVector>>(&Points))
{
SetValue(Context, Point, &Points);
}
}
/*--------------------------------------------------------------------------------------------------------*/
void FMakeBoxDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FBox>(&Box))
{
if (DataType == EMakeBoxDataTypeEnum::Dataflow_MakeBox_DataType_MinMax)
{
FVector MinVal = GetValue<FVector>(Context, &Min);
FVector MaxVal = GetValue<FVector>(Context, &Max);
SetValue(Context, FBox(MinVal, MaxVal), &Box);
}
else if (DataType == EMakeBoxDataTypeEnum::Dataflow_MakeBox_DataType_CenterSize)
{
FVector CenterVal = GetValue<FVector>(Context, &Center);
FVector SizeVal = GetValue<FVector>(Context, &Size);
SetValue(Context, FBox(CenterVal - 0.5 * SizeVal, CenterVal + 0.5 * SizeVal), &Box);
}
}
}
/*--------------------------------------------------------------------------------------------------------*/
void FMakeSphereDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FSphere>(&Sphere))
{
FVector CenterVal = GetValue<FVector>(Context, &Center);
float RadiusVal = GetValue<float>(Context, &Radius);
SetValue(Context, FSphere(CenterVal, RadiusVal), &Sphere);
}
}
#if WITH_EDITOR
bool FMakeSphereDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
{
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
}
void FMakeSphereDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
{
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
{
FVector Min = Center - FVector(Radius);
FVector Max = Center + FVector(Radius);
DataflowRenderingInterface.SetLineWidth(1.0);
DataflowRenderingInterface.SetWireframe(true);
DataflowRenderingInterface.SetWorldPriority();
DataflowRenderingInterface.SetColor(FLinearColor::Gray);
DataflowRenderingInterface.DrawBox(0.5 * FVector(Max - Min), FQuat::Identity, 0.5 * FVector(Min + Max), 1.0);
}
}
#endif
/*--------------------------------------------------------------------------------------------------------*/
void FMakeLiteralFloatDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<float>(&Float))
{
SetValue(Context, Value, &Float);
}
}
void FMakeLiteralFloatDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<float>(&Float))
{
SetValue(Context, Float, &Float);
}
}
//-----------------------------------------------------------------------------------------------
FMakeLiteralDoubleDataflowNode::FMakeLiteralDoubleDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Double);
}
void FMakeLiteralDoubleDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Double))
{
SetValue(Context, Double, &Double);
}
}
//-----------------------------------------------------------------------------------------------
void FMakeLiteralIntDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<int32>(&Int))
{
SetValue(Context, Value, &Int);
}
}
void FMakeLiteralIntDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<int32>(&Int))
{
SetValue(Context, Int, &Int);
}
}
void FMakeLiteralBoolDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<bool>(&Bool))
{
SetValue(Context, Value, &Bool);
}
}
void FMakeLiteralBoolDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<bool>(&Bool))
{
SetValue(Context, Bool, &Bool);
}
}
void FMakeLiteralVectorDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FVector>(&Vector))
{
const FVector Value(GetValue<float>(Context, &X, X), GetValue<float>(Context, &Y, Y), GetValue<float>(Context, &Z, Z));
SetValue(Context, Value, &Vector);
}
}
void FMakeTransformDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FTransform>(&OutTransform))
{
SetValue(Context,
FTransform(FQuat::MakeFromEuler(GetValue<FVector>(Context, &InRotation))
, GetValue<FVector>(Context, &InTranslation)
, GetValue<FVector>(Context, &InScale))
, &OutTransform);
}
}
/* -------------------------------------------------------------------------------- */
FMakeTransformDataflowNode_v2::FMakeTransformDataflowNode_v2(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Translation);
RegisterInputConnection(&Rotation);
RegisterInputConnection(&Rotator) .SetCanHidePin(true) .SetPinIsHidden(true);
RegisterInputConnection(&Quat).SetCanHidePin(true).SetPinIsHidden(true);
RegisterInputConnection(&Scale);
RegisterOutputConnection(&Transform);
}
void FMakeTransformDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FTransform>(&Transform))
{
const FVector InTranslation = GetValue(Context, &Translation);
const FVector InScale = GetValue(Context, &Scale);
FQuat OutQuat;
if (IsConnected(&Rotation))
{
const FVector InRotation = GetValue(Context, &Rotation);
OutQuat = FQuat::MakeFromEuler(InRotation);
}
else if (IsConnected(&Rotator))
{
const FRotator InRotator = GetValue(Context, &Rotator);
OutQuat = FQuat::MakeFromRotator(InRotator);
}
else if (IsConnected(&Quat))
{
const FQuat InQuat = GetValue(Context, &Quat);
OutQuat = InQuat;
}
FTransform OutTransform = FTransform(OutQuat, InTranslation, InScale);
SetValue(Context, OutTransform, &Transform);
}
}
/* -------------------------------------------------------------------------------- */
void FMakeQuaternionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FQuat>(&Quaternion))
{
const FQuat Value(GetValue<float>(Context, &X, X), GetValue<float>(Context, &Y, Y), GetValue<float>(Context, &Z, Z), GetValue<float>(Context, &W, W));
SetValue(Context, Value, &Quaternion);
}
}
void FMakeFloatArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&FloatArray))
{
const int32 InNumElements = GetValue(Context, &NumElements);
const float InValue = GetValue(Context, &Value);
TArray<float> OutFloatArray;
OutFloatArray.Init(InValue, InNumElements);
SetValue(Context, OutFloatArray, &FloatArray);
}
}
void FMakeCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Collection))
{
SetValue(Context, FManagedArrayCollection(), &Collection);
}
}
/* -------------------------------------------------------------------------------- */
FMakeRotatorDataflowNode::FMakeRotatorDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Pitch);
RegisterInputConnection(&Yaw);
RegisterInputConnection(&Roll);
RegisterOutputConnection(&Rotator);
}
void FMakeRotatorDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Rotator))
{
const float InPitch = GetValue(Context, &Pitch);
const float InYaw = GetValue(Context, &Yaw);
const float InRoll = GetValue(Context, &Roll);
SetValue(Context, FRotator(InPitch, InYaw, InRoll), &Rotator);
}
}
/* -------------------------------------------------------------------------------- */
FBreakTransformDataflowNode::FBreakTransformDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Transform);
RegisterOutputConnection(&Translation);
RegisterOutputConnection(&Rotation);
RegisterOutputConnection(&Rotator);
RegisterOutputConnection(&Quat);
RegisterOutputConnection(&Scale);
}
void FBreakTransformDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Translation) ||
Out->IsA(&Rotation) ||
Out->IsA(&Rotator) ||
Out->IsA(&Quat) ||
Out->IsA(&Scale))
{
const FTransform InTransform = GetValue(Context, &Transform);
const FVector OutTranslation = InTransform.GetTranslation();
const FVector OutRotationAsEuler = InTransform.GetRotation().Euler();
const FRotator OutRotator = InTransform.GetRotation().Rotator();
const FQuat OutQuat = InTransform.GetRotation();
const FVector OutScale = InTransform.GetScale3D();
SetValue(Context, OutTranslation, &Translation);
SetValue(Context, OutRotationAsEuler, &Rotation);
SetValue(Context, OutRotator, &Rotator);
SetValue(Context, OutQuat, &Quat);
SetValue(Context, OutScale, &Scale);
}
}
/* -------------------------------------------------------------------------------- */
FMakeSphereMeshDataflowNode::FMakeSphereMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Mesh);
}
void FMakeSphereMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
FSphereGenerator SphereGenerator;
SphereGenerator.Radius = FMath::Max(FMathf::ZeroTolerance, Radius);
SphereGenerator.NumPhi = FMath::Max(3, NumPhi);
SphereGenerator.NumTheta = FMath::Max(3, NumTheta);
SphereGenerator.bPolygroupPerQuad = false;
SphereGenerator.Generate();
DynMesh.Copy(&SphereGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakeCapsuleMeshDataflowNode::FMakeCapsuleMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Mesh);
}
void FMakeCapsuleMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
FCapsuleGenerator CapsuleGenerator;
CapsuleGenerator.Radius = FMath::Max(FMathf::ZeroTolerance, Radius);
CapsuleGenerator.SegmentLength = FMath::Max(FMathf::ZeroTolerance, SegmentLength);
CapsuleGenerator.NumHemisphereArcSteps = FMath::Max(5, NumHemisphereArcSteps);
CapsuleGenerator.NumCircleSteps = FMath::Max(3, NumCircleSteps);
CapsuleGenerator.NumSegmentSteps = FMath::Max(0, NumSegmentSteps);
CapsuleGenerator.bPolygroupPerQuad = false;
CapsuleGenerator.Generate();
DynMesh.Copy(&CapsuleGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakeCylinderMeshDataflowNode::FMakeCylinderMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Mesh);
}
void FMakeCylinderMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
FCylinderGenerator CylinderGenerator;
CylinderGenerator.Radius[0] = FMath::Max(FMathf::ZeroTolerance, Radius1);
CylinderGenerator.Radius[1] = FMath::Max(FMathf::ZeroTolerance, Radius2);
CylinderGenerator.Height = FMath::Max(FMathf::ZeroTolerance, Height);
CylinderGenerator.LengthSamples = LengthSamples;
CylinderGenerator.AngleSamples = AngleSamples;
CylinderGenerator.bCapped = true;
CylinderGenerator.bPolygroupPerQuad = false;
CylinderGenerator.Generate();
DynMesh.Copy(&CylinderGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakeBoxMeshDataflowNode::FMakeBoxMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Mesh);
}
void FMakeBoxMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
FGridBoxMeshGenerator GridBoxMeshGenerator;
GridBoxMeshGenerator.Box = UE::Geometry::FOrientedBox3d(Center, 0.5 * Size);
GridBoxMeshGenerator.EdgeVertices = FIndex3i(SubdivisionsX + 1, SubdivisionsY + 1, SubdivisionsZ + 1);
GridBoxMeshGenerator.bPolygroupPerQuad = false;
GridBoxMeshGenerator.Generate();
DynMesh.Copy(&GridBoxMeshGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakePlaneDataflowNode::FMakePlaneDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&BasePoint) .SetCanHidePin(true).SetPinIsHidden(true);
RegisterInputConnection(&Normal) .SetCanHidePin(true).SetPinIsHidden(true);
RegisterOutputConnection(&Plane);
}
void FMakePlaneDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Plane))
{
const FVector InBasePoint = GetValue(Context, &BasePoint);
const FVector InNormal = GetValue(Context, &Normal);
const FPlane OutPlane = FPlane(InBasePoint, InNormal);
SetValue(Context, OutPlane, &Plane);
}
}
#if WITH_EDITOR
bool FMakePlaneDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
{
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
}
void FMakePlaneDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
{
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
{
DebugDrawRenderSettings.SetDebugDrawSettings(DataflowRenderingInterface);
const FVector InBasePoint = GetValue(Context, &BasePoint);
FVector InNormal = GetValue(Context, &Normal);
FSimpleDebugDrawMesh Mesh;
Mesh.MakeRectangleMesh(FVector(0.0), PlaneSizeMultiplier * 10.f, PlaneSizeMultiplier * 10.f, 11, 11);
const FVector Up = FVector::UpVector;
FQuat Quat = FQuat::FindBetweenVectors(Up, Normal);
FTransform PlaneTransform = FTransform::Identity;
PlaneTransform.SetRotation(Quat);
PlaneTransform.SetTranslation(InBasePoint);
for (int32 VertexIdx = 0; VertexIdx < Mesh.GetMaxVertexIndex(); ++VertexIdx)
{
Mesh.Vertices[VertexIdx] = PlaneTransform.TransformPosition(Mesh.Vertices[VertexIdx]);
}
DataflowRenderingInterface.DrawMesh(Mesh);
// Draw normal
InNormal.Normalize();
DataflowRenderingInterface.DrawLine(InBasePoint, InBasePoint + InNormal * 2.f);
}
}
#endif
/* -------------------------------------------------------------------------------- */
FMakeDiscMeshDataflowNode::FMakeDiscMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Mesh);
}
void FMakeDiscMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
FDiscMeshGenerator DiscGenerator;
DiscGenerator.Radius = FMath::Max(FMathf::ZeroTolerance, Radius);
DiscGenerator.Normal = FVector3f(Normal);
DiscGenerator.AngleSamples = AngleSamples;
DiscGenerator.RadialSamples = RadialSamples;
DiscGenerator.StartAngle = StartAngle;
DiscGenerator.EndAngle = EndAngle;
DiscGenerator.bSinglePolygroup = true;
DiscGenerator.Generate();
DynMesh.Copy(&DiscGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakeStairMeshDataflowNode::FMakeStairMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterOutputConnection(&Mesh);
}
void FMakeStairMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
if (StairType == EDataflowStairTypeEnum::Linear)
{
FLinearStairGenerator StairGenerator;
StairGenerator.NumSteps = NumSteps;
StairGenerator.StepWidth = StepWidth;
StairGenerator.StepHeight = StepHeight;
StairGenerator.StepDepth = StepDepth;
StairGenerator.bScaleUVByAspectRatio = true;
StairGenerator.bPolygroupPerQuad = true;
StairGenerator.Generate();
DynMesh.Copy(&StairGenerator);
}
else if (StairType == EDataflowStairTypeEnum::Floating)
{
FFloatingStairGenerator StairGenerator;
StairGenerator.NumSteps = NumSteps;
StairGenerator.StepWidth = StepWidth;
StairGenerator.StepHeight = StepHeight;
StairGenerator.StepDepth = StepDepth;
StairGenerator.bScaleUVByAspectRatio = true;
StairGenerator.bPolygroupPerQuad = true;
StairGenerator.Generate();
DynMesh.Copy(&StairGenerator);
}
else if (StairType == EDataflowStairTypeEnum::Curved)
{
FCurvedStairGenerator StairGenerator;
StairGenerator.NumSteps = NumSteps;
StairGenerator.StepWidth = StepWidth;
StairGenerator.StepHeight = StepHeight;
StairGenerator.CurveAngle = CurveAngle;
StairGenerator.InnerRadius = InnerRadius;
StairGenerator.bScaleUVByAspectRatio = true;
StairGenerator.bPolygroupPerQuad = true;
StairGenerator.Generate();
DynMesh.Copy(&StairGenerator);
}
else if (StairType == EDataflowStairTypeEnum::Spiral)
{
FSpiralStairGenerator StairGenerator;
StairGenerator.NumSteps = NumSteps;
StairGenerator.StepWidth = StepWidth;
StairGenerator.StepHeight = StepHeight;
StairGenerator.CurveAngle = CurveAngle;
StairGenerator.InnerRadius = InnerRadius;
StairGenerator.bScaleUVByAspectRatio = true;
StairGenerator.bPolygroupPerQuad = true;
StairGenerator.Generate();
DynMesh.Copy(&StairGenerator);
}
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakeRectangleMeshDataflowNode::FMakeRectangleMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Origin) .SetCanHidePin(true).SetPinIsHidden(true);
RegisterInputConnection(&Normal) .SetCanHidePin(true).SetPinIsHidden(true);
RegisterOutputConnection(&Mesh);
}
void FMakeRectangleMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
const FVector InOrigin = GetValue(Context, &Origin);
const FVector InNormal = GetValue(Context, &Normal);
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
FRectangleMeshGenerator RectangleGenerator;
RectangleGenerator.Origin = InOrigin;
RectangleGenerator.Normal = FVector3f(InNormal);
RectangleGenerator.Width = Width;
RectangleGenerator.Height = Height;
RectangleGenerator.WidthVertexCount = WidthVertexCount;
RectangleGenerator.HeightVertexCount = HeightVertexCount;
RectangleGenerator.bSinglePolyGroup = true;
RectangleGenerator.Generate();
DynMesh.Copy(&RectangleGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */
FMakeTorusMeshDataflowNode::FMakeTorusMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Origin).SetCanHidePin(true).SetPinIsHidden(true);
RegisterOutputConnection(&Mesh);
}
void FMakeTorusMeshDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
using namespace UE::Geometry;
if (Out->IsA(&Mesh))
{
const FVector InOrigin = GetValue(Context, &Origin);
TObjectPtr<UDynamicMesh> NewMesh = NewObject<UDynamicMesh>();
NewMesh->Reset();
FDynamicMesh3& DynMesh = NewMesh->GetMeshRef();
TArray<FVector3d> ProfileCurve; ProfileCurve.SetNumUninitialized(ProfileVertexCount);
TArray<FFrame3d> SweepCurve; SweepCurve.SetNumUninitialized(SweepVertexCount);
FVector Vec1(0.0, -Radius1, 0.0);
const float RotateAngle1 = 360.f / float(ProfileVertexCount);
// Create profile curve
for (int32 Idx = 0; Idx < ProfileVertexCount; ++Idx)
{
ProfileCurve[Idx] = Vec1;
Vec1 = Vec1.RotateAngleAxis(RotateAngle1, FVector::XAxisVector);
}
FVector Vec2(0.0, -Radius2, 0.0);
const float RotateAngle2 = 360.f / float(SweepVertexCount);
TQuaternion<double> Quat(FVector::ZAxisVector, RotateAngle2, true);
FFrame3d Frame; // Construct a frame positioned at(0, 0, 0) aligned to the unit axes
// Create sweep curve
for (int32 Idx = 0; Idx < SweepVertexCount; ++Idx)
{
FFrame3d Frame1 = Frame;
Frame1.Origin = Vec2 + InOrigin;
SweepCurve[Idx] = Frame1;
Frame.Rotate(Quat);
Vec2 = Vec2.RotateAngleAxis(RotateAngle2, FVector::ZAxisVector);
}
FProfileSweepGenerator SweepGenerator;
SweepGenerator.ProfileCurve = ProfileCurve;
SweepGenerator.SweepCurve = SweepCurve;
SweepGenerator.bSweepCurveIsClosed = true;
SweepGenerator.bProfileCurveIsClosed = true;
SweepGenerator.Generate();
DynMesh.Copy(&SweepGenerator);
SetValue(Context, NewMesh, &Mesh);
}
}
/* -------------------------------------------------------------------------------- */