Loading...
Loading...
Blender to web export workflows for 3D models and animations. Use this skill when exporting Blender models to glTF for web, optimizing 3D assets for Three.js or Babylon.js, batch processing models with Python scripts, automating Blender workflows, or creating web-ready 3D pipelines. Triggers on tasks involving Blender glTF export, bpy scripting, 3D asset optimization, model compression, texture baking, or Blender automation. Exports models for threejs-webgl, react-three-fiber, and babylonjs-engine skills.
npx skill4agent add freshtechbro/claudedesignskills blender-web-pipeline.gltf = JSON + external .bin + external textures
.glb = Single binary file (recommended for web)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'
)# 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
)#!/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/outputimport 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)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)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)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)#!/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!"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();
}
});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');import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders/glTF';
BABYLON.SceneLoader.ImportMesh(
'',
'/models/',
'exported.glb',
scene,
(meshes) => {
console.log('Loaded meshes:', meshes);
}
);# 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')# 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')# 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])☐ 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
)batch_export.pyoptimize_model.pygenerate_lods.pygltf_export_guide.mdbpy_api_reference.mdoptimization_strategies.mdexport_template.blendshader_library/