А вы полагали, мы тут обойдем эту тему стороной? Кто бы что ни думал или говорил по поводу нейросеток — это новые инструменты, многие из которых, пусть еще и находятся в зачаточном состоянии, уже оказывают огромное влияние на подход к работе и многие рабочие процессы.
Это очень техническая статья и здесь будет много конкретной узко-специализированной практики, но опыт, который я получил, разбираясь с ChatGPT для написания простых программ, может пригодиться при решении очень широкого спектра задач.
Вся информация, касательно особенностей ChatGPT и API Blender'а актуальна на момент написания статьи (начало февраля 2023 года, версия Blender — 3.3.3 LTS), так что, если вы читаете это из будущего, возможно, у вас уже все по-другому :)
По образованию я — программист, с некоторым опытом разработки ПО (в довольно далеком прошлом). Конечно же, работая в VFx, полностью уйти от программирования не удается (например, Houdini, по-сути, это инструмент визуального программирования компьютерной графики). Я знаком с языком Python, но вот API Blender'а, несмотря на более чем 12-летний стаж работы с ним, мне изучить толком так и не довелось: задачи по написанию каких-то специфических скриптов возникали редко, и решить их, как правило, помогали коллеги, лучше меня умеющие в blender-скрипты.
Задача 1: автоматизация преобразований
Но, как водится, когда-то приходится внять «зову к странствиям». В моем случае я оказался в ситуации, когда мне срочно надо было обрабоать простым, но очень специфическим образом около двух тысяч несложных объектов в Blender'е.
В этой главе рассматривается довольно специфическая задача, но ввиду ее простоты на примере решения удобно разобрать основные моменты работы с ChatGPT. Если вас интересует толоько аддон, который может быть полезен на практике, смело листайте вниз ко 2-й задаче.
Постановка задачи
Мой клиент заказал у неких 3D-моделеров, не работающих в Blender'е, порядка двадцати 3D-моделей, каждая из которых состояла из 50-200 отдельных объектов. Ко мне эти модели попали в виде fbx-файлов, а отдать их нужно было как blend-файлы, причем, принципиально важным моментом было то, что каждый элемент каждой модели (каждый отдельный mesh-объект сцены) в своем исходном масштабе (равном единице) должен иметь размеры 100х100х100 см, а его фактические размеры (например, 10х2500х1200 см) должны были достигаться за счет соответсвующего масштаба по осям (то есть, для приведенного примера, масштаб по 3 осям должен был составлять (0.1, 25, 12) единиц).
Если бы количество объектов для обработки всего было бы 10-20 штук, я не стал бы заморачиваться, и сделал всё вручную. Но объектов слишком много, а также модели еще могли быть скорректированы в будущем, значит, обработку для них пришлось бы повторить (возможно, не один раз). С такими вводными, единственный правильный подход — автоматизация процесса.
Подход к решению
Алгоритм преобразований максимально простой: необходимо запомнить размеры объекта, затем задать размеры по всем трем осям равным 100 см, применить трансформации масштаба и потом назначить запомненные размеры объекту (тем самым будет установлен нужный масштаб при фактическом размере объекта 100х100х100 см).
Geometry Nodes решить такую задачу не могут, поэтому мне нужен был Python-скрипт. Без знаний API написание нужной программы заняло бы больше времени, чем я был готов сам потратить на решение этой задачи. Современные проблемы требуют современных решений, так что в этот раз я решил не лезть в мануалы, а поставить задачу перед ChatGPT. Ранее я уже немного экспериментировал с написанием фрагментов кода в нем, поэтому настрой был довольно оптимистичный. Главное, что я уясил из предыдущих экспериментов — это два основных момента:
- ChatGPT — это очень сырая штука, так что он часто не дописывает ответы, особенно, если они длинные; поэтому его ответы и фрагменты кода, которые я запрашиваю, должны быть максимально короткими;
- сразу просить написать готовый скрипт — не лучшая идея: скорее всего, он будет содержать много функциональных неточностей, которые будет сложно исправлять; гораздо лучше писать программу постепенно, как если бы я разрабатывал ее сам, усложняя и добавляя возможности.
Чтобы поэтапно подойти к итоговому решению, я набросал себе простой алгоритм «высокого уровня» подхода к разработке, который включал следующие этапы, позволяющие отслеживать правильность решения:
- Создать панель с кнопкой: при нажатии программа должна запомнить размеры выбранного объекта и затем задать размеры из сохраненных значений.
- Добавить применение трансформации масштаба между двумя операциями.
- Свести все операции в работу одной кнопки ”Retransform”.
- Поменять программу так, чтобы кнопка работала не для выделенного объекта, а для всех mesh-объектов сцены.
Пишем код с ChatGPT
Первый мой запрос выглядел следующим образом:
Write me a smibple blender script that creates 2 buttons: one remembers (stores) the object's dimensions and other applies that stored values to the selected object
«Напиши мне простой скрипт для блендера, который создает 2 кнопки: одна запоминает (хранит) размеры объекта, а другая — применяет эти сохраненные значения к выбранному объекту». Услужливый бот незамедлительно согласился:
Полный текст полученного кода можно посмотреть по этой ссылке (я и дальше буду публиковать их по ссылке, чтобы не захламлять текст статьи).
Этот код я вставил в текстовый редактор Blender и запустил программу на выполнение. Соответствующая панелька появилась среди свойств объекта, но вот нажатие на “Remember Size” вызывало ошибку AttributeError: 'Object' object has no attribute 'remember_dimensions', о чем я и пообщался далее с ботом. Он ошибку признал и оперативно исправил:
Новый вариант (ссылка на код) заработал как положено: одна кнопка сохраняла размеры, вторая применяла эти размеры к выбранному объекту.
Далее я попросил добавить еще одну кнопку, которая задавала бы размер объекта по всем трем осям равным 10 (1 метр при масштабе единиц измерения сцены 0,1 м) и применяла бы масштаб.
Этот код почти работал как надо за исключением того, что, после изменения размерностей, применение масштаба (Apply Scale) к объекту не выполнялось. К этому моменту программа стала (внезапно) уже слишком длинная для стабильной работы ChatGPT (он уже начал грешить тем, что дописывал сообщения через раз), а мне нужно было добавить всего одну строчку (по моим соображениям). Так что я просто полез в стандартный поисковик за ответом и практически сразу нашел его:
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
Важно понимать, что эта конструкция работает с выделенным объектом. Три кнопки мне уже были ни к чему, так что я совместил весь код в одну функцию, почистил комментарии, добавил применение трансформаций и в итоге получил простейшую панель с одной «волшебной кнопкой», которая делала все операции с объектом, которые мне были нужны:
Здесь можно посмотреть итоговый код и скачать .py-файл.
Осталось решить одну задачу: как я уже упоминал, объектов в сцене было очень много, поэтому протыкивать вручную каждый мне не очень хотелось. Играть с ChatGPT — одно удовольствие, поэтому решение этого простого момента я также возложил на него. Чтобы нам с ним работать с одной и той же версией программы, я сначала сгрузил весь программный код ему в сообщении (бот отлично понял, что этот код делает), а потом попросил внести изменения:
Здесь можно посмотреть наше последнее общение с ChatGPT по этому вопросу. И всё работало почти хорошо за исключением того, что применение трансформаций (масштаба) перестало выполняться. Как я уже упоминал, в том виде конструкция работала только для выделенного объекта, а когда программа перебирает все объекты в сцене, они не выделяются.
Не став долго разбираться, как можно применить трансформации для не-выделенного объекта, я просто доработал код, найдя в сети, как программно выделить объект в сцене obj.select_set(True) и как это выделение снять после того, как нужная операция выполнена: obj.select_set(False). В итоге скрипт приобрел свой финальный вид.
Промежуточный итог
Конечно, это не полноценный аддон, и функционал, мягко говоря, очень специфический и узконаправленный, но я поэкспериментировал с инструментом, узнал некоторые нюансы и меньше, чем за час получил решение задачи, которая в ручном режиме отняла бы у меня не один рабочй день — считай, решил свою проблему моментально, да еще и с огромным плюсом во времени/деньгах.
Этот успех подтолкнул меня к решению гораздо более распространенной задачи, которая также не давала мне покоя последние недели.
Задача 2: аддон для создания архива проекта Blender
У Blender есть удобная функция: упаковка-распаковка внешних файлов текстур в blend-файл, что позволяет переносить сцену между разными компьютерами, не теряя связанные файлы. Но как быть, если в проект прилинкованы еще и другие blend-файлы, плюс десяток alembic-ов с объектами и анимациями?
Постановка задачи
Я работаю над небольшой серией анимационных роликов с гуманоидными персонажами. Этот проект проходит через несколько студий, и на момент старта по техническим причинам мы не стали использовать USD-формат, который, возможно, мог бы отчасти решить проблемы, описываемые ниже. Вместо этого мы выстроили довольно линейный пайплайн, в конце которого нахожусь, собственно, я.
Персонажи и анимированные элементы локации присылают мне в виде alembic-файлов. Для сохранения единообразия материалов и внешнего вида деталей сцен, я использую линковку к blend-файлам с материалами и группами объектов, вроде расстановки предметов в интерьере. Моя задача — собрать все объекты в финальные сцены, сделать материалы, настроить освещение, высчитать (отрендерить) всё и сделать композитинг (этой теме будет посвящена отдельная статья, когда мы сей проект закончим).
Поначалу я не думал об использовании рендер-ферм (или обращаться за помощью с рендером к коллегам), но со временем сроки начали сокращаться, поэтому моих собственных мощностей стало нехватать. И все острее становился вопрос: как мне просто и быстро передать сцену на другую машину, не потеряв все эти связи с файлами? А в более широкой перспективе — как вообще делать архивы подобных проектов, чтобы не собирать вручную файлы по всему компьютеру, и не раздувать blend-файлы, встраивая в них изображения?
Нужен был аддон. И теперь, уже успешно сделав нечто подобное, я чувствовал, что готов попытаться сделать его самостоятельно (используя ChatGPT).
Пишем код в ChatGPT. Часть первая
Начал опять с самого простого, чтобы потом постепенно усложнять: попросил написать скрипт, который выводил быв консоль список всех внешних файлов:
А после попросил добавить к ним также внешние алембики и файлы сцен блендера:
Код заработал не сразу — возникло несколько ошибок, которые я сообщил боту, и он (в итоге успешно) попытался их исправить:
После исправления последней, скрипт заработал. Полная переписка с итоговым рабочим кодом доступна по этой ссылке (если захотите самостоятельно протестировать код, не забудьте, что в сцене должны быть внешние файлы, а результаты выводятся в консоль — ее нужно открыть).
Следующий шаг — скопировать все найденные файлы в одну папку: я написал запрос боту, чтобы новая версия программы создавала папку “assets”, в которую копировала бы все найденные внешние файлы. Скрипт, вроде бы, заработал, но для контроля выполнения программы я попросил добавить вывод отчета в консоль:
Листинг переписки доступен здесь.
Дальше стали возникать сложности (подозреваю, что во многом потому, что я даже не пытался особо углубляться в суть разработки и просто решал задачу в лоб — но в том был и смыл: я старался максимально отстраниться от разработки и минимизировать время, которое я сам трачу на решение). Их все я без зазрения совести адресовал нейросетке, попутно отмечая, как бот из контекста хорошо понимает мои запросы в моменты, когда мой английский сбоил, выдавая опечатки и грамматические ошибки. Переписку можно посмотреть тут.
Под конец до меня дошло то, что надо было сделать одним из первых шагов — исключить дубликаты файлов. Правда, на этом ошибки не закончились, и я предположил, что дело в относительных путях к файлам, формат которых в Blender может быть не совместим с моей операционной системой... но тут ChatGPT сломался.
На момент описываемых событий это означало, что надо начинать новый чат, чтобы продолжить работу. Хорошо, что бот может вспомнить любой ваш с ним диалог.
Пишем код в ChatGPT. Часть вторая
Правда в этот раз напоминать пришлось максимально конкретно: самым простым способом оказался просто отправить ему предыдущий программный код.
В итоге оно вспомнило: «Да, я помню, что помогал вам написать этот скрипт. Предоставленный вами скрипт является скриптом Python Blender, который экспортирует все связанные файлы (текстуры, связанные библиотеки и файлы кэша Alembic) используемые в текущей сцене Blender в каталог «assets» в том же каталоге, что и файл blend. Скрипт использует модуль bpy, который является Python API Blender, для доступа к данным Blender и выполнения операций».
И я повторил свой запрос по поводу путей файлов:
Бот внес изменения, но ошибки по-прежнему возникали — глядя на консольный вывод, я пытался направить нейросеть на правильное решение:
Код выглядел корректно, но, похоже, сканирование всех прилинкованных файлов, включало также и файлы аддонов, что вызывало дополнительные ошибки работы с путями и доступом к файлам. Я это понял чуть позже, но на момент работы с кодом, я решил подойти к вопросу в более общем ключе, попросив включить в код обработчики ситуаций, когда обрабатываемый файл не существует, и когда есть проблемы с доступом — это решило проблему (в конце-концов все мои рабочие файлы вряд ли располагались по путям с закрытым доступом, а те, которые попадали, меня не интересовали).
Текст переписки можно посмотреть по этой ссылке. Этот скрипт уже выполнялся без критических ошибок, копируя задействованные в сцене файлы в папку “assets”.
Осталась последняя задача: заменить пути для всех скопированных файлов с оригинальных на новые, в папке ”assets”. И в момент ее реализации ChatGPT опять начал неприятно глючить — в этот раз стало слетать форматирование, и вместо программного кода я стал получать markdown-форматированный текст:
Следующие 10-15 минут прошли забавно: я пытался привести нейросеть в чувства, направляя ее в сторону корректного результата (я очень не хотел вручную править и перепроверять код — слишком много ошибок можно было совершить, потом исправлять, а я не хотел тратить столько времени) — все «веселье» в галерее — листайте:
В итоге я решил пойти на крайние меры. Обновил страницу и начал новый чат, скормив в первом сообщении боту последнюю полную версию скрипта. Хорошо, что он ее признал!
Я сразу же попросил и уменьшить количество комментариев, и сделать так, чтобы для всех скопированных файлов программа заменяла старые пути на новые.
Бот починился и даже выдал целиком программный код, который работал! Да, в консоли выскакивали ошибки и предупреждения для некоторых файлов, но программа выполнилась полностью, и все материалы, текстуры и связанные алембики были на месте с новыми путями к каталогу “assets” — ссылка на результат.
Последнее, что нужно было сделать — чтобы пути были не абсолютными, а относительными (ведь на другой машине проект может находиться совсем по другому пути). Самый простой способ — в конце программы снова пройтись по всем путям и преобразовать их в относительные.
Форматирование опять сломалось, но мне не хотелось еще раз пытаться заставить его писать правильно, поэтому я просто скопировал код в редактор и поправил отступы. В результате я получил не самый оптимизированный, но готовый рабочий скрипт, решающий мою задачу! Ура!
Превращаем скрипт в аддон
Оставался еще нюанс: скрипт — это не аддон. А я хотел получить именно постоянно висящую панельку, которая торчала бы у меня в Blender под рукой, готовая выполнить сбор файлов в любое время дня и ночи по моей первой прихоти! Поэтому, мы продолжили («мы пахали: я и трактор», — да-да).
Этот сеанс с ChatGPT также уже забаговался, поэтому я просто запустил новый, и начал с простых вещей: попросил сделать панель с кнопкой. Функционал кнопки должен был быть максимально простой, чтобы я позже подставил туда свой код, сгенерированный ранее:
Напиши мне простой аддон для Blender, который создаст панель с заголовком “Asset Collector”, одним полем ввода с меткой “Assets folder name” и значением по умолчанию “assets”, и кнопкой “Collect”. Кнопка должна просто выводить “Collected!” в консоль.
Конечно, панель — это еще не аддон, но полученного кода мне хватало для реализации всего оставшегося функционала. Это был тот момент, когда дописать самому стало быстрее, чем просить кого-нибудь это сделать (даже такую исполнительную штуку как ChatGPT).
Я добавил в текст этой программы сгенерированный ранее код: дописал нужные инструкции import, вставил в тело функции execute() кнопки весь функционал предыдущего скрипта. А чтобы скрипт был именно аддоном, добавил соответствующий заголовок bl_info (как он пишется, я просто нашел в интернете):
Вот такой получился итоговый код и, собственно, сам аддон, который можно установить в Blender и использовать по необходимости.
Замечания (вместо послесловия)
Конечно, этот скрипт не идеален. Он генерирует большое количество ошибок и предупреждений, а сам код может быть еще оптимизирован (например, в части замены абсолютных путей на относительные).
Но всего за пару часов я смог получить рабочий инструмент, который решил мою проблему (при том, что самостоятельно я бы это делал гораздо дольше, разбираясь в API и особенностях разработки). На данный момент уже два ролика были успешно «упакованы» этим аддоном и отправлены для рендера на другие машины, так что «оно работает» — пользуйтесь, если нужно! :)
Если кто-то решит допилить этот аддон до «более правильного» состояния — милости прошу: весь код открыт, берите, пользуйтесь, развивайте, делитесь в комментариях! Ну и, как обычно, если у вас остались вопросы, появились замечания или предложения, пишите — прочитаю, учту, отреагирую. Подписывайтесь на этот журнал, канал в Телеграме и/или мой личный канал в Телеге, где не только про VFx, рассказывайте вашим знакомым — вдруг подобный материал будет кому-нибудь еще интересен и/или полезен.
Всего хорошего!