blender-web-pipeline について
blender-web-pipelineは、Blenderのモデルやアニメーションを主にglTF 2.0などのウェブ向け形式へ書き出すスキルです。3Dアセットやウェブコンテンツの制作向けに、Python自動化、バッチ処理、最適化を扱います。
主な機能
- 01glTF 2.0の書き出しと最適化
- 02Python(bpy)による自動化
- 03Blenderファイルのバッチ処理
- 04テクスチャのベイクと圧縮
- 05LODモデルの生成
- 06ジオメトリとマテリアルの最適化
活用シーン
- 01BlenderアセットのGLB書き出し
- 023Dモデルの一括変換
- 03ウェブ向けモデルとテクスチャの最適化
- 04ウェブ3Dアセット制作パイプラインの構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ freshtechbro/ claudedesignskills --skill blender-web-pipelineインストール後、Claude Code で/blender-web-pipelineを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/README.mdreferences/bpy_api_reference.mdgltf_export_guide.mdoptimization_strategies.mdscripts/batch_export.pygenerate_lods.pyoptimize_model.py詳細
Blender Web Pipeline
概要
Blender Web Pipeline スキルでは、Blender から Web に最適化された形式(主に glTF 2.0)で 3D モデルやアニメーションを書き出すワークフローを提供します。バッチ処理用の Python スクリプト、Web パフォーマンス向けの最適化手法、Three.js や Babylon.js などの Web 3D ライブラリとの連携について説明します。
このスキルを使用する場面:
- Web アプリケーション向けに Blender モデルを書き出す
- 複数の 3D アセットをバッチ処理する
- Web 配信向けにファイルサイズを最適化する
- Blender の反復作業を自動化する
- 3D Web コンテンツ用の本番パイプラインを構築する
- レガシー形式を glTF に変換する
主な機能:
- 最適化を含む glTF 2.0 の書き出し
- Python(bpy)による自動化スクリプト
- テクスチャのベイクと圧縮
- LOD(詳細度)の生成
- バッチ処理ワークフロー
- Web 向けのマテリアルとライティングの最適化
基本概念
glTF 2.0 形式
Web に glTF を使用する理由:
- Web 向けの業界標準 3D 形式
- 効率的なバイナリーエンコーディング(.glb)
- PBR マテリアルに対応
- アニメーションとスキニングに対応
- カスタムデータで拡張可能
- 幅広いライブラリに対応(Three.js、Babylon.js など)
glTF と GLB の比較:
.gltf = JSON + external .bin + external textures
.glb = Single binary file (recommended for web)
Blender Python API(bpy)
Python を通じて Blender のデータや操作にアクセスします:
import bpy
# Access scene data
scene = bpy.context.scene
objects = bpy.data.objects
# Modify objects
obj = bpy.data.objects['Cube']
obj.location = (0, 0, 1)
obj.scale = (2, 2, 2)
# Export glTF
bpy.ops.export_scene.gltf(
filepath='/path/to/model.glb',
export_format='GLB'
)
Web 最適化の目標
目標指標:
- ファイルサイズ:モデルあたり <5 MB(理想は <1 MB)
- ポリゴン数:リアルタイム用途では <50k 三角形
- テクスチャ解像度:最大 2048x2048(1024x1024 を推奨)
- ドローコール:テクスチャアトラスで最小化
- 読み込み時間:平均的な接続環境で <2 秒
よくあるパターン
1. 基本的な glTF の書き出し(手動)
# Blender Python Console or script
import bpy
# Select objects to export (optional - exports all if none selected)
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects['MyModel'].select_set(True)
# Export as GLB
bpy.ops.export_scene.gltf(
filepath='/path/to/output.glb',
export_format='GLB', # Binary format
use_selection=True, # Export selected only
export_apply=True, # Apply modifiers
export_texcoords=True, # UV coordinates
export_normals=True, # Normals
export_materials='EXPORT', # Export materials
export_colors=True, # Vertex colors
export_cameras=False, # Skip cameras
export_lights=False, # Skip lights
export_animations=True, # Include animations
export_draco_mesh_compression_enable=True, # Compress geometry
export_draco_mesh_compression_level=6, # 0-10 (6 recommended)
export_draco_position_quantization=14, # 8-14 bits
export_draco_normal_quantization=10, # 8-10 bits
export_draco_texcoord_quantization=12 # 8-12 bits
)
2. バッチ書き出し用 Python スクリプト
#!/usr/bin/env blender --background --python
"""
Batch export all .blend files in a directory to glTF
Usage: blender --background --python batch_export.py -- /path/to/blend/files
"""
import bpy
import os
import sys
# Get command line arguments after --
argv = sys.argv
argv = argv[argv.index("--") + 1:] if "--" in argv else []
input_dir = argv[0] if argv else "/path/to/models"
output_dir = argv[1] if len(argv) > 1 else input_dir + "_gltf"
# Create output directory
os.makedirs(output_dir, exist_ok=True)
# Find all .blend files
blend_files = [f for f in os.listdir(input_dir) if f.endswith('.blend')]
print(f"Found {len(blend_files)} .blend files")
for blend_file in blend_files:
input_path = os.path.join(input_dir, blend_file)
output_name = blend_file.replace('.blend', '.glb')
output_path = os.path.join(output_dir, output_name)
print(f"Processing: {blend_file}")
# Open blend file
bpy.ops.wm.open_mainfile(filepath=input_path)
# Export as GLB with optimizations
bpy.ops.export_scene.gltf(
filepath=output_path,
export_format='GLB',
export_apply=True,
export_draco_mesh_compression_enable=True,
export_draco_mesh_compression_level=6
)
print(f" Exported: {output_name}")
print("Batch export complete!")
バッチスクリプトを実行します:
blender --background --python batch_export.py -- /models/source /models/output
3. Web 向けにモデルを最適化する(デシメーション)
import bpy
def optimize_mesh(obj, target_ratio=0.5):
"""Reduce polygon count using decimation modifier."""
if obj.type != 'MESH':
return
# Add Decimate modifier
decimate = obj.modifiers.new(name='Decimate', type='DECIMATE')
decimate.ratio = target_ratio # 0.5 = 50% of original polygons
decimate.use_collapse_triangulate = True
# Apply modifier
bpy.context.view_layer.objects.active = obj
bpy.ops.object.modifier_apply(modifier='Decimate')
print(f"Optimized {obj.name}: {len(obj.data.polygons)} polygons")
# Optimize all selected meshes
for obj in bpy.context.selected_objects:
optimize_mesh(obj, target_ratio=0.3)
4. Web 向けのテクスチャベイク
import bpy
def bake_textures(obj, resolution=1024):
"""Bake all materials to single texture."""
# Setup bake settings
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.bake_type = 'COMBINED'
# Create bake image
bake_image = bpy.data.images.new(
name=f"{obj.name}_bake",
width=resolution,
height=resolution
)
# Create bake material
mat = bpy.data.materials.new(name=f"{obj.name}_baked")
mat.use_nodes = True
nodes = mat.node_tree.nodes
# Add Image Texture node
tex_node = nodes.new(type='ShaderNodeTexImage')
tex_node.image = bake_image
tex_node.select = True
nodes.active = tex_node
# Assign material
if obj.data.materials:
obj.data.materials[0] = mat
else:
obj.data.materials.append(mat)
# Select object
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
# Bake
bpy.ops.object.bake(type='COMBINED')
# Save baked texture
bake_image.filepath_raw = f"/tmp/{obj.name}_bake.png"
bake_image.file_format = 'PNG'
bake_image.save()
print(f"Baked {obj.name} to {bake_image.filepath_raw}")
# Bake selected objects
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
bake_textures(obj, resolution=2048)
5. LOD(詳細度)の生成
import bpy
def generate_lods(obj, lod_levels=[0.75, 0.5, 0.25]):
"""Generate LOD copies with decreasing polygon counts."""
lod_objects = []
for i, ratio in enumerate(lod_levels):
# Duplicate object
lod_obj = obj.copy()
lod_obj.data = obj.data.copy()
lod_obj.name = f"{obj.name}_LOD{i}"
# Link to scene
bpy.context.collection.objects.link(lod_obj)
# Add Decimate modifier
decimate = lod_obj.modifiers.new(name='Decimate', type='DECIMATE')
decimate.ratio = ratio
# Apply modifier
bpy.context.view_layer.objects.active = lod_obj
bpy.ops.object.modifier_apply(modifier='Decimate')
lod_objects.append(lod_obj)
print(f"Created {lod_obj.name}: {len(lod_obj.data.polygons)} polygons")
return lod_objects
# Generate LODs for selected object
if bpy.context.active_object:
generate_lods(bpy.context.active_object)
6. テクスチャ圧縮を使用して書き出す
import bpy
import os
def export_optimized_gltf(filepath, texture_max_size=1024):
"""Export glTF with downscaled textures."""
# Downscale all textures
for img in bpy.data.images:
if img.size[0] > texture_max_size or img.size[1] > texture_max_size:
img.scale(texture_max_size, texture_max_size)
print(f"Downscaled {img.name} to {texture_max_size}x{texture_max_size}")
# Export with Draco compression
bpy.ops.export_scene.gltf(
filepath=filepath,
export_format='GLB',
export_apply=True,
export_image_format='JPEG', # JPEG for smaller size (or PNG for quality)
export_jpeg_quality=85, # 0-100
export_draco_mesh_compression_enable=True,
export_draco_mesh_compression_level=8, # Max compression
export_draco_position_quantization=12,
export_draco_normal_quantization=8,
export_draco_texcoord_quantization=10
)
# Export optimized
export_optimized_gltf('/path/to/optimized.glb', texture_max_size=512)
7. コマンドラインによる自動化
#!/bin/bash
# Batch export Blender files to glTF without opening GUI
SCRIPT_DIR="$(dirname "$0")"
# Export all .blend files in current directory
for blend_file in *.blend; do
echo "Exporting $blend_file..."
blender --background "$blend_file" --python - <<EOF
import bpy
import os
# Get output filename
filename = os.path.splitext(bpy.data.filepath)[0]
output = filename + '.glb'
# Export
bpy.ops.export_scene.gltf(
filepath=output,
export_format='GLB',
export_apply=True,
export_draco_mesh_compression_enable=True,
export_draco_mesh_compression_level=6
)
print(f'Exported to {output}')
EOF
done
echo "All files exported!"
連携パターン
Three.js との連携
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
const loader = new GLTFLoader();
// Setup Draco decoder for compressed models
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');
loader.setDRACOLoader(dracoLoader);
// Load Blender export
loader.load('/models/exported.glb', (gltf) => {
scene.add(gltf.scene);
// Play animations
if (gltf.animations.length > 0) {
const mixer = new THREE.AnimationMixer(gltf.scene);
const action = mixer.clipAction(gltf.animations[0]);
action.play();
}
});
React Three Fiber との連携
import { useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/models/exported.glb');
return <primitive object={scene} />;
}
// Preload for better performance
useGLTF.preload('/models/exported.glb');
Babylon.js との連携
import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders/glTF';
BABYLON.SceneLoader.ImportMesh(
'',
'/models/',
'exported.glb',
scene,
(meshes) => {
console.log('Loaded meshes:', meshes);
}
);
最適化手法
1. ジオメトリの最適化
デシメートモディファイアー:
# Reduce polygon count by 70%
obj.modifiers.new(name='Decimate', type='DECIMATE')
obj.modifiers['Decimate'].ratio = 0.3
距離で統合:
# Remove duplicate vertices
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles(threshold=0.0001)
bpy.ops.object.mode_set(mode='OBJECT')
面を三角形化:
# Ensure all faces are triangles (required for some engines)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.quads_convert_to_tris()
bpy.ops.object.mode_set(mode='OBJECT')
2. テクスチャの最適化
画像の圧縮:
# Save textures as JPEG (lossy but smaller)
for img in bpy.data.images:
img.file_format = 'JPEG'
img.filepath_raw = f"/output/{img.name}.jpg"
img.save()
テクスチャアトラス:
# Combine multiple textures into one atlas
# Use Smart UV Project for automatic atlasing
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.smart_project(angle_limit=66, island_margin=0.02)
bpy.ops.object.mode_set(mode='OBJECT')
3. マテリアルの簡略化
PBR に変換:
# Ensure materials use Principled BSDF (glTF standard)
for mat in bpy.data.materials:
if not mat.use_nodes:
mat.use_nodes = True
nodes = mat.node_tree.nodes
principled = nodes.get('Principled BSDF')
if not principled:
principled = nodes.new(type='ShaderNodeBsdfPrincipled')
output = nodes.get('Material Output')
mat.node_tree.links.new(principled.outputs[0], output.inputs[0])
よくある問題
1. ファイルサイズが大きい
問題: 書き出した .glb ファイルが 20 MB 以上になる
解決策:
- Draco 圧縮を有効にする(60~90% 削減)
- テクスチャ解像度を下げる(2048 → 1024 または 512)
- テクスチャには PNG ではなく JPEG を使用する
- ジオメトリをデシメーションする(目標:<50k 三角形)
- 未使用のマテリアルやテクスチャを削除する
2. 書き出し後にテクスチャが見つからない
問題: Web ビューアーにテクスチャが表示されない
解決策:
- すべての画像が保存されていることを確認する(パックされていない状態)
- テクスチャには相対パスを使用する
- 「Export Images」を有効にして書き出す
- 画像形式の互換性を確認する(PNG/JPEG)
3. アニメーションが再生されない
問題: アニメーションが書き出されない、または正しく再生されない
解決策:
- アニメーションが NLA ストリップではなくタイムライン上にあることを確認する
- 「Export Animations」を有効にして書き出す
- アニメーションアクションがオブジェクトに割り当てられていることを確認する
- 複雑なリグには「Bake Actions」を使用する
4. マテリアルの見た目が異なる
問題: Web と Blender でマテリアルのレンダリング結果が異なる
解決策:
- Principled BSDF を使用する(glTF PBR にマッピングされます)
- カスタムシェーダーノードは使用しない(書き出されません)
- 対応しているテクスチャタイプ(Base Color、Metallic、Roughness、Normal、Emission)を使用する
- デプロイ前に glTF ビューアーでテストする
5. 書き出しに時間がかかる
問題: 書き出しに 10 分以上かかる
解決策:
- 書き出し前にモディファイアーを適用する(非破壊のまま書き出さない)
- ジオメトリの複雑さを下げる
- 未使用データを削除する(孤立データのクリーンアップ)
- コマンドラインで書き出す(GUI より高速)
6. ブラウザーでのパフォーマンスの問題
問題: ブラウザーでモデルの動作が遅くなります
解決策:
- LOD(詳細度)を生成します
- 繰り返し使うオブジェクトにはインスタンシングを使用します
- ドローコールを制限します(オブジェクトを統合し、テクスチャアトラスを使用します)
- ポリゴン数を減らします(50k トライアングル未満)
- シェーダーを最適化します(透明度や屈折を避けます)
ベストプラクティス
エクスポート前のチェックリスト
☐ Apply all modifiers
☐ Merge vertices (remove doubles)
☐ Triangulate faces (if required)
☐ Optimize polygon count (<50k triangles)
☐ UV unwrap all meshes
☐ Bake materials (if complex)
☐ Resize textures (max 2048x2048)
☐ Use Principled BSDF materials
☐ Remove unused data (orphan cleanup)
☐ Name objects descriptively
☐ Set origin points correctly
☐ Apply transformations (Ctrl+A)
エクスポート設定
# Recommended glTF export settings
bpy.ops.export_scene.gltf(
filepath='/output.glb',
export_format='GLB', # Binary format
export_apply=True, # Apply modifiers
export_image_format='JPEG', # Smaller file size
export_jpeg_quality=85, # Quality vs size
export_draco_mesh_compression_enable=True, # Enable compression
export_draco_mesh_compression_level=6, # Balance speed/size
export_animations=True, # Include animations
export_lights=False, # Skip lights (recreate in code)
export_cameras=False # Skip cameras
)
リソース
このスキルには、以下が含まれています。
scripts/
batch_export.py- .blend ファイルを glTF に一括エクスポートしますoptimize_model.py- ジオメトリとテクスチャをウェブ向けに最適化しますgenerate_lods.py- LOD のコピーを自動生成します
references/
gltf_export_guide.md- glTF エクスポートの完全なリファレンスbpy_api_reference.md- Blender Python API のクイックリファレンスoptimization_strategies.md- 最適化手法の詳細
assets/
export_template.blend- エクスポート用に事前設定されたテンプレートshader_library/- ウェブ向けに最適化された PBR シェーダー
関連スキル
- threejs-webgl - エクスポートした glTF モデルを Three.js で読み込んでレンダリングします
- react-three-fiber - React アプリケーションで glTF モデルを使用します
- babylonjs-engine - ウェブ向けの代替 3D エンジン
- playcanvas-engine - glTF のインポートに対応したゲームエンジン