天天看点

python调用fbxsdk

Part1为什么是python

python调用fbxsdk

python拥有非常强大的生态,而且安装使用极其方便。只需要一个pip安装即可解决大多数问题。如json解析、数据库操作、网络操作等等,但是C++操作这些就显得有些麻烦。所以能用python解决的问题,就尽量选择他,一定没错。fbx官方提供了C++和python两种fbx解析的库。参考网址:https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2020-3

python调用fbxsdk

Part2官方库存在问题

下载安装官方的sdk之后,我们发现一个问题如下图:

python调用fbxsdk

官方提供的库只支持python2.7和3.3版本。为什么说存在问题呢?看下图:

python调用fbxsdk

我们vscode对python的支持需要版本大于3.6。如果我们采用官方的版本进行开发的话,vscode就只能当做文本编辑器了,其强大的断点调试功能无法使用。这也是目前无法接受的事情。

Part3高版本python支持

幸好,aotodesk官方提供了FBX Python Bindings,我们可以自己编译对应版本的python库进行使用。这里就不去编译了,我们采用热心网友已经编译好的库。https://github.com/Shi-Iho/FBX-Python-SDK-for-Python3.x 其提供了两个版本的pyhon库,3.7和3.8.亲测3.7版本可以使用。

python调用fbxsdk

Part4fbx库的安装

我们需要找到python的安装目录,然后将python的3个库(fbx.pyd、FbxCommon.py、fbxsip.pyd)拷贝到lib\site-packages目录下,我这里目录如下:

Programs\Python\Python37\lib\site-packages      

然后还需要在该目录新建一个空fbx文件夹,之后即可在代码中进行调用。

Part5代码调用

1加载fbx文件

我们以加载一个场景为例,来研究pyhon如何获取fbx的数据。只需要两三行代码即可加载一个fbx文件。示例如下:

from fbx import *
import FbxCommon as FbxCommon

sdk_manager, scene = FbxCommon.InitializeSdkObjects()
lResult = FbxCommon.LoadScene(sdk_manager, scene, 'tt.fbx')      

其中sdk_manager是fbxsdk的内存管理对象,scene就是我们加载的fbx文件的场景。

2获取网格体对象

每个场景会有一个根节点,我们通过如下方法来获取。

root_node = scene.GetRootNode()      

fbx是用一颗树来管理对象,每个树的节点称为node。由于我们主要关注网格体对象,所以就以这个为示例。网格体对象不是node节点,而且其属性值,通过如下方法获取:

lAttributeType = (pNode.GetNodeAttribute().GetAttributeType())
if lAttributeType == FbxNodeAttribute.eMesh:
    lMesh = pNode.GetNodeAttribute ()      

3获取网格对象基本属性

1、获取顶点数据

lControlPointsCount = lMesh.GetControlPointsCount()
lControlPoints = lMesh.GetControlPoints()      

2、获取面数据

lPolygonCount = pMesh.GetPolygonCount()
for i in range(lPolygonCount):
    lPolygonSize = pMesh.GetPolygonSize(i)
    for j in range(lPolygonSize):
        lControlPointIndex = pMesh.GetPolygonVertex(i, j)      

说明:

lPolygonCount:面的总个数

lPolygonSize:面的形状(三角形或者四边形)

lControlPointIndex:面的顶点的索引,这里顶点数据到上面的lControlPoints中去获取

3、uv坐标

uv坐标和顶点的获取方式不太一样,需要遍历Layer获取。而Layer可能会有多个,这样网格体就具备了多套uv的能力。

for l in range(pMesh.GetLayerCount()):
    leUV = pMesh.GetLayer(l).GetUVs()      

4、获取法线

法线的获取与uv坐标的获取方式类似,都需要遍历Layer来获取。

for j in range(pMesh.GetLayerCount()):
    leNormals = pMesh.GetLayer(j).GetNormals()      

5、获取材质

材质并没有存储在mesh中,而是需要到node节点中去获取。获取方法如下:

lNode = pMesh.GetNode()
lMaterialCount = lNode.GetMaterialCount()
for lCount in range(lMaterialCount):
    lMaterial = lNode.GetMaterial(lCount)      

材质对象和网格体对象是两个互相独立的对象,之后都与node节点进行关联。不过网格体对象的Layer中也会记录引用材质对象的索引。

Part6总结

python库对fbx格式常见的解析基本上都可以支持,特别是文件读取和输出,官方提供的示例代码可以满足日常的基本需求。

python调用fbxsdk

但是我遇到一个需要:

需要拷贝一个fbx节点,并能保存相关的连接信息,如何材质等。我开始找到了实现函数如下:

newMesh = FbxMesh.Clone(lMesh, FbxMesh.eDeepClone, FbxMesh)      

但是保存出来的fbx文件缺失了材质的信息。后来找到的官方的一句描述:

By default, the connections are NOT cloned. If the desired effect is to clone the connections as well, you must clone using the FbxCloneManager(refer to this class documentation for further details).      

即我们只能通过FbxCloneManager来实现节点的连接信息的拷贝,在尝试通过python库调用的时候,发现没有这个对象。报错信息如下:

python调用fbxsdk

最后只能调转到C++来实现这个功能了。即下一篇我们将研究如何通过C++代码实现一个完整节点的克隆。

4写在最后