Files
UnrealEngine/Engine/Plugins/Runtime/GeometryProcessing/Source/DynamicMesh/Public/Operations/TransferDynamicMeshAttributes.h
2025-05-18 13:04:45 +08:00

200 lines
6.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GeometryTypes.h"
#include "UObject/NameTypes.h"
#include "TransformTypes.h"
#define UE_API DYNAMICMESH_API
// Forward declarations
class FProgressCancel;
namespace UE::Geometry
{
class FDynamicMesh3;
template<typename MeshType> class TMeshAABBTree3;
typedef TMeshAABBTree3<FDynamicMesh3> FDynamicMeshAABBTree3;
class FMeshNormals;
}
namespace UE
{
namespace Geometry
{
/**
* Transfer vertex colors from one mesh (source) to another (target).
*/
class FTransferVertexColorAttribute
{
public:
enum class ETransferMethod : uint8
{
// For every vertex on the target mesh, find the closest point on the surface of the source mesh. If that point
// is within the SearchRadius, and their normals differ by less than the NormalThreshold, then we directly copy
// the weights from the source point to the target mesh vertex.
ClosestPointOnSurface = 0,
// Same as the ClosestPointOnSurface but for all the vertices we didn't copy the weights directly, automatically
// compute the smooth weights.
Inpaint = 1
};
//
// Optional Inputs
//
/** Set this to be able to cancel the running operation. */
FProgressCancel* Progress = nullptr;
/** Enable/disable multi-threading. */
bool bUseParallel = true;
/** The transfer method to compute the bone weights. */
ETransferMethod TransferMethod = ETransferMethod::ClosestPointOnSurface;
/** Transform applied to the input target mesh or target point before transfer. */
FTransformSRT3d TargetToWorld = FTransformSRT3d::Identity();
//
// Optional Inputs for ETransferMethod::Inpaint method
//
/** Radius for searching the closest point. If negative, all points are considered. */
double SearchRadius = -1;
/**
* Maximum angle (in radians) difference between target and source point normals to be considered a match.
* If negative, normals are ignored.
*/
double NormalThreshold = -1;
/**
* If true, when the closest point doesn't pass the normal threshold test, will try again with a flipped normal.
* This helps with layered meshes where the "inner" and "outer" layers are close to each other but whose normals
* are pointing in the opposite directions.
*/
bool LayeredMeshSupport = false;
/** The number of optional post-processing smoothing iterations applied to the vertices without the match. */
int32 NumSmoothingIterations = 0;
/** The strength of each post-processing smoothing iteration. */
float SmoothingStrength = 0.0f;
/** If true, will use the intrinsic Delaunay mesh to construct sparse Cotangent Laplacian matrix. */
bool bUseIntrinsicLaplacian = false;
/**
* Optional mask where if ForceInpaint[VertexID] != 0 we want to force the colors for the vertex to be computed
* automatically.
*
* @note Only used when TransferMethod == ETransferMethod::Inpaint.
* The size must be equal to the InTargetMesh.MaxVertexID(), otherwise the mask is ignored.
*/
TArray<float> ForceInpaint;
/**
* Optional subset of target mesh vertices to transfer weights to.
* If left empty, skin weights will be transferred to all target mesh vertices.
*/
TArray<int32> TargetVerticesSubset;
//
// Outputs
//
/** MatchedVertices[VertexID] is set to true for a target mesh vertex ID with a match found, false otherwise. */
TArray<bool> MatchedVertices;
/** Creates vertex instances per triangle to be able to have per-face vertex colors. */
bool bHardEdges = false;
/** Ratio used to blend a vertex between its position and the center of the face (0 = vertex position, 1 = face centroid) */
float BiasRatio = UE_KINDA_SMALL_NUMBER;
protected:
/** Source mesh we are transferring colors from. */
const FDynamicMesh3* SourceMesh = nullptr;
/**
* The caller can optionally specify the source mesh BVH in case this operator is run on multiple target meshes
* while the source mesh remains the same. Otherwise BVH tree will be computed.
*/
const FDynamicMeshAABBTree3* SourceBVH = nullptr;
/** If the caller doesn't pass BVH for the source mesh then we compute one. */
TUniquePtr<FDynamicMeshAABBTree3> InternalSourceBVH;
/** If the source mesh doesn't have per-vertex normals then compute them */
TUniquePtr<FMeshNormals> InternalSourceMeshNormals;
public:
/**
* @param InSourceMesh The mesh we are transferring colors from
* @param SourceBVH Optional source mesh BVH. If not provided, one will be computed internally.
*
* @note Assumes that the InSourceMesh has a primary colors attribute.
*/
UE_API FTransferVertexColorAttribute(const FDynamicMesh3* InSourceMesh, const FDynamicMeshAABBTree3* SourceBVH = nullptr);
UE_API virtual ~FTransferVertexColorAttribute();
/**
* @return EOperationValidationResult::Ok if we can apply operation, or error code if we cannot.
*/
UE_API virtual EOperationValidationResult Validate();
/**
* Transfer the colors from the source mesh to the given target mesh and store the result in the primary colors attribute.
*
* @param InOutTargetMesh Target mesh we are transferring colors into
*
* @return true if the algorithm succeeds, false if it failed or was canceled by the user.
*/
UE_API virtual bool TransferColorsToMesh(FDynamicMesh3& InOutTargetMesh);
/**
* Compute the color for a given point using the ETransferMethod::ClosestPointOnSurface algorithm.
*
* @param OutColor Color computed for the input transformed point.
* @param InPoint Point for which we are computing the color.
* @param InNormal Normal at the input point. Should be set if NormalThreshold >= 0.
*
* @return true if the algorithm succeeds, false if it failed to find the matching point or was canceled by the user.
*/
UE_API bool TransferColorToPoint(FVector4f& OutColor, const FVector3d& InPoint, const FVector3f& InNormal = FVector3f::Zero()) const;
protected:
/** @return if true, abort the computation. */
UE_API virtual bool Cancelled();
/**
* Find the closest point on the surface of the source mesh and return the ID of the triangle containing it and its
* barycentric coordinates.
*
* @return true if point is found, false otherwise
*/
UE_API bool FindClosestPointOnSourceSurface(const FVector3d& InPoint, const FTransformSRT3d& InToWorld, int32& OutTriID, FVector3d& OutBary) const;
/**
* Transfer the colors from the source mesh to the given target mesh using the closest point algorithm.
* @return the number of matching vertices / elements
*/
UE_API int32 TransferUsingClosestPoint(FDynamicMesh3& InOutTargetMesh, const TUniquePtr<FMeshNormals>& InTargetMeshNormals);
};
} // end namespace UE::Geometry
} // end namespace UE
#undef UE_API