You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Moved GeometryCollection Dataflow nodes into separate implemetation files by category - Changed Dataflow node category to "Terminal" on terminal nodes - Added DataflowGeoemtryCollection, DataflowFlesh categories to nodes - Addded black default color to terminal category and changed default color for non-specified categories to yellow - Added comments to all GeometryCollection nodes - Updated existing Dataflow nodes #rb Brice.Criswell, Cedric.Caillaud, Harsha.Reddy #preflight 6377d7d5e30d4388499a07c0 [CL 23206811 by gustav melich in ue5-main branch]
264 lines
10 KiB
C++
264 lines
10 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Dataflow/GeometryCollectionFracturingNodes.h"
|
|
#include "Dataflow/DataflowCore.h"
|
|
|
|
#include "Engine/StaticMesh.h"
|
|
#include "GeometryCollection/GeometryCollectionObject.h"
|
|
#include "GeometryCollection/ManagedArrayCollection.h"
|
|
#include "GeometryCollection/GeometryCollection.h"
|
|
#include "GeometryCollection/GeometryCollectionEngineUtility.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 "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 UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionFracturingNodes)
|
|
|
|
namespace Dataflow
|
|
{
|
|
|
|
void GeometryCollectionFracturingNodes()
|
|
{
|
|
static const FLinearColor CDefaultNodeBodyTintColor = FLinearColor(0.f, 0.f, 0.f, 0.5f);
|
|
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FUniformScatterPointsDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRadialScatterPointsDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FVoronoiFractureDataflowNode);
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FPlaneCutterDataflowNode);
|
|
|
|
// GeometryCollection|Fracture
|
|
DATAFLOW_NODE_REGISTER_CREATION_FACTORY_NODE_COLORS_BY_CATEGORY("GeometryCollection|Fracture", FLinearColor(1.f, 1.f, 0.8f), CDefaultNodeBodyTintColor);
|
|
}
|
|
}
|
|
|
|
void FUniformScatterPointsDataflowNode::Evaluate(Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TArray<FVector>>(&Points))
|
|
{
|
|
const FBox& BBox = GetValue<FBox>(Context, &BoundingBox);
|
|
if (BBox.GetVolume() > 0.f)
|
|
{
|
|
FRandomStream RandStream(GetValue<float>(Context, &RandomSeed));
|
|
|
|
const FVector Extent(BBox.Max - BBox.Min);
|
|
const int32 NumPoints = RandStream.RandRange(GetValue<int32>(Context, &MinNumberOfPoints), GetValue<int32>(Context, &MaxNumberOfPoints));
|
|
|
|
TArray<FVector> PointsArr;
|
|
PointsArr.Reserve(NumPoints);
|
|
for (int32 Idx = 0; Idx < NumPoints; ++Idx)
|
|
{
|
|
PointsArr.Emplace(BBox.Min + FVector(RandStream.FRand(), RandStream.FRand(), RandStream.FRand()) * Extent);
|
|
}
|
|
|
|
SetValue<TArray<FVector>>(Context, PointsArr, &Points);
|
|
}
|
|
else
|
|
{
|
|
// ERROR: Invalid BoundingBox input
|
|
SetValue<TArray<FVector>>(Context, TArray<FVector>(), &Points);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FRadialScatterPointsDataflowNode::Evaluate(Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<TArray<FVector>>(&Points))
|
|
{
|
|
const FVector::FReal RadialStep = GetValue<float>(Context, &Radius) / GetValue<int32>(Context, &RadialSteps);
|
|
const FVector::FReal AngularStep = 2 * PI / GetValue<int32>(Context, &AngularSteps);
|
|
|
|
FRandomStream RandStream(GetValue<float>(Context, &RandomSeed));
|
|
FVector UpVector(GetValue<FVector>(Context, &Normal));
|
|
UpVector.Normalize();
|
|
FVector BasisX, BasisY;
|
|
UpVector.FindBestAxisVectors(BasisX, BasisY);
|
|
|
|
TArray<FVector> PointsArr;
|
|
|
|
FVector::FReal Len = RadialStep * .5;
|
|
for (int32 ii = 0; ii < GetValue<int32>(Context, &RadialSteps); ++ii, Len += RadialStep)
|
|
{
|
|
FVector::FReal Angle = FMath::DegreesToRadians(GetValue<float>(Context, &AngleOffset));
|
|
for (int32 kk = 0; kk < AngularSteps; ++kk, Angle += AngularStep)
|
|
{
|
|
FVector RotatingOffset = Len * (FMath::Cos(Angle) * BasisX + FMath::Sin(Angle) * BasisY);
|
|
PointsArr.Emplace(GetValue<FVector>(Context, &Center) + RotatingOffset + (RandStream.VRand() * RandStream.FRand() * Variability));
|
|
}
|
|
}
|
|
|
|
SetValue<TArray<FVector>>(Context, PointsArr, &Points);
|
|
}
|
|
}
|
|
|
|
|
|
static float GetMaxVertexMovement(float Grout, float Amplitude, int OctaveNumber, float Persistence)
|
|
{
|
|
float MaxDisp = Grout;
|
|
float AmplitudeScaled = Amplitude;
|
|
for (int32 OctaveIdx = 0; OctaveIdx < OctaveNumber; OctaveIdx++, AmplitudeScaled *= Persistence)
|
|
{
|
|
MaxDisp += FMath::Abs(AmplitudeScaled);
|
|
}
|
|
return MaxDisp;
|
|
}
|
|
|
|
void FVoronoiFractureDataflowNode::Evaluate(Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
if (TUniquePtr<FGeometryCollection> GeomCollection = TUniquePtr<FGeometryCollection>(InCollection.NewCopy<FGeometryCollection>()))
|
|
{
|
|
const TArray<FVector>& Sites = GetValue<TArray<FVector>>(Context, &Points);
|
|
if (Sites.Num() > 0)
|
|
{
|
|
//
|
|
// Compute BoundingBox for ManagedArrayIn
|
|
//
|
|
FBox BoundingBox(ForceInit);
|
|
|
|
if (InCollection.HasAttribute("Transform", FGeometryCollection::TransformGroup) &&
|
|
InCollection.HasAttribute("Parent", FGeometryCollection::TransformGroup) &&
|
|
InCollection.HasAttribute("TransformIndex", FGeometryCollection::GeometryGroup) &&
|
|
InCollection.HasAttribute("BoundingBox", FGeometryCollection::GeometryGroup))
|
|
{
|
|
const TManagedArray<FTransform>& Transforms = InCollection.GetAttribute<FTransform>("Transform", FGeometryCollection::TransformGroup);
|
|
const TManagedArray<int32>& ParentIndices = InCollection.GetAttribute<int32>("Parent", FGeometryCollection::TransformGroup);
|
|
const TManagedArray<int32>& TransformIndices = InCollection.GetAttribute<int32>("TransformIndex", FGeometryCollection::GeometryGroup);
|
|
const TManagedArray<FBox>& BoundingBoxes = InCollection.GetAttribute<FBox>("BoundingBox", FGeometryCollection::GeometryGroup);
|
|
|
|
TArray<FMatrix> TmpGlobalMatrices;
|
|
GeometryCollectionAlgo::GlobalMatrices(Transforms, ParentIndices, TmpGlobalMatrices);
|
|
|
|
if (TmpGlobalMatrices.Num() > 0)
|
|
{
|
|
for (int32 BoxIdx = 0; BoxIdx < BoundingBoxes.Num(); ++BoxIdx)
|
|
{
|
|
const int32 TransformIndex = TransformIndices[BoxIdx];
|
|
BoundingBox += BoundingBoxes[BoxIdx].TransformBy(TmpGlobalMatrices[TransformIndex]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Compute Voronoi Bounds
|
|
//
|
|
FBox VoronoiBounds = BoundingBox;
|
|
VoronoiBounds += FBox(Sites);
|
|
|
|
float GroutVal = GetValue<float>(Context, &Grout);
|
|
float AmplitudeVal = GetValue<float>(Context, &Amplitude);
|
|
int32 OctaveNumberVal = GetValue<int32>(Context, &OctaveNumber);
|
|
float PersistenceVal = GetValue<float>(Context, &Persistence);
|
|
|
|
VoronoiBounds = VoronoiBounds.ExpandBy(GetMaxVertexMovement(GroutVal, AmplitudeVal, OctaveNumberVal, PersistenceVal) + KINDA_SMALL_NUMBER);
|
|
|
|
//
|
|
// Voronoi Fracture
|
|
//
|
|
FNoiseSettings NoiseSettings;
|
|
NoiseSettings.Amplitude = AmplitudeVal;
|
|
NoiseSettings.Frequency = GetValue<float>(Context, &Frequency);
|
|
NoiseSettings.Octaves = OctaveNumberVal;
|
|
NoiseSettings.PointSpacing = GetValue<float>(Context, &PointSpacing);
|
|
NoiseSettings.Lacunarity = GetValue<float>(Context, &Lacunarity);
|
|
NoiseSettings.Persistence = GetValue<float>(Context, &Persistence);;
|
|
|
|
FVoronoiDiagram Voronoi(Sites, VoronoiBounds, .1f);
|
|
|
|
FPlanarCells VoronoiPlanarCells = FPlanarCells(Sites, Voronoi);
|
|
VoronoiPlanarCells.InternalSurfaceMaterials.NoiseSettings = NoiseSettings;
|
|
|
|
const TArrayView<const int32>& TransformIndicesArray(TransformIndices.GetConstArray());
|
|
|
|
float CollisionSampleSpacingVal = GetValue<float>(Context, &CollisionSampleSpacing);
|
|
float RandomSeedVal = GetValue<float>(Context, &RandomSeed);
|
|
|
|
int ResultGeometryIndex = CutMultipleWithPlanarCells(VoronoiPlanarCells, *GeomCollection, TransformIndicesArray, GroutVal, CollisionSampleSpacingVal, RandomSeedVal, FTransform().Identity);
|
|
|
|
SetValue<FManagedArrayCollection>(Context, (const FManagedArrayCollection&)(*GeomCollection), &Collection);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FPlaneCutterDataflowNode::Evaluate(Dataflow::FContext& Context, const FDataflowOutput* Out) const
|
|
{
|
|
if (Out->IsA<FManagedArrayCollection>(&Collection))
|
|
{
|
|
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
|
|
if (TUniquePtr<FGeometryCollection> GeomCollection = TUniquePtr<FGeometryCollection>(InCollection.NewCopy<FGeometryCollection>()))
|
|
{
|
|
TArray<FPlane> CuttingPlanes;
|
|
TArray<FTransform> CuttingPlaneTransforms;
|
|
|
|
float RandomSeedVal = GetValue<float>(Context, &RandomSeed);
|
|
FRandomStream RandStream(RandomSeedVal);
|
|
|
|
FBox Bounds = GetValue<FBox>(Context, &BoundingBox);
|
|
const FVector Extent(Bounds.Max - Bounds.Min);
|
|
|
|
CuttingPlaneTransforms.Reserve(CuttingPlaneTransforms.Num() + NumPlanes);
|
|
for (int32 ii = 0; ii < NumPlanes; ++ii)
|
|
{
|
|
FVector Position(Bounds.Min + FVector(RandStream.FRand(), RandStream.FRand(), RandStream.FRand()) * Extent);
|
|
CuttingPlaneTransforms.Emplace(FTransform(FRotator(RandStream.FRand() * 360.0f, RandStream.FRand() * 360.0f, 0.0f), Position));
|
|
}
|
|
|
|
for (const FTransform& Transform : CuttingPlaneTransforms)
|
|
{
|
|
CuttingPlanes.Add(FPlane(Transform.GetLocation(), Transform.GetUnitAxis(EAxis::Z)));
|
|
}
|
|
|
|
FInternalSurfaceMaterials InternalSurfaceMaterials;
|
|
FNoiseSettings NoiseSettings;
|
|
|
|
float AmplitudeVal = GetValue<float>(Context, &Amplitude);
|
|
if (AmplitudeVal > 0.0f)
|
|
{
|
|
NoiseSettings.Amplitude = AmplitudeVal;
|
|
NoiseSettings.Frequency = GetValue<float>(Context, &Frequency);
|
|
NoiseSettings.Lacunarity = GetValue<float>(Context, &Lacunarity);
|
|
NoiseSettings.Persistence = GetValue<float>(Context, &Persistence);
|
|
NoiseSettings.Octaves = GetValue<int32>(Context, &OctaveNumber);
|
|
NoiseSettings.PointSpacing = GetValue<float>(Context, &PointSpacing);
|
|
|
|
InternalSurfaceMaterials.NoiseSettings = NoiseSettings;
|
|
}
|
|
|
|
if (GeomCollection->HasAttribute("TransformIndex", "Geometry"))
|
|
{
|
|
const TManagedArray<int32>& TransformIndices = GeomCollection->GetAttribute<int32>("TransformIndex", "Geometry");
|
|
const TArrayView<const int32>& TransformIndicesArray(TransformIndices.GetConstArray());
|
|
|
|
float CollisionSampleSpacingVal = GetValue<float>(Context, &CollisionSampleSpacing);
|
|
float GroutVal = GetValue<float>(Context, &Grout);
|
|
|
|
int ResultGeometryIndex = CutMultipleWithMultiplePlanes(CuttingPlanes, InternalSurfaceMaterials, *GeomCollection, TransformIndicesArray, GroutVal, CollisionSampleSpacingVal, RandomSeedVal, FTransform().Identity);
|
|
|
|
SetValue<FManagedArrayCollection>(Context, (const FManagedArrayCollection&)(*GeomCollection), &Collection);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|