You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#jira UE-140251 #rnx #rb rinat.abdrashitov #preflight 61f47b8274510448a68f54cf #ROBOMERGE-AUTHOR: tyson.brochu #ROBOMERGE-SOURCE: CL 18780378 in //UE5/Release-5.0/... via CL 18780942 via CL 18781364 #ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v903-18687472) [CL 18781666 by tyson brochu in ue5-main branch]
312 lines
8.8 KiB
C++
312 lines
8.8 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "GeometryFlowMeshProcessingModule.h"
|
|
#include "GeometryFlowCoreNodes.h"
|
|
#include "GeometryFlowNodeUtil.h"
|
|
#include "DataTypes/DynamicMeshData.h"
|
|
#include "Util/ProgressCancel.h"
|
|
|
|
namespace UE
|
|
{
|
|
namespace GeometryFlow
|
|
{
|
|
|
|
using namespace UE::Geometry;
|
|
|
|
|
|
class FProcessMeshBaseNode : public FNode
|
|
{
|
|
public:
|
|
static const FString InParamMesh() { return TEXT("Mesh"); }
|
|
static const FString OutParamResultMesh() { return TEXT("ResultMesh"); }
|
|
|
|
public:
|
|
FProcessMeshBaseNode()
|
|
{
|
|
AddInput(InParamMesh(), MakeUnique<FDynamicMeshInput>());
|
|
|
|
AddOutput(OutParamResultMesh(), MakeUnique<FDynamicMeshOutput>());
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
//
|
|
// FProcessMeshBaseNode API that subclasses must/can implement
|
|
//
|
|
|
|
virtual void ProcessMesh(
|
|
const FNamedDataMap& DatasIn,
|
|
const FDynamicMesh3& MeshIn,
|
|
FDynamicMesh3& MeshOut,
|
|
TUniquePtr<FEvaluationInfo>& EvaluationInfo)
|
|
{
|
|
check(false); // subclass must implement ProcessMesh()
|
|
}
|
|
|
|
virtual void ProcessMeshInPlace(
|
|
const FNamedDataMap& DatasIn,
|
|
FDynamicMesh3& MeshInOut,
|
|
TUniquePtr<FEvaluationInfo>& EvaluationInfo)
|
|
{
|
|
ensureMsgf(false, TEXT("TProcessMeshBaseNode::ProcessMeshInPlace called but not defined!"));
|
|
}
|
|
|
|
|
|
virtual void CheckAdditionalInputs(const FNamedDataMap& DatasIn, bool& bRecomputeRequired, bool& bAllInputsValid)
|
|
{
|
|
// none
|
|
}
|
|
|
|
public:
|
|
|
|
virtual void Evaluate(
|
|
const FNamedDataMap& DatasIn,
|
|
FNamedDataMap& DatasOut,
|
|
TUniquePtr<FEvaluationInfo>& EvaluationInfo) override
|
|
{
|
|
if (ensure(DatasOut.Contains(OutParamResultMesh())))
|
|
{
|
|
bool bAllInputsValid = true;
|
|
bool bRecomputeRequired = ( IsOutputAvailable(OutParamResultMesh()) == false );
|
|
TSafeSharedPtr<IData> MeshArg = FindAndUpdateInputForEvaluate(InParamMesh(), DatasIn, bRecomputeRequired, bAllInputsValid);
|
|
CheckAdditionalInputs(DatasIn, bRecomputeRequired, bAllInputsValid);
|
|
if (bAllInputsValid)
|
|
{
|
|
if (bRecomputeRequired)
|
|
{
|
|
// if execution is interrupted by ProgressCancel, make sure this node is recomputed next time through
|
|
ClearAllOutputs();
|
|
|
|
bool bIsMeshMutable = DatasIn.GetDataFlags(InParamMesh()).bIsMutableData;
|
|
if (bIsMeshMutable)
|
|
{
|
|
UE_LOG(LogGeometryFlowMeshProcessing, Display, TEXT("[%s] RECOMPUTING MeshOp In Place!"), *GetIdentifier());
|
|
|
|
FDynamicMesh3 EditableMesh;
|
|
MeshArg->GiveTo<FDynamicMesh3>(EditableMesh, (int)EMeshProcessingDataTypes::DynamicMesh);
|
|
ProcessMeshInPlace(DatasIn, EditableMesh, EvaluationInfo);
|
|
|
|
if (EvaluationInfo && EvaluationInfo->Progress && EvaluationInfo->Progress->Cancelled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// store new result
|
|
TSafeSharedPtr<FDataDynamicMesh> Result = MakeSafeShared<FDataDynamicMesh>();
|
|
Result->MoveData(MoveTemp(EditableMesh));
|
|
SetOutput(OutParamResultMesh(), Result);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogGeometryFlowMeshProcessing, Display, TEXT("[%s] RECOMPUTING MeshOp"), *GetIdentifier());
|
|
|
|
// do we ever want to support using a copy of the source mesh?
|
|
const FDynamicMesh3& SourceMesh = MeshArg->GetDataConstRef<FDynamicMesh3>((int)EMeshProcessingDataTypes::DynamicMesh);
|
|
|
|
// run mesh processing
|
|
FDynamicMesh3 ResultMesh;
|
|
ProcessMesh(DatasIn, SourceMesh, ResultMesh, EvaluationInfo);
|
|
|
|
if (EvaluationInfo && EvaluationInfo->Progress && EvaluationInfo->Progress->Cancelled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// store new result
|
|
TSafeSharedPtr<FDataDynamicMesh> Result = MakeSafeShared<FDataDynamicMesh>();
|
|
Result->MoveData(MoveTemp(ResultMesh));
|
|
SetOutput(OutParamResultMesh(), Result);
|
|
}
|
|
|
|
EvaluationInfo->CountCompute(this);
|
|
}
|
|
DatasOut.SetData(OutParamResultMesh(), GetOutput(OutParamResultMesh()));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* FSimpleInPlaceProcessMeshBaseNode provides a standard pattern for a simple "In-Place" mesh
|
|
* processing operation, eg something like recomputing normals where it would not make
|
|
* sense to cache the output and there are no configuration settings. The subclass only
|
|
* has to implement the ApplyNodeToMesh() function.
|
|
*/
|
|
class FSimpleInPlaceProcessMeshBaseNode : public FProcessMeshBaseNode
|
|
{
|
|
public:
|
|
FSimpleInPlaceProcessMeshBaseNode()
|
|
{
|
|
// we can mutate input mesh
|
|
ConfigureInputFlags(InParamMesh(), FNodeInputFlags::Transformable());
|
|
}
|
|
|
|
virtual void ProcessMesh( const FNamedDataMap& DatasIn, const FDynamicMesh3& MeshIn, FDynamicMesh3& MeshOut, TUniquePtr<FEvaluationInfo>& EvaluationInfo) override
|
|
{
|
|
MeshOut = MeshIn;
|
|
ApplyNodeToMesh(MeshOut, EvaluationInfo);
|
|
}
|
|
|
|
virtual void ProcessMeshInPlace( const FNamedDataMap& DatasIn, FDynamicMesh3& MeshInOut, TUniquePtr<FEvaluationInfo>& EvaluationInfo) override
|
|
{
|
|
ApplyNodeToMesh(MeshInOut, EvaluationInfo);
|
|
}
|
|
|
|
// subclasses only have to implement this
|
|
virtual void ApplyNodeToMesh(FDynamicMesh3& MeshInOut, TUniquePtr<FEvaluationInfo>& EvaluationInfo) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<typename SettingsType>
|
|
class TProcessMeshWithSettingsBaseNode : public FNode
|
|
{
|
|
public:
|
|
using SettingsDataType = TMovableData<SettingsType, SettingsType::DataTypeIdentifier>;
|
|
|
|
public:
|
|
static const FString InParamMesh() { return TEXT("Mesh"); }
|
|
static const FString InParamSettings() { return TEXT("Settings"); }
|
|
static const FString OutParamResultMesh() { return TEXT("ResultMesh"); }
|
|
|
|
protected:
|
|
TProcessMeshWithSettingsBaseNode()
|
|
{
|
|
AddInput(InParamMesh(), MakeUnique<FDynamicMeshInput>());
|
|
AddInput(InParamSettings(), MakeUnique<TBasicNodeInput<SettingsType, SettingsType::DataTypeIdentifier>>());
|
|
|
|
AddOutput(OutParamResultMesh(), MakeUnique<FDynamicMeshOutput>());
|
|
}
|
|
|
|
|
|
virtual void ProcessMesh(
|
|
const FNamedDataMap& DatasIn,
|
|
const SettingsType& SettingsIn,
|
|
const FDynamicMesh3& MeshIn,
|
|
FDynamicMesh3& MeshOut,
|
|
TUniquePtr<FEvaluationInfo>& EvaluationInfo)
|
|
{
|
|
}
|
|
|
|
virtual void ProcessMeshInPlace(
|
|
const FNamedDataMap& DatasIn,
|
|
const SettingsType& SettingsIn,
|
|
FDynamicMesh3& MeshInOut,
|
|
TUniquePtr<FEvaluationInfo>& EvaluationInfo)
|
|
{
|
|
ensureMsgf(false, TEXT("TProcessMeshWithSettingsBaseNode::ProcessMeshInPlace called but not defined!"));
|
|
}
|
|
|
|
|
|
virtual void CheckAdditionalInputs(const FNamedDataMap& DatasIn, bool& bRecomputeRequired, bool& bAllInputsValid)
|
|
{
|
|
// none
|
|
}
|
|
|
|
public:
|
|
|
|
virtual void Evaluate(
|
|
const FNamedDataMap& DatasIn,
|
|
FNamedDataMap& DatasOut,
|
|
TUniquePtr<FEvaluationInfo>& EvaluationInfo) override
|
|
{
|
|
if (ensure(DatasOut.Contains(OutParamResultMesh())))
|
|
{
|
|
bool bAllInputsValid = true;
|
|
bool bRecomputeRequired = ( IsOutputAvailable(OutParamResultMesh()) == false );
|
|
TSafeSharedPtr<IData> MeshArg = FindAndUpdateInputForEvaluate(InParamMesh(), DatasIn, bRecomputeRequired, bAllInputsValid);
|
|
TSafeSharedPtr<IData> SettingsArg = FindAndUpdateInputForEvaluate(InParamSettings(), DatasIn, bRecomputeRequired, bAllInputsValid);
|
|
CheckAdditionalInputs(DatasIn, bRecomputeRequired, bAllInputsValid);
|
|
if (bAllInputsValid)
|
|
{
|
|
if (bRecomputeRequired)
|
|
{
|
|
// if execution is interrupted by ProgressCancel, make sure this node is recomputed next time through
|
|
ClearAllOutputs();
|
|
|
|
// always make a copy of settings
|
|
SettingsType Settings;
|
|
SettingsArg->GetDataCopy(Settings, SettingsType::DataTypeIdentifier);
|
|
|
|
bool bIsMeshMutable = DatasIn.GetDataFlags(InParamMesh()).bIsMutableData;
|
|
if (bIsMeshMutable)
|
|
{
|
|
UE_LOG(LogGeometryFlowMeshProcessing, Display, TEXT("[%s] RECOMPUTING MeshOp In Place!"), *GetIdentifier());
|
|
|
|
FDynamicMesh3 EditableMesh;
|
|
MeshArg->GiveTo<FDynamicMesh3>(EditableMesh, (int)EMeshProcessingDataTypes::DynamicMesh);
|
|
ProcessMeshInPlace(DatasIn, Settings, EditableMesh, EvaluationInfo);
|
|
|
|
if (EvaluationInfo && EvaluationInfo->Progress && EvaluationInfo->Progress->Cancelled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// store new result
|
|
TSafeSharedPtr<FDataDynamicMesh> Result = MakeSafeShared<FDataDynamicMesh>();
|
|
Result->MoveData(MoveTemp(EditableMesh));
|
|
SetOutput(OutParamResultMesh(), Result);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogGeometryFlowMeshProcessing, Display, TEXT("[%s] RECOMPUTING MeshOp"), *GetIdentifier());
|
|
|
|
// do we ever want to support using a copy of the source mesh?
|
|
const FDynamicMesh3& SourceMesh = MeshArg->GetDataConstRef<FDynamicMesh3>((int)EMeshProcessingDataTypes::DynamicMesh);
|
|
|
|
// run mesh processing
|
|
FDynamicMesh3 ResultMesh;
|
|
ProcessMesh(DatasIn, Settings, SourceMesh, ResultMesh, EvaluationInfo);
|
|
|
|
if (EvaluationInfo && EvaluationInfo->Progress && EvaluationInfo->Progress->Cancelled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// store new result
|
|
TSafeSharedPtr<FDataDynamicMesh> Result = MakeSafeShared<FDataDynamicMesh>();
|
|
Result->MoveData(MoveTemp(ResultMesh));
|
|
SetOutput(OutParamResultMesh(), Result);
|
|
}
|
|
|
|
EvaluationInfo->CountCompute(this);
|
|
}
|
|
DatasOut.SetData(OutParamResultMesh(), GetOutput(OutParamResultMesh()));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // end namespace GeometryFlow
|
|
} // end namespace UE
|
|
|
|
|