Files
UnrealEngine/Engine/Plugins/Editor/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODBarycentricUtilities.h
2025-05-18 13:04:45 +08:00

152 lines
5.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include <array>
#include "Math/Vector.h" // For FVector
#include "ProxyLODTwoDTriangleUtilities.h"
namespace ProxyLOD
{
/**
* Double precision array of length 3, used primarily for Barycentric coords.
*/
typedef std::array<double, 3> DArray3d;
// Interpolate Vertex Data to the location given in Barycentric Coords.
template <typename T>
static T InterpolateVertexData(const DArray3d& BarycentricPos, const T(&VertexData)[3])
{
// In order BarycentricCoords = normalized distance from {V1V2 edge, V2V0 edge, V0V1 edge}.
return BarycentricPos[0] * VertexData[0] + BarycentricPos[1] * VertexData[1] + BarycentricPos[2] * VertexData[2];
}
/**
* Compute Scaled Distances for all three sided of a 2d triangle V1V2, V2V0, V0V1 to the given point in the plane.
*
* @param Vertices Define a triangle on a 2d plane.
* @param Point A 2d point, form which to measure the scaled distances.
*
* @param OutScaledDistances Scaled distances to the three edges (V1-V2, V2-V0, V0-V1).
*/
static inline void ComputeScaledDistances(const DTriangle2d& Vertices, const DVec2d& Point, DArray3d& OutScaledDistances)
{
OutScaledDistances[0] = ScaledDistanceToLine(Vertices[1], Vertices[2], Point); // alpha = 0 on V1V2
OutScaledDistances[1] = ScaledDistanceToLine(Vertices[2], Vertices[0], Point); // beta = 0 on V2V0
OutScaledDistances[2] = ScaledDistanceToLine(Vertices[0], Vertices[1], Point); // gamma = 0 on V0V1
}
/**
* Convert pre-computed Scaled Distances to Barycentric coordinates for a 2d triangle V1V2, V2V0, V0V1.
*
* NB: In practice, use ComputeScaledDistances to arrive at signed scaled distances between triangle edges and a point
* If the signs all indicate (i.e. all positive) the point is inside the given triangle,
* use this function to convert to Barycentric coords.
*
* @param Vertices Define a triangle on a 2d plane.
* @param InOutScaledDistances Precomputed scaled distances to a 2d point to be converted to Barycentric on return.
*
*/
static inline void ConvertScaledDistanceToBarycentric(const DTriangle2d& Vertices, DArray3d& InOutScaledDistances)
{
InOutScaledDistances[0] /= ScaledDistanceToLine(Vertices[1], Vertices[2], Vertices[0]); // alpha = 1 at V[0]
InOutScaledDistances[1] /= ScaledDistanceToLine(Vertices[2], Vertices[0], Vertices[1]); // beta = 1 at V[1]
InOutScaledDistances[2] /= ScaledDistanceToLine(Vertices[0], Vertices[1], Vertices[2]); // gamma = 1 at V[2]
}
/**
* Compute the barycentric weights at 2D @param Point assuming the 2D vertices are given in counter clockwise order.
*
* NB: This is for 2D triangles and points.
*
* @param Vertices Define a triangle on a 2d plane.
* @param Point Point on the plane.
*
* @return Barycentric coordinates (alpha, beta, gamma) of the point relative to the input triangle.
* alpha = 1 at Vertices[0], beta = 1 at Vertices[1] and gamma = 1 at Vertices[2]
*/
static DArray3d ComputeBarycentricWeights(const DTriangle2d& Vertices, const DVec2d& Point)
{
// The result
DArray3d Weights;
ComputeScaledDistances(Vertices, Point, Weights);
// The scaled distance between the point and each vertex. Note Weight[i] = 1 when Point = Vi
ConvertScaledDistanceToBarycentric(Vertices, Weights);
return Weights;
}
// Computes the Barycentric weights for a point projected onto the plane of a triangle.
/**
* Compute the barycentric weights at 3D @param Point projected onto the plane of triangle described in 3d.
* assuming triangle ertices are given in counter clockwise order.
*
* NB: This is for 3D triangles and points.
*
* @param Vertices Define a triangle.
* @param Point Point in 3d space.
*
* @return Barycentric coordinates (alpha, beta, gamma) of the point relative to the input triangle.
* alpha = 1 at Vertices[0], beta = 1 at Vertices[1] and gamma = 1 at Vertices[2]
*/
static DArray3d ComputeBarycentricWeights(const FVector3f(&Vertices)[3], const FVector3f& Point)
{
if (1)
{
const FVector3f U = Vertices[1] - Vertices[0];
const FVector3f V = Vertices[2] - Vertices[0];
const FVector3f W = Point - Vertices[0];
const FVector3f NormDir = FVector3f::CrossProduct(U, V);
const float NSqr = FVector3f::DotProduct(NormDir, NormDir);
FVector3f Tmp = FVector3f::CrossProduct(U, W);
double Gamma = FVector3f::DotProduct(Tmp, NormDir) / NSqr;
Tmp = FVector3f::CrossProduct(W, V);
double Beta = FVector3f::DotProduct(Tmp, NormDir) / NSqr;
DArray3d Result = { 1. - Gamma - Beta, Beta, Gamma };
return Result;
}
else
{
// Alternate calculation of the weights at the projected point.
// Should be equivalent (more explicit but slower)
const FVector3f E10 = Vertices[1] - Vertices[0];
const FVector3f E20 = Vertices[2] - Vertices[0];
const FVector3f Ndir = FVector3f::CrossProduct(E10, E20);
float LengthSqr = FVector3f::DotProduct(Ndir, Ndir);
// project point
const FVector3f Pprime = Point - Ndir * FVector3f::DotProduct(Point, Ndir) / LengthSqr;
const FVector3f E21 = Vertices[2] - Vertices[1];
const FVector3f Na = FVector3f::CrossProduct(E21, Pprime - Vertices[1]);
const FVector3f Nb = -FVector3f::CrossProduct(E20, Pprime - Vertices[2]);
const FVector3f Nc = FVector3f::CrossProduct(E10, Pprime - Vertices[0]);
float Alpha = FVector3f::DotProduct(Na, Ndir) / LengthSqr;
float Beta = FVector3f::DotProduct(Nb, Ndir) / LengthSqr;
float Gamma = FVector3f::DotProduct(Nc, Ndir) / LengthSqr;
DArray3d Result = { Alpha, Beta, Gamma };
return Result;
}
}
}