// Copyright Epic Games, Inc. All Rights Reserved. #include "Dataflow/GeometryCollectionMaterialNodes.h" #include "Dataflow/DataflowCore.h" #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 UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionMaterialNodes) namespace UE::Dataflow { void GeometryCollectionMaterialNodes() { DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FAddMaterialToCollectionDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FReAssignMaterialInCollectionDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMaterialsInfoDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetMaterialFromMaterialsArrayDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSetMaterialInMaterialsArrayDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeMaterialDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FMakeMaterialsArrayDataflowNode); } } void FAddMaterialToCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Collection) || Out->IsA>>(&Materials)) { FManagedArrayCollection InCollection = GetValue(Context, &Collection); TArray> InMaterials = GetValue>>(Context, &Materials); const FDataflowFaceSelection& InFaceSelection = GetValue(Context, &FaceSelection); TObjectPtr InOutsideMaterial = GetValue>(Context, &OutsideMaterial); TObjectPtr InInsideMaterial = GetValue>(Context, &InsideMaterial); int32 NewIndex; if (InCollection.HasAttribute("Internal", FGeometryCollection::FacesGroup)) { if (bAssignOutsideMaterial || bAssignInsideMaterial) { TManagedArray& MaterialIDs = InCollection.ModifyAttribute("MaterialID", FGeometryCollection::FacesGroup); const TManagedArray& Internals = InCollection.GetAttribute("Internal", FGeometryCollection::FacesGroup); if (bAssignOutsideMaterial) { NewIndex = InMaterials.Add(InOutsideMaterial); // Update MaterialIdx for selected outside faces for (int32 FaceIdx = 0; FaceIdx < InFaceSelection.Num(); ++FaceIdx) { if (!Internals[FaceIdx] && InFaceSelection.IsSelected(FaceIdx)) { MaterialIDs[FaceIdx] = NewIndex; } } } if (bAssignInsideMaterial) { NewIndex = InMaterials.Add(InInsideMaterial); // Update MaterialIdx for selected inside faces for (int32 FaceIdx = 0; FaceIdx < InFaceSelection.Num(); ++FaceIdx) { if (Internals[FaceIdx] && InFaceSelection.IsSelected(FaceIdx)) { MaterialIDs[FaceIdx] = NewIndex; } } } } } SetValue(Context, MoveTemp(InMaterials), &Materials); SetValue(Context, MoveTemp(InCollection), &Collection); } } void FReAssignMaterialInCollectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Collection)) { FManagedArrayCollection InCollection = GetValue(Context, &Collection); const FDataflowFaceSelection& InFaceSelection = GetValue(Context, &FaceSelection); const TArray>& InMaterials = GetValue>>(Context, &Materials); int32 InOutsideMaterialIdx = GetValue(Context, &OutsideMaterialIdx); int32 InInsideMaterialIdx = GetValue(Context, &InsideMaterialIdx); if (InMaterials.Num() > 0) { if (InCollection.HasAttribute("Internal", FGeometryCollection::FacesGroup)) { if (bAssignOutsideMaterial || bAssignInsideMaterial) { TManagedArray& MaterialIDs = InCollection.ModifyAttribute("MaterialID", FGeometryCollection::FacesGroup); const TManagedArray& Internals = InCollection.GetAttribute("Internal", FGeometryCollection::FacesGroup); if (bAssignOutsideMaterial) { if (InOutsideMaterialIdx >= 0 && InOutsideMaterialIdx < InMaterials.Num()) { // Update MaterialIdx for selected outside faces for (int32 FaceIdx = 0; FaceIdx < InFaceSelection.Num(); ++FaceIdx) { if (!Internals[FaceIdx] && InFaceSelection.IsSelected(FaceIdx)) { MaterialIDs[FaceIdx] = InOutsideMaterialIdx; } } } } if (bAssignInsideMaterial) { if (InInsideMaterialIdx >= 0 && InInsideMaterialIdx < InMaterials.Num()) { // Update MaterialIdx for selected inside faces for (int32 FaceIdx = 0; FaceIdx < InFaceSelection.Num(); ++FaceIdx) { if (Internals[FaceIdx] && InFaceSelection.IsSelected(FaceIdx)) { MaterialIDs[FaceIdx] = InInsideMaterialIdx; } } } } } } } // move the collection to the output to avoid making another copy SetValue(Context, MoveTemp(InCollection), &Collection); SetValue(Context, InMaterials, &Materials); } } void FMaterialsInfoDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&String)) { const TArray>& InMaterials = GetValue>>(Context, &Materials); FString OutputStr; OutputStr.Appendf(TEXT("\n----------------------------------------\n")); OutputStr.Appendf(TEXT("Number of Materials: %d\n"), InMaterials.Num()); int32 Idx = 0; for (const TObjectPtr& Material : InMaterials) { OutputStr.Appendf(TEXT("%4d: %s\n"), Idx, *(Material->GetFullName())); Idx++; } OutputStr.Appendf(TEXT("----------------------------------------\n")); SetValue(Context, OutputStr, &String); } } void FGetMaterialFromMaterialsArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>(&Material)) { const TArray>& InMaterials = GetValue>>(Context, &Materials); int32 InMaterialIdx = GetValue(Context, &MaterialIdx); if (InMaterials.Num() > 0) { if (InMaterialIdx >= 0 && InMaterialIdx < InMaterials.Num()) { SetValue(Context, InMaterials[InMaterialIdx], &Material); return; } } SetValue(Context, TObjectPtr(), &Material); } } void FSetMaterialInMaterialsArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>>(&Materials)) { TArray> InMaterials = GetValue>>(Context, &Materials); TObjectPtr InMaterial = GetValue>(Context, &Material); int32 InMaterialIdx = GetValue(Context, &MaterialIdx); if (Operation == ESetMaterialOperationTypeEnum::Dataflow_SetMaterialOperationType_Add) { InMaterials.Add(InMaterial); } else { if (InMaterialIdx >= 0 && InMaterialIdx < InMaterials.Num()) { InMaterials.Insert(InMaterial, InMaterialIdx); } } SetValue(Context, MoveTemp(InMaterials), &Materials); } } void FMakeMaterialDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>(&Material)) { SetValue(Context, InMaterial, &Material); } } void FMakeMaterialsArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>>(&Materials)) { SetValue(Context, TArray>(), &Materials); } }