Files
UnrealEngine/Engine/Plugins/Runtime/GeometryProcessing/Source/GeometryAlgorithms/Private/DynamicMeshMikkTWrapper.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

170 lines
5.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DynamicMeshMikkTWrapper.h"
#include "DynamicMesh/DynamicMesh3.h"
// on platforms that build the mikkt library (win/mac/linux) its build.cs will define this:
#if WITH_MIKKTSPACE
#include "mikktspace.h"
#endif //WITH_MIKKTSPACE
#if WITH_MIKKTSPACE
namespace DynamicMeshMikkTWrapper
{
using namespace UE::Geometry;
namespace DynamicMeshMikkTInterface
{
struct FDynamicMeshInfo
{
const FDynamicMesh3* Mesh;
const FDynamicMeshNormalOverlay* NormalOverlay;
const FDynamicMeshUVOverlay* UVOverlay;
FMeshTangentsd* TangentsOut;
};
int MikkGetNumFaces(const SMikkTSpaceContext* Context)
{
const FDynamicMeshInfo* MeshInfo = (const FDynamicMeshInfo*)(Context->m_pUserData);
return MeshInfo->Mesh->MaxTriangleID();
}
int MikkGetNumVertsOfFace(const SMikkTSpaceContext* Context, const int FaceIdx)
{
const FDynamicMeshInfo* MeshInfo = (const FDynamicMeshInfo*)(Context->m_pUserData);
return MeshInfo->Mesh->IsTriangle(FaceIdx) ? 3 : 0;
}
void MikkGetPosition(const SMikkTSpaceContext* Context, float Position[3], const int FaceIdx, const int VertIdx)
{
const FDynamicMeshInfo* MeshInfo = (const FDynamicMeshInfo*)(Context->m_pUserData);
FIndex3i Triangle = MeshInfo->Mesh->GetTriangle(FaceIdx);
FVector3d VertexPos = MeshInfo->Mesh->GetVertex(Triangle[VertIdx]);
Position[0] = (float)VertexPos.X;
Position[1] = (float)VertexPos.Y;
Position[2] = (float)VertexPos.Z;
}
void MikkGetNormal(const SMikkTSpaceContext* Context, float Normal[3], const int FaceIdx, const int VertIdx)
{
const FDynamicMeshInfo* MeshInfo = (const FDynamicMeshInfo*)(Context->m_pUserData);
FIndex3i NormTriangle = MeshInfo->NormalOverlay->GetTriangle(FaceIdx);
FVector3f Normalf;
if (NormTriangle.A == IndexConstants::InvalidID)
{
Normalf = FVector3f::ZAxisVector;
}
else
{
MeshInfo->NormalOverlay->GetElement(NormTriangle[VertIdx], Normalf);
}
Normal[0] = Normalf.X;
Normal[1] = Normalf.Y;
Normal[2] = Normalf.Z;
}
void MikkGetTexCoord(const SMikkTSpaceContext* Context, float UV[2], const int FaceIdx, const int VertIdx)
{
const FDynamicMeshInfo* MeshInfo = (const FDynamicMeshInfo*)(Context->m_pUserData);
FIndex3i UVTriangle = MeshInfo->UVOverlay->GetTriangle(FaceIdx);
FVector2f UVf;
if (UVTriangle.A == IndexConstants::InvalidID)
{
UV[0] = UV[1] = 0.f;
}
else
{
MeshInfo->UVOverlay->GetElement(UVTriangle[VertIdx], UVf);
UV[0] = UVf.X;
UV[1] = UVf.Y;
}
}
void MikkSetTSpaceBasic(const SMikkTSpaceContext* Context, const float Tangent[3], const float BitangentSign, const int FaceIdx, const int VertIdx)
{
FDynamicMeshInfo* MeshInfo = (FDynamicMeshInfo*)(Context->m_pUserData);
FVector3d Tangentd(Tangent[0], Tangent[1], Tangent[2]);
FIndex3i NormTriangle = MeshInfo->NormalOverlay->GetTriangle(FaceIdx);
FVector3d Normald = (NormTriangle.A != IndexConstants::InvalidID) ? (FVector3d)MeshInfo->NormalOverlay->GetElement(NormTriangle[VertIdx]) : FVector3d::ZAxisVector;
FVector3d Bitangentd = VectorUtil::Bitangent(Normald, Tangentd, -(double)BitangentSign);
MeshInfo->TangentsOut->SetPerTriangleTangent(FaceIdx, VertIdx, Tangentd, Bitangentd);
}
void MikkSetTSpace(const SMikkTSpaceContext* Context, const float Tangent[3], const float BiTangent[3],
const float MagS, const float MagT, const tbool bIsOrientationPreserving,
const int FaceIdx, const int VertIdx)
{
FDynamicMeshInfo* MeshInfo = (FDynamicMeshInfo*)(Context->m_pUserData);
FVector3d Tangentd(Tangent[0], Tangent[1], Tangent[2]);
FVector3d Bitangentd(BiTangent[0], BiTangent[1], BiTangent[2]);
MeshInfo->TangentsOut->SetPerTriangleTangent(FaceIdx, VertIdx, Tangentd, Bitangentd);
}
}
bool IsSupported()
{
return true;
}
bool ComputeTangents(FMeshTangentsd& MeshTangents, int32 TargetUVLayer)
{
if (!MeshTangents.GetMesh())
{
return false;
}
const FDynamicMesh3& SourceMesh = *MeshTangents.GetMesh();
if (!SourceMesh.HasAttributes() || SourceMesh.Attributes()->NumNormalLayers() == 0 || TargetUVLayer < 0 || TargetUVLayer >= SourceMesh.Attributes()->NumUVLayers())
{
return false;
}
MeshTangents.InitializeTriVertexTangents(true);
DynamicMeshMikkTInterface::FDynamicMeshInfo MeshInfo;
MeshInfo.Mesh = &SourceMesh;
MeshInfo.NormalOverlay = SourceMesh.Attributes()->PrimaryNormals();
MeshInfo.UVOverlay = SourceMesh.Attributes()->GetUVLayer(TargetUVLayer);
MeshInfo.TangentsOut = &MeshTangents;
SMikkTSpaceInterface MikkTInterface;
MikkTInterface.m_getNormal = DynamicMeshMikkTInterface::MikkGetNormal;
MikkTInterface.m_getNumFaces = DynamicMeshMikkTInterface::MikkGetNumFaces;
MikkTInterface.m_getNumVerticesOfFace = DynamicMeshMikkTInterface::MikkGetNumVertsOfFace;
MikkTInterface.m_getPosition = DynamicMeshMikkTInterface::MikkGetPosition;
MikkTInterface.m_getTexCoord = DynamicMeshMikkTInterface::MikkGetTexCoord;
MikkTInterface.m_setTSpaceBasic = DynamicMeshMikkTInterface::MikkSetTSpaceBasic;
MikkTInterface.m_setTSpace = nullptr;
SMikkTSpaceContext MikkTContext;
MikkTContext.m_pInterface = &MikkTInterface;
MikkTContext.m_pUserData = (void*)(&MeshInfo);
MikkTContext.m_bIgnoreDegenerates = false;
// execute mikkt
genTangSpaceDefault(&MikkTContext);
return true;
}
}
#else
namespace DynamicMeshMikkTWrapper
{
bool IsSupported()
{
return false;
}
bool ComputeTangents(UE::Geometry::FMeshTangentsd& ComputedTangents, int32 UVLayer)
{
return false;
}
}
#endif