Files
2025-05-18 13:04:45 +08:00

172 lines
7.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "VectorTypes.h"
#include "IntVectorTypes.h"
#include "BoxTypes.h"
#include "Containers/StaticArray.h"
#include "DynamicMesh/DynamicMeshAttributeSet.h"
#define UE_API DYNAMICMESH_API
class FProgressCancel;
namespace UE
{
namespace Geometry
{
class FDynamicMesh3;
enum class ELatticeInterpolation : uint8
{
Linear = 0,
Cubic = 1
};
struct FLatticeExecutionInfo
{
bool bParallel = true;
int CancelCheckSize = 100000; // Number of vertices to process before checking for cancel
};
/**
* Free-form deformation lattice. Initialize it with a mesh and desired resolution, get the initial lattice points out.
* Then pass in deformed lattice points and it will compute deformed mesh vertex positions.
*/
class FFFDLattice
{
public:
/// Linear interpolation information. There should be one of these per mesh vertex.
struct FEmbedding
{
FVector3i LatticeCell = { -1, -1, -1 }; // Original point is in the hexahedron whose Min corner is LatticeCell
FVector3d CellWeighting = { 0,0,0 }; // Original linear interpolation weights of the point in the cell
};
/// Create a lattice that fits the given mesh and has the given resolution along each dimension. Also precompute
/// the weight of each mesh vertex inside the appropriate lattice cell.
UE_API FFFDLattice(const FVector3i& InDims, const FDynamicMesh3& InMesh, float Padding);
/// Create a lattice that fits the oriented box defined by the AABB and Transform, and has the given resolution along each dimension. Also precompute
/// the weight of each mesh vertex inside the appropriate lattice cell. Mesh vertices outside of the oriented bounding box should have a LatticeCell value of {-1, -1, -1}.
UE_API FFFDLattice(const FVector3i& InDims, const FDynamicMesh3* Mesh, float Padding, const FAxisAlignedBox3d& InInitialBounds, const FTransformSRT3d& LatticeTransform = FTransformSRT3d::Identity());
/// Whether the given vertex has a valid embedding, i.e. whether the original vertex location was inside a lattice cell and it would be affected by lattice deformation
UE_API bool VertexHasValidEmbedding(int32 VertexIndex) const;
/// Using the Lattice's current control point positions and the original embedding information, compute the
/// deformed mesh vertex positions.
UE_API void GetDeformedMeshVertexPositions(const TArray<FVector3d>& LatticeControlPoints,
TArray<FVector3d>& OutVertexPositions,
ELatticeInterpolation Interpolation = ELatticeInterpolation::Linear,
FLatticeExecutionInfo ExecutionInfo = FLatticeExecutionInfo(),
FProgressCancel* Progress = nullptr) const;
/// Using the Lattice's current control point positions, the original embedding information, and the original
/// normals contained in an overlay, compute the new rotated normals
UE_API void GetRotatedOverlayNormals(const TArray<FVector3d>& LatticeControlPoints,
const FDynamicMeshNormalOverlay* NormalOverlay,
TArray<FVector3f>& OutNormals,
ELatticeInterpolation Interpolation = ELatticeInterpolation::Linear,
FLatticeExecutionInfo ExecutionInfo = FLatticeExecutionInfo(),
FProgressCancel* Progress = nullptr) const;
/// Using the Lattice's current control point positions, the original embedding information, and the original
/// normals, compute the new rotated normals
UE_API void GetRotatedMeshVertexNormals(const TArray<FVector3d>& LatticeControlPoints,
const TArray<FVector3f>& OriginalNormals,
TArray<FVector3f>& OutNormals,
ELatticeInterpolation Interpolation,
FLatticeExecutionInfo ExecutionInfo,
FProgressCancel* Progress) const;
/// Return the set of lattice corner positions in undeformed state
UE_API void GenerateInitialLatticePositions(TArray<FVector3d>& OutLatticePositions) const;
/// Return the lattice edges by index. The indices refer to the array of lattice positions returned by GenerateInitialLatticePositions
UE_API void GenerateLatticeEdges(TArray<FVector2i>& OutLatticeEdges) const;
/// Number of lattice points in each dimension
const FVector3i& GetDimensions() const
{
return Dimensions;
}
/// 3D size of a lattice cell
const FVector3d& GetCellSize() const
{
return CellSize;
}
/// Extents of the lattice before it is deformed
const FAxisAlignedBox3d& GetInitialBounds() const
{
return InitialBounds;
}
/// Get the index into the flat TArray of positions given the (i,j,k) coordinates in the lattice
int ControlPointIndexFromCoordinates(int i, int j, int k) const
{
int Idx = k + Dimensions.Z * (j + Dimensions.Y * i);
return Idx;
}
/// Get the index into the flat TArray of positions given the (i,j,k) coordinates in the lattice
int ControlPointIndexFromCoordinates(const FVector3i& Index) const
{
return ControlPointIndexFromCoordinates(Index.X, Index.Y, Index.Z);
}
protected:
// Lattice transform
FTransformSRT3d Transform;
// Number of lattice points in each dimension
FVector3i Dimensions;
// Extents of the lattice before it is deformed
FAxisAlignedBox3d InitialBounds;
// 3D size of a lattice cell
FVector3d CellSize;
// Interpolation weights and cell indices per vertex of the input FDynamicMesh3
TArray<FEmbedding> VertexEmbeddings;
// Ccnstructor helper function for setting up lattice data
void InitLattice(float Padding);
/// For each vertex in Mesh, compute the lattice cell it resides in and its weighting
UE_API void ComputeInitialEmbedding(const FDynamicMesh3& Mesh, FLatticeExecutionInfo ExecutionInfo = FLatticeExecutionInfo());
/// Compute cell index and linear interpolation weights for a given point
UE_API FVector3d ComputeTrilinearWeights(const FVector3d& Pt, FVector3i& GridCoordinates) const;
/// Helper for linear interpolation. Returns lattice points at (I,J,K) and (I+1,J,K).
UE_API void GetValuePair(int I, int J, int K, FVector3d& A, FVector3d& B, const TArray<FVector3d>& LatticeControlPoints) const;
/// Use the given cell index and weights to compute the interpolated position
UE_API FVector3d InterpolatedPosition(const FEmbedding& VertexEmbedding, const TArray<FVector3d>& LatticeControlPoints) const;
UE_API FVector3d InterpolatedPositionCubic(const FEmbedding& VertexEmbedding, const TArray<FVector3d>& LatticeControlPoints) const;
UE_API FMatrix3d LinearInterpolationJacobian(const FEmbedding& VertexEmbedding, const TArray<FVector3d>& LatticeControlPoints) const;
UE_API FMatrix3d CubicInterpolationJacobian(const FEmbedding& VertexEmbedding, const TArray<FVector3d>& LatticeControlPoints) const;
/// Clamp the given index to [0, Dims] and return the current lattice point position at the clamped index
UE_API FVector3d ClosestLatticePosition(const FVector3i& VirtualControlPointIndex, const TArray<FVector3d>& LatticeControlPoints) const;
/// Compute the extrapolated position for a "virtual" lattice control point outside of the actual lattice
UE_API FVector3d ExtrapolatedLatticePosition(const FVector3i& VirtualPointIndex, const TArray<FVector3d>& LatticeControlPoints) const;
};
} // end namespace UE::Geometry
} // end namespace UE
#undef UE_API