任意ディレクトリ内にある、
全てのfbxファイルを
ASCIIフォーマット、又はBINARYフォーマットに
一括で変換したい時があったので、
python fbx sdk でやってみました。
環境
- macOS Catalina
- python 3.7.0
- FBX Python SDK (2020.0.1)
FBX Python Bindings
公式ドキュメントを参考に、FBX Python Bindings を環境に入れます。
Installing Python FBX (2020.0.1)
ちなみに、その時の最新版をみたい場合は、
下記のようにいくと取りにいけるようです。
https://www.autodesk.com/products/fbx/overview -> GET FBX SDK -> FBX Python Bindings
変換する
FBXファイルのフォーマット変換は、
こんな感じでできるようです。
from fbx import FbxManager
from fbx import FbxScene
from fbx import FbxImporter
from fbx import FbxExporter
FBX_MANAGER = FbxManager.Create()
def _get_file_fomrat(format_name):
io_plugin_registry = FBX_MANAGER.GetIOPluginRegistry()
for format_id in range(io_plugin_registry.GetWriterFormatCount()):
if io_plugin_registry.WriterIsFBX(format_id):
desc = io_plugin_registry.GetWriterFormatDescription(format_id)
if format_name in desc:
return format_id
# Default format is auto
return -1
def _convert(path, file_format_id):
scene = FbxScene.Create(FBX_MANAGER, "")
importer = FbxImporter.Create(FBX_MANAGER, "")
importer.Initialize(path, -1)
importer.Import(scene)
importer.Destroy()
exporter = FbxExporter.Create(FBX_MANAGER, "")
exporter.Initialize(path, file_format_id)
exporter.Export(scene)
exporter.Destroy()
scene.Destroy()
# 対象のfbxファイルを、バイナリに変換する
_convert('target_fbx_file_path', _get_file_fomrat('binary'))
# 対象のfbxファイルを、アスキーに変換する
_convert('target_fbx_file_path', _get_file_fomrat('ascii'))
変換前に、対象がバイナリフォーマットか確認する
同じフォーマットに変換するのは無駄なので、
目的と同じフォーマットへの変換を除外するようにします。
こちらに、非公式のようですがバイナリフォーマットの
ヘッダー情報が載っているので参考にしてみます。
※こちらにもある
※公式の情報が見当たらない。。。
FBX_BINARY_SIGNATURE = b"Kaydara FBX Binary \x00\x1A\x00"
FBX_BINARY_SIGNATURE_LENGTH = len(FBX_BINARY_SIGNATURE)
def _is_binary_fbx(path):
with open(path, 'rb') as file:
return file.read(FBX_BINARY_SIGNATURE_LENGTH) == FBX_BINARY_SIGNATURE
return False
先頭23bytesは固定のバイナリデータなので、
必要な分だけファイル読み込みをして比較しています。
変換メソッドの最初に、この判定を仕込むと、
目的のフォーマットと違うファイルだけ変換されるようになります。
def _convert(path, file_format_id, required_binary):
if _is_binary_fbx(path) != required_binary:
scene = FbxScene.Create(FBX_MANAGER, "")
importer = FbxImporter.Create(FBX_MANAGER, "")
importer.Initialize(path, -1)
importer.Import(scene)
importer.Destroy()
exporter = FbxExporter.Create(FBX_MANAGER, "")
exporter.Initialize(path, file_format_id)
exporter.Export(scene)
exporter.Destroy()
scene.Destroy()
マルチプロセスで高速化する
1fbxの変換を1jobとして、
ファイル単位での変換を並列化して
高速化をねらってみます。
concurrent.futures.ProcessPoolExecutorを使います。
python 3.x系が必要になります。
import concurrent.futures
with concurrent.futures.ProcessPoolExecutor() as executor:
executor.submit(_convert, 'target_fbx_file_path', _get_file_fomrat('ascii'), false)
Walkするー
任意ディレクトリ内を全て対象にしたいので、
os.walk します。
import os
import sys
with concurrent.futures.ProcessPoolExecutor() as executor:
file_format_id = _get_file_fomrat('binary')
for root, _dirs, files in os.walk('target_directory_path'):
for filename in files:
if filename.endswith('.fbx'):
path = os.path.join(root, filename)
executor.submit(_convert, path, file_format_id, true)
これで少しは早く、一括変換が可能になったと思います。
出力ファイルの FBX File Version を指定する
変換後のファイルは使っているFBX SDKのバージョンに依存しますが、
下記のように指定することができます。
from fbx import FbxSceneRenamer
# FBXVersion: 7500 になる
exporter.SetFileExportVersion('FBX201600', FbxSceneRenamer.eNone)
# FBXVersion: 7200 になる
exporter.SetFileExportVersion('FBX201200', FbxSceneRenamer.eNone)
指定できるバージョンは
fbxio.h で定義されている
FBX_xxxx_xx_COMPATIBLE 系の文字列です。
まとめ
まとめると、下記にアップしたもののようになります。
https://github.com/yassy0413/fbx-file-utility-python/blob/master/fbx_file_format_utility.py