qvib.pro
EN

~9 мин чтения · всем · Обновлено: 28.07.2026

6 рутин Blender, которые ИИ пишет скриптом на bpy

6 рутинных задач в Blender, которые ИИ пишет скриптом на bpy

Коротко

Нейросеть не заменит вам моделлинг, но уверенно закрывает механическую часть: то, что делается одинаково по каждому объекту и отличается только именем и координатами. Шесть задач, где скрипт на bpy окупается с первого запуска: батч-переименование по правилу движка, применение трансформаций пачкой, Smart UV для объектов без развёртки, поштучный экспорт в отдельные файлы, пресеты рендера и чистка файла от осиротевших датаблоков.

Ключ к тому, чтобы это работало, не в промпте, а в форме результата: просите один скрипт с блоком настроек наверху, работой по выделению (а не по всей сцене) и флагом DRY_RUN, который сначала печатает план и ничего не трогает. Дальше вы читаете план глазами, а не откатываете сцену.

Главный источник поломок — не «глупая модель», а разъезд версий: bpy меняется каждый релиз, и код, написанный по памяти, ломается на переименованных операторах. Лечится тем, что версию Blender вы указываете в промпте явно, а спорные вызовы сверяете с документацией.

Зачем это нужно

Разница между «сделать руками» и «сделать скриптом» становится ощутимой не на одном объекте, а на тридцати. Ниже — задачи, которые чаще всего попадают в этот разряд, и то, чем в каждой рискуете.

Задача Руками Что делает скрипт Риск
Переименование по правилу Клик по каждому объекту в аутлайнере Префикс/суффикс, нумерация, синхронизация имени меша с именем объекта Затрёт осмысленные имена — нужен предпросмотр
Применение трансформаций Ctrl+A на каждом, легко пропустить Находит объекты со scale != 1 и правит только их Ломает объекты с шейпкеями и связанными данными
Smart UV для пачки Вход в Edit Mode на каждом объекте Разворачивает только те, где uv_layers пуст Перезапишет ручную развёртку, если не проверять
Поштучный экспорт Выделить — экспорт — повторить N раз Файл на объект, единые оси и путь Молча перезапишет существующие файлы
Пресеты рендера Десяток полей в панели Движок, семплы, разрешение, формат, путь вывода одной строкой Идентификаторы движка меняются между версиями
Чистка файла Перезапуск и ручной поиск дублей orphans_purge, разбор материалов .001, лишние UV-слои Необратимо; сначала сохранить копию

Отдельно стоит сказать, чего в этом списке нет. Здесь нет ретопологии, шейдинга «чтобы красиво» и всего, что требует визуальной оценки. Такие задачи скриптом не ставятся, потому что критерий «хорошо» не формализуется — и это граница, за которой ИИ в Blender стабильно перестаёт помогать. Подробнее про эту границу — в разборе 3D-модель по тексту через Claude и Blender MCP.

Готовый пример целиком

Один скрипт на четыре задачи сразу: переименовать, применить масштаб, развернуть UV там, где её нет, и выгрузить каждый объект отдельным OBJ. Работает по выделению. При DRY_RUN = True только печатает таблицу того, что собирается сделать.

import bpy
from pathlib import Path

# ---- настройки -----------------------------------------------------------
PREFIX     = "SM_"                                  # префикс под игровой движок
EXPORT_DIR = Path(bpy.path.abspath("//export"))     # рядом с .blend
UV_MARGIN  = 0.02
DRY_RUN    = True                                   # True — ничего не менять

targets = [o for o in bpy.context.selected_objects if o.type == 'MESH']
if not targets:
    raise RuntimeError("Ничего не выделено — скрипт работает только по выделению")

plan = []
for i, obj in enumerate(targets, 1):
    plan.append({
        "obj": obj,
        "old": obj.name,
        "new": f"{PREFIX}{obj.name.split('.')[0]}_{i:02d}",
        "fix_scale": any(abs(s - 1.0) > 1e-4 for s in obj.scale),
        "make_uv": len(obj.data.uv_layers) == 0,
    })

print(f"{'было':22} {'станет':22} scale  uv")
for p in plan:
    print(f"{p['old']:22} {p['new']:22} "
          f"{'да' if p['fix_scale'] else '—':6} {'да' if p['make_uv'] else '—'}")

if DRY_RUN:
    print(f"ПЛАН. Объектов: {len(plan)}. Ничего не изменено.")
else:
    EXPORT_DIR.mkdir(parents=True, exist_ok=True)
    for p in plan:
        obj = p["obj"]
        obj.name = obj.data.name = p["new"]

        bpy.ops.object.select_all(action='DESELECT')
        obj.select_set(True)
        bpy.context.view_layer.objects.active = obj

        if p["fix_scale"]:
            bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

        if p["make_uv"]:
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.uv.smart_project(island_margin=UV_MARGIN)
            bpy.ops.object.mode_set(mode='OBJECT')

        bpy.ops.wm.obj_export(
            filepath=str(EXPORT_DIR / f"{p['new']}.obj"),
            export_selected_objects=True,
            forward_axis='NEGATIVE_Z',
            up_axis='Y',
        )
    print(f"Готово. Обработано: {len(plan)}. Файлы: {EXPORT_DIR}")

Запускать — во вкладке Scripting или через execute_blender_code, если Blender подключён по MCP (порядок подключения — в статье Blender MCP и Claude).

Разбор по частям

Блок настроек наверху. Это не косметика. Скрипт с константами в первых десяти строках правится за пять секунд без перечитывания логики — и его можно отдать коллеге, который в Python не заходит.

DRY_RUN и отделение плана от действия. Сначала собирается список того, что будет сделано, потом печатается, и только затем выполняется. Модель по умолчанию пишет иначе — сразу цикл с изменениями, — так что этот пункт нужно требовать в промпте явно. Он же превращает «ой, я переименовал всю сцену» в «посмотрел таблицу, поправил префикс».

Работа по selected_objects, а не по bpy.data.objects. Скрипт, который ходит по всей сцене, рано или поздно заденет то, что трогать не следовало. Выделение — естественный ограничитель области действия.

Условие вместо безусловного действия. fix_scale и make_uv проверяются, а не применяются всем подряд. Именно поэтому скрипт не затирает ручную развёртку: len(obj.data.uv_layers) == 0 — дешёвая, но точная проверка.

Переключение активного объекта перед операторами. Большинство bpy.ops.* действуют на активный объект и текущий контекст. Отсюда классическая ошибка сгенерированного кода — вызов оператора без bpy.context.view_layer.objects.active, падающий с RuntimeError: Operator ... poll() failed, context is incorrect. Если оператор упорно не проходит poll, помогает контекстный менеджер bpy.context.temp_override(...) — он появился в Blender 3.2 вместо старого способа передавать контекст словарём.

Параметры smart_project и obj_export в примере — не выдумка: island_margin, export_selected_objects, forward_axis, up_axis есть в текущей документации API. Это то, что стоит проверять в первую очередь, потому что именно имена аргументов модель придумывает чаще всего.

Чего в него класть не надо

Ничего необратимого без копии. bpy.ops.outliner.orphans_purge() чистит все датаблоки без пользователей — и делает это молча. Перед такими вещами сохраняйте отдельный файл, а не полагайтесь на Ctrl+Z: часть операций через отмену не проходит.

Всё, что оценивается глазами. «Расставь красиво», «подбери свет», «сделай топологию чище» — это не задачи для скрипта. Модель сгенерирует правдоподобный код, он выполнится без ошибок, и результат будет мимо.

Geometry Nodes. Сборка нодовых деревьев кодом формально возможна, но дальше нескольких узлов связи начинают собираться неверно, а отладка съедает больше времени, чем ручная сборка.

Один мега-скрипт на всё. Чем длиннее скрипт, тем дороже каждая ошибка: падение на середине оставляет сцену в промежуточном состоянии. Четыре шага в одном цикле — потолок; дальше лучше разбивать на отдельные запуски.

Секреты и абсолютные пути с именем пользователя. Скрипты уходят в чат целиком. Путь вида //export относительно .blend лучше домашней папки во всех смыслах.

Как поддерживать в актуальном виде

bpy — не стабильный API, и это главная причина, по которой «работавший месяц назад» скрипт вдруг падает. Три реальных примера того, на чём спотыкается сгенерированный код:

  • В Blender 4.0 удалили питоновские импортёр и экспортёр OBJ: bpy.ops.export_scene.obj больше нет, вместо него bpy.ops.wm.obj_export. Модель, обученная на старых туториалах, до сих пор пишет первый вариант.
  • В 3.2 передача контекста оператору словарём объявлена устаревшей в пользу Context.temp_override.
  • В 5.0 идентификатор движка EEVEE сменился с BLENDER_EEVEE_NEXT на BLENDER_EEVEE, а многие рендер-пассы переименовали.

Что с этим делать практически:

  1. В промпте указывайте версию явно: «целевая версия Blender 4.2 LTS, имена операторов и аргументов сверяй с документацией этой версии». Без этого модель усредняет по всему, что видела.
  2. Держите скрипты в отдельной папке репозитория, а не в текстовых блоках .blend. Тогда правки видны в диффе, а ИИ-клиент читает и правит их файлами напрямую — через MCP-сервер filesystem или обычный доступ к проекту.
  3. Первый прогон после обновления Blender — всегда с DRY_RUN = True.
  4. Ошибку poll() failed или TypeError по имени аргумента не «дожимайте» промптом: откройте страницу оператора в документации API и подставьте правильную сигнатуру руками, это быстрее.

Если скриптов набирается больше десятка, имеет смысл подключить к клиенту доступ к файлам и запуску — общий порядок описан в статье как подключить MCP к Claude Code.

Сверялись по первоисточникам: bpy.ops.uv, bpy.ops.wm, release notes Blender 4.0, release notes Blender 3.2, release notes Blender 5.0.

Частые вопросы

Нужно ли знать Python, чтобы этим пользоваться?

Читать — да, писать — нет. Скрипт, который вы не можете прочитать построчно, вы не можете и проверить: он выполнится, ничего не сообщит, и последствия всплывут через неделю в другом файле. Минимум, который стоит освоить, — цикл for, условие if и понимание разницы между bpy.data (данные файла) и bpy.context (текущее состояние интерфейса). Этого хватает, чтобы отличить безопасный скрипт от опасного.

Чем это отличается от готовых аддонов для батч-операций?

Аддоны покрывают типовые случаи и делают это лучше — если ваш случай типовой. Скрипт выигрывает там, где правило своё: «переименовать по имени коллекции, но только меши, и только те, у которых нет UV». Разумная схема — аддоны для повторяющегося, генерация для разового и специфичного под конкретный проект.

Почему скрипт падает с «context is incorrect»?

Оператор запускается не из той области интерфейса, где он допустим, либо нет активного объекта. Проверьте, что перед вызовом выставлены obj.select_set(True) и bpy.context.view_layer.objects.active = obj, а для операторов, привязанных к конкретному редактору, используйте bpy.context.temp_override(). Запуск из консоли Blender и из вкладки Scripting дают разный контекст — это тоже частая причина.

Можно ли отдать это локальной модели, без облака?

Можно, но на длинных скриптах локальные модели заметно чаще путают имена аргументов, и цикл «запустил — ошибка — правка» съедает выигрыш. Если сцена под NDA и код с именами объектов не должен покидать периметр — это единственный вариант, и тогда закладывайте больше итераций. Промежуточный компромисс: писать скрипт облачной моделью на обезличенном примере, а применять локально.

Насколько безопасно давать ИИ запускать код прямо в Blender?

Ровно настолько, насколько вы готовы потерять текущий файл. Выполнение кода в Blender не изолировано: скрипт имеет доступ к файловой системе с правами вашего пользователя. Практический минимум — отдельный .blend под эксперименты, сохранение перед каждым запуском и чтение кода перед выполнением. Автозапуск без просмотра оставьте для скриптов, которые уже отработали десяток раз.

Читайте также