scenario-blender-export について
scenario-blender-export は、Blender のアセットをゲームエンジン、Web 形式、USD パイプライン、3D プリント向けに準備するスキルです。エンジン別のプリセットに出荷前監査と再インポート比較を組み合わせ、エクスポート成功だけでは分からない差異を確認します。
主な機能
- 01エンジン別プリセットでのエクスポート
- 02エクスポート前のアセット監査
- 03再インポートによるファイル比較
- 04GLB の内容と拡張機能の要約
- 05LOD とコリジョンメッシュの生成
- 06対応モデル形式の一括変換
活用シーン
- 01Unity または Unreal Engine 向けのキャラクター FBX 作成
- 02Godot または Web 向け GLB のエクスポート
- 03往復比較によるモデル差異の確認
- 04モデルフォルダーの変換とレポート確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-blender-exportインストール後、Claude Code で/scenario-blender-exportを入力して読み込まれたか確認します。
同梱ファイルreferences/engines.mdscripts/bx_export.py
詳細
Blender エクスポート(エンジン対応ファイル)
エクスポーターがFINISHEDを返したときではなく、ファイルを再インポートして計測したときに、エクスポートは完了です。まずアセットをゲートし、プリセットを使ってエクスポートした後、ファイルをラウンドトリップします。このスキルはscenario-blender-expert(実行チャネル、納品ゲート)を基盤とし、そのスクリプトをインポートするため、2つを並べてインストールしてください。ここに記載されている関連スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人実行の場合は、ツールのスキーマを確認して進め、不足していることを明示してください。
ツールキット:scripts/bx_export.py。エンジンごとの情報とその出典:
references/engines.md。
クイックリファレンス
| 対象 | プリセット | ファイル | エンジン側 |
|---|---|---|---|
| Unity、静的メッシュ | unity | FBX | インポート時のデフォルト設定 |
| Unity、キャラクター | unity_skeletal | FBX | Bake Axis Conversionはオフのままにする |
| Unreal Engine | unreal | FBX | Convert Scene Unit(センチメートルに変換) |
| Unreal Engine、キャラクター | unreal_skeletal | FBX | ルートボーンを1つにする |
| Godot 4 | godot | GLB | インポート時のデフォルト設定。ドックでGenerate LODs |
| Roblox | roblox | FBX | メッシュあたり20,000三角形 |
| three.jsとWeb | web | GLB、meshopt、WebP | MeshoptDecoder。Godotでは使用不可 |
| 任意のglTFリーダー | gltf | GLB | |
| USDパイプライン | usd | USDC | |
| Apple AR Quick Look | usdz | USDZ、2048テクスチャ | |
| 3Dプリント | print | ミリメートル単位のSTL | スライサーはミリメートルを読み取る |
UnityとGodotのプリセットはUnity 6000.3とGodot 4.7.2にインポートして計測済みです。unreal、unreal_skeletal、robloxはEpicとRobloxのドキュメントに準拠しており、Blenderのラウンドトリップのみ検証済みです。計測結果はreferences/engines.mdに記載されています。
手順
- ゲートする。
scenario-blender-expertのbx_audit.deliverable(parts, profile)を実行し、すべてのエラーを修正します。オブジェクトに残ったスケールは、ノードのトランスフォームとしてエンジンに渡されます。 - プリセットを選ぶ。 表から選択します。ファイルに必要なオブジェクトをすべて渡します。スキン付きメッシュとそのアーマチュア、LODメッシュとそのグループ、レンダーメッシュと並べるコリジョンメッシュなどです。
- エクスポートする:
bxe.export(path, preset, objects, **overrides)。エクスポーターのキーワード引数はどれもプリセットを上書きします。たとえば、アニメーションファイルを作成する場合は、robloxでbake_anim=Trueを指定します。結果には使用した設定が記録されます。 - ラウンドトリップする:
bxe.round_trip(path, objects, preset=...)は、バックグラウンドのBlenderでファイルを再インポートし、開いているシーンには手を加えません。サイズ(1 mm)、三角形数、変形ボーン、ルートボーン(1つを想定)、アーマチュアのスケール、シェイプキー、およびオブジェクトに保存されているすべてのアクションを名前で比較します。その後、差分をすべて一覧表示します。それぞれを修正するか、想定どおりである理由を説明してください。 - glTFの内容を確認する:
bxe.glb_summary(path)は、Blenderを使わずにextensions_required、モーフターゲット、スキン、クリップ、画像タイプを一覧表示します。ローダーは、対応していない拡張機能を必要とするファイルを拒否します。 - エンジンで確認する: エンジンにインポートして確認します。
scenario-unity-pipeline-automation、scenario-unreal-pipeline-automation、またはscenario-godot-pipeline-automationを使います。
スケール、軸、単位
- Blender はメートル単位で、Z 軸が上向き、アセットの正面は -Y を向きます。glTF はメートル単位で、Y 軸が上向きです
(
export_yup)。FBX では軸がメタデータとして保存され、プリセットは前方 -Z、上方 Y を指定します。 scene.unit_settings.scale_lengthは 1.0 のままにします。それ以外の値では、すべてのエクスポートが再スケーリングされます。- エクスポート前にオブジェクトのスケールを適用します。
obj.data.transform(Matrix.Diagonal(obj.scale).to_4x4())を実行してから、obj.scale = (1, 1, 1)を設定すると、エンジンのノードはスケール 1 でインポートされます。 - FBX のスケール:
unityはFBX_SCALE_ALLを指定します(Unity はファイルスケールを 1 として読み込みます)。unrealはFBX_SCALE_NONEを維持します(Unity はファイルスケールを 0.01、つまりセンチメートル単位のファイルとして読み込みます)。robloxは Roblox のエクスポート要件に従い、FBX_SCALE_UNITSを使用します。 - STL には単位がなく、スライサーはミリメートル単位として読み込むため、
printは 1000 倍します。
キャラクター
- アーマチュアとそのメッシュをエクスポートします。
use_armature_deform_onlyを有効にするとコントロールボーンが除外されるため、 すべての変形ボーンを 1 つのルートボーン配下にある 1 つの階層にまとめます。Unreal のインポーターは「Found multiple roots. The importer only supports one root per mesh.」と報告します。 - すべてのプリセットで
add_leaf_bonesはオフです。有効のままにすると、各チェーンにリターゲティングを妨げる余分な末端ボーンが追加されます。 unity_skeletalとunreal_skeletalはすべてのアクションをベイクします(bake_anim_use_all_actions)。アクションごとに 1 つのクリップが作成されます。Unity では各クリップにArmature|Actionという名前が付けられるため (実測値:Rig|Wave)、アクション名はクリップに表示したい名前にします。glTF では各アクションがそれぞれの名前でアニメーションとしてエクスポートされます。robloxはアニメーションをエクスポートしません。アニメーション付きのファイルを出力するには、export()とround_trip()にbake_anim=Trueを渡します。これにより、アクションも比較されます。- シェイプキーは FBX(ブレンドシェイプ)、glTF(モーフターゲット、名前は
extras.targetNames内)、USD で受け渡されます。ARKit やビジームのセットの作成はscenario-blender-riggingの担当です。 - Roblox:頂点ごとのインフルエンスは最大 4 つ、ボーンは固定(スケール 1、回転 0)、ルートは原点に置きインフルエンスを割り当てず、メッシュごとにアニメーショントラックを 1 つにします。
max(len(v.groups) for v in obj.data.vertices)でインフルエンスを確認します。
LOD とコリジョン
bxe.lods(obj, ratios=(0.5, 0.25))はメッシュ名をName_LOD0に変更し、デシメートしたName_LOD1..nをNameという空オブジェクトの下に追加します。この空オブジェクトが親の下でメッシュに置き換わります。対象は静的メッシュのみです。 スキンメッシュの場合は処理を拒否します。Unity はこれらの名前から LOD グループを作成します。Godot はインポート時に LOD を生成します(Generate LODs)。 Unreal のドキュメントには「Import LODs」と記載されており、すべての LOD で同じピボットを共有します。このグループは通常の FBX Null としてエクスポートされますが、 Unreal でのインポート結果は未測定です。bxe.collision(obj, engine, shape)は、インポーター向けの名前が付いたコリジョンメッシュを追加します。- Unreal:
UCX_Name_00(凸包)またはUBX_Name_00(ボックス)。同じ FBX にエクスポートされます。 - Godot:
convex(1 つの凸包)とbox(境界ボックス。ボックスコライダー)の場合はName-convcolonly、mesh(メッシュをトライメッシュとして扱う。静的ボディのみ)の場合はName-colonlyです。 - Unity と Roblox:None を返します。コライダーはエディターで設定します。
- Unreal:
- デシメーションにより UV シームやシルエットが損なわれることがあります。エクスポート前に
bx_reviewで各 LOD を確認します。
一括変換
blender -b --factory-startup --python-exit-code 1 -P bx_export.py -- \
--batch /abs/in /abs/out --preset godot --profile game
フォルダー内のすべてのモデル(GLB、glTF、FBX、OBJ、USD、STL、PLY)について、空のシーンにインポートし、納品ゲートを実行してプリセットでエクスポートした後、再インポートして比較します。各ファイルのゲートエラー、サイズ、往復変換の差異を含む /abs/out/report.json が出力されます。失敗したファイルがあってもフォルダー全体の処理は停止せず、そのファイルには failed エントリが作成されます。同じ名前の入力が 2 つある場合は、出力名に形式を含めます
(hero_fbx.glb、hero_glb.glb)。一括処理を完了とする前に、レポートを開いて確認してください。
例:生成した GLB を Unity と Godot に渡す
import sys
sys.path.append("/abs/skills/scenario-blender-expert/scripts")
sys.path.append("/abs/skills/scenario-blender-export/scripts")
import bpy, bx_audit, bx_export as bxe
bpy.ops.wm.read_factory_settings(use_empty=True)
bpy.ops.import_scene.gltf(filepath="/abs/in/robot.glb")
parts = [o.name for o in bpy.context.scene.objects if o.type == "MESH"]
gate = bx_audit.deliverable(parts, profile="game")
print(gate["errors"]) # fix each one, then gate again until "pass" is True
bxe.export("/abs/out/robot.fbx", "unity", parts)
print(bxe.round_trip("/abs/out/robot.fbx", parts, preset="unity")["diffs"]) # []
bxe.export("/abs/out/robot.glb", "godot", parts)
print(bxe.glb_summary("/abs/out/robot.glb")["extensions_required"]) # []
生成した GLB では、1 つのアセット内の各パーツがそれぞれ個別のオブジェクトになっていて、すべて同じピボットを共有していることがよくあります。エンジン側でパーツをアニメーションさせたり、入れ替えたりする場合は、オブジェクトを分けたままにします。単一の静的プロップにする場合は、パーツを選択して bpy.ops.object.join を実行し、結合してから、再度ゲートを実行します。
よくある間違い
FINISHEDが出た時点でエクスポート成功と判断してしまうこと。エクスポーターは、エンジンがインポート時に100倍スケールにしたファイルや、スキンなしでインポートしたファイルでも成功します。- スキン付きメッシュをアーマチュアなしでエクスポートすること、またはメッシュなしでアーマチュアをエクスポートすること。
- アーマチュアノードの回転を取り除くために「Bake Axis Conversion」や「Apply Transform」を設定すること。どちらも回転を取り除けず、前者はキャラクターの向きを変えてしまいます。
- Godot で
webプリセットを使うこと、またはデコーダーのないローダーで圧縮済み GLB を使うこと。まずextensions_requiredを確認してください。 - FBX のテクスチャを外部パスのままにすること。プリセットはテクスチャをコピーして埋め込むため(
path_mode="COPY"、embed_textures=True)、ファイル単体で持ち運べます。export()は、拡張子のないパック済み画像(GLB のインポート時にそのようになる画像)に、まず.jpgまたは.pngという名前を付けます。一度も保存されていない画像(新しいベイクターゲット)や、編集後に保存されていない画像は、ピクセルのパック済みコピーとして持ち運ばれます(packed_unsaved_images)。 - テクスチャ付き FBX が Unity でテクスチャなしに見えること。デフォルトのインポートでは、埋め込みテクスチャはファイル内に保持されます。「Extract Textures」(Materials タブ)でモデルのフォルダーに展開すると割り当てられます。
- Blender のスケールのまま STL を使うこと。10 cm のパーツが 0.1 mm で印刷されます。
- 見た目を確認せずに LOD をエクスポートすること。デシメーションで薄い部分が潰れることがあります。