// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Dataflow/DataflowEngine.h" #include "FractureEngineSampling.h" #include "GeometryCollectionSamplingNodes.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 UDynamicMesh; /** Flags to control which mesh point filtering method(s) are applied */ UENUM(meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true")) enum class EFilterPointSetWithMeshDataflowMethodFlags : uint8 { None = 0 UMETA(Hidden), // Use the winding number to filter inside or outside of the mesh Winding = 1 << 0, // Filter away points below a minimum mesh distance MinDistance = 1 << 1, // Filter away points above a maximum mesh distance MaxDistance = 1 << 2 }; ENUM_CLASS_FLAGS(EFilterPointSetWithMeshDataflowMethodFlags) /** * * Filter a point set to only the points inside or outside of a given mesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FFilterPointSetWithMeshDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FFilterPointSetWithMeshDataflowNode, "FilterPointsWithMesh", "PointSampling", "") DATAFLOW_NODE_RENDER_TYPE("PointsRender", FName("TArray"), "SamplePoints") public: FFilterPointSetWithMeshDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()); private: /** Mesh to use to filter point set */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr TargetMesh; UPROPERTY(EditAnywhere, Category=Options, meta=(Bitmask, BitmaskEnum="/Script/GeometryCollectionNodes.EFilterPointSetWithMeshDataflowMethodFlags")) uint8 FilterMethod = (uint8)EFilterPointSetWithMeshDataflowMethodFlags::Winding; /** Whether to keep the points inside or (if false) outside the mesh, when filtering by Winding Number. */ UPROPERTY(EditAnywhere, Category = WindingNumber, meta = (DataflowInput, EditCondition = "FilterMethod & \"/Script/GeometryCollectionNodes.EFilterPointSetWithMeshDataflowMethodFlags::Winding\"")) bool bKeepInside = true; /** The winding number threshold to use for determining whether a point is inside or outside of the mesh, if corresponding Filter Method is set */ UPROPERTY(EditAnywhere, Category = WindingNumber, meta = (DataflowInput)) float WindingThreshold = .5f; /** The min distance to surface to keep, if corresponding Filter Method is set */ UPROPERTY(EditAnywhere, Category = Distance, meta = (DataflowInput, EditCondition = "FilterMethod & \"/Script/GeometryCollectionNodes.EFilterPointSetWithMeshDataflowMethodFlags::MinDistance\"")) float MinDistance = 0.f; /** The max distance to surface to keep, if corresponding Filter Method is set */ UPROPERTY(EditAnywhere, Category = Distance, meta = (DataflowInput, EditCondition = "FilterMethod & \"/Script/GeometryCollectionNodes.EFilterPointSetWithMeshDataflowMethodFlags::MaxDistance\"")) float MaxDistance = 1000.f; /** * Whether to use signed distances for the Min and Max Distance thresholds. Otherwise, unsigned distance is used. * Note: Signs are computed via the Winding Number. The sign is negative if the point's Winding Number is below the Winding Threshold. */ UPROPERTY(EditAnywhere, Category = Distance, meta = (DataflowInput)) bool bUseSignedDistance = false; /** Points to filter */ UPROPERTY(meta = (DataflowInput, DataflowOutput)) TArray SamplePoints; virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * Uniform Sampling on a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FUniformPointSamplingDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FUniformPointSamplingDataflowNode, "UniformPointSampling", "PointSampling", "") DATAFLOW_NODE_RENDER_TYPE("PointsRender", FName("TArray"), "SamplePoints") public: /** Mesh to sample points on */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr TargetMesh; /** Desired "radius" of sample points. Spacing between samples is at least 2x this value. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SamplingRadius = 10.f; /** Maximum number of samples requested. If 0 or default value, mesh will be maximally sampled */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0)) int32 MaxNumSamples = 0; /** Density of subsampling used in Poisson strategy. Larger numbers mean "more accurate" (but slower) results. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SubSampleDensity = 10.f; /** Random Seed used to initialize sampling strategies */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) int32 RandomSeed = 0; /** Sampled positions on the mesh */ UPROPERTY(meta = (DataflowOutput)) TArray SamplePoints; /** Sampled triangleID */ UPROPERTY(meta = (DataflowOutput)) TArray SampleTriangleIDs; /** Barycentric Coordinates of each Sample Point in it's respective Triangle. */ UPROPERTY(meta = (DataflowOutput)) TArray SampleBarycentricCoords; /** Number of Sampled positions on the mesh */ UPROPERTY(meta = (DataflowOutput)) int32 NumSamplePoints = 0; FUniformPointSamplingDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&TargetMesh); RegisterInputConnection(&SamplingRadius) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&MaxNumSamples) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&SubSampleDensity) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&RandomSeed) .SetCanHidePin(true).SetPinIsHidden(true); RegisterOutputConnection(&SamplePoints); RegisterOutputConnection(&SampleTriangleIDs); RegisterOutputConnection(&SampleBarycentricCoords); RegisterOutputConnection(&NumSamplePoints); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * NonUniform Sampling on a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FNonUniformPointSamplingDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FNonUniformPointSamplingDataflowNode, "NonUniformPointSampling", "PointSampling", "") DATAFLOW_NODE_RENDER_TYPE("PointsRender", FName("TArray"), "SamplePoints") public: /** Mesh to sample points on */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr TargetMesh; /** Desired "radius" of sample points. Spacing between samples is at least 2x this value. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SamplingRadius = 10.f; /** Maximum number of samples requested. If 0 or default value, mesh will be maximally sampled */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0)) int32 MaxNumSamples = 0; /** Density of subsampling used in Poisson strategy. Larger numbers mean "more accurate" (but slower) results. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SubSampleDensity = 10.f; /** Random Seed used to initialize sampling strategies */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) int32 RandomSeed = 0; /** If MaxSampleRadius > SampleRadius, then output sample radius will be in range [SampleRadius, MaxSampleRadius] */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float MaxSamplingRadius = 10.f; /** SizeDistribution setting controls the distribution of sample radii */ UPROPERTY(EditAnywhere, Category = Distribution) ENonUniformSamplingDistributionMode SizeDistribution = ENonUniformSamplingDistributionMode::ENonUniformSamplingDistributionMode_Uniform; /** SizeDistributionPower is used to control how extreme the Size Distribution shift is. Valid range is [1,10] */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SizeDistributionPower = 2.f; /** Sampled positions on the mesh */ UPROPERTY(meta = (DataflowOutput)) TArray SamplePoints; /** Sampled radii */ UPROPERTY(meta = (DataflowOutput)) TArray SampleRadii; /** Sampled triangleID */ UPROPERTY(meta = (DataflowOutput)) TArray SampleTriangleIDs; /** Barycentric Coordinates of each Sample Point in it's respective Triangle. */ UPROPERTY(meta = (DataflowOutput)) TArray SampleBarycentricCoords; /** Number of Sampled positions on the mesh */ UPROPERTY(meta = (DataflowOutput)) int32 NumSamplePoints = 0; FNonUniformPointSamplingDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&TargetMesh); RegisterInputConnection(&SamplingRadius) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&MaxNumSamples) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&SubSampleDensity) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&RandomSeed) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&MaxSamplingRadius) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&SizeDistributionPower) .SetCanHidePin(true).SetPinIsHidden(true); RegisterOutputConnection(&SamplePoints); RegisterOutputConnection(&SampleRadii); RegisterOutputConnection(&SampleTriangleIDs); RegisterOutputConnection(&SampleBarycentricCoords); RegisterOutputConnection(&NumSamplePoints); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; /** * * VertexWeighted Sampling on a DynamicMesh * */ USTRUCT(meta = (DataflowGeometryCollection)) struct FVertexWeightedPointSamplingDataflowNode : public FDataflowNode { GENERATED_USTRUCT_BODY() DATAFLOW_NODE_DEFINE_INTERNAL(FVertexWeightedPointSamplingDataflowNode, "VertexWeightedPointSampling", "PointSampling", "") DATAFLOW_NODE_RENDER_TYPE("PointsRender", FName("TArray"), "SamplePoints") public: /** Mesh to sample points on */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TObjectPtr TargetMesh; /** Weight array */ UPROPERTY(meta = (DataflowInput, DataflowIntrinsic)) TArray VertexWeights; /** Desired "radius" of sample points. Spacing between samples is at least 2x this value. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SamplingRadius = 10.f; /** Maximum number of samples requested. If 0 or default value, mesh will be maximally sampled */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0)) int32 MaxNumSamples = 0; /** Density of subsampling used in Poisson strategy. Larger numbers mean "more accurate" (but slower) results. */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SubSampleDensity = 10.f; /** Random Seed used to initialize sampling strategies */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput)) int32 RandomSeed = 0; /** If MaxSampleRadius > SampleRadius, then output sample radius will be in range [SampleRadius, MaxSampleRadius] */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float MaxSamplingRadius = 10.f; /** SizeDistribution setting controls the distribution of sample radii */ UPROPERTY(EditAnywhere, Category = Distribution) ENonUniformSamplingDistributionMode SizeDistribution = ENonUniformSamplingDistributionMode::ENonUniformSamplingDistributionMode_Uniform; /** SizeDistributionPower is used to control how extreme the Size Distribution shift is. Valid range is [1,10] */ UPROPERTY(EditAnywhere, Category = Options, meta = (DataflowInput, UIMin = 0.f)) float SizeDistributionPower = 2.f; UPROPERTY(EditAnywhere, Category = Distribution) ENonUniformSamplingWeightMode WeightMode = ENonUniformSamplingWeightMode::ENonUniformSamplingWeightMode_WeightedRandom; UPROPERTY(EditAnywhere, Category = Options) bool bInvertWeights = false; /** Sampled positions on the mesh */ UPROPERTY(meta = (DataflowOutput)) TArray SamplePoints; /** Sampled radii */ UPROPERTY(meta = (DataflowOutput)) TArray SampleRadii; /** Sampled triangleID */ UPROPERTY(meta = (DataflowOutput)) TArray SampleTriangleIDs; /** Barycentric Coordinates of each Sample Point in it's respective Triangle. */ UPROPERTY(meta = (DataflowOutput)) TArray SampleBarycentricCoords; /** Number of Sampled positions on the mesh */ UPROPERTY(meta = (DataflowOutput)) int32 NumSamplePoints = 0; FVertexWeightedPointSamplingDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid = FGuid::NewGuid()) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&TargetMesh); RegisterInputConnection(&VertexWeights); RegisterInputConnection(&SamplingRadius) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&MaxNumSamples) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&SubSampleDensity) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&RandomSeed) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&MaxSamplingRadius) .SetCanHidePin(true).SetPinIsHidden(true); RegisterInputConnection(&SizeDistributionPower) .SetCanHidePin(true).SetPinIsHidden(true); RegisterOutputConnection(&SamplePoints); RegisterOutputConnection(&SampleRadii); RegisterOutputConnection(&SampleTriangleIDs); RegisterOutputConnection(&SampleBarycentricCoords); RegisterOutputConnection(&NumSamplePoints); } virtual void Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const override; }; namespace UE::Dataflow { void GeometryCollectionSamplingNodes(); }