blender-web-pipeline

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Blender Web Pipeline

Blender Web 流水线

Overview

概述

Blender Web Pipeline skill provides workflows for exporting 3D models and animations from Blender to web-optimized formats (primarily glTF 2.0). It covers Python scripting for batch processing, optimization techniques for web performance, and integration with web 3D libraries like Three.js and Babylon.js.
When to use this skill:
  • Exporting Blender models for web applications
  • Batch processing multiple 3D assets
  • Optimizing file sizes for web delivery
  • Automating repetitive Blender tasks
  • Creating production pipelines for 3D web content
  • Converting legacy formats to glTF
Key capabilities:
  • glTF 2.0 export with optimization
  • Python (bpy) automation scripts
  • Texture baking and compression
  • LOD (Level of Detail) generation
  • Batch processing workflows
  • Material and lighting optimization for web
Blender Web 流水线技能提供了将Blender中的3D模型与动画导出为Web优化格式(主要是glTF 2.0)的工作流。它涵盖了用于批量处理的Python脚本编写、针对Web性能的优化技术,以及与Three.js和Babylon.js等Web 3D库的集成。
何时使用本技能:
  • 将Blender模型导出用于Web应用
  • 批量处理多个3D资源
  • 优化文件体积以适配Web传输
  • 自动化重复的Blender任务
  • 为Web 3D内容创建生产流水线
  • 将旧格式转换为glTF
核心功能:
  • 带优化的glTF 2.0导出
  • Python(bpy)自动化脚本
  • 纹理烘焙与压缩
  • LOD(细节层次)生成
  • 批量处理工作流
  • 面向Web的材质与光照优化

Core Concepts

核心概念

glTF 2.0 Format

glTF 2.0 格式

Why glTF for Web:
  • Industry-standard 3D format for web
  • Efficient binary encoding (.glb)
  • PBR materials support
  • Animation and skinning
  • Extensible with custom data
  • Wide library support (Three.js, Babylon.js, etc.)
glTF vs GLB:
.gltf = JSON + external .bin + external textures
.glb  = Single binary file (recommended for web)
为何在Web中使用glTF:
  • Web领域的标准3D格式
  • 高效的二进制编码(.glb)
  • 支持PBR材质
  • 支持动画与蒙皮
  • 可扩展自定义数据
  • 广泛的库支持(Three.js、Babylon.js等)
glTF 与 GLB 对比:
.gltf = JSON + 外部.bin文件 + 外部纹理
.glb  = 单一二进制文件(推荐用于Web)

Blender Python API (bpy)

Blender Python API(bpy)

Access Blender data and operations via Python:
python
import bpy
通过Python访问Blender数据与操作:
python
import bpy

Access scene data

Access scene data

scene = bpy.context.scene objects = bpy.data.objects
scene = bpy.context.scene objects = bpy.data.objects

Modify objects

Modify objects

obj = bpy.data.objects['Cube'] obj.location = (0, 0, 1) obj.scale = (2, 2, 2)
obj = bpy.data.objects['Cube'] obj.location = (0, 0, 1) obj.scale = (2, 2, 2)

Export glTF

Export glTF

bpy.ops.export_scene.gltf( filepath='/path/to/model.glb', export_format='GLB' )
undefined
bpy.ops.export_scene.gltf( filepath='/path/to/model.glb', export_format='GLB' )
undefined

Web Optimization Goals

Web优化目标

Target Metrics:
  • File size: <5 MB per model (ideal <1 MB)
  • Polygon count: <50k triangles for real-time
  • Texture resolution: 2048x2048 max (1024x1024 preferred)
  • Draw calls: Minimize via texture atlases
  • Load time: <2 seconds on average connection
关键指标:
  • 文件体积:每个模型小于5MB(理想值小于1MB)
  • 多边形数量:实时渲染场景小于50k个三角形
  • 纹理分辨率:最大2048x2048(推荐1024x1024)
  • 绘制调用:通过纹理图集最小化
  • 加载时间:在普通网络环境下小于2秒

Common Patterns

常见模式

1. Basic glTF Export (Manual)

1. 基础glTF导出(手动)

python
undefined
python
undefined

Blender Python Console or script

Blender Python Console or script

import bpy
import bpy

Select objects to export (optional - exports all if none selected)

Select objects to export (optional - exports all if none selected)

bpy.ops.object.select_all(action='DESELECT') bpy.data.objects['MyModel'].select_set(True)
bpy.ops.object.select_all(action='DESELECT') bpy.data.objects['MyModel'].select_set(True)

Export as GLB

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 )
undefined
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 )
undefined

2. Python Script for Batch Export

2. 批量导出的Python脚本

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
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 --

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"
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

Create output directory

os.makedirs(output_dir, exist_ok=True)
os.makedirs(output_dir, exist_ok=True)

Find all .blend files

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!")

**Run batch script:**

```bash
blender --background --python batch_export.py -- /models/source /models/output
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!")

**运行批量脚本:**

```bash
blender --background --python batch_export.py -- /models/source /models/output

3. Optimize Model for Web (Decimation)

3. 为Web优化模型(减面)

python
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")
python
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

Optimize all selected meshes

for obj in bpy.context.selected_objects: optimize_mesh(obj, target_ratio=0.3)
undefined
for obj in bpy.context.selected_objects: optimize_mesh(obj, target_ratio=0.3)
undefined

4. Texture Baking for Web

4. Web纹理烘焙

python
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}")
python
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

Bake selected objects

for obj in bpy.context.selected_objects: if obj.type == 'MESH': bake_textures(obj, resolution=2048)
undefined
for obj in bpy.context.selected_objects: if obj.type == 'MESH': bake_textures(obj, resolution=2048)
undefined

5. Generate LOD (Level of Detail)

5. 生成LOD(细节层次)

python
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
python
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

Generate LODs for selected object

if bpy.context.active_object: generate_lods(bpy.context.active_object)
undefined
if bpy.context.active_object: generate_lods(bpy.context.active_object)
undefined

6. Export with Texture Compression

6. 带纹理压缩的导出

python
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
    )
python
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

export_optimized_gltf('/path/to/optimized.glb', texture_max_size=512)
undefined
export_optimized_gltf('/path/to/optimized.glb', texture_max_size=512)
undefined

7. Command-Line Automation

7. 命令行自动化

bash
#!/bin/bash
bash
#!/bin/bash

Batch export Blender files to glTF without opening GUI

Batch export Blender files to glTF without opening GUI

SCRIPT_DIR="$(dirname "$0")"
SCRIPT_DIR="$(dirname "$0")"

Export all .blend files in current directory

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
for blend_file in *.blend; do echo "Exporting $blend_file..."
blender --background "$blend_file" --python - <<EOF
import bpy import os

Get output filename

Get output filename

filename = os.path.splitext(bpy.data.filepath)[0] output = filename + '.glb'
filename = os.path.splitext(bpy.data.filepath)[0] output = filename + '.glb'

Export

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!"
undefined
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!"
undefined

Integration Patterns

集成模式

With Three.js

与Three.js集成

javascript
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();
  }
});
javascript
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();
  }
});

With React Three Fiber

与React Three Fiber集成

jsx
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');
jsx
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');

With Babylon.js

与Babylon.js集成

javascript
import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders/glTF';

BABYLON.SceneLoader.ImportMesh(
  '',
  '/models/',
  'exported.glb',
  scene,
  (meshes) => {
    console.log('Loaded meshes:', meshes);
  }
);
javascript
import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders/glTF';

BABYLON.SceneLoader.ImportMesh(
  '',
  '/models/',
  'exported.glb',
  scene,
  (meshes) => {
    console.log('Loaded meshes:', meshes);
  }
);

Optimization Techniques

优化技巧

1. Geometry Optimization

1. 几何体优化

Decimate Modifier:
python
undefined
减面修改器:
python
undefined

Reduce polygon count by 70%

Reduce polygon count by 70%

obj.modifiers.new(name='Decimate', type='DECIMATE') obj.modifiers['Decimate'].ratio = 0.3

**Merge by Distance:**
```python
obj.modifiers.new(name='Decimate', type='DECIMATE') obj.modifiers['Decimate'].ratio = 0.3

**合并顶点:**
```python

Remove duplicate vertices

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')

**Triangulate Faces:**
```python
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')

**三角化面:**
```python

Ensure all faces are triangles (required for some engines)

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')
undefined
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')
undefined

2. Texture Optimization

2. 纹理优化

Image Compression:
python
undefined
图片压缩:
python
undefined

Save textures as JPEG (lossy but smaller)

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()

**Texture Atlas:**
```python
for img in bpy.data.images: img.file_format = 'JPEG' img.filepath_raw = f"/output/{img.name}.jpg" img.save()

**纹理图集:**
```python

Combine multiple textures into one atlas

Combine multiple textures into one atlas

Use Smart UV Project for automatic atlasing

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')
undefined
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')
undefined

3. Material Simplification

3. 材质简化

Convert to PBR:
python
undefined
转换为PBR材质:
python
undefined

Ensure materials use Principled BSDF (glTF standard)

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])
undefined
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])
undefined

Common Pitfalls

常见陷阱

1. Large File Sizes

1. 文件体积过大

Problem: Exported .glb files are 20+ MB
Solutions:
  • Enable Draco compression (60-90% reduction)
  • Reduce texture resolution (2048 → 1024 or 512)
  • Use JPEG instead of PNG for textures
  • Decimate geometry (target <50k triangles)
  • Remove unused materials/textures
问题: 导出的.glb文件体积超过20MB
解决方案:
  • 启用Draco压缩(可减少60-90%体积)
  • 降低纹理分辨率(从2048降至1024或512)
  • 用JPEG替代PNG格式存储纹理
  • 对几何体进行减面处理(目标三角形数量小于50k)
  • 删除未使用的材质与纹理

2. Missing Textures in Export

2. 导出中丢失纹理

Problem: Textures don't appear in web viewer
Solutions:
  • Ensure all images are saved (not packed)
  • Use relative paths for textures
  • Export with "Export Images" enabled
  • Check image format compatibility (PNG/JPEG)
问题: 纹理在Web查看器中不显示
解决方案:
  • 确保所有图片已保存(而非打包状态)
  • 为纹理使用相对路径
  • 导出时启用"导出图片"选项
  • 检查图片格式兼容性(PNG/JPEG)

3. Animations Not Playing

3. 动画无法播放

Problem: Animations don't export or play incorrectly
Solutions:
  • Ensure animations are on timeline (not NLA strips)
  • Export with "Export Animations" enabled
  • Check animation actions are assigned to objects
  • Use "Bake Actions" for complex rigs
问题: 动画未导出或播放异常
解决方案:
  • 确保动画位于时间轴(而非NLA条带)
  • 导出时启用"导出动画"选项
  • 检查动画动作是否已分配给对象
  • 为复杂绑定使用"烘焙动作"功能

4. Materials Look Different

4. 材质显示效果不一致

Problem: Materials render differently in web vs Blender
Solutions:
  • Use Principled BSDF (maps to glTF PBR)
  • Avoid custom shader nodes (won't export)
  • Use supported texture types (Base Color, Metallic, Roughness, Normal, Emission)
  • Test in glTF viewer before deploying
问题: 材质在Web中的渲染效果与Blender中不同
解决方案:
  • 使用Principled BSDF材质(对应glTF PBR标准)
  • 避免使用自定义着色器节点(无法导出)
  • 使用支持的纹理类型(基础色、金属度、粗糙度、法线、自发光)
  • 部署前在glTF查看器中测试

5. Slow Export Times

5. 导出速度过慢

Problem: Export takes 10+ minutes
Solutions:
  • Apply modifiers before export (don't export non-destructively)
  • Reduce geometry complexity
  • Remove unused data (orphan cleanup)
  • Use command-line export (faster than GUI)
问题: 导出耗时超过10分钟
解决方案:
  • 导出前应用所有修改器(不要以非破坏性方式导出)
  • 降低几何体复杂度
  • 删除未使用的数据(清理孤立资源)
  • 使用命令行导出(比GUI更快)

6. Performance Issues in Browser

6. 浏览器中性能问题

Problem: Model lags in browser
Solutions:
  • Generate LODs (Level of Detail)
  • Use instancing for repeated objects
  • Limit draw calls (merge objects, texture atlases)
  • Reduce polygon count (<50k triangles)
  • Optimize shaders (avoid transparency/refraction)
问题: 模型在浏览器中卡顿
解决方案:
  • 生成LOD(细节层次)模型
  • 对重复对象使用实例化
  • 限制绘制调用(合并对象、使用纹理图集)
  • 减少多边形数量(小于50k三角形)
  • 优化着色器(避免透明/折射效果)

Best Practices

最佳实践

Pre-Export Checklist

导出前检查清单

☐ 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)
☐ 应用所有修改器
☐ 合并顶点(移除重复项)
☐ 三角化面(如需要)
☐ 优化多边形数量(小于50k三角形)
☐ 为所有网格进行UV展开
☐ 烘焙材质(如材质复杂)
☐ 调整纹理尺寸(最大2048x2048)
☐ 使用Principled BSDF材质
☐ 删除未使用的数据(清理孤立资源)
☐ 为对象设置有意义的名称
☐ 正确设置原点
☐ 应用变换(Ctrl+A)

Export Settings

导出设置

python
undefined
python
undefined

Recommended glTF export settings

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 )
undefined
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 )
undefined

Resources

资源

This skill includes:
本技能包含:

scripts/

scripts/

  • batch_export.py
    - Batch export .blend files to glTF
  • optimize_model.py
    - Optimize geometry and textures for web
  • generate_lods.py
    - Generate LOD copies automatically
  • batch_export.py
    - 将.blend文件批量导出为glTF
  • optimize_model.py
    - 为Web优化几何体与纹理
  • generate_lods.py
    - 自动生成LOD副本

references/

references/

  • gltf_export_guide.md
    - Complete glTF export reference
  • bpy_api_reference.md
    - Blender Python API quick reference
  • optimization_strategies.md
    - Detailed optimization techniques
  • gltf_export_guide.md
    - 完整的glTF导出参考
  • bpy_api_reference.md
    - Blender Python API快速参考
  • optimization_strategies.md
    - 详细的优化技巧

assets/

assets/

  • export_template.blend
    - Pre-configured export template
  • shader_library/
    - Web-optimized PBR shaders
  • export_template.blend
    - 预配置的导出模板
  • shader_library/
    - 适用于Web的PBR着色器库

Related Skills

相关技能

  • threejs-webgl - Load and render exported glTF models in Three.js
  • react-three-fiber - Use glTF models in React applications
  • babylonjs-engine - Alternative 3D engine for web
  • playcanvas-engine - Game engine that supports glTF import
  • threejs-webgl - 在Three.js中加载并渲染导出的glTF模型
  • react-three-fiber - 在React应用中使用glTF模型
  • babylonjs-engine - 适用于Web的替代3D引擎
  • playcanvas-engine - 支持glTF导入的游戏引擎