LoginSignup
4
2

More than 3 years have passed since last update.

PythonでFBXファイルを ASCII <--> BINARY 変換

Last updated at Posted at 2020-01-08

任意ディレクトリ内にある、
全ての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ファイルのフォーマット変換は、
こんな感じでできるようです。

こちらを参考にさせてもらいました

任意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ファイルがバイナリフォーマットであるか確認する
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

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2