Files
UnrealEngine/Engine/Plugins/Interchange/Runtime/Source/Parsers/Fbx/Private/FbxHelper.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

350 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "FbxHelper.h"
#include "CoreMinimal.h"
#include "FbxAPI.h"
#include "FbxConvert.h"
#include "FbxInclude.h"
#include "InterchangeHelper.h"
#include "Nodes/InterchangeBaseNode.h"
#include "Nodes/InterchangeUserDefinedAttribute.h"
#define GeneratedLODNameSuffix "_GeneratedLOD_"
namespace UE
{
namespace Interchange
{
namespace Private
{
FString FFbxHelper::GetMeshName(FbxGeometryBase* Mesh) const
{
if (!Mesh)
{
return {};
}
FString DefaultPrefix;
if (Mesh->GetAttributeType() == FbxNodeAttribute::eMesh)
{
DefaultPrefix = TEXT("Mesh");
}
else if (Mesh->GetAttributeType() == FbxNodeAttribute::eShape)
{
DefaultPrefix = TEXT("Shape");
}
return GetNodeAttributeName(Mesh, DefaultPrefix);
}
FString FFbxHelper::GetMeshUniqueID(FbxGeometryBase* Mesh) const
{
if (!Mesh)
{
return {};
}
FString MeshUniqueID;
if (Mesh->GetAttributeType() == FbxNodeAttribute::eMesh)
{
MeshUniqueID = TEXT("Mesh");
}
else if (Mesh->GetAttributeType() == FbxNodeAttribute::eShape)
{
MeshUniqueID = TEXT("Shape");
}
return GetNodeAttributeUniqueID(Mesh, MeshUniqueID);
}
FString FFbxHelper::GetNodeAttributeName(FbxNodeAttribute* NodeAttribute, const FStringView DefaultNamePrefix) const
{
FString NodeAttributeName = FFbxHelper::GetFbxObjectName(NodeAttribute);
if (NodeAttributeName.IsEmpty())
{
if (NodeAttribute->GetNodeCount() > 0)
{
NodeAttributeName = FString(DefaultNamePrefix) + TEXT("_") + FFbxHelper::GetFbxObjectName(NodeAttribute->GetNode(0));
}
else
{
uint64 UniqueFbxObjectID = NodeAttribute->GetUniqueID();
NodeAttributeName += GetUniqueIDString(UniqueFbxObjectID);
}
}
return NodeAttributeName;
}
FString FFbxHelper::GetNodeAttributeUniqueID(FbxNodeAttribute* NodeAttribute, const FStringView Prefix) const
{
if (!NodeAttribute)
{
return {};
}
FString NodeAttributeUniqueID = FString(TEXT("\\")) + Prefix + TEXT("\\");
FString NodeAttributeName = FFbxHelper::GetFbxObjectName(NodeAttribute);
if (NodeAttributeName.IsEmpty())
{
if (NodeAttribute->GetNodeCount() > 0)
{
NodeAttributeName = FFbxHelper::GetFbxNodeHierarchyName(NodeAttribute->GetNode(0));
}
else
{
NodeAttributeName = GetNodeAttributeName(NodeAttribute, Prefix);
}
}
NodeAttributeUniqueID += NodeAttributeName;
return NodeAttributeUniqueID;
}
FString FFbxHelper::GetFbxPropertyName(const FbxProperty& Property) const
{
FString PropertyName = FFbxConvert::MakeString(Property.GetName());
UE::Interchange::SanitizeName(PropertyName);
return PropertyName;
}
FString FFbxHelper::GetFbxObjectName(const FbxObject* Object, bool bIsJoint) const
{
if (!Object)
{
return FString();
}
FString ObjName = FFbxConvert::MakeString(Object->GetName());
ManageNamespace(ObjName);
UE::Interchange::SanitizeName(ObjName, bIsJoint);
return ObjName;
}
FString FFbxHelper::GetFbxNodeHierarchyName(const FbxNode* Node) const
{
if (!Node)
{
return FString();
}
TArray<FString> UniqueIDTokens;
const FbxNode* ParentNode = Node;
while (ParentNode)
{
//As we don't want the name to have the namespace removed,
//we manually generate the name here:
FString ParentNodeName = FFbxConvert::MakeString(ParentNode->GetName());
UE::Interchange::SanitizeName(ParentNodeName);
UniqueIDTokens.Add(ParentNodeName);
ParentNode = ParentNode->GetParent();
}
FString UniqueID;
for (int32 TokenIndex = UniqueIDTokens.Num() - 1; TokenIndex >= 0; TokenIndex--)
{
UniqueID += UniqueIDTokens[TokenIndex];
if (TokenIndex > 0)
{
UniqueID += TEXT(".");
}
}
return UniqueID;
}
void FFbxHelper::ManageNamespace(FString& ObjectName) const
{
if (bKeepFbxNamespace)
{
if (ObjectName.Contains(TEXT(":")))
{
ObjectName.ReplaceInline(TEXT(":"), TEXT("_"));
}
}
else
{
// Remove namespaces
int32 LastNamespaceTokenIndex = INDEX_NONE;
if (ObjectName.FindLastChar(TEXT(':'), LastNamespaceTokenIndex))
{
//+1 to remove the ':' character we found
ObjectName.RightChopInline(LastNamespaceTokenIndex + 1, EAllowShrinking::Yes);
}
}
}
void FFbxHelper::ManageNamespaceAndRenameObject(FString& ObjectName, FbxObject* Object) const
{
if (bKeepFbxNamespace)
{
if (ObjectName.Contains(TEXT(":")))
{
ObjectName.ReplaceInline(TEXT(":"), TEXT("_"));
Object->SetName(TCHAR_TO_UTF8(*ObjectName));
}
}
else
{
// Remove namespaces
int32 LastNamespaceTokenIndex = INDEX_NONE;
if (ObjectName.FindLastChar(TEXT(':'), LastNamespaceTokenIndex))
{
//+1 to remove the ':' character we found
ObjectName.RightChopInline(LastNamespaceTokenIndex + 1, EAllowShrinking::Yes);
Object->SetName(TCHAR_TO_UTF8(*ObjectName));
}
}
}
FString FFbxHelper::GetUniqueIDString(const uint64 UniqueID) const
{
FStringFormatNamedArguments FormatArguments;
FormatArguments.Add(TEXT("UniqueID"), UniqueID);
return FString::Format(TEXT("{UniqueID}"), FormatArguments);
}
void ProcessCustomAttribute(FFbxParser& Parser, UInterchangeBaseNode* UnrealNode, FbxProperty Property, const TOptional<FString>& PayloadKey)
{
FString PropertyName = Parser.GetFbxHelper()->GetFbxPropertyName(Property);
switch (Property.GetPropertyDataType().GetType())
{
case EFbxType::eFbxBool:
{
bool PropertyValue = Property.Get<bool>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxChar:
{
int8 PropertyValue = Property.Get<int8>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxUChar:
{
uint8 PropertyValue = Property.Get<uint8>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxShort:
{
int16 PropertyValue = Property.Get<int16>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxUShort:
{
uint16 PropertyValue = Property.Get<uint16>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxInt:
{
int32 PropertyValue = Property.Get<int32>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxUInt:
{
uint32 PropertyValue = Property.Get<uint32>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxLongLong:
{
int64 PropertyValue = Property.Get<int64>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxULongLong:
{
uint64 PropertyValue = Property.Get<uint64>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxHalfFloat:
{
FbxHalfFloat HalfFloat = Property.Get<FbxHalfFloat>();
FFloat16 PropertyValue = FFloat16(HalfFloat.value());
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxFloat:
{
float PropertyValue = Property.Get<float>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxDouble:
{
double PropertyValue = Property.Get<double>();
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxDouble2:
{
FbxDouble2 Vec = Property.Get<FbxDouble2>();
FVector2D PropertyValue = FVector2D(Vec[0], Vec[1]);
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxDouble3:
{
FbxDouble3 Vec = Property.Get<FbxDouble3>();
FVector3d PropertyValue = FVector3d(Vec[0], Vec[1], Vec[2]);
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxDouble4:
{
FbxDouble4 Vec = Property.Get<FbxDouble4>();
FVector4d PropertyValue = FVector4d(Vec[0], Vec[1], Vec[2], Vec[3]);
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxEnum:
{
//Convert enum to uint8
FbxEnum EnumValue = Property.Get<FbxEnum>();
uint8 PropertyValue = static_cast<uint8>(EnumValue);
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
case EFbxType::eFbxString:
{
FbxString StringValue = Property.Get<FbxString>();
FString PropertyValue = FFbxConvert::MakeString(StringValue.Buffer());
UInterchangeUserDefinedAttributesAPI::CreateUserDefinedAttribute(UnrealNode, PropertyName, PropertyValue, PayloadKey);
}
break;
}
}
void ProcessCustomAttributes(FFbxParser& Parser, FbxObject* Object, UInterchangeBaseNode* UnrealNode)
{
FbxProperty Property = Object->GetFirstProperty();
//Add all custom Attributes for the node
while (Property.IsValid())
{
EFbxType PropertyType = Property.GetPropertyDataType().GetType();
if (Property.GetFlag(FbxPropertyFlags::eUserDefined))
{
ProcessCustomAttribute(Parser, UnrealNode, Property);
}
//Inspect next node property
Property = Object->GetNextProperty(Property);
}
}
}//ns Private
}//ns Interchange
}//ns UE