天天看點

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寫在最後