// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Dataflow/DataflowEngine.h" #include "GeometryCollection/ManagedArrayCollection.h" #include "DynamicMesh/DynamicMesh3.h" #include "UDynamicMesh.h" #include "GeometryCollectionUtilityNodes.h" #include "GeometryCollectionDebugNodes.generated.h" #if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_5 namespace Dataflow = UE::Dataflow; #else namespace UE_DEPRECATED(5.5, "Use UE::Dataflow instead.") Dataflow {} #endif //~ Dataflow nodes that are useful for debugging a geometry collection-related dataflow graph // Convert convex hulls on a geometry collection to a dynamic mesh USTRUCT(meta = (DataflowGeometryCollection)) struct FConvexHullToMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FConvexHullToMeshDataflowNode, "Convex Hull to Mesh", "GeometryCollection|Mesh", "") private: UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) FManagedArrayCollection Collection; /** Optional transform selection to convert hulls from -- if not provided, all convex hulls will be converted. */ UPROPERTY(meta = (DataflowInput)) FDataflowTransformSelection OptionalSelectionFilter; /** Whether to robustly extract valid/manifold meshes to represent the convex hulls. Note: Not necessary for simple visualization, but useful for downstream processing. */ UPROPERTY(EditAnywhere, Category = Options) bool bUseRobustHulls = true; /** Single mesh aggregating all the convex hulls together */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; /** Array of meshes for each convex hull found */ UPROPERTY(meta = (DataflowOutput)) TArray> Meshes; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; public: FConvexHullToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); }; // Convert a sphere covering, as generated by the 'protect negative space' option on the "Generate Cluster Convex Hull" nodes, to a dynamic mesh USTRUCT(meta = (DataflowGeometryCollection)) struct FSphereCoveringToMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FSphereCoveringToMeshDataflowNode, "Sphere Covering to Mesh", "GeometryCollection|Mesh", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("FDynamicMesh3"), "Mesh") public: // The sphere covering to convert to a mesh UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) FDataflowSphereCovering SphereCovering; // Number of vertices to use along each axis when creating a mesh for each sphere UPROPERTY(EditAnywhere, Category = Options, meta = (ClampMin = 2)) int32 VerticesAlongEachSide = 8; UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; FSphereCoveringToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&SphereCovering); RegisterOutputConnection(&Mesh); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; // Report the number of spheres in a sphere covering USTRUCT(meta = (DataflowGeometryCollection)) struct FSphereCoveringCountSpheresNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FSphereCoveringCountSpheresNode, "Get Sphere Covering Sphere Count", "SphereCovering", "") public: // The sphere covering to evaluate UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) FDataflowSphereCovering SphereCovering; // Number of spheres in the sphere covering UPROPERTY(meta = (DataflowOutput)) int32 NumSpheres = 0; FSphereCoveringCountSpheresNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&SphereCovering); RegisterOutputConnection(&NumSpheres); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override { if (Out->IsA(&NumSpheres)) { const FDataflowSphereCovering& InSphereCovering = GetValue(Context, &SphereCovering); SetValue(Context, InSphereCovering.Spheres.Num(), &NumSpheres); } } }; // Convert a mesh to a string formatted as an OBJ file, which can be read by many external mesh viewers USTRUCT(meta = (DataflowGeometryCollection)) struct FMeshToOBJStringDebugDataflowNode: public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FMeshToOBJStringDebugDataflowNode, "Convert Mesh to OBJ String", "GeometryCollection|Development", "") public: UPROPERTY(meta = (DataflowInput)) TObjectPtr Mesh; // Whether to flip the orientation of the triangles in the OBJ output UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) bool bInvertFaces = false; // A string representing the input mesh in the OBJ file format UPROPERTY(meta = (DataflowOutput)) FString StringOBJ; FMeshToOBJStringDebugDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Mesh); RegisterInputConnection(&bInvertFaces); RegisterOutputConnection(&StringOBJ); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; // Write a string to a file USTRUCT(meta = (DataflowGeometryCollection)) struct FWriteStringToFile : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FWriteStringToFile, "Write String to File", "GeometryCollection|Development", "") public: // Where file should be written on disk UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) FString FilePath; // Contents of the file to write UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) FString FileContents; FWriteStringToFile(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&FileContents); RegisterInputConnection(&FilePath); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; namespace UE::Dataflow { void GeometryCollectionDebugNodes(); }