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++代碼實作一個完整節點的克隆。