mcpField
B
blender-mcp

blender-mcp

github.com/vladmdgolamクリエイティブ・メディア92.4k 回インストール2 週間前に更新
リポジトリ

blender-mcp について

blender-mcpは、Blenderシーンの確認とGLTF書き出し準備のためのワークフロースキルです。MCPの接続確認、シーンやマテリアルの分析、ヘッドレスCLIでの書き出し、最適化、検証を案内します。

主な機能

  1. 01MCP接続とツールのヘルスチェック
  2. 02シーン階層とマテリアルの確認
  3. 03ヘッドレスCLIによるGLTF書き出し手順
  4. 04テクスチャとメッシュの最適化
  5. 05アセットとアニメーションの書き出し検証

活用シーン

  1. 01Blender MCP接続の診断
  2. 02シーンやマテリアルの書き出し問題の発見
  3. 03Web向けGLBアセットの準備
  4. 04書き出したテクスチャ、メッシュ、アニメーションの確認

MCP 対応

get_scene_info、execute_python、screenshotなどのBlender MCPツールを使い、シーンと接続状態を確認する方法を案内します。MCPサーバーはGLTF書き出しでタイムアウトするため、書き出しにはBlenderのヘッドレスCLIを使います。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/vladmdgolam/agent-skills --skill blender-mcp

インストール後、Claude Code で/blender-mcpを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
asset-integrations.md
errors.md
texture-optimization.md

詳細

Blender MCP

ツールの選択

すばやく確認するには、構造化 MCP ツール(get_scene_info、screenshot)を使用します。

複雑な処理(階層の走査、マテリアルの抽出、アニメーションのベイク処理、一括操作)には、execute_python を使用します。bpy API に完全にアクセスでき、ツールのスキーマによる制約を回避できます。

GLTF のエクスポートにはヘッドレス CLIを使用してください。MCP サーバーはエクスポート処理中にタイムアウトします。

ヘルスチェック(必ず最初に実施)

  1. get_scene_info — 接続を確認します(デフォルトポートは 9876)
  2. execute_python で print("ok") を実行 — Python が動作することを確認します
  3. screenshot — ビューポートをキャプチャできることを確認します

MCP が応答しない場合は、Blender MCP アドオンが有効になっていることと、ソケットサーバーが実行中であることを確認してください。

エクスポートの完全なワークフロー

以下は、エンドツーエンドの手順です。順番に実行してください。手順を省略しないでください。

ステップ 1:ヘルスチェック

ほかの作業を始める前に、MCP が動作していることを確認します。

# In MCP tool call:
get_scene_info
execute_python: print("ok")
screenshot

いずれかの手順が失敗した場合は、作業を中断し、まず MCP の接続を修復してください。既知のエラーと回避策を参照してください。

ステップ 2:シーンを確認

完全な階層の抽出を実行し、対象を把握します。

import bpy, json

def extract_hierarchy(obj, depth=0):
    data = {
        "name": obj.name,
        "type": obj.type,
        "location": list(obj.location),
        "rotation": list(obj.rotation_euler),
        "scale": list(obj.scale),
        "visible": not obj.hide_viewport,
        "children": [],
    }
    if obj.type == 'MESH' and obj.data:
        data["vertices"] = len(obj.data.vertices)
        data["faces"] = len(obj.data.polygons)
        data["materials"] = [slot.material.name for slot in obj.material_slots if slot.material]
    if obj.type == 'LIGHT':
        data["light_type"] = obj.data.type
        data["energy"] = obj.data.energy
        data["color"] = list(obj.data.color)
    for mod in obj.modifiers:
        if mod.type == 'ARRAY':
            data.setdefault("modifiers", []).append({
                "type": "ARRAY",
                "count": mod.count,
                "offset_object": mod.offset_object.name if mod.offset_object else None,
            })
    for child in obj.children:
        data["children"].append(extract_hierarchy(child, depth + 1))
    return data

scene_data = {
    "name": bpy.context.scene.name,
    "fps": bpy.context.scene.render.fps,
    "frame_start": bpy.context.scene.frame_start,
    "frame_end": bpy.context.scene.frame_end,
    "objects": [],
}
for obj in bpy.context.scene.objects:
    if obj.parent is None:
        scene_data["objects"].append(extract_hierarchy(obj))

print(json.dumps(scene_data, indent=2))

次の点を確認してください。

  • Array モディファイア(ベイクするとファイルサイズが急増するため、実行時に複製する必要があります)
  • 頂点数の多いオブジェクト(エクスポートが遅くなったり、GLB が大きくなったりするリスクがあります)
  • エクスポートするかどうかを判断する必要がある非表示オブジェクト
  • マテリアルが設定されていないオブジェクト(空の material_slots)
ステップ 3:マテリアルを確認

エクスポートで失われる可能性のある設定を事前に把握するため、マテリアルの抽出を実行します。

import bpy, json

def extract_materials():
    materials = []
    for mat in bpy.data.materials:
        if not mat.use_nodes:
            continue
        info = {"name": mat.name, "nodes": [], "warnings": []}
        has_principled = False
        for node in mat.node_tree.nodes:
            node_data = {"type": node.type, "name": node.name}
            if node.type == 'BSDF_PRINCIPLED':
                has_principled = True
                for inp in node.inputs:
                    if inp.is_linked:
                        node_data[inp.name] = "linked"
                    elif hasattr(inp, 'default_value'):
                        val = inp.default_value
                        try:
                            node_data[inp.name] = list(val)
                        except TypeError:
                            node_data[inp.name] = float(val)
            if node.type == 'TEX_IMAGE' and node.image:
                node_data["image"] = node.image.filepath
                node_data["size"] = [node.image.size[0], node.image.size[1]]
                if node.image.size[0] > 2048:
                    info["warnings"].append(f"Large texture: {node.image.filepath} ({node.image.size[0]}x{node.image.size[1]})")
            if node.type in ('TEX_NOISE', 'TEX_VORONOI', 'TEX_WAVE', 'TEX_MUSGRAVE'):
                info["warnings"].append(f"Procedural texture node '{node.name}' ({node.type}) will be LOST on GLTF export")
            if node.type == 'VALTORGB':  # Color Ramp
                info["warnings"].append(f"Color Ramp '{node.name}' remapping will be LOST on GLTF export")
        if not has_principled:
            info["warnings"].append("No Principled BSDF found — export result unpredictable")
        info["nodes"].append(node_data)
        materials.append(info)
    return materials

result = extract_materials()
for mat in result:
    if mat["warnings"]:
        print(f"WARN [{mat['name']}]: {'; '.join(mat['warnings'])}")
print(json.dumps(result, indent=2))

先に進む前に、すべての警告を確認してください。プロシージャルテクスチャを今すぐベイクするか、エクスポート後に実行時にマテリアルを修正するかを判断します。

ステップ 4:ヘッドレス CLI でエクスポート

MCP サーバーは GLTF のエクスポートを処理できません(タイムアウト)。必ずヘッドレス CLI を使用してください。

# Use 'blender' if it's on PATH, otherwise use the platform-specific path:
#   macOS:   /Applications/Blender.app/Contents/MacOS/Blender
#   Windows: "C:\Program Files\Blender Foundation\Blender 4.x\blender.exe"
#   Linux:   /usr/bin/blender
blender \
  --background "/path/to/scene.blend" \
  --python-expr "
import bpy, os
export_path = '/path/to/output.glb'
os.makedirs(os.path.dirname(os.path.abspath(export_path)), exist_ok=True)
bpy.ops.export_scene.gltf(
    filepath=export_path,
    export_format='GLB',
    export_apply=False,
    export_animations=True,
    export_nla_strips=True,
    export_cameras=True,
    export_lights=False,
    export_draco_mesh_compression_enable=False,
)
size_mb = os.path.getsize(export_path) / 1024 / 1024
print(f'Export complete: {export_path} ({size_mb:.1f} MB)')
"

重要なフラグ:

  • export_apply=False — モディファイアをベイクしません(Array モディファイアを適用すると、1 MB が 56 MB になります)
  • export_draco_mesh_compression_enable=False — Draco 圧縮は後から gltf-transform で適用します
  • スペースを含む可能性のあるパスはすべて引用符で囲みます
ステップ 5:gltf-transform で最適化

エクスポートが成功した後に実行します。必ず個別の手順を使用し、optimize は使用しないでください。

# 1. Inspect raw export first
npx @gltf-transform/cli inspect output.glb

# 2. Resize textures (max 1K for web/mobile)
npx @gltf-transform/cli resize output.glb resized.glb --width 1024 --height 1024

# 3. WebP compression (quality 90 preserves detail)
npx @gltf-transform/cli webp resized.glb webp.glb --quality 90

# 4. Draco mesh compression (LAST — irreversible)
npx @gltf-transform/cli draco webp.glb final.glb

# 5. Inspect final result
npx @gltf-transform/cli inspect final.glb

予想されるサイズ削減量:未圧縮で約 22 MB → WebP で約 3.7 MB → Draco で約 1 MB。詳細な測定値については、references/texture-optimization.mdを参照してください。

ステップ 6:検証

納品前に、以下の「エクスポート後の検証」チェックリストをすべて実行してください。

エクスポート後の検証チェックリスト

エクスポートのたびに、GLB を統合作業に渡す前に以下を確認してください。

  • ファイルサイズが適切であること — 一般的な Web シーンでは、最適化前の GLB は 30 MB 未満、最適化後の GLB は 5 MB 未満にします。これらのしきい値を超えるものがあれば報告してください。
  • gltf-transform CLI で検査すること — npx @gltf-transform/cli inspect final.glb を実行し、メッシュ数、テクスチャ数、テクスチャサイズ、アニメーション数、アクセサーのサイズを確認します。予期しない重複がないことを確認してください。
  • Babylon.js Sandbox でビジュアルテストを行うこと — sandbox.babylonjs.com に GLB をドラッグ&ドロップします。メッシュが正しく描画されること、テクスチャが表示されること、アニメーションが再生されること、黒やピンクのマテリアルがないことを確認してください。
  • Three.js のコンソールエラーがないこと — 最小構成の Three.js GLTFLoader テストページで読み込み、ブラウザーのコンソールを確認します。よくあるエラー:THREE.GLTFLoader: Unknown extension、テクスチャファイルの欠落、未対応の Draco バージョン。
  • マテリアルを抜き取り確認すること — 3~5 個のマテリアルを選び、ラフネス、メタルネス、ベースカラーが正しく見えることを目視で確認します。Blender のビューポートレンダーと比較してください。フラットに見えるものや、光沢が強すぎるものがあれば報告してください。
  • アニメーションを抜き取り確認すること — シーンにアニメーションがある場合は、Babylon.js Sandbox または Three.js で少なくとも 1 つが正しく再生されることを確認します。フレーム数が想定どおりであることも確認してください。
  • 名前のマッピングが検証済みであること — ランタイムコードがメッシュ名を参照する場合は、GLTF エクスポート時の変換後も名前が一致することを確認します(スペース → アンダースコア、ドットを削除)。重大なルール 5 を参照してください。
  • テクスチャの欠落がないこと — Babylon.js Sandbox のネットワークタブを確認します。テクスチャファイルへの 404 がないこと、すべてのテクスチャが GLB 内に格納されていることを確認してください。

例

例 1:アニメーション付きのキャラクターリグをエクスポートする

シナリオ: アーマチュア、3 つの NLA アクション(idle、walk、run)、PBR テクスチャセットを持ち、ペアレント化によって武器が取り付けられた人型キャラクターがあります。Three.js シーン用の Web 対応 GLB が必要です。

手順 1:ヘルスチェックとシーンの検査

# MCP tool calls
get_scene_info
execute_python: print("ok")

手順 2:リグを検査する

import bpy, json

# Check armature and NLA strips
for obj in bpy.data.objects:
    if obj.type == 'ARMATURE':
        print(f"Armature: {obj.name}")
        if obj.animation_data:
            print(f"  Active action: {obj.animation_data.action.name if obj.animation_data.action else 'None'}")
            for track in obj.animation_data.nla_tracks:
                print(f"  NLA track: {track.name}")
                for strip in track.strips:
                    print(f"    Strip: {strip.name}, frames {strip.frame_start}-{strip.frame_end}")

手順 3:エクスポートで失われるマテリアル情報を確認する

上記のマテリアル抽出を実行します。キャラクターの場合、以下に注意してください。

  • プロシージャルスキンテクスチャノード(Noise → 色の変化)— これらは失われます
  • 布地のラフネスに使われている Color Ramp — これは失われ、ラフネスはフラットに見えます
  • 判断:プロシージャルな変化を画像テクスチャにベイクするか、ランタイムでラフネス値を調整します

手順 4:エクスポートする

blender \
  --background "/path/to/character.blend" \
  --python-expr "
import bpy, os, tempfile
export_dir = tempfile.gettempdir()
bpy.ops.export_scene.gltf(
    filepath=os.path.join(export_dir, 'character.glb'),
    export_format='GLB',
    export_apply=False,
    export_animations=True,
    export_nla_strips=True,
    export_cameras=False,
    export_lights=False,
    export_draco_mesh_compression_enable=False,
    export_skins=True,
    export_morph=True,
)
print('done:', os.path.getsize(os.path.join(export_dir, 'character.glb')) / 1024 / 1024, 'MB')
"

手順 5:アニメーションがエクスポートされたことを確認する

npx @gltf-transform/cli inspect character.glb | grep -i anim

期待される出力:アニメーション 3 つ(Idle、Walk、Run)。0 の場合は、NLA ストリップがミュートされていないか、トラックがソロに設定されていないか確認してください。

手順 6:最適化する

npx @gltf-transform/cli resize character.glb char_resized.glb --width 1024 --height 1024
npx @gltf-transform/cli webp char_resized.glb char_webp.glb --quality 90
npx @gltf-transform/cli draco char_webp.glb character_final.glb

手順 7:ランタイムでアニメーションを設定する(Three.js)

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import * as THREE from 'three';

const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');

const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);

loader.load('/character_final.glb', (gltf) => {
    const mixer = new THREE.AnimationMixer(gltf.scene);
    const clips = gltf.animations; // [Idle, Walk, Run]
    const idleAction = mixer.clipAction(clips.find(c => c.name === 'Idle'));
    idleAction.play();
    // Animate mixer in render loop: mixer.update(delta)
});

例 2:マテリアルのエクスポートで失われる情報をデバッグする(ラフネスがフラットに見える)

シナリオ: エクスポート後、金属パネルのマテリアルが Three.js で均一にフラットで、光沢のある見た目になります。Blender では Noise Texture → Color Ramp → ラフネス入力によるラフネスの変化がありました。

手順 1:Blender で問題を確認する

import bpy, json

mat = bpy.data.materials.get("MetalPanel")
if mat and mat.use_nodes:
    for node in mat.node_tree.nodes:
        print(f"Node: {node.type} - {node.name}")
        for inp in node.inputs:
            if inp.is_linked:
                print(f"  Input '{inp.name}': linked to something")

期待される出力には、以下の内容が表示されます。

Node: BSDF_PRINCIPLED - Principled BSDF
  Input 'Roughness': linked to something
Node: VALTORGB - Color Ramp         <-- this will NOT export
Node: TEX_NOISE - Noise Texture     <-- this will NOT export

手順 2:GLTF に渡された内容を把握する

エクスポート時には Principled BSDF のラフネス入力がエクスポートされます。Color Ramp に接続されている場合、GLTF エクスポーターは入力ソケットの default_value(フォールバック値)を使用します。通常は 0.5 で、完全にフラットな値です。

手順 3A:Blender でベイクして修正する(最高品質)

import bpy

# Select the object
obj = bpy.data.objects["MetalPanelMesh"]
bpy.context.view_layer.objects.active = obj
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)

# Create a new image to bake into
bake_img = bpy.data.images.new("MetalPanel_roughness_baked", width=1024, height=1024)
bake_img.colorspace_settings.name = 'Non-Color'

# Add image texture node to material
mat = obj.active_material
nodes = mat.node_tree.nodes
img_node = nodes.new('ShaderNodeTexImage')
img_node.image = bake_img
nodes.active = img_node

# Bake roughness (use ROUGHNESS pass or EMIT trick)
bpy.context.scene.cycles.bake_type = 'ROUGHNESS'
bpy.ops.object.bake(type='ROUGHNESS', save_mode='INTERNAL')

# Save baked image
import tempfile, os
bake_path = os.path.join(tempfile.gettempdir(), 'MetalPanel_roughness_baked.png')
bake_img.filepath_raw = bake_path
bake_img.file_format = 'PNG'
bake_img.save()
print(f"Baked roughness to {bake_path}")

その後、新しい画像テクスチャノードを Roughness 入力に接続して、再エクスポートします。

手順 3B:Three.js のランタイムで修正する(簡易パッチ)

ベイクできない場合は、読み込み後にマテリアルを上書きします。

loader.load('/metal_panel.glb', (gltf) => {
    gltf.scene.traverse((child) => {
        if (child.isMesh && child.material) {
            const mats = Array.isArray(child.material) ? child.material : [child.material];
            mats.forEach(mat => {
                if (mat.name === 'MetalPanel') {
                    // Instead of flat 0.5, set a textured roughness or varied value
                    mat.roughness = 0.3;  // adjust to match intended look
                    mat.metalness = 0.9;
                    mat.needsUpdate = true;
                }
            });
        }
    });
});

手順 4:修正を確認する

再エクスポートして、検証チェックリストを実行します。Babylon.js Sandbox で金属パネルのマテリアルを Blender のビューポートのスクリーンショットと比較し、ラフネスの変化が保持されていることを確認してください。

重大なルール

1. MCP サーバーはエクスポート時にタイムアウトする

Blender MCP サーバーでは GLTF エクスポートを処理できません。タイムアウトを超えるためです。必ずヘッドレス CLI を使用してください。

blender --background "scene.blend" --python-expr "
import bpy, os
export_path = 'output.glb'
os.makedirs(os.path.dirname(export_path), exist_ok=True)
bpy.ops.export_scene.gltf(
    filepath=export_path,
    export_format='GLB',
    export_apply=False,
    export_animations=True,
    export_nla_strips=True,
    export_cameras=True,
    export_lights=False,
    export_draco_mesh_compression_enable=False,
)
print(f'Size: {os.path.getsize(export_path)/1024/1024:.1f} MB')
"
2. エクスポート時にモディファイアーを適用しない

export_apply=False に設定してください。配列モディファイアー(円形パターン、線形の反復)を適用すると、ファイルサイズが膨れ上がります。代わりに、実行時に複製してください。

例:Array モディファイアーを使用したローラーインスタンス 16 個の場合、GLB は約 1 MB です。適用すると、GLB は約 56 MB になります。

3. まずは Draco なしでエクスポートする

gltf-transform で最適化する予定がある場合は、Draco 圧縮なしでエクスポートしてください。既存の Draco データを再エンコードすると、メッシュが破損します。Draco の適用は最後の手順にしてください。

4. プロシージャルテクスチャは GLTF にエクスポートされない

以下の Blender ノード設定はエクスポート時に失われます。

ノード設定失われるもの回避策
Noise Texture → roughnessプロシージャルチェーン全体テクスチャにベイクするか、実行時にシェーダーパッチを適用
roughness テクスチャ上の Color Ramp値の再マッピング範囲roughness 値を手動で設定するか、実行時に再マッピング
プロシージャルバンプ(Noise → Bump)バンプの詳細Blender でノーマルマップをベイク
複雑な係数を使った Mix Shaderブレンドロジックエクスポート前に単一の BSDF に簡略化

エクスポートされるもの: 平坦な roughness/metallic 値、画像テクスチャ(Color Ramp による再マッピングを除く)、ベイク済みノーマルマップ、PBR テクスチャセット(baseColor、metallicRoughness、normal)。

5. GLTF の名前マッピング

Blender の名前は GLTF では次のように変換されます。

  • スペース → アンダースコア
  • ピリオド → 削除
  • 末尾のスペース → 末尾のアンダースコア
BlenderGLTF
RINGS ball LRINGS_ball_L
Sphere.003Sphere003
RINGS L.001RINGS_L001
RINGS S (末尾にスペース)RINGS_S_

コード内でメッシュを参照する場合は、Blender ではなく、エクスポートした GLB 内の名前を必ず確認してください。

6. gltf-transform の optimize は絶対に使わない

optimize コマンドには、メッシュジオメトリを破壊する simplify が含まれています。代わりに、個別の手順を使用してください。

# Resize textures (max 1024x1024)
npx @gltf-transform/cli resize input.glb resized.glb --width 1024 --height 1024

# WebP texture compression
npx @gltf-transform/cli webp resized.glb webp.glb --quality 90

# Draco mesh compression (LAST step)
npx @gltf-transform/cli draco webp.glb output.glb
7. スペースを含むパスは引用符で囲む

Blender プロジェクトのパスには、スペースが含まれることがよくあります。必ず二重引用符で囲んでください。

blender --background "$HOME/Downloads/blend 3/scene.blend" ...

シーン抽出のパターン

マテリアル、トランスフォーム、モディファイアーを含む完全な階層:

import bpy, json

def extract_hierarchy(obj, depth=0):
    data = {
        "name": obj.name,
        "type": obj.type,
        "location": list(obj.location),
        "rotation": list(obj.rotation_euler),
        "scale": list(obj.scale),
        "visible": not obj.hide_viewport,
        "children": [],
    }
    if obj.type == 'MESH' and obj.data:
        data["vertices"] = len(obj.data.vertices)
        data["faces"] = len(obj.data.polygons)
        data["materials"] = [slot.material.name for slot in obj.material_slots if slot.material]
    if obj.type == 'LIGHT':
        data["light_type"] = obj.data.type
        data["energy"] = obj.data.energy
        data["color"] = list(obj.data.color)
        if obj.data.type == 'AREA':
            data["size"] = obj.data.size
            data["size_y"] = obj.data.size_y
    # Array modifiers (important for runtime replication)
    for mod in obj.modifiers:
        if mod.type == 'ARRAY':
            data.setdefault("modifiers", []).append({
                "type": "ARRAY",
                "count": mod.count,
                "offset_object": mod.offset_object.name if mod.offset_object else None,
            })
    for child in obj.children:
        data["children"].append(extract_hierarchy(child, depth + 1))
    return data

scene_data = {
    "name": bpy.context.scene.name,
    "fps": bpy.context.scene.render.fps,
    "frame_start": bpy.context.scene.frame_start,
    "frame_end": bpy.context.scene.frame_end,
    "objects": [],
}

for obj in bpy.context.scene.objects:
    if obj.parent is None:
        scene_data["objects"].append(extract_hierarchy(obj))

print(json.dumps(scene_data, indent=2))

マテリアル抽出のパターン

import bpy, json

def extract_materials():
    materials = []
    for mat in bpy.data.materials:
        if not mat.use_nodes:
            continue
        info = {"name": mat.name, "nodes": []}
        for node in mat.node_tree.nodes:
            node_data = {"type": node.type, "name": node.name}
            if node.type == 'BSDF_PRINCIPLED':
                for inp in node.inputs:
                    if inp.is_linked:
                        node_data[inp.name] = "linked"
                    elif hasattr(inp, 'default_value'):
                        val = inp.default_value
                        try:
                            node_data[inp.name] = list(val)
                        except TypeError:
                            node_data[inp.name] = float(val)
            if node.type == 'TEX_IMAGE' and node.image:
                node_data["image"] = node.image.filepath
                node_data["size"] = [node.image.size[0], node.image.size[1]]
            info["nodes"].append(node_data)
        materials.append(info)
    return materials

print(json.dumps(extract_materials(), indent=2))

アニメーションのキーフレーム抽出

import bpy, json

def extract_animation(obj):
    if not obj.animation_data or not obj.animation_data.action:
        return None
    tracks = []
    for fc in obj.animation_data.action.fcurves:
        keyframes = []
        for kp in fc.keyframe_points:
            keyframes.append({
                "frame": int(kp.co[0]),
                "value": float(kp.co[1]),
                "interpolation": kp.interpolation,
            })
        tracks.append({
            "data_path": fc.data_path,
            "index": fc.array_index,
            "keyframes": keyframes,
        })
    return {"object": obj.name, "tracks": tracks}

animations = []
for obj in bpy.data.objects:
    anim = extract_animation(obj)
    if anim:
        animations.append(anim)

print(json.dumps(animations, indent=2))

GLTF エクスポート設定のリファレンス

設定値理由
export_format'GLB'単一のバイナリファイル
export_applyFalseモディファイアー(Array など)をベイクしない
export_animationsTrueアニメーションデータを含める
export_nla_stripsTrueNLA ストリップをアクションにベイクする
export_camerasTrueカメラリグを含める
export_lightsFalseライトは実行時(Three.js/R3F)に処理する
export_draco_mesh_compression_enableFalse後から gltf-transform で Draco を適用する

テクスチャ最適化パイプライン

目標:許容できる視覚品質を保ちながら、GLB を最小サイズにすること。

Blender export (no Draco) → resize (1K max) → WebP (q90) → Draco
   ~22 MB                    ~3.7 MB           ~3.7 MB      ~1 MB

主なポイント:

  • 4K テクスチャ(4096x4096)は、テクスチャ 1 枚あたり約 89 MB の GPU メモリを使用します。1K では約 5.6 MB です。16 分の 1 に削減できます。
  • PNG の metallicRoughness テクスチャは、品質 85〜90 の WebP にするとよく圧縮されます。
  • モバイル GPU(Adreno、Mali)では、テクスチャのダウンスケーリングが特に効果的です。
  • npx @gltf-transform/cli inspect model.glb で確認できます。

具体的なコマンドと品質指標については、references/texture-optimization.md を参照してください。

アセット連携

設定済みの場合、Blender MCP から利用できます。

連携機能
PolyHaven無料の HDRI、テクスチャ、3D モデルを検索、ダウンロード、インポートし、マテリアルを自動設定
Sketchfabモデルを検索、ダウンロード(アクセストークンが必要)
Hyper3D Rodinテキストの説明や参照画像から 3D モデルを生成
Hunyuan3Dテキストプロンプト、画像、またはその両方から 3D アセットを作成

使用例とワークフローのパターンについては、references/asset-integrations.md を参照してください。

既知のエラーと回避策

エラーの一覧については、references/errors.md を参照してください。

データ出力

  • 小さな結果(シーン情報、単一オブジェクト)には、print() + json.dumps() を使用します
  • 大きな抽出結果(階層全体、アニメーションデータ、マテリアルレポート)には、tempfile.gettempdir() を使用します
  • メタデータ(シーン名、fps、フレーム範囲、Blender のバージョン)を必ず含めます

コメント