Skip to content

Commit ca1a3c9

Browse files
author
Roberto De Ioris
committed
added api for importing fbx transform curves
1 parent a943cea commit ca1a3c9

File tree

3 files changed

+178
-1
lines changed

3 files changed

+178
-1
lines changed

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,8 @@ static PyMethodDef ue_PyUObject_methods[] = {
920920
{ "sequencer_remove_camera_cut_track", (PyCFunction)py_ue_sequencer_remove_camera_cut_track, METH_VARARGS, "" },
921921
{ "sequencer_remove_master_track", (PyCFunction)py_ue_sequencer_remove_master_track, METH_VARARGS, "" },
922922
{ "sequencer_remove_track", (PyCFunction)py_ue_sequencer_remove_track, METH_VARARGS, "" },
923+
{ "sequencer_import_fbx_transform", (PyCFunction)py_ue_sequencer_import_fbx_transform, METH_VARARGS, "" },
924+
923925
#endif
924926
{ "sequencer_sections", (PyCFunction)py_ue_sequencer_sections, METH_VARARGS, "" },
925927
{ "sequencer_track_sections", (PyCFunction)py_ue_sequencer_track_sections, METH_VARARGS, "" },

Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "Sections/MovieSceneVectorSection.h"
2121
#include "Runtime/MovieScene/Public/MovieSceneFolder.h"
2222
#include "Runtime/MovieScene/Public/MovieSceneSpawnable.h"
23+
#include "Editor/UnrealEd/Public/FbxImporter.h"
24+
#include "Editor/MovieSceneTools/Public/MatineeImportTools.h"
2325
#endif
2426

2527
#if WITH_EDITOR
@@ -752,7 +754,7 @@ PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args)
752754
section_transform->AddKey(time, ty, (EMovieSceneKeyInterpolation)interpolation);
753755
section_transform->AddKey(time, tz, (EMovieSceneKeyInterpolation)interpolation);
754756

755-
757+
756758
FTransformKey rx = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::X, transform.GetRotation().Euler().X, unwind);
757759
FTransformKey ry = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::Y, transform.GetRotation().Euler().Y, unwind);
758760
FTransformKey rz = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::Z, transform.GetRotation().Euler().Z, unwind);
@@ -1017,5 +1019,177 @@ PyObject *py_ue_sequencer_get_display_name(ue_PyUObject *self, PyObject * args)
10171019

10181020
return PyErr_Format(PyExc_Exception, "the uobject does not expose the GetDefaultDisplayName() method");
10191021
}
1022+
1023+
PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * args)
1024+
{
1025+
ue_py_check(self);
1026+
1027+
char *filename;
1028+
char *nodename;
1029+
PyObject *py_force_front_x_axis = nullptr;
1030+
1031+
if (!PyArg_ParseTuple(args, "ss|o:sequencer_import_fbx_transform", &filename, &nodename, &py_force_front_x_axis))
1032+
return nullptr;
1033+
1034+
UMovieScene3DTransformSection *section = ue_py_check_type<UMovieScene3DTransformSection>(self);
1035+
if (!section)
1036+
return PyErr_Format(PyExc_Exception, "uobject is not a UMovieScene3DTransformSection");
1037+
1038+
UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance();
1039+
1040+
UnFbx::FBXImportOptions* ImportOptions = FbxImporter->GetImportOptions();
1041+
bool bConverteScene = ImportOptions->bConvertScene;
1042+
bool bConverteSceneUnit = ImportOptions->bConvertSceneUnit;
1043+
bool bForceFrontXAxis = ImportOptions->bForceFrontXAxis;
1044+
1045+
ImportOptions->bConvertScene = true;
1046+
ImportOptions->bConvertSceneUnit = true;
1047+
ImportOptions->bForceFrontXAxis = py_force_front_x_axis && PyObject_IsTrue(py_force_front_x_axis);
1048+
1049+
FString FbxFilename = FString(UTF8_TO_TCHAR(filename));
1050+
FString FbxNodeName = FString(UTF8_TO_TCHAR(nodename));
1051+
1052+
const FString Extension = FPaths::GetExtension(FbxFilename);
1053+
if (!FbxImporter->ImportFromFile(FbxFilename, Extension, true))
1054+
{
1055+
FbxImporter->ReleaseScene();
1056+
ImportOptions->bConvertScene = bConverteScene;
1057+
ImportOptions->bConvertSceneUnit = bConverteSceneUnit;
1058+
ImportOptions->bForceFrontXAxis = bForceFrontXAxis;
1059+
return PyErr_Format(PyExc_Exception, "unable to import Fbx file");
1060+
}
1061+
1062+
UnFbx::FFbxCurvesAPI CurveAPI;
1063+
FbxImporter->PopulateAnimatedCurveData(CurveAPI);
1064+
1065+
TArray<FString> AllNodeNames;
1066+
CurveAPI.GetAllNodeNameArray(AllNodeNames);
1067+
1068+
for (FString NodeName : AllNodeNames)
1069+
{
1070+
if (NodeName != FbxNodeName)
1071+
continue;
1072+
1073+
// Look for transforms explicitly
1074+
FInterpCurveFloat Translation[3];
1075+
FInterpCurveFloat EulerRotation[3];
1076+
FInterpCurveFloat Scale[3];
1077+
FTransform DefaultTransform;
1078+
CurveAPI.GetConvertedTransformCurveData(NodeName, Translation[0], Translation[1], Translation[2], EulerRotation[0], EulerRotation[1], EulerRotation[2], Scale[0], Scale[1], Scale[2], DefaultTransform);
1079+
1080+
for (int32 ChannelIndex = 0; ChannelIndex < 3; ++ChannelIndex)
1081+
{
1082+
EAxis::Type ChannelAxis = EAxis::X;
1083+
if (ChannelIndex == 1)
1084+
{
1085+
ChannelAxis = EAxis::Y;
1086+
}
1087+
else if (ChannelIndex == 2)
1088+
{
1089+
ChannelAxis = EAxis::Z;
1090+
}
1091+
section->GetTranslationCurve(ChannelAxis).SetDefaultValue(DefaultTransform.GetLocation()[ChannelIndex]);
1092+
section->GetRotationCurve(ChannelAxis).SetDefaultValue(DefaultTransform.GetRotation().Euler()[ChannelIndex]);
1093+
section->GetScaleCurve(ChannelAxis).SetDefaultValue(DefaultTransform.GetScale3D()[ChannelIndex]);
1094+
}
1095+
1096+
float MinTime = FLT_MAX;
1097+
float MaxTime = -FLT_MAX;
1098+
1099+
const int NumCurves = 3; // Trans, Rot, Scale
1100+
for (int32 CurveIndex = 0; CurveIndex < NumCurves; ++CurveIndex)
1101+
{
1102+
for (int32 ChannelIndex = 0; ChannelIndex < 3; ++ChannelIndex)
1103+
{
1104+
EAxis::Type ChannelAxis = EAxis::X;
1105+
if (ChannelIndex == 1)
1106+
{
1107+
ChannelAxis = EAxis::Y;
1108+
}
1109+
else if (ChannelIndex == 2)
1110+
{
1111+
ChannelAxis = EAxis::Z;
1112+
}
1113+
1114+
FInterpCurveFloat* CurveFloat = nullptr;
1115+
FRichCurve* ChannelCurve = nullptr;
1116+
bool bNegative = false;
1117+
1118+
if (CurveIndex == 0)
1119+
{
1120+
CurveFloat = &Translation[ChannelIndex];
1121+
ChannelCurve = &section->GetTranslationCurve(ChannelAxis);
1122+
if (ChannelIndex == 1)
1123+
{
1124+
bNegative = true;
1125+
}
1126+
}
1127+
else if (CurveIndex == 1)
1128+
{
1129+
CurveFloat = &EulerRotation[ChannelIndex];
1130+
ChannelCurve = &section->GetRotationCurve(ChannelAxis);
1131+
if (ChannelIndex == 1 || ChannelIndex == 2)
1132+
{
1133+
bNegative = true;
1134+
}
1135+
}
1136+
else if (CurveIndex == 2)
1137+
{
1138+
CurveFloat = &Scale[ChannelIndex];
1139+
ChannelCurve = &section->GetScaleCurve(ChannelAxis);
1140+
}
1141+
1142+
if (ChannelCurve != nullptr && CurveFloat != nullptr)
1143+
{
1144+
ChannelCurve->Reset();
1145+
1146+
for (int32 KeyIndex = 0; KeyIndex < CurveFloat->Points.Num(); ++KeyIndex)
1147+
{
1148+
MinTime = FMath::Min(MinTime, CurveFloat->Points[KeyIndex].InVal);
1149+
MaxTime = FMath::Max(MaxTime, CurveFloat->Points[KeyIndex].InVal);
1150+
1151+
float ArriveTangent = CurveFloat->Points[KeyIndex].ArriveTangent;
1152+
if (KeyIndex > 0)
1153+
{
1154+
ArriveTangent = ArriveTangent / (CurveFloat->Points[KeyIndex].InVal - CurveFloat->Points[KeyIndex - 1].InVal);
1155+
}
1156+
1157+
float LeaveTangent = CurveFloat->Points[KeyIndex].LeaveTangent;
1158+
if (KeyIndex < CurveFloat->Points.Num() - 1)
1159+
{
1160+
LeaveTangent = LeaveTangent / (CurveFloat->Points[KeyIndex + 1].InVal - CurveFloat->Points[KeyIndex].InVal);
1161+
}
1162+
1163+
if (bNegative)
1164+
{
1165+
ArriveTangent = -ArriveTangent;
1166+
LeaveTangent = -LeaveTangent;
1167+
}
1168+
1169+
FMatineeImportTools::SetOrAddKey(*ChannelCurve, CurveFloat->Points[KeyIndex].InVal, CurveFloat->Points[KeyIndex].OutVal, ArriveTangent, LeaveTangent, CurveFloat->Points[KeyIndex].InterpMode);
1170+
}
1171+
1172+
ChannelCurve->RemoveRedundantKeys(KINDA_SMALL_NUMBER);
1173+
ChannelCurve->AutoSetTangents();
1174+
}
1175+
}
1176+
}
1177+
1178+
section->SetStartTime(MinTime);
1179+
section->SetEndTime(MaxTime);
1180+
1181+
FbxImporter->ReleaseScene();
1182+
ImportOptions->bConvertScene = bConverteScene;
1183+
ImportOptions->bConvertSceneUnit = bConverteScene;
1184+
ImportOptions->bForceFrontXAxis = bConverteScene;
1185+
Py_RETURN_NONE;
1186+
}
1187+
1188+
FbxImporter->ReleaseScene();
1189+
ImportOptions->bConvertScene = bConverteScene;
1190+
ImportOptions->bConvertSceneUnit = bConverteSceneUnit;
1191+
ImportOptions->bForceFrontXAxis = bForceFrontXAxis;
1192+
return PyErr_Format(PyExc_Exception, "unable to find specified node in Fbx file");
1193+
}
10201194
#endif
10211195

Source/UnrealEnginePython/Private/UObject/UEPySequencer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ PyObject *py_ue_sequencer_remove_spawnable(ue_PyUObject *, PyObject *);
3030
PyObject *py_ue_sequencer_remove_camera_cut_track(ue_PyUObject *, PyObject *);
3131
PyObject *py_ue_sequencer_remove_master_track(ue_PyUObject *, PyObject *);
3232
PyObject *py_ue_sequencer_remove_track(ue_PyUObject *, PyObject *);
33+
PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *, PyObject *);
3334
#endif
3435
PyObject *py_ue_sequencer_sections(ue_PyUObject *, PyObject *);
3536
PyObject *py_ue_sequencer_possessables(ue_PyUObject *, PyObject *);

0 commit comments

Comments
 (0)