FBX SDK PYTHON (2020)を使ってみる
まず、仮想環境を構築
マニュアルを見ると、パイソン3.10しか対応してないのぽいので、
まず、仮想環境を構築してみます。
これはCtrl+Shift+pで構築します。
あらかじめパイソン3.10をインストールしてそのバージョンを選択してください。(直接そのフォルダに3.10を配置することができるのかもしれないがやり方がわからない)
おわったらVSCを再起動して
実際に仮想環境で3.10か確認する。
ちゃんと仮想環境で実行されてるようです。
sdkをインストール
次にサイトから
FBX SDK 2020.3.7 Python (exe - 2799Kb)
をインストールしてインストールされた中から、whlファイルをプロジェクトフォルダに移動します。
whlとは
whlファイルは単体のモジュールインストールファイルで、もしパイソンのプラットフォーム(つまり、3.10以外)だったらエラーが起こるので気をつけてください。
無事インストールされました。
念の為pip listで再起動した後、仮想環境でインストールされてるかも確認します。
問題なくクリーンな環境でfbxのモジュールがインストールサれてることがわかりました。便利ですね。仮想環境って。
では簡単なfbxのスクリプトを実行してみます。
オブジェクトの全てのノードが表示されるスクリプトです。
import fbx
def print_node_hierarchy(node, indent=0):
print(" " * indent + node.GetName())
for i in range(node.GetChildCount()):
print_node_hierarchy(node.GetChild(i), indent + 1)
def main():
# FBXマネージャーの作成
fbx_manager = fbx.FbxManager.Create()
if not fbx_manager:
print("Error: Unable to create FBX manager!")
return
# FBXインポーターの作成
fbx_importer = fbx.FbxImporter.Create(fbx_manager, "")
# FBXファイルを読み込む
if not fbx_importer.Initialize("190_スマホ用ジンバル.fbx"):
print("Error: Unable to initialize FBX importer!")
return
# ノードを取得する
fbx_scene = fbx.FbxScene.Create(fbx_manager, "MyScene")
fbx_importer.Import(fbx_scene)
root_node = fbx_scene.GetRootNode()
if root_node:
print("Root node:", root_node.GetName())
print("Node hierarchy:")
print_node_hierarchy(root_node)
# インポーターを解放する
fbx_importer.Destroy()
# FBXマネージャーを解放する
fbx_manager.Destroy()
if __name__ == "__main__":
main()
結果
Root node: RootNode
Node hierarchy:
RootNode
ジンバル
ジンバル_006
ジンバル_002
ジンバル_005
ジンバル_001
ジンバル_007
ジンバル_003
ジンバル_004
スマホ
問題なく出力されてます。
次にボーンの情報を習得するスクリプトをサンプルを参考に作ってみました。
import fbx
# 列挙型の定義
from DisplayCommon import *
from fbx import FbxSkeleton
from fbx import FbxNodeAttribute
def display(pNode):
objtype=None
if pNode.GetNodeAttribute() == None:
print("NULL Node Attribute\n")
objtype="NULL"
else:
lAttributeType = (pNode.GetNodeAttribute().GetAttributeType())
if lAttributeType == FbxNodeAttribute.EType.eMarker:
print("###type : eMarker")
objtype="eMarker"
elif lAttributeType == FbxNodeAttribute.EType.eSkeleton:
print("###type : eSkeleton")
objtype="eSkeleton"
elif lAttributeType == FbxNodeAttribute.EType.eMesh:
print("###type : eMesh")
objtype="eMesh"
elif lAttributeType == FbxNodeAttribute.EType.eNurbs:
print("###type : eNurbs")
objtype="eNurbs"
elif lAttributeType == FbxNodeAttribute.EType.ePatch:
print("###type : ePatch")
objtype="ePatch"
elif lAttributeType == FbxNodeAttribute.EType.eCamera:
print("###type : eCamera")
objtype="eCamera"
elif lAttributeType == FbxNodeAttribute.EType.eLight:
print("###type : eLight")
objtype="eLight"
return objtype
def DisplaySkeleton(pNode):
objtype=display(pNode)
lSkeleton = pNode.GetNodeAttribute()
if objtype=="eSkeleton":
DisplayString("Skeleton Name: ", pNode.GetName())
lSkeletonTypes = [ "Root", "Limb", "Limb Node", "Effector" ]
DisplayString(" Type: ", lSkeletonTypes[lSkeleton.GetSkeletonType().value])
if lSkeleton.GetSkeletonType() == FbxSkeleton.EType.eLimb:
DisplayDouble(" Limb Length: ", lSkeleton.LimbLength.Get())
elif lSkeleton.GetSkeletonType() == FbxSkeleton.EType.eLimbNode:
DisplayDouble(" Limb Node Size: ", lSkeleton.Size.Get())
elif lSkeleton.GetSkeletonType() == FbxSkeleton.EType.eRoot:
DisplayDouble(" Limb Root Size: ", lSkeleton.Size.Get())
DisplayColor(" Color: ", lSkeleton.GetLimbNodeColor())
else:
pass
def process_node_hierarchy(node):
DisplaySkeleton(node)
for i in range(node.GetChildCount()):
process_node_hierarchy(node.GetChild(i))
def main():
# FBXマネージャーの作成
fbx_manager = fbx.FbxManager.Create()
if not fbx_manager:
print("Error: Unable to create FBX manager!")
return
# FBXインポーターの作成
fbx_importer = fbx.FbxImporter.Create(fbx_manager, "")
# FBXファイルを読み込む
if not fbx_importer.Initialize("body.fbx"):
print("Error: Unable to initialize FBX importer!")
return
# ノードを取得する
fbx_scene = fbx.FbxScene.Create(fbx_manager, "MyScene")
fbx_importer.Import(fbx_scene)
root_node = fbx_scene.GetRootNode()
if root_node:
print("Node and Attribute types:")
process_node_hierarchy(root_node)
# インポーターを解放する
fbx_importer.Destroy()
# FBXマネージャーを解放する
fbx_manager.Destroy()
if __name__ == "__main__":
main()
サンプルを利用してるのですが、DisplayCommon.pyの中身はこれです。
"""
Copyright (C) 2001 - 2010 Autodesk, Inc. and/or its licensors.
All Rights Reserved.
The coded instructions, statements, computer programs, and/or related material
(collectively the "Data") in these files contain unpublished information
proprietary to Autodesk, Inc. and/or its licensors, which is protected by
Canada and United States of America federal copyright law and by international
treaties.
The Data may not be disclosed or distributed to third parties, in whole or in
part, without the prior written consent of Autodesk, Inc. ("Autodesk").
THE DATA IS PROVIDED "AS IS" AND WITHOUT WARRANTY.
ALL WARRANTIES ARE EXPRESSLY EXCLUDED AND DISCLAIMED. AUTODESK MAKES NO
WARRANTY OF ANY KIND WITH RESPECT TO THE DATA, EXPRESS, IMPLIED OR ARISING
BY CUSTOM OR TRADE USAGE, AND DISCLAIMS ANY IMPLIED WARRANTIES OF TITLE,
NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OR USE.
WITHOUT LIMITING THE FOREGOING, AUTODESK DOES NOT WARRANT THAT THE OPERATION
OF THE DATA WILL BE UNINTERRUPTED OR ERROR FREE.
IN NO EVENT SHALL AUTODESK, ITS AFFILIATES, PARENT COMPANIES, LICENSORS
OR SUPPLIERS ("AUTODESK GROUP") BE LIABLE FOR ANY LOSSES, DAMAGES OR EXPENSES
OF ANY KIND (INCLUDING WITHOUT LIMITATION PUNITIVE OR MULTIPLE DAMAGES OR OTHER
SPECIAL, DIRECT, INDIRECT, EXEMPLARY, INCIDENTAL, LOSS OF PROFITS, REVENUE
OR DATA, COST OF COVER OR CONSEQUENTIAL LOSSES OR DAMAGES OF ANY KIND),
HOWEVER CAUSED, AND REGARDLESS OF THE THEORY OF LIABILITY, WHETHER DERIVED
FROM CONTRACT, TORT (INCLUDING, BUT NOT LIMITED TO, NEGLIGENCE), OR OTHERWISE,
ARISING OUT OF OR RELATING TO THE DATA OR ITS USE OR ANY OTHER PERFORMANCE,
WHETHER OR NOT AUTODESK HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS
OR DAMAGE.
"""
def DisplayString(pHeader, pValue="" , pSuffix=""):
lString = pHeader
lString += str(pValue)
lString += pSuffix
print(lString)
def DisplayBool(pHeader, pValue, pSuffix=""):
lString = pHeader
if pValue:
lString += "true"
else:
lString += "false"
lString += pSuffix
print(lString)
def DisplayInt(pHeader, pValue, pSuffix=""):
lString = pHeader
lString += str(pValue)
lString += pSuffix
print(lString)
def DisplayDouble(pHeader, pValue, pSuffix=""):
print("%s%f%s" % (pHeader, pValue, pSuffix))
def Display2DVector(pHeader, pValue, pSuffix=""):
print("%s%f, %f%s" % (pHeader, pValue[0], pValue[1], pSuffix))
def Display3DVector(pHeader, pValue, pSuffix=""):
print("%s%f, %f, %f%s" % (pHeader, pValue[0], pValue[1], pValue[2], pSuffix))
def Display4DVector(pHeader, pValue, pSuffix=""):
print("%s%f, %f, %f, %f%s" % (pHeader, pValue[0], pValue[1], pValue[2], pValue[3], pSuffix))
def DisplayColor(pHeader, pValue, pSuffix=""):
print("%s%f (red), %f (green), %f (blue)%s" % (pHeader, pValue.mRed, pValue.mGreen, pValue.mBlue, pSuffix))
こういった情報がずらっと出てきます。
###type : eSkeleton
Skeleton Name: right_skateC1_bb_
Type: Limb Node
Limb Node Size: 33.333333
Color: 0.800000 (red), 0.800000 (green), 0.800000 (blue)
###type : eSkeleton
Skeleton Name: right_skateC_end_bb_
Type: Limb Node
Limb Node Size: 33.333333
Color: 0.800000 (red), 0.800000 (green), 0.800000 (blue)
###type : eMesh
注意点として、ネットの情報だとスケルトンなどのオブジェクトタイプは
fbx.FbxNodeAttribute.eSkeleton:
などとチャットGPTなどで解答しますがFbxNodeAttributeの後は列挙型のクラスが続くので、厳密には
fbx.FbxNodeAttribute.EType.eSkeleton
といった感じで定義しましょう。(ETypeを入れるだけ)
とりあえず、サンプルを見ることをおすすめします。
サンプルはモジュールが入ってるexeを解凍したらドキュメントと一緒に入ってます。