5.4 KiB
5.4 KiB
title, date, excerpt, tags, rating
title | date | excerpt | tags | rating |
---|---|---|---|---|
FBXAnimation导入逻辑 | 2023-12-11 11:28:36 | ⭐ |
BVHImport插件中的案例
UObject* UBVHImportFactory::FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& FileName, const TCHAR* Parms, FFeedbackContext* Warn, bool& bOutOperationCanceled)
{
if (!shouldImport) {
return nullptr;
}
bool fileSuccess = BVHFile.ImportData(TCHAR_TO_ANSI(*FileName));
const bool bIsUnattended = (IsAutomatedImport()
|| FApp::IsUnattended()
|| IsRunningCommandlet()
|| GIsRunningUnattendedScript);
// Check if it's a re-import
if (InParent != nullptr)
{
UObject* ExistingObject = StaticFindObject(UObject::StaticClass(), InParent, *InName.ToString());
if (ExistingObject)
{
//reimport逻辑略
}
}
if (fileSuccess)
{
UAnimSequence* AnimSequence = NewObject<UAnimSequence>(InParent, InName, Flags & ~EObjectFlags::RF_Transactional);
if (Skeleton == NULL) {
//创建骨骼资产略
}
else {
AnimSequence->SetSkeleton(Skeleton);//Skeleton bvhSkel
AnimSequence->SetPreviewMesh(PreviewMesh);
}
ExtractAnimDataFromBVHFile(AnimSequence);
return AnimSequence;
}
return nullptr;
}
void UBVHImportFactory::ExtractAnimDataFromBVHFile(UAnimSequence* AnimSequence) {
if (AnimSequence)
{
// create animation
IAnimationDataController& Controller = AnimSequence->GetController();
Controller.OpenBracket(LOCTEXT("ImportBVHAnimation", "Importing BVH Animation"));
Controller.ResetModel();
// Write animation data into animation sequence.
// Extract transform of hip to create root motion.
const FReferenceSkeleton& RefSkeleton = AnimSequence->GetSkeleton()->GetReferenceSkeleton();
const FName RootName = RefSkeleton.GetBoneName(0);
const int32 NumOfKeys = BVHFile.Root->FrameOffset.Num();
AnimSequence->ImportFileFramerate = (float)BVHFile.Header.DataRate;
AnimSequence->ImportResampleFramerate = BVHFile.Header.DataRate;
Controller.SetPlayLength(float(NumOfKeys - 1) / (float)BVHFile.Header.DataRate);
Controller.SetFrameRate(FFrameRate(BVHFile.Header.DataRate, 1));
RecursiveReadKeysFromNode(Controller, BVHFile.Root.Get());
Controller.NotifyPopulated();
Controller.CloseBracket();
AnimSequence->AdditiveAnimType = EAdditiveAnimationType::AAT_None;
AnimSequence->PostEditChange();
FAssetRegistryModule::AssetCreated(AnimSequence);
AnimSequence->MarkPackageDirty();
}
}
void UBVHImportFactory::RecursiveReadKeysFromNode(IAnimationDataController& Controller, FNode* Node)
{
if (Node)
{
Controller.AddBoneTrack(Node->Name,false);
Controller.SetBoneTrackKeys(Node->Name, Node->FrameOffset, Node->FrameQuat, Node->FrameScale,false);
if (Node->Children.Num() > 0)
{
for (NodePtr Child : Node->Children)
{
RecursiveReadKeysFromNode(Controller, Child.Get());
}
}
}
}
UE5中使用FBXSDK导入动画逻辑
- UAnimSequence * UEditorEngine::ImportFbxAnimation
- UAnimSequence * UnFbx::FFbxImporter::ImportAnimations
UE5中FBXSDK相关函数调用方式:
- bool FFbxImporter::OpenFile(FString Filename)
- bool FFbxImporter::ImportFile(FString Filename, bool bPreventMaterialNameClash /=false/)
参考
- Interchange\Runtime\Source\Parsers
- InterchangeFbxParser.Build.cs
- FbxInclude.h:FBXSDK头文件包含问题。
UE5中使用FBXSDK导出动画逻辑
- FFbxExporter::ExportSkeletalMeshToFbx => FFbxExporter::ExportAnimSequence => FFbxExporter::ExportAnimSequenceToFbx
- FFbxExporter::CorrectAnimTrackInterpolation
直接导出会有问题,所以UE在这里做了一步Correct:
// The curve code doesn't differentiate between angles and other data, so an interpolation from 179 to -179
// will cause the bone to rotate all the way around through 0 degrees. So here we make a second pass over the
// rotation tracks to convert the angles into a more interpolation-friendly format.
FFbxExporter::CorrectAnimTrackInterpolation()
{
void FFbxExporter::CorrectAnimTrackInterpolation( TArray<FbxNode*>& BoneNodes, FbxAnimLayer* InAnimLayer )
{
// Add the animation data to the bone nodes
for(int32 BoneIndex = 0; BoneIndex < BoneNodes.Num(); ++BoneIndex)
{
FbxNode* CurrentBoneNode = BoneNodes[BoneIndex];
// Fetch the AnimCurves
FbxAnimCurve* Curves[3];
Curves[0] = CurrentBoneNode->LclRotation.GetCurve(InAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
Curves[1] = CurrentBoneNode->LclRotation.GetCurve(InAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
Curves[2] = CurrentBoneNode->LclRotation.GetCurve(InAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
for(int32 CurveIndex = 0; CurveIndex < 3; ++CurveIndex)
{
FbxAnimCurve* CurrentCurve = Curves[CurveIndex];
CurrentCurve->KeyModifyBegin();
float CurrentAngleOffset = 0.f;
for(int32 KeyIndex = 1; KeyIndex < CurrentCurve->KeyGetCount(); ++KeyIndex)
{
float PreviousOutVal = CurrentCurve->KeyGetValue( KeyIndex-1 );
float CurrentOutVal = CurrentCurve->KeyGetValue( KeyIndex );
float DeltaAngle = (CurrentOutVal + CurrentAngleOffset) - PreviousOutVal;
if(DeltaAngle >= 180)
{
CurrentAngleOffset -= 360;
}
else if(DeltaAngle <= -180)
{
CurrentAngleOffset += 360;
}
CurrentOutVal += CurrentAngleOffset;
CurrentCurve->KeySetValue(KeyIndex, CurrentOutVal);
}
CurrentCurve->KeyModifyEnd();
}
}
}
导入Curve相关逻辑
UnFbx::FFbxImporter::ImportCurveToAnimSequence() => UnFbx::FFbxImporter::ImportCurve()