mcpField
S
scenario-blender-export

scenario-blender-export

github.com/scenario-labsクリエイティブ・メディア1.2k117 回インストール1 日前に更新
リポジトリ

scenario-blender-export について

scenario-blender-export は、Blender のアセットをゲームエンジン、Web 形式、USD パイプライン、3D プリント向けに準備するスキルです。エンジン別のプリセットに出荷前監査と再インポート比較を組み合わせ、エクスポート成功だけでは分からない差異を確認します。

主な機能

  1. 01エンジン別プリセットでのエクスポート
  2. 02エクスポート前のアセット監査
  3. 03再インポートによるファイル比較
  4. 04GLB の内容と拡張機能の要約
  5. 05LOD とコリジョンメッシュの生成
  6. 06対応モデル形式の一括変換

活用シーン

  1. 01Unity または Unreal Engine 向けのキャラクター FBX 作成
  2. 02Godot または Web 向け GLB のエクスポート
  3. 03往復比較によるモデル差異の確認
  4. 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、静的メッシュunityFBXインポート時のデフォルト設定
Unity、キャラクターunity_skeletalFBXBake Axis Conversionはオフのままにする
Unreal EngineunrealFBXConvert Scene Unit(センチメートルに変換)
Unreal Engine、キャラクターunreal_skeletalFBXルートボーンを1つにする
Godot 4godotGLBインポート時のデフォルト設定。ドックでGenerate LODs
RobloxrobloxFBXメッシュあたり20,000三角形
three.jsとWebwebGLB、meshopt、WebPMeshoptDecoder。Godotでは使用不可
任意のglTFリーダーgltfGLB
USDパイプラインusdUSDC
Apple AR Quick LookusdzUSDZ、2048テクスチャ
3Dプリントprintミリメートル単位のSTLスライサーはミリメートルを読み取る

UnityとGodotのプリセットはUnity 6000.3とGodot 4.7.2にインポートして計測済みです。unreal、unreal_skeletal、robloxはEpicとRobloxのドキュメントに準拠しており、Blenderのラウンドトリップのみ検証済みです。計測結果はreferences/engines.mdに記載されています。

手順

  1. ゲートする。 scenario-blender-expertのbx_audit.deliverable(parts, profile)を実行し、すべてのエラーを修正します。オブジェクトに残ったスケールは、ノードのトランスフォームとしてエンジンに渡されます。
  2. プリセットを選ぶ。 表から選択します。ファイルに必要なオブジェクトをすべて渡します。スキン付きメッシュとそのアーマチュア、LODメッシュとそのグループ、レンダーメッシュと並べるコリジョンメッシュなどです。
  3. エクスポートする: bxe.export(path, preset, objects, **overrides)。エクスポーターのキーワード引数はどれもプリセットを上書きします。たとえば、アニメーションファイルを作成する場合は、robloxでbake_anim=Trueを指定します。結果には使用した設定が記録されます。
  4. ラウンドトリップする: bxe.round_trip(path, objects, preset=...)は、バックグラウンドのBlenderでファイルを再インポートし、開いているシーンには手を加えません。サイズ(1 mm)、三角形数、変形ボーン、ルートボーン(1つを想定)、アーマチュアのスケール、シェイプキー、およびオブジェクトに保存されているすべてのアクションを名前で比較します。その後、差分をすべて一覧表示します。それぞれを修正するか、想定どおりである理由を説明してください。
  5. glTFの内容を確認する: bxe.glb_summary(path)は、Blenderを使わずにextensions_required、モーフターゲット、スキン、クリップ、画像タイプを一覧表示します。ローダーは、対応していない拡張機能を必要とするファイルを拒否します。
  6. エンジンで確認する: エンジンにインポートして確認します。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 を返します。コライダーはエディターで設定します。
  • デシメーションにより 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 をエクスポートすること。デシメーションで薄い部分が潰れることがあります。

コメント