Skip to content

Commit 4d38ba6

Browse files
author
Roberto De Ioris
committed
improved FBX api with pose support
1 parent 2d996cb commit 4d38ba6

12 files changed

Lines changed: 368 additions & 5 deletions

File tree

Source/UnrealEnginePython/Private/Fbx/UEPyFbx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "UEPyFbxNode.h"
1212
#include "UEPyFbxObject.h"
1313
#include "UEPyFbxProperty.h"
14+
#include "UEPyFbxPose.h"
1415

1516
void ue_python_init_fbx(PyObject *);
1617

Source/UnrealEnginePython/Private/Fbx/UEPyFbxImporter.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@
66

77
#include "UEPyFbx.h"
88

9+
static PyObject *py_ue_fbx_importer_get_anim_stack_count(ue_PyFbxImporter *self, PyObject *args) {
10+
return PyLong_FromLong(self->fbx_importer->GetAnimStackCount());
11+
}
12+
13+
static PyObject *py_ue_fbx_importer_get_take_local_time_span(ue_PyFbxImporter *self, PyObject *args) {
14+
int index;
15+
if (!PyArg_ParseTuple(args, "i", &index)) {
16+
return nullptr;
17+
}
18+
19+
FbxTakeInfo *take_info = self->fbx_importer->GetTakeInfo(index);
20+
if (!take_info)
21+
return PyErr_Format(PyExc_Exception, "unable to get FbxTakeInfo for index %d", index);
22+
23+
FbxTimeSpan time_span = take_info->mLocalTimeSpan;
24+
return Py_BuildValue((char *)"(ff)", time_span.GetStart().GetSecondDouble(), time_span.GetStop().GetSecondDouble());
25+
}
26+
927
static PyObject *py_ue_fbx_importer_initialize(ue_PyFbxImporter *self, PyObject *args) {
1028
char *filename;
1129
PyObject *py_object;
@@ -46,6 +64,8 @@ static PyObject *py_ue_fbx_importer_import(ue_PyFbxImporter *self, PyObject *arg
4664
static PyMethodDef ue_PyFbxImporter_methods[] = {
4765
{ "initialize", (PyCFunction)py_ue_fbx_importer_initialize, METH_VARARGS, "" },
4866
{ "_import", (PyCFunction)py_ue_fbx_importer_import, METH_VARARGS, "" },
67+
{ "get_anim_stack_count", (PyCFunction)py_ue_fbx_importer_get_anim_stack_count, METH_VARARGS, "" },
68+
{ "get_take_local_time_span", (PyCFunction)py_ue_fbx_importer_get_take_local_time_span, METH_VARARGS, "" },
4969
{ NULL } /* Sentinel */
5070
};
5171

Source/UnrealEnginePython/Private/Fbx/UEPyFbxManager.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,26 @@ static PyObject *py_ue_fbx_manager_set_io_settings(ue_PyFbxManager *self, PyObje
2121
Py_RETURN_NONE;
2222
}
2323

24+
static PyObject *py_ue_fbx_manager_create_missing_bind_poses(ue_PyFbxManager *self, PyObject *args) {
25+
PyObject *py_object;
26+
if (!PyArg_ParseTuple(args, "O", &py_object)) {
27+
return nullptr;
28+
}
29+
30+
ue_PyFbxScene *py_fbx_scene = py_ue_is_fbx_scene(py_object);
31+
if (!py_fbx_scene) {
32+
return PyErr_Format(PyExc_Exception, "argument is not a FbxScene");
33+
}
34+
35+
self->fbx_manager->CreateMissingBindPoses(py_fbx_scene->fbx_scene);
36+
37+
Py_RETURN_NONE;
38+
}
39+
40+
2441
static PyMethodDef ue_PyFbxManager_methods[] = {
2542
{ "set_io_settings", (PyCFunction)py_ue_fbx_manager_set_io_settings, METH_VARARGS, "" },
43+
{ "create_missing_bind_poses", (PyCFunction)py_ue_fbx_manager_create_missing_bind_poses, METH_VARARGS, "" },
2644
{ NULL } /* Sentinel */
2745
};
2846

@@ -99,6 +117,7 @@ void ue_python_init_fbx(PyObject *module) {
99117
ue_python_init_fbx_node(module);
100118
ue_python_init_fbx_object(module);
101119
ue_python_init_fbx_property(module);
120+
ue_python_init_fbx_pose(module);
102121
}
103122

104123

Source/UnrealEnginePython/Private/Fbx/UEPyFbxNode.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ static PyObject *py_ue_fbx_node_get_child(ue_PyFbxNode *self, PyObject *args) {
4040
return py_ue_new_fbx_node(fbx_node);
4141
}
4242

43+
static PyObject *py_ue_fbx_node_get_parent(ue_PyFbxNode *self, PyObject *args) {
44+
FbxNode *fbx_node = self->fbx_node->GetParent();
45+
if (!fbx_node) {
46+
return PyErr_Format(PyExc_Exception, "unable to retrieve FbxNode parent");
47+
}
48+
return py_ue_new_fbx_node(fbx_node);
49+
}
50+
4351
static PyObject *py_ue_fbx_node_get_node_attribute(ue_PyFbxNode *self, PyObject *args) {
4452

4553
FbxNodeAttribute *fbx_node_attribute = self->fbx_node->GetNodeAttribute();
@@ -65,13 +73,52 @@ static PyObject *py_ue_fbx_node_get_node_attribute_by_index(ue_PyFbxNode *self,
6573
return py_ue_new_fbx_object(fbx_node_attribute);
6674
}
6775

76+
static PyObject *py_ue_fbx_node_evaluate_local_transform(ue_PyFbxNode *self, PyObject *args) {
77+
float t;
78+
if (!PyArg_ParseTuple(args, "f", &t)) {
79+
return nullptr;
80+
}
81+
FbxTime time;
82+
time.SetSecondDouble(t);
83+
FbxAMatrix& matrix = self->fbx_node->EvaluateLocalTransform(time);
84+
FTransform transform;
85+
FbxVector4 mt = matrix.GetT();
86+
FbxQuaternion mq = matrix.GetQ();
87+
FbxVector4 ms = matrix.GetS();
88+
transform.SetTranslation(FVector(mt[0], -mt[1], mt[2]));
89+
transform.SetRotation(FQuat(mq[0], -mq[1], mq[2], -mq[3]));
90+
transform.SetScale3D(FVector(ms[0], ms[1], ms[2]));
91+
return py_ue_new_ftransform(transform);
92+
}
93+
94+
static PyObject *py_ue_fbx_node_evaluate_global_transform(ue_PyFbxNode *self, PyObject *args) {
95+
float t;
96+
if (!PyArg_ParseTuple(args, "f", &t)) {
97+
return nullptr;
98+
}
99+
FbxTime time;
100+
time.SetSecondDouble(t);
101+
FbxAMatrix& matrix = self->fbx_node->EvaluateGlobalTransform(time);
102+
FTransform transform;
103+
FbxVector4 mt = matrix.GetT();
104+
FbxQuaternion mq = matrix.GetQ();
105+
FbxVector4 ms = matrix.GetS();
106+
transform.SetTranslation(FVector(mt[0], -mt[1], mt[2]));
107+
transform.SetRotation(FQuat(mq[0], -mq[1], mq[2], -mq[3]));
108+
transform.SetScale3D(FVector(ms[0], ms[1], ms[2]));
109+
return py_ue_new_ftransform(transform);
110+
}
111+
68112
static PyMethodDef ue_PyFbxNode_methods[] = {
69113
{ "get_child_count", (PyCFunction)py_ue_fbx_node_get_child_count, METH_VARARGS, "" },
70114
{ "get_name", (PyCFunction)py_ue_fbx_node_get_name, METH_VARARGS, "" },
115+
{ "evaluate_local_transform", (PyCFunction)py_ue_fbx_node_evaluate_local_transform, METH_VARARGS, "" },
116+
{ "evaluate_global_transform", (PyCFunction)py_ue_fbx_node_evaluate_global_transform, METH_VARARGS, "" },
71117
{ "get_local_translation", (PyCFunction)py_ue_fbx_node_get_local_translation, METH_VARARGS, "" },
72118
{ "get_local_rotation", (PyCFunction)py_ue_fbx_node_get_local_rotation, METH_VARARGS, "" },
73119
{ "get_local_scaling", (PyCFunction)py_ue_fbx_node_get_local_scaling, METH_VARARGS, "" },
74120
{ "get_child", (PyCFunction)py_ue_fbx_node_get_child, METH_VARARGS, "" },
121+
{ "get_parent", (PyCFunction)py_ue_fbx_node_get_parent, METH_VARARGS, "" },
75122
{ "get_node_attribute", (PyCFunction)py_ue_fbx_node_get_node_attribute, METH_VARARGS, "" },
76123
{ "get_node_attribute_count", (PyCFunction)py_ue_fbx_node_get_node_attribute_count, METH_VARARGS, "" },
77124
{ "get_node_attribute_by_index", (PyCFunction)py_ue_fbx_node_get_node_attribute_by_index, METH_VARARGS, "" },
@@ -144,5 +191,11 @@ PyObject *py_ue_new_fbx_node(FbxNode *fbx_node) {
144191
return (PyObject *)ret;
145192
}
146193

194+
ue_PyFbxNode *py_ue_is_fbx_node(PyObject *obj) {
195+
if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFbxNodeType))
196+
return nullptr;
197+
return (ue_PyFbxNode *)obj;
198+
}
199+
147200
#endif
148201
#endif

Source/UnrealEnginePython/Private/Fbx/UEPyFbxNode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ void ue_python_init_fbx_node(PyObject *);
1616

1717
PyObject *py_ue_new_fbx_node(FbxNode *);
1818

19+
ue_PyFbxNode *py_ue_is_fbx_node(PyObject *);
20+
1921
#endif

Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ static PyObject *py_ue_fbx_object_get_channels_count(ue_PyFbxObject *self, PyObj
6565
return PyLong_FromLong(fbx_anim_curve_node->GetChannelsCount());
6666
}
6767

68+
static PyObject *py_ue_fbx_object_to_node(ue_PyFbxObject *self, PyObject *args) {
69+
FbxNode *fbx_node = FbxCast<FbxNode>(self->fbx_object);
70+
if (!fbx_node)
71+
return PyErr_Format(PyExc_Exception, "object is not a FbxNode");
72+
return py_ue_new_fbx_node(fbx_node);
73+
}
74+
6875
static PyObject *py_ue_fbx_object_get_channel_name(ue_PyFbxObject *self, PyObject *args) {
6976
int index;
7077
if (!PyArg_ParseTuple(args, "i", &index)) {
@@ -89,8 +96,8 @@ static PyObject *py_ue_fbx_object_get_curve_count(ue_PyFbxObject *self, PyObject
8996

9097
static PyObject *py_ue_fbx_object_get_curve(ue_PyFbxObject *self, PyObject *args) {
9198
int channel;
92-
int index;
93-
if (!PyArg_ParseTuple(args, "ii", &channel, &index)) {
99+
int index = 0;
100+
if (!PyArg_ParseTuple(args, "i|i:get_curve", &channel, &index)) {
94101
return nullptr;
95102
}
96103
FbxAnimCurveNode *fbx_anim_curve_node = FbxCast<FbxAnimCurveNode>(self->fbx_object);
@@ -135,6 +142,7 @@ static PyMethodDef ue_PyFbxObject_methods[] = {
135142
{ "get_member_count", (PyCFunction)py_ue_fbx_object_get_member_count, METH_VARARGS, "" },
136143
{ "get_member", (PyCFunction)py_ue_fbx_object_get_member, METH_VARARGS, "" },
137144
{ "get_name", (PyCFunction)py_ue_fbx_object_get_name, METH_VARARGS, "" },
145+
{ "to_node", (PyCFunction)py_ue_fbx_object_to_node, METH_VARARGS, "" },
138146
{ "get_class_name", (PyCFunction)py_ue_fbx_object_get_class_name, METH_VARARGS, "" },
139147
{ "get_first_property", (PyCFunction)py_ue_fbx_object_get_first_property, METH_VARARGS, "" },
140148
{ "get_next_property", (PyCFunction)py_ue_fbx_object_get_next_property, METH_VARARGS, "" },
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#if ENGINE_MINOR_VERSION > 12
2+
#include "UnrealEnginePythonPrivatePCH.h"
3+
4+
#if WITH_EDITOR
5+
6+
#include "UEPyFbx.h"
7+
8+
static PyObject *py_ue_fbx_pose_get_count(ue_PyFbxPose *self, PyObject *args) {
9+
return PyLong_FromLong(self->fbx_pose->GetCount());
10+
}
11+
12+
static PyObject *py_ue_fbx_pose_get_name(ue_PyFbxPose *self, PyObject *args) {
13+
return PyUnicode_FromString(self->fbx_pose->GetName());
14+
}
15+
16+
static PyObject *py_ue_fbx_pose_is_bind_pose(ue_PyFbxPose *self, PyObject *args) {
17+
if (self->fbx_pose->IsBindPose()) {
18+
Py_RETURN_TRUE;
19+
}
20+
Py_RETURN_FALSE;
21+
}
22+
23+
static PyObject *py_ue_fbx_pose_is_rest_pose(ue_PyFbxPose *self, PyObject *args) {
24+
if (self->fbx_pose->IsRestPose()) {
25+
Py_RETURN_TRUE;
26+
}
27+
Py_RETURN_FALSE;
28+
}
29+
30+
static PyObject *py_ue_fbx_pose_get_node(ue_PyFbxPose *self, PyObject *args) {
31+
int index;
32+
if (!PyArg_ParseTuple(args, "i", &index)) {
33+
return nullptr;
34+
}
35+
FbxNode *fbx_node = self->fbx_pose->GetNode(index);
36+
if (!fbx_node) {
37+
return PyErr_Format(PyExc_Exception, "unable to retrieve FbxNode at index %d", index);
38+
}
39+
return py_ue_new_fbx_node(fbx_node);
40+
}
41+
42+
static PyObject *py_ue_fbx_pose_find(ue_PyFbxPose *self, PyObject *args) {
43+
PyObject *py_obj;
44+
if (!PyArg_ParseTuple(args, "O", &py_obj)) {
45+
return nullptr;
46+
}
47+
48+
ue_PyFbxNode *py_node = py_ue_is_fbx_node(py_obj);
49+
if (!py_node)
50+
return PyErr_Format(PyExc_Exception, "argument is not a FbxNode");
51+
52+
int index = self->fbx_pose->Find(py_node->fbx_node);
53+
if (index < 0)
54+
return PyErr_Format(PyExc_Exception, "unable to retrieve FbxNode index from FbxPose");
55+
56+
return PyLong_FromLong(index);
57+
}
58+
59+
static PyObject *py_ue_fbx_pose_get_transform(ue_PyFbxPose *self, PyObject *args) {
60+
int index;
61+
if (!PyArg_ParseTuple(args, "i", &index)) {
62+
return nullptr;
63+
}
64+
65+
FbxMatrix fbx_matrix = self->fbx_pose->GetMatrix(index);
66+
FbxAMatrix matrix = *(FbxAMatrix *)&fbx_matrix;
67+
FTransform transform;
68+
FbxVector4 mt = matrix.GetT();
69+
FbxQuaternion mq = matrix.GetQ();
70+
FbxVector4 ms = matrix.GetS();
71+
transform.SetTranslation(FVector(mt[0], -mt[1], mt[2]));
72+
transform.SetRotation(FQuat(mq[0], -mq[1], mq[2], -mq[3]));
73+
transform.SetScale3D(FVector(ms[0], ms[1], ms[2]));
74+
return py_ue_new_ftransform(transform);
75+
}
76+
77+
static PyMethodDef ue_PyFbxPose_methods[] = {
78+
{ "get_count", (PyCFunction)py_ue_fbx_pose_get_count, METH_VARARGS, "" },
79+
{ "get_name", (PyCFunction)py_ue_fbx_pose_get_name, METH_VARARGS, "" },
80+
{ "get_node", (PyCFunction)py_ue_fbx_pose_get_node, METH_VARARGS, "" },
81+
{ "is_bind_pose", (PyCFunction)py_ue_fbx_pose_is_bind_pose, METH_VARARGS, "" },
82+
{ "is_rest_pose", (PyCFunction)py_ue_fbx_pose_is_rest_pose, METH_VARARGS, "" },
83+
{ "find", (PyCFunction)py_ue_fbx_pose_find, METH_VARARGS, "" },
84+
{ "get_transform", (PyCFunction)py_ue_fbx_pose_get_transform, METH_VARARGS, "" },
85+
{ NULL } /* Sentinel */
86+
};
87+
88+
static PyTypeObject ue_PyFbxPoseType = {
89+
PyVarObject_HEAD_INIT(NULL, 0)
90+
"unreal_engine.FbxPose", /* tp_name */
91+
sizeof(ue_PyFbxPose), /* tp_basicsize */
92+
0, /* tp_itemsize */
93+
0, /* tp_dealloc */
94+
0, /* tp_print */
95+
0, /* tp_getattr */
96+
0, /* tp_setattr */
97+
0, /* tp_reserved */
98+
0, /* tp_repr */
99+
0, /* tp_as_number */
100+
0, /* tp_as_sequence */
101+
0, /* tp_as_mapping */
102+
0, /* tp_hash */
103+
0, /* tp_call */
104+
0, /* tp_str */
105+
0, /* tp_getattro */
106+
0, /* tp_setattro */
107+
0, /* tp_as_buffer */
108+
Py_TPFLAGS_DEFAULT, /* tp_flags */
109+
"Unreal Engine FbxPose", /* tp_doc */
110+
0, /* tp_traverse */
111+
0, /* tp_clear */
112+
0, /* tp_richcompare */
113+
0, /* tp_weaklistoffset */
114+
0, /* tp_iter */
115+
0, /* tp_iternext */
116+
ue_PyFbxPose_methods, /* tp_methods */
117+
0, /* tp_members */
118+
0, /* tp_getset */
119+
};
120+
121+
static int py_ue_fbx_pose_init(ue_PyFbxPose *self, PyObject * args) {
122+
PyObject *py_object;
123+
char *name;
124+
if (!PyArg_ParseTuple(args, "Os", &py_object, &name)) {
125+
return -1;
126+
}
127+
128+
ue_PyFbxManager *py_fbx_manager = py_ue_is_fbx_manager(py_object);
129+
if (!py_fbx_manager) {
130+
PyErr_SetString(PyExc_Exception, "argument is not a FbxManager");
131+
return -1;
132+
}
133+
134+
self->fbx_pose = FbxPose::Create(py_fbx_manager->fbx_manager, name);
135+
return 0;
136+
}
137+
138+
void ue_python_init_fbx_pose(PyObject *ue_module) {
139+
ue_PyFbxPoseType.tp_new = PyType_GenericNew;;
140+
ue_PyFbxPoseType.tp_init = (initproc)py_ue_fbx_pose_init;
141+
if (PyType_Ready(&ue_PyFbxPoseType) < 0)
142+
return;
143+
144+
Py_INCREF(&ue_PyFbxPoseType);
145+
PyModule_AddObject(ue_module, "FbxPose", (PyObject *)&ue_PyFbxPoseType);
146+
}
147+
148+
PyObject *py_ue_new_fbx_pose(FbxPose *fbx_pose) {
149+
ue_PyFbxPose *ret = (ue_PyFbxPose *)PyObject_New(ue_PyFbxPose, &ue_PyFbxPoseType);
150+
ret->fbx_pose = fbx_pose;
151+
return (PyObject *)ret;
152+
}
153+
154+
#endif
155+
#endif
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
#include "UnrealEnginePython.h"
3+
4+
#if WITH_EDITOR
5+
6+
#include <fbxsdk.h>
7+
8+
struct ue_PyFbxPose {
9+
PyObject_HEAD
10+
/* Type-specific fields go here. */
11+
FbxPose *fbx_pose;
12+
};
13+
14+
15+
void ue_python_init_fbx_pose(PyObject *);
16+
17+
PyObject *py_ue_new_fbx_pose(FbxNode *);
18+
19+
#endif

Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ static PyObject *py_ue_fbx_property_get_name(ue_PyFbxProperty *self, PyObject *a
99
return PyUnicode_FromString(self->fbx_property.GetName());
1010
}
1111

12+
static PyObject *py_ue_fbx_property_get_double3(ue_PyFbxProperty *self, PyObject *args) {
13+
FbxDouble3 value = self->fbx_property.Get<FbxDouble3>();
14+
return Py_BuildValue((char *)"(fff)", value[0], value[1], value[2]);
15+
}
16+
1217
static PyObject *py_ue_fbx_property_is_valid(ue_PyFbxProperty *self, PyObject *args) {
1318
if (self->fbx_property.IsValid()) {
1419
Py_RETURN_TRUE;
@@ -38,6 +43,7 @@ static PyObject *py_ue_fbx_property_get_curve_node(ue_PyFbxProperty *self, PyObj
3843

3944
static PyMethodDef ue_PyFbxProperty_methods[] = {
4045
{ "get_name", (PyCFunction)py_ue_fbx_property_get_name, METH_VARARGS, "" },
46+
{ "get_double3", (PyCFunction)py_ue_fbx_property_get_double3, METH_VARARGS, "" },
4147
{ "is_valid", (PyCFunction)py_ue_fbx_property_is_valid, METH_VARARGS, "" },
4248
{ "get_curve_node", (PyCFunction)py_ue_fbx_property_get_curve_node, METH_VARARGS, "" },
4349
{ NULL } /* Sentinel */

0 commit comments

Comments
 (0)