Part1为什么是python

python拥有非常强大的生态,而且安装使用极其方便。只需要一个pip安装即可解决大多数问题。如json解析、数据库操作、网络操作等等,但是C++操作这些就显得有些麻烦。所以能用python解决的问题,就尽量选择他,一定没错。fbx官方提供了C++和python两种fbx解析的库。参考网址:https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2020-3
Part2官方库存在问题
下载安装官方的sdk之后,我们发现一个问题如下图:
官方提供的库只支持python2.7和3.3版本。为什么说存在问题呢?看下图:
我们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版本可以使用。
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格式常见的解析基本上都可以支持,特别是文件读取和输出,官方提供的示例代码可以满足日常的基本需求。
但是我遇到一个需要:
需要拷贝一个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库调用的时候,发现没有这个对象。报错信息如下:
最后只能调转到C++来实现这个功能了。即下一篇我们将研究如何通过C++代码实现一个完整节点的克隆。