// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Dataflow/DataflowEngine.h" #include "Dataflow/DataflowMesh.h" #include "GeometryCollection/ManagedArrayCollection.h" #include "Dataflow/DataflowSelection.h" #include "DynamicMesh/DynamicMesh3.h" #include "DynamicMeshProcessor.h" #if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_6 // Some mesh-specific nodes have been moved to their own plugin #include "Dataflow/MeshBooleanNodes.h" #endif #include "GeometryCollectionMeshNodes.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 class FGeometryCollection; class UStaticMesh; class UDynamicMesh; class UMaterialInterface; /** * * Converts points into a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FPointsToMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FPointsToMeshDataflowNode, "PointsToMesh", "Mesh|Utilities", "") public: /** Points input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TArray Points; /** Mesh output */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; /** Mesh triangle count */ UPROPERTY(meta = (DataflowOutput)) int32 TriangleCount = 0; FPointsToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Points); RegisterOutputConnection(&Mesh); RegisterOutputConnection(&TriangleCount); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * Base class for nodes that applying Geometry Script Mesh Processors */ USTRUCT() struct FMeshProcessorDataflowNodeBase : public FDataflowNode { GENERATED_USTRUCT_BODY() public: FMeshProcessorDataflowNodeBase() = default; FMeshProcessorDataflowNodeBase(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid), OwningObject(InParam.OwningObject) { } ~FMeshProcessorDataflowNodeBase() { TeardownBlueprintEvent(); } protected: UPROPERTY(EditAnywhere, Category = "Processor Type") TSubclassOf MeshProcessor = nullptr; UPROPERTY(EditAnywhere, Instanced, NoClear, Category = "Instance", meta = (ShowOnlyInnerProperties)) TObjectPtr MeshProcessorInstance; virtual void PostSerialize(const FArchive& Ar) override final { Super::PostSerialize(Ar); if (Ar.IsLoading()) { TeardownBlueprintEvent(); SetupBlueprintEvent(); } } private: virtual void OnPropertyChanged(UE::Dataflow::FContext& Context, const FPropertyChangedEvent& PropertyChangedEvent) override; // Handling for the selected blueprint being changed under the node (e.g., recompiled) FDelegateHandle BlueprintChangeDelegateHandle; void TeardownBlueprintEvent(); void SetupBlueprintEvent(); // Remember the parent UObject so that we can properly parent MeshProcessorInstance when the MeshProcessor changes UPROPERTY(Transient) TObjectPtr OwningObject; }; /** * Apply a Geometry Script Mesh Processors to an input UDynamicMesh */ USTRUCT(meta = (DataflowGeometryCollection)) struct FApplyMeshProcessorToMeshDataflowNode final : public FMeshProcessorDataflowNodeBase { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FApplyMeshProcessorToMeshDataflowNode, "ApplyGeometryScriptToMesh", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("FDynamicMesh3"), "Mesh") public: /** Input/Output mesh */ UPROPERTY(meta = (DataflowInput, DataflowOutput, DataflowPassthrough = "Mesh", DataflowIntrinsic)) TObjectPtr Mesh; FApplyMeshProcessorToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FMeshProcessorDataflowNodeBase(InParam, InGuid) { RegisterInputConnection(&Mesh); RegisterOutputConnection(&Mesh, &Mesh); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * Apply a Geometry Script Mesh Processors to the geometry of selected transforms in a geometry collection */ USTRUCT(meta = (DataflowGeometryCollection)) struct FApplyMeshProcessorToGeometryCollectionDataflowNode final : public FMeshProcessorDataflowNodeBase { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FApplyMeshProcessorToGeometryCollectionDataflowNode, "ApplyGeometryScriptToCollection", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FGeometryCollection::StaticType(), "Collection") public: /** Input/Output mesh */ UPROPERTY(meta = (DataflowInput, DataflowOutput, DataflowPassthrough = "Collection", DataflowIntrinsic)) FManagedArrayCollection Collection; /** Selected bones will have geometry script processing applied (if they have geometry). If not connected, all geometry will be processed. */ UPROPERTY(meta = (DataflowInput)) FDataflowTransformSelection TransformSelection; /** Whether the processed mesh will have edges at normal/UV/color seams welded so they are treated as one edge during processing. */ UPROPERTY(EditAnywhere, Category = Options) bool bWeldVertices = true; /** Whether to preserve isolated vertices which aren't used by any triangles. */ UPROPERTY(EditAnywhere, Category = Options) bool bPreserveIsolatedVertices = true; FApplyMeshProcessorToGeometryCollectionDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FMeshProcessorDataflowNodeBase(InParam, InGuid) { RegisterInputConnection(&Collection); RegisterInputConnection(&TransformSelection); RegisterOutputConnection(&Collection, &Collection); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Converts a Collection to a set of Dynamic Meshes per selected Transform * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FCollectionSelectionToMeshesDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FCollectionSelectionToMeshesDataflowNode, "CollectionSelectionToMeshes", "Mesh|Utilities", "") //DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("FDynamicMesh3"), "Meshes") public: /** Collection to convert*/ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) FManagedArrayCollection Collection; /** Geometry on or under selected bones will be converted to meshes, optionally after filtering the selection to leaves. If not connected, all geometry will be processed. */ UPROPERTY(meta = (DataflowInput)) FDataflowTransformSelection TransformSelection; /** Whether to convert the input selection to only leaves, which may directly store geometry. Otherwise, meshes for selected cluster nodes will be generated by appending together geometry from leaf nodes. */ UPROPERTY(EditAnywhere, Category = Options) bool bConvertSelectionToLeaves = true; /** Whether the processed mesh will have edges at normal/UV/color seams welded so they are treated as one edge during processing. */ UPROPERTY(EditAnywhere, Category = Options) bool bWeldVertices = true; /** Whether to preserve isolated vertices which aren't used by any triangles. */ UPROPERTY(EditAnywhere, Category = Options) bool bPreserveIsolatedVertices = true; /** Output Array of DynamicMesh */ UPROPERTY(meta = (DataflowOutput)) TArray> Meshes; FCollectionSelectionToMeshesDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Append Array of Meshes to Collection * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FAppendMeshesToCollectionDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FAppendMeshesToCollectionDataflowNode, "AppendMeshesToCollection", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FGeometryCollection::StaticType(), "Collection") public: /** Meshes will be appended to this collection */ UPROPERTY(meta = (DataflowInput, DataflowOutput, DataflowPassthrough = "Collection", DataflowIntrinsic)) FManagedArrayCollection Collection; /** Selection of added transforms */ UPROPERTY(meta = (DataflowOutput)) FDataflowTransformSelection AddedSelection; /** Dynamic Meshes to append */ UPROPERTY(meta = (DataflowInput)) TArray> Meshes; /** Index of parent bone for appended meshes. If invalid, meshes will be appended to a root node. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) int32 ParentIndex = -1; FAppendMeshesToCollectionDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Converts a BoundingBox into a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FBoxToMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FBoxToMeshDataflowNode, "BoxToMesh", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender",FName("FDynamicMesh3"), "Mesh") public: /** BoundingBox input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) FBox Box = FBox(ForceInit); /** Mesh output */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; /** Mesh triangle count */ UPROPERTY(meta = (DataflowOutput)) int32 TriangleCount = 0; FBoxToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Box); RegisterOutputConnection(&Mesh); RegisterOutputConnection(&TriangleCount); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Collects information from the DynamicMesh and outputs it into a formatted string * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FMeshInfoDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FMeshInfoDataflowNode, "MeshInfo", "Mesh|Utilities", "") public: /** DynamicMesh for the information */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr Mesh; /** Formatted output string */ UPROPERTY(meta = (DataflowOutput)) FString InfoString = FString(""); FMeshInfoDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Mesh); RegisterOutputConnection(&InfoString); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Converts a DynamicMesh to a Collection * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FMeshToCollectionDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FMeshToCollectionDataflowNode, "MeshToCollection", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender",FGeometryCollection::StaticType(), "Collection") public: /** DynamicMesh to convert */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr Mesh; /** Output Collection */ UPROPERTY(meta = (DataflowOutput)) FManagedArrayCollection Collection; /** Whether to split the mesh into multiple bones based on the mesh connectivity */ UPROPERTY(EditAnywhere, Category = "General", meta = (DataflowInput)); bool bSplitIslands = false; /** Whether to consider coincident vertices as connected even if the topology does not connect them */ UPROPERTY(EditAnywhere, Category = "General"); bool bConnectIslandsByVertexOverlap = false; /** Vertices closer than this distance are considered to be overlapping */ UPROPERTY(EditAnywhere, Category = "General", meta = (ClampMin = 0.0)); float ConnectVerticesThreshold = 0.001; /** Whether to add a root cluster for the single mesh case. Note if the mesh is split, the root cluster will always be added. */ UPROPERTY(EditAnywhere, Category = "General", meta = (DataflowInput)); bool bAddClusterRootForSingleMesh = false; FMeshToCollectionDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Converts a Collection to a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FCollectionToMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FCollectionToMeshDataflowNode, "CollectionToMesh", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender",FName("FDynamicMesh3"), "Mesh") public: /** Collection to convert*/ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) FManagedArrayCollection Collection; UPROPERTY(EditAnywhere, Category = "General", meta = (DisplayName = "Center Pivot")); bool bCenterPivot = false; /** Output DynamicMesh */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; FCollectionToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Collection); RegisterOutputConnection(&Mesh); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Converts a StaticMesh into a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FStaticMeshToMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FStaticMeshToMeshDataflowNode, "StaticMeshToMesh", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender",FName("FDynamicMesh3"), {"Mesh", "MaterialArray"}) public: /** StaticMesh to convert */ UPROPERTY(EditAnywhere, Category = "StaticMesh", meta = (DataflowInput)); TObjectPtr StaticMesh; /** Output the HiRes representation, if set to true and HiRes doesn't exist it will output empty mesh */ UPROPERTY(EditAnywhere, Category = "StaticMesh", meta = (DisplayName = "Use HiRes")); bool bUseHiRes = false; /** Specifies the LOD level to use */ UPROPERTY(EditAnywhere, Category = "StaticMesh", meta = (DisplayName = "LOD Level")); int32 LODLevel = 0; /** Output mesh */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; /** Output materials */ UPROPERTY(meta = (DataflowOutput)) TArray> MaterialArray; FStaticMeshToMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&StaticMesh); RegisterOutputConnection(&Mesh); RegisterOutputConnection(&MaterialArray); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Appends two meshes * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FMeshAppendDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FMeshAppendDataflowNode, "MeshAppend", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender",FName("FDynamicMesh3"), "Mesh") public: /** Mesh input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr Mesh1; /** Mesh input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr Mesh2; /** Output mesh */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; FMeshAppendDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Mesh1); RegisterInputConnection(&Mesh2); RegisterOutputConnection(&Mesh); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Combine two Dataflow meshes * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FDataflowMeshAppendDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FDataflowMeshAppendDataflowNode, "DataflowMeshAppend", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("UDataflowMesh"), "Mesh" ) public: FDataflowMeshAppendDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); private: /** Mesh input/output */ UPROPERTY(meta = (DataflowInput, DataflowOutput, DataflowPassthrough = "Mesh", DataflowIntrinsic)) TObjectPtr Mesh; /** Mesh to append */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr AppendMesh; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Create a UDataflow mesh from an input UDynamicMesh and material array * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FMakeDataflowMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FMakeDataflowMeshDataflowNode, "MakeDataflowMesh", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("UDataflowMesh"), "Mesh") public: FMakeDataflowMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); private: /** DynamicMesh input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr InMesh; /** Materials input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TArray> InMaterials; /** DataflowMesh output */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * Create a new UV layer/channel in a UDataflowMesh */ USTRUCT(meta = (DataflowGeometryCollection)) struct FDuplicateMeshUVChannelNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FDuplicateMeshUVChannelNode, "DuplicateMeshUVChannelNode", "Mesh|Utilities", "Mesh UV DataflowMesh") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("UDataflowMesh"), "Mesh", "UVChannel") public: FDuplicateMeshUVChannelNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); private: /** DataflowMesh input/output */ UPROPERTY(meta = (DataflowInput, DataflowOutput, DataflowPassthrough = "Mesh", DataflowIntrinsic)) TObjectPtr Mesh; /** Index of the source UV channel */ UPROPERTY(EditAnywhere, Category = Options) int32 SourceUVChannel = -1; /** Index of the added UV channel */ UPROPERTY(meta = (DataflowOutput)) int32 NewUVChannel = -1; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; UENUM(BlueprintType) enum class EDataflowMeshSplitIslandsMethod : uint8 { NoSplit, ByMeshTopology, ByVertexOverlap }; /** * * Split a mesh into a connected islands * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FSplitMeshIslandsDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FSplitMeshIslandsDataflowNode, "SplitMeshIslands", "Mesh|Utilities", "") public: FSplitMeshIslandsDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); private: /** Mesh input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr Mesh; /** Meshes output */ UPROPERTY(meta = (DataflowOutput)) TArray> Meshes; /** Whether to consider coincident vertices as connected even if the topology does not connect them */ UPROPERTY(EditAnywhere, Category = "General"); EDataflowMeshSplitIslandsMethod SplitMethod = EDataflowMeshSplitIslandsMethod::ByMeshTopology; /** Vertices closer than this distance are considered to be overlapping */ UPROPERTY(EditAnywhere, Category = "General", meta = (ClampMin = 0.0, EditCondition = "SplitMethod == EDataflowMeshSplitIslandsMethod::ByVertexOverlap")); float ConnectVerticesThreshold = 0.001; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Split a UDataflow mesh into a UDynamicMesh and a material array * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FSplitDataflowMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FSplitDataflowMeshDataflowNode, "SplitDataflowMesh", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender", FName("FDynamicMesh3"), { "Mesh", "MaterialArray" }) public: FSplitDataflowMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); private: /** DataflowMesh input */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr InMesh; /** DyanmicMesh output */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; /** Materials output */ UPROPERTY(meta = (DataflowOutput)) TArray> MaterialArray; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Copies the same mesh with scale onto points * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FMeshCopyToPointsDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FMeshCopyToPointsDataflowNode, "ScatterMeshes", "Mesh|Utilities", "") DATAFLOW_NODE_RENDER_TYPE("SurfaceRender",FName("FDynamicMesh3"), "Mesh") public: /** Points to copy meshes onto */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TArray Points; /** Mesh to copy onto points */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic, DisplayName = "MeshToScatter")) TObjectPtr MeshToCopy; /** Scale applied to the mesh */ UPROPERTY(EditAnywhere, Category = "Copy"); float Scale = 1.f; /** merged result mesh */ UPROPERTY(meta = (DataflowOutput)) TObjectPtr Mesh; /** Result meshes as individual ones */ UPROPERTY(meta = (DataflowOutput)) TArray> Meshes; FMeshCopyToPointsDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Points); RegisterInputConnection(&MeshToCopy); RegisterOutputConnection(&Mesh); RegisterOutputConnection(&Meshes); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Outputs Mesh data * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FGetMeshDataDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FGetMeshDataDataflowNode, "GetMeshData", "Mesh|Utilities", "") public: /** Mesh for the data */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr Mesh; /** Number of vertices */ UPROPERTY(meta = (DataflowOutput)) int32 VertexCount = 0; /** Number of edges */ UPROPERTY(meta = (DataflowOutput)) int32 EdgeCount = 0; /** Number of triangles */ UPROPERTY(meta = (DataflowOutput)) int32 TriangleCount = 0; FGetMeshDataDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Mesh); RegisterOutputConnection(&VertexCount); RegisterOutputConnection(&EdgeCount); RegisterOutputConnection(&TriangleCount); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; namespace UE::Dataflow { void GeometryCollectionMeshNodes(); }