Blender AI Wiki / English Поиск

PIPELINE & STUDIO: OPENPYPE / AYON

Production pipeline management for Blender studios

🏗 Пайплайн 11 блоков кода обновлено 2026-10-01

Production pipeline management for Blender studios


🎯 WHAT IS OPENPYPE / AYON?

Feature OpenPype AYON
Status Mature, stable Active development (OpenPype successor)
Architecture Python, MongoDB, Qt Python, PostgreSQL, React/Qt
DCC Support Blender, Maya, Houdini, Nuke, 3dsMax, etc. Same + more
Key Feature Project anatomy, publishing, versioning Modern UI, better API, cloud-ready
License LGPL Apache 2.0

🏗️ ARCHITECTURE

┌─────────────────────────────────────────────────────────────┐
│                        SERVER                                 │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐         │
│  │  Mongo  │  │  REST   │  │  Web UI │  │  Events │         │
│  │   DB    │  │   API   │  │         │  │  Bus    │         │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘         │
└─────────────────────────────────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│   BLENDER     │    │   HOUDINI     │    │    NUKE       │
│  (Addon)      │    │  (Package)    │    │  (Menu)       │
└───────────────┘    └───────────────┘    └───────────────┘

🚀 INSTALLATION

Server (Docker)

# docker-compose.yml
version: '3.8'
services:
  mongo:
    image: mongo:6
    volumes:
      - mongo_data:/data/db
    ports:
      - "27017:27017"

  openpype:
    image: ynput/openpype:latest
    environment:
      - MONGO_URL=mongodb://mongo:27017
      - OPENPYPE_MONGO_DATABASE=openpype
      - OPENPYPE_SECRET=your-secret-key
    ports:
      - "8080:8080"
    volumes:
      - ./config:/app/config
      - ./data:/app/data
    depends_on:
      - mongo

volumes:
  mongo_data:

Client (Blender Addon)

# Install via OpenPype Launcher
# 1. Download OpenPype Launcher from GitHub Releases
# 2. Run launcher, login to server
# 3. Click "Install Blender Addon"
# 4. Select Blender executable
# 5. Restart Blender

# Or manual install:
# 1. Download OpenPype client zip
# 2. Extract to: ~/.config/blender/4.2/scripts/addons/openpype
# 3. Enable in Preferences → Add-ons

⚙️ CONFIGURATION

Project Anatomy (Project Structure)

# config/anatomy.yaml
project:
  name: "MyProject"
  code: "MPJ"
  
anatomy:
  roots:
    work: "/mnt/storage/projects/MyProject/work"
    publish: "/mnt/storage/projects/MyProject/publish"
    scratch: "/tmp/openpype_scratch"
  
  templates:
    # File naming
    work_file: "{root[work]}/{project[name]}/{asset[type]}/{asset[name]}/work/{task[name]}/v{version:03d}/{asset[name]}_{task[name]}_v{version:03d}.{ext}"
    publish_file: "{root[publish]}/{project[name]}/{asset[type]}/{asset[name]}/publish/{subset[name]}/v{version:03d}/{subset[name]}_v{version:03d}.{ext}"
    
    # Folder structure
    folder: "{root[work]}/{project[name]}/{asset[type]}/{asset[name]}/{task[name]}"
    
    # Naming conventions
    version_padding: 3
    frame_padding: 4

  # Asset types
  asset_types:
    - character
    - prop
    - environment
    - vehicle
    - fx
    - camera
    - rig
  
  # Tasks
  tasks:
    - modeling
    - rigging
    - surfacing
    - layout
    - animation
    - fx
    - lighting
    - compositing
  
  # Subsets (what gets published)
  subsets:
    modelMain:
      families: ["model"]
      tasks: ["modeling"]
      extensions: [".abc", ".usd", ".fbx", ".obj"]
    modelProxy:
      families: ["model"]
      tasks: ["modeling"]
      extensions: [".abc", ".usd"]
    lookDev:
      families: ["lookdev"]
      tasks: ["surfacing"]
      extensions: [".ma", ".usd", ".ass"]
    rigMain:
      families: ["rig"]
      tasks: ["rigging"]
      extensions: [".ma", ".usd"]
    animation:
      families: ["animation"]
      tasks: ["animation"]
      extensions: [".abc", ".usd"]
    layout:
      families: ["layout"]
      tasks: ["layout"]
      extensions: [".abc", ".usd"]
    fx:
      families: ["fx"]
      tasks: ["fx"]
      extensions: [".abc", ".vdb", ".bgeo.sc"]
    lighting:
      families: ["lighting"]
      tasks: ["lighting"]
      extensions: [".ma", ".usd"]
    comp:
      families: ["comp"]
      tasks: ["compositing"]
      extensions: [".nk", ".exr", ".mov"]

🔌 BLENDER ADDON SETUP

Installation & Setup

# In Blender after installing OpenPype addon:
# 1. Preferences → Add-ons → OpenPype → Configure
# 2. Set Server URL: http://localhost:8080
# 3. Login with credentials
# 4. Select Project
# 4. OpenPype menu appears in top bar

# Auto-setup on Blender start
import bpy

def setup_openpype():
    import openpype.hosts.blender.api as op_blender
    
    # Auto-connect to server
    op_blender.connect_to_server("http://localhost:8080")
    
    # Set project
    op_blender.set_current_project("MyProject")
    
    # Load tools
    op_blender.install_tools()

bpy.app.handlers.load_post.append(lambda _: setup_openpype())

📦 PUBLISHING WORKFLOW

Publisher UI (Blender)

# Publisher is built into OpenPype Blender addon
# Access via: OpenPype → Publisher

# Publish Steps:
# 1. Select instances to publish
# 2. Validate (auto-runs validators)
# 4. Review validation results
# 5. Click "Publish"
# 6. Check progress in UI
# 7. Verify in OpenPype Web UI

# Custom Validators
class ValidateMeshNonManifold(pyblish.api.InstancePlugin):
    """Check for non-manifold geometry"""
    order = pyblish.api.ValidatorOrder
    families = ["model"]
    
    def process(self, instance):
        import bpy
        import bmesh
        
        obj = instance.data["object"]
        bm = bmesh.new()
        bm.from_mesh(obj.data)
        
        non_manifold = [e for e in bm.edges if not e.is_manifold]
        bm.free()
        
        if non_manifold:
            raise ValueError(f"Non-manifold edges found: {len(non_manifold)}")

# Custom Extractors
class ExtractAlembic(pyblish.api.Extractor):
    """Export Alembic cache"""
    order = pyblish.api.ExtractorOrder
    families = ["animation", "fx"]
    
    def extract(self, instance):
        import bpy
        from pathlib import Path
        
        staging_dir = Path(self.staging_dir(instance))
        filepath = staging_dir / f"{instance.name}.abc"
        
        # Select objects
        bpy.ops.object.select_all(action='DESELECT')
        for obj in instance.data["objects"]:
            obj.select_set(True)
        bpy.context.view_layer.objects.active = instance.data["objects"][0]
        
        # Export Alembic
        bpy.ops.wm.alembic_export(
            filepath=str(filepath),
            selected=True,
            start=instance.context.data["frameStart"],
            end=instance.context.data["frameEnd"],
            selected=True,
            flatten=True,
            subsamples=4,
        )
        
        # Add to representations
        if "representations" not in instance.data:
            instance.data["representations"] = []
        
        instance.data["representations"].append({
            "name": "abc",
            "ext": "abc",
            "files": filepath.name,
            "stagingDir": str(staging_dir),
        )

🎯 WORKFLOW EXAMPLES

Character Pipeline

# Character Publishing Pipeline
"""
1. Modeling → Publish "modelMain" (Alembic/USD)
   ↓
2. Rigging → Reference modelMain → Publish "rigMain" (Maya/USD)
   ↓
3. Surfacing → Reference modelMain → Publish "lookDev" (Materials + Textures)
   ↓
4. Animation → Reference rigMain → Publish "animation" (Alembic/USD)
   ↓
5. Lighting → Reference animation + lookDev → Publish "lighting" (USD)
   ↓
6. Compositing → Publish "comp" (EXR + NK)
"""

# Publish Template
class PublishCharacter(pyblish.api.ContextPlugin):
    order = pyblish.api.ContextPluginOrder
    
    def process(self, context):
        # Define what to publish for a character
        instances = [
            {
                "name": "hero_modelMain",
                "family": "model",
                "subset": "modelMain",
                "objects": ["hero_geo"],
            },
            {
                "name": "hero_rigMain",
                "family": "rig",
                "subset": "rigMain",
                "objects": ["hero_rig"],
            },
            {
                "name": "hero_lookDev",
                "family": "lookdev",
                "subset": "lookDev",
                "objects": ["hero_geo"],
            },
        ]
        
        for inst_data in instances:
            instance = context.create_instance(inst_data["name"])
            instance.data.update({
                "family": inst_data["family"],
                "subset": inst_data["subset"],
                "objects": inst_data["objects"],
            })

🔧 AYON SPECIFICS (Next Gen)

AYON Advantages

# AYON improvements over OpenPype:
- Modern React-based Web UI
- GraphQL API instead of REST
- PostgreSQL instead of MongoDB
- Better multi-site support
- Built-in review tools (ftrack-style)
- Improved artist UI in DCCs
- Better plugin system
- Cloud-ready (Kubernetes)

AYON Blender Addon

# AYON Blender addon (similar to OpenPype but improved)
# Installation: Same process via AYON Launcher

# Key differences:
# - Uses GraphQL API
# - Better settings management
# - Improved publisher UI
- Better dependency tracking
- Integrated review tools

📊 PROJECT MANAGEMENT

Shot Management

# Shot Pipeline
class ShotManager:
    def __init__(self, project_name):
        self.project = project_name
    
    def create_shot(self, sequence, shot_number, description=""):
        """Create shot entity in OpenPype/AYON"""
        shot_name = f"{sequence}{shot_number:03d}"
        
        # Create folder structure
        shot_path = Path(f"shots/{sequence}/{shot_name}")
        shot_path.mkdir(parents=True, exist_ok=True)
        
        # Create entity in OpenPype
        # (via API)
        return shot_name
    
    def assign_tasks(self, shot_name, tasks):
        """Assign tasks to artists"""
        for task_name, artist in tasks.items():
            # Create task entity
            # Assign to artist
            pass
    
    def get_shot_status(self, shot_name):
        """Get shot progress"""
        # Query OpenPype for task statuses
        pass

🚀 DEPLOYMENT

Production Deployment

# docker-compose.prod.yml
version: '3.8'
services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: ayon
      POSTGRES_USER: ayon
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    deploy:
      resources:
        limits:
          memory: 2G

  ayon-server:
    image: ynput/ayon-server:latest
    environment:
      - POSTGRES_HOST=postgres
      - POSTGRES_DB=ayon
      - POSTGRES_USER=ayon
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - AYON_SECRET=${AYON_SECRET}
      - AYON_ADMIN_EMAIL=${ADMIN_EMAIL}
      - AYON_ADMIN_PASSWORD=${ADMIN_PASSWORD}
    ports:
      - "8080:8080"
    depends_on:
      - postgres
    deploy:
      replicas: 2
      resources:
        limits:
          memory: 4G
        reservations:
          memory: 2G

  ayon-frontend:
    image: ynput/ayon-frontend:latest
    ports:
      - "80:80"
    depends_on:
      - ayon-server

volumes:
  postgres_data:


🌍 MULTILANG

Language File
English multilang/en/pipeline/openpype_ayon.md
Russian multilang/ru/pipeline/openpype_ayon.md

Связанные материалы

Подобраны по тегам и категории.