Всем привет! Если вы ранее читали этот блог, то наверняка знаете, что летом прошлого года (август, 2020) я начал разработку собственного пакета инструментов для 3D-визуализации, моделирования, анимации и управления данными – «Lamp».
Стоит отметить, что, несмотря на столь нескромное описание данного проекта, в большей мере, «Lamp» – это лишь набор сопутствующих инструментов ко всем перечисленным выше областям (3D-визуализация, моделирование, анимация и управление данными).
И пускай «Lamp» нельзя назвать отдельным программным продуктом (программным обеспечением), тем не менее, это проприетарный инструмент, являющийся встраиваемым модулем для основного программного обеспечения. В нашем случае, таким программным обеспечением является Autodesk Maya.
В этой статье, на примере «Lamp», мы поговорим о некоторых проблемах, связанных с разработкой подобных проприетарных инструментов, и поговорим о проблемах в оптимизации рабочих процессов, в которых применяются эти инструменты.
Проприетарные инструменты
Концепция инструмента
Как бы банально это ни звучало – любой проект начинается с идеи. Именно определение концепции инструмента задаёт тон всей разработке и влияет на ключевые этапы в ходе реализации и внедрении этого инструментария.
И понятие «концепции» я определяю в самом широком значении.
Концепция – это не только красивое описание инструмента, включающее в себя основные его характеристики. Она также должна содержать в себе ответы на фундаментальные вопросы:
- Для чего нужен этот инструмент?
- Какова область его применения?
- Насколько широко он будет применяться в работе?
- Насколько целесообразно заниматься поддержкой этого инструмента уже после окончания разработки и внедрения?
Ответив на эти вопросы заранее вы сможете избежать множества нарастающих проблем в будущем. Чем лучше вы будете знакомы со своим инструментом ещё до начала процесса его создания, тем более качественный продукт получите по итогу.
Определяясь с концепцией стоит также продумать и способы внедрения этого инструмента в ваш рабочий процесс (пайплайн).
Если вы работаете один, то вам удастся избежать множества проблем, присущих сотрудничеству между отделами.
Если у вас есть команда или даже полноценная студия, делящаяся на отделы, то это значительно усложняет задачу; ведь в таком случае придётся опираться на методы сотрудничества, которые используются внутри вашего рабочего процесса.
(В этом вам поможет ответ на вопрос 'Насколько широко он будет применяться в работе?')
Заранее стоит продумать и варианты расширения возможностей инструментария. В ходе объёмной работы не редко появляется потребность в масштабируемости отдельных инструментов или всего инструментария в целом. А, как это часто бывает, ваш инструмент по каким-то причинам не был приспособлен к такому. Сразу же начинаются проблемы с доработкой инструмента под ваши нужды или приходится переписывать его с самого начала. В самом худшем случае от него и вовсе отказываются.
Дабы подобное не происходило, следует заранее позаботиться о возможности дополнять ваш инструмент, портировать его под другие программные или аппаратные решения, или обеспечить удобную совместимость с другими инструментами.
Начальный этап разработки
Первый этап в разработке зачастую предполагает множество подготовительных и организационных мероприятий. Однако я упущу эти моменты, поскольку они крайне индивидуальны, и рассказывать о том, «кто и как» создаёт папки и репозитории – не очень интересно.
Та что я сразу перейду к процессу разработки, минуя все эти организационные вопросы.
С чего начать
Приступив к разработке, у многих с самого начала возникает один, на первый взгляд банальный, но сложный вопрос: «А с чего начать?»
Дело в том, что разработка каких-либо нативных дополнений к существующему ПО всегда требует совмещать собственные идеи с уже существующей базой. Вы не можете диктовать свои условия программе, для которой пишите этот инструмент. Наоборот, у неё есть свои правила, под которые вам необходимо подстроиться.
В случае с «Lamp», мне сразу нужно было понять от каких возможностей я могу отталкиваться.
Autodesk Maya имеет специфичную структуру. Большая часть программы построена из скриптов на её собственном языке – MEL (Maya Embedded Language). И это огромный плюс к модульности данного ПО.
Следовательно, я понимал, что у меня есть возможность реализовать модульную структуру в «Lamp», при том на разных уровнях. Специфика May'и позволяла мне вмешиваться в её собственные процессы и влиять на них.
Проще говоря, я мог легко транслировать свои инструменты в любую задачу, для которой у Maya уже есть решение. Если мне нужно разбить кусок геометрии при помощи собственного алгоритма, то Maya уже умеет идентифицировать новообразованные меши (геометрию), поскольку такая функциональность в ней уже есть – инструмент (команда) Detach.
Помимо этого, Maya широко поддерживает сценарии (скрипты) Python, и их также можно интегрировать в совершенно разные процессы.
Как видите, уже здесь решился ряд проблем с последующей интеграцией идей в существующую функциональность программного обеспечения. Однако чёткого ответа на вопрос «с чего начать?» всё ещё нет.
А начать нужно как-раз таки с написания связующих элементов между вашим инструментарием и программным обеспечением, поскольку в дальнейшем, вам придётся отталкиваться именно от возможностей, упомянутых выше.
Реализация технической части инструментария
Под технической частью чаще всего понимается основа программного продукта. Одним словом – код, который не видно простому пользователю.
У каждого инструмента техническая составляющая уникальна. Нельзя вывести единую формулу создания алгоритмов и функциональности, которая будет справедлива для каждого. Однако всем им присущ ряд одинаковых проблем.
Сперва, это – оптимизация.
В своих статьях, обычно, я ставлю вопрос оптимизации уже в самом конце, хоть он и является ключевым для всей работы. Но говоря о разработке дополнений к основному программному обеспечению, стоит осознавать риски, которые вы возлагаете на компьютеры и ПО при интеграции этих инструментов. Проще говоря, ваш инструмент не должен нагружать программу и заставлять терять её в производительности; то же касается и компьютера.
Логика.
Затем, наиболее распространены проблемы с построением логических связей в работе вашей функциональности.
Я имею ввиду отсутствие рационального взгляда при реализации каких-то вещей. Вы можете задействовать какие-то части программного обеспечения через посредников или даже написать собственную службу. Однако, если данную функциональность можно реализовать несколько иным способом, используя другие методы или пути в программном обеспечении, и тем самым реализовать эту функциональность напрямую, минуя этих посредников, – это необходимо делать.
Возможно я даю несколько запутанные и довольно абстрактные объяснения, но просто держа эти мысли в голове, на практике вы поймёте, что они довольно просто применимы.
Интеграция непосредственно при разработке.
Говоря об интеграции на этапе разработки, нужно сделать сноску, что этот этап интеграции не равен этапу интеграции уже готового инструмента в программное обеспечение или рабочий процесс.
Если мы говорим о полноценных инструментариях, включающих в себя множество инструментов, то интеграция отдельных инструментов в ходе разработки – обыденное дело, поскольку работа, в большей мере, ведётся параллельно.
И именно здесь, зачастую, многие не заботятся о возможных рисках должным образом.
В ходе пополнения инструментария новыми инструментами, а также при изменении или дополнении отдельных, уже интегрированных инструментов, построение всего инструментария может существенно меняться.
Вновь необходимо учитывать структуру проекта. С точки зрения построения архитектуры, ваш инструментарий должен соответствовать техническим особенностям, которые вы изначально установили.
Если начнут появляться расхождения в фундаментальном устройстве проекта, то, есть риск возникновения конфликтов между инструментами и появления разного рода критических ошибок.
Этап активной разработки
На этапе активной разработки не редко появляются проблемы, которые было бы довольно сложно предугадать вначале.
Когда речь идёт о большом проекте, подразумевающим совместное использование и интеграцию в рабочий процесс, очень сильно встаёт вопрос масштабируемости этого проекта.
Масштабируемость
Тут мы вновь возвращаемся к концепции проекта.
Возможность масштабировать свой инструментарий или отдельные его инструменты необходимо предусматривать заранее. Т.е. эта идея должна входить в изначальный концепт проекта, чтобы позаботиться о соответствующих технических решениях на самых ранних этапах разработки.
В противном случае, есть риск того, что вам придётся переписать весь проект, дабы добавить возможность его масштабировать.
Это, в свою очередь, приведёт к катастрофической потере времени, сил и средств, затрачиваемых на разработку. А если мы говорим про студийный пайплайн, нацеленный на разработку коммерческих шоу (мультфильмов, блоков эффектов для фильмов) – то это просто недопустимо.
В случае с Lamp у меня не было подобных ограничений, но увеличивать время разработки было крайне нежелательно.
Правда серьёзных проблем с возможностью масштабировать весь инструментарий и отдельные инструменты у меня не возникло, поскольку я предусмотрел это с самого начала.
Все проблемы касались исключительно совместимости тех или иных решений. Начиная от языка программирования, на котором был написан тот или иной инструмент, и заканчивая связующими элементами непосредственно внутри самого программного обеспечения, т.е. внутри Maya.
Как пример, сам инструмент Lamp Hurd Cut (инструмент для разбивания объекта на отдельные части) был написан на MEL, в то время, как алгоритмы, которые он задействовал были написаны на Python.
При этом, Lamp Hurd Cut предлагал несколько способов разбить объект, каждый из которых основан на разных алгоритмах.
Первый алгоритм – Voronoi, основанный на инструменте с открытым исходным кодом – Voronoi Shatter. По сути, я просто взял готовый алгоритм и использовал его без каких-либо изменений.
Второй алгоритм – ULBA (Universal Lamp Breakdown Algorithm – Универсальный алгоритм разбивки Lamp). Это уже самописный алгоритм, со своей спецификой и особенностями.
При этом каждый из этих инструментов использует разный тип взаимодействия с объектом, который следует разбить.
В первом случае – это процедурная генерация объектов в пространстве, на основе данных изначального объекта и указанного количества необходимых частей на которые будет разбит объект. А во втором – взаимодействие происходит совершенно иначе. Деление геометрии происходит схожим образом с работой инструмента Insert Edge Loop Tool, только со случайной генерацией направления новообразованных краёв (Edges). А само разбитие по этим краям происходит с применением методов, на которых основаны такие команды как Detach и Separate.
В конце-концов, изначальный скрипт через который работал Voronoi Shatter и вовсе подразумевал наличие опорных точек в виде локаторов (объектов типа NURBS-кривых), через которые он проводил края (Edges).
Всё это привело к тому, что скрипт Lamp Hurd Cut должен был совмещать в себе множество всевозможных функций и их вариаций, алгоритмов и прочей технической составляющей, которая ко всему, была ещё тесно связана с самой Maya.
Здесь требовался совершенно новые подход к разделению всей этой функциональности, которую было необходимо уместить в одном инструменте. И я нашёл решение.
Каждая функция, каждое обращение к алгоритмам, каждый вызов инструментов Maya были распределены в отдельные потоки, управление которыми происходило через основной скрипт – Lamp Hurd Cut. Который, к слову, насчитывает всего 505 строк кода, что, казалось бы, для инструмента подобных масштабов крайне мало.
Распределение функциональности на отдельные потоки, которые Maya могла исполнять без потери производительности, позволили мне не только уместить сразу два ресурсоёмких алгоритма в рамках одного инструмента, но и дала возможность дополнять этот инструмент какой угодно функциональностью в будущем.
Данный метод можно назвать модульным подходом в реализации инструментов. А модульность – гарантированная возможность масштабировать ваш инструмент.
Другой вопрос о дополнении всего инструментария в целом.
Иногда появляется потребность в реализации нового рабочего процесса, который требует применения дополнительных технологий. И если этот рабочий процесс подразумевает использование дополнения в связке с основным инструментарием, то здесь следует говорить о возможности этот инструментарий дополнять; о возможности интегрировать (частично или полностью) ещё какие-то технологии в него.
Насколько сильно вы сможете масштабировать свой инструментарий в рамках вашего основного рабочего процесса или нового подхода к вашему привычному рабочему процессу?
Если вновь вернуться к Lamp, то этот инструментарий начал разрабатываться на стыке моей работы с динамикой и началом изучения мной анимации. Поэтому вскоре после первых рабочих версий Lamp, которые я тут же начал использовать в своей работе, связанной с моделированием, – мне потребовались инструменты для работы с анимацией.
В этот момент появилось такое ответвление как Gawk.
Gawk – система лицевой анимации для Maya и Houdini, которую позднее планируется расширить до полноценной системы анимации разного уровня.
При реализации и внедрении Gawk нужен был совершенно новый подход. Я не мог просто привязать новую пачку инструментов к Lamp, никак не затронув основной инструментарий.
Дабы пояснить эту мысль, на случай, если у вас возникнут вопросы по типу: «А почему бы просто не сделать Gawk полностью самостоятельным инструментарием, даже без намёка привязки к Lamp», – скажу следующее... Суть Lamp заключается именно в централизации инструментов, быстром доступе к ним и удобстве в использовании. Если эти инструменты не будут управляться Lamp, они просто не будут в него включены. А если они не будут в него включены, то они теряют смысл как дополнение.
Гибкость
Здесь речь пойдёт больше не о технической части, а о тех возможностях, которые предлагает ваш инструментарий и его отдельные инструменты в частности; о том, как широко или более точечно эти инструменты смогут применять аниматоры, моделлеры, художники по текстурам, риггеры и т.д.
И снова мы возвращаемся к концепции проекта.
Если ваш инструментарий имеет конкретное направление, допустим, ускорение работы моделлеров, то весь проект будет заточен именно под реализацию инструментов, удовлетворяющих их потребности. Следовательно, пользы отделу текстурирования от него будет не много.
Однако, если мы берём во внимание довольно частные случае, при которых, другие отделы тоже начинают видеть полезность данного инструментария в их работе, то встаёт вопрос рациональности использования данного метода. Т.е., насколько это хорошо, если отдел текстурирования будет использовать систему рандомного назначения текстур при разбивании объектов (Lamp Hurd Cut).
Если это одна из функций конкретного инструмента, которые ну никак не вяжется с работой текстурщика, то возможно стоит задуматься о реализации этой функции в качестве самостоятельной единицы.
Как уже было сказано выше, в Lamp Hurd Cut есть система произвольного назначения текстур между разрезанными полигонами, для разграничения внутренней и внешней стороны объектов.
И предположим, что у меня была бы своя производственная команда, работающая над анимационным фильмом.
Моделировщикам и художникам по визуальным эффектам пришлось бы широко применять Lamp Hurd Cut в сценах с разрушениями. Их работа с данным инструментом была бы крайне уместна, чего нельзя сказать про художников по текстурам, которые, предположим, также смогли найти применение Lamp Hurd Cut в своей работе.
Если из инструмента, призванного разбивать объекты, извлечь нужную им функциональность, и реализовать в качестве отдельной кнопки, то они смогли бы спокойно использовать нужную для них функцию, не пребегая к подобным костылям.
В нашем случае, это была бы функция произвольного присваивания текстур с внешней и внутренней стороны объекта, которая, к примеру, позволила бы им более гибко управлять экстерьерной и интерьерной отделкой рушащихся зданий.
Другой вопрос, когда инструмент, созданный для конкретных задач, начинает применяться другими отделами полностью. Т.е. они задействуют не только его отдельную функциональность, а весь инструмент в принципе.
Здесь мы снова говорим о рациональности: насколько эффективно данный инструмент применяется в работе разных отделов, и насколько сильно он влияет на результативность отделов. Если это просто смотрится дико, но не несёт огромных рисков, то данную методику можно не исключать из рабочего процесса... по крайне мере пока. Особенно, если работа уже во всю идёт, и удовлетворить потребность какого-то отдела в данной функциональности, другим, более безболезненным способом не получится.
Главное, чтобы эти методы не превратились в откровенный костыль, который в будущем может стать серьёзным препятствием в решении ваших задач.
Почему этот вопрос поднимается на этапе активной разработки, а не в самом конце? Всё довольно просто. По мере разработки инструментария вы можете эффективно дорабатывать каждый инструмент под все вышеописанные нужды; в то время как после окончания разработки, это принесёт лишь очередные потери времени и средств.
Финальный этап разработки
В глобальном смысле этот этап значит многое, ведь именно на нём происходит вся отладка и последующая доработка инструмента. Однако каких-то общих проблем я здесь выделить не могу, так как все мероприятия по той же отладке довольно однотипны, а проблемы, наоборот, в большей мере индивидуальны для каждого инструмента.
И всё же есть некоторые организационные моменты, которые стоит упомянуть.
Сперва это стандарты и методы, согласно которым вы строите финальную версию инструмента. Они зачастую бывают специфичными и, опять же, индивидуальными. Каждый разработчик дорабатывает какие-то решения в соответствии со своим виденьем, и этот процесс зачастую может сильно разниться с устоявшимися методами.
Важно понимать, что процесс доработки инструмента не должен противоречить процессу разработки в целом. Я имею ввиду, что вы не должны вносить кардинальные изменения на этапе доработки существующих решений.
Если вы не уверены в возможностях и той функциональности, которые обеспечивает ваш инструмент, то этот вопрос нужно решать ХОТЯ БЫ в середине процесса разработки, но никак не в конце.
Помимо этого, ваши методы не должны ломать проект. Отладка, порождающая ещё больше багов – никуда не годится.
При этом, не важно согласно каким стандартам вы определяете, что проект готов. Главное, эти стандарты должны удовлетворять одному единственному требованию – наличие должной оптимизации. Возвращаясь к этому вопросу ещё раз: ваш инструмент не должен оказывать негативное влияние на программное обеспечение или аппаратные системы пользователей.
Ну и теперь мы наконец переходим к завершающему этапу в разработке проприетарного инструментария.
Интеграция в рабочий процесс
Как правило, большинство аниматоров придерживается позиции заниматься исключительно своей работой, а все технические задачи отводить техническому отделу. В результате чего, во время интеграции каких-либо инструментов возникает не мало проблем в результате конфликтов потребностей в рабочем процессе аниматоров.
Здесь я уже имею ввиду потребности не в каких-то возможностях, а всё построение рабочего процесса аниматоров в целом. Сейчас поясню...
У каждого аниматора есть собственный рабочий процесс, который может быть навеян требованиями студии, а может быть и не навеян. В любом случае, не важно насколько сильна зависимость от студийного пайплайна, каждый аниматор выстраивает свою работу так, как ему удобнее.
Это порождает некоторые проблемы в совместимости используемых инструментов и методов работы.
Если аниматоры, моделлеры, художники по текстурам и свету, риггеры и т.д. ограничены едиными правилами студийного пайплайна, то вы несколько упрощаете себе задачу. Просто потому что вам не нужно дополнительно подстраивать ваш инструментарий под каждый отдел и под каждого конкретного работника в этом отделе.
Поскольку данный инструментарий уже включён в ваш студийный рабочий процесс – все отделы принимают его как одну из необходимостей для выполнения работы в рамках студии.
Если же ваш инструментарий распространяется на не большую команду энтузиастов, где потребности каждого конкретного человека более выражены, то вам придётся уже тщательней решать вопрос с интеграцией инструментария в ваш рабочий процесс.
Концептуально, «Lamp» больше присущ второй вариант, поскольку на данный момент этот инструмент настолько проприетарен, что не выходит за рамки моего личного использования. Тем не менее, я был бы не против рассмотреть его и в контексте студийного пайплайна.
Студийный рабочий процесс
Как уже было сказано ранее, в рамках студийного рабочего процесса вся работа крайне ограничена условиями и порядком этого рабочего процесса. В особых случаях ему может быть присуща гибкость, но если мы будем брать во внимание анимационных гигантов, то они попросту не могут себе этого позволить, так как любые отхождения от графика несут риски по потере времени и, как следствие, денег.
Поэтому работая в анимационной студии все отделы придерживаются установленного порядка, принимая все его условности и требования. А также удовлетворяя свои потребности в каких бы то ни было возможностях, из того, что предлагает этот рабочий процесс.
Проще говоря, отделам приходится подчиняться тем условиям, которые выдвигает студийный рабочий процесс. В противном случае, работа будет попросту невозможна.
Это позволяет интегрировать инструменты в рамках вашего инструментария в совершенно разные отделы, использовать метод параллельной работы, и при этом не испытывать проблем с совместимостью.
Если вновь брать в пример «Lamp», то он предлагает ряд инструментов, каждый из которых может быть применён соответствующим отделом. Эти инструменты логически поделены на отдельные группы, каждая из которых представляет свой набор функциональности «Lamp». Условно эти наборы предоставляют специальные возможности для каждого отдела: 3D-визуализация, моделирование, анимация и управление данными. Поэтому взаимодействие конкретных отделов с данным инструментарием может происходить исключительно в рамках соответствующего набора инструментов.
К примеру: аниматору требуется скрипт, который запишет изменения атрибутов (Attributes) объекта в каждый кадр секвенции на определённом промежутке. Для этого он может воспользоваться инструментом Real-Time Animation Recorder (rtAnimationRecorder) из системы Gawk, которая включена как набор инструментов для анимации в «Lamp». После чего, этому аниматору необходимо исправить режим образования кривых (сгладить их и повысить плавность анимации) между кадрами анимации в Graph Editor'е. Для этого он также может воспользоваться специальным инструментом, включённым в «Lamp».
Тем самым, аниматор не будет выходить за пределы набора инструментов, связанных с анимацией.
В то время, как риггер может использовать инструмент CTRL Сreator, позволяющий быстро создавать примитивы из кривых.
В это же время, художнику по текстурам может потребоваться преобразовать назначенные на скорую руку материалы типа lambert, в aiStandartSurface, но с сохранением атрибута цвета (чтобы цвет остался такой же, как на lambert'е). Для этого он может воспользоваться mcToArnold, также включенной в «Lamp».
Как вы уже могли понять, слаженная работа всех отделом достигается банальным разграничением различной функциональности и возможностей «Lamp», никак не нарушая работу этих отделов. Они могут работать параллельно, при этом, находясь в рамках одного рабочего процесса. Они даже могут использовать разные типы и версии Maya, но всё равно использовать широкие возможности «Lamp», не испытывая проблем с совместимостью.
Другой вопрос: А что, если не ограничивать работу конкретного отдела соответствующим набором инструментов?
В этом случае вы получите довольно уникальный опыт, который я уже описывал выше: каждый отдел, в случае чего, сможет найти применение каких-то инструментов или функций инструментов, напрямую не связанных с задачами этого отдела, но позволяющими реализовывать какие-то отдельные моменты. Как это было с использованием системой рандомного присваивания текстур при разбивании объектов. Однако здесь вновь встаёт вопрос рациональности, который мы уже подробно рассмотрели выше.
Рабочий процесс в рамках небольшой команды
В рамках команды энтузиастов проприетарные инструменты зачастую становятся проблемой, если они не адаптированы под массового пользователя.
Как я уже говорил, каждый аниматор выстраивает свой рабочий процесс так, как ему удобно. Тоже самое делает и моделлер, и риггер, и художники по текстурам и свету.
Большинство проблем, связанных с совместимостью возникают на процессе рендеринга, и возникают у людей, которые занимаются рендерингом конечного результата.
В остальном, слаженная работа между аниматором и риггером, аниматором и моделлером и т.д. может достигаться просто одинаковыми версиями программного обеспечения. Если у вас, как у аниматора, Maya 2020, и у вашего риггера Maya того же года (вне зависимости от патча), то никаких проблем с передачей рига у вас не возникнет.
Однако включая в вашу работу проприетарный инструмент, вы стоклнётесь с рядом уже описанных ранее вопросов и проблем.
Каковы его производственные особенности? (может быть вы использовали специфичные библиотеки и фреймворки, требующие специальных системных файлов)
- Как он был интегрирован и адаптирован под программное обеспечение?
- Насколько он гибок? Как его можно расширить?
- Как передавать сцены, создаваемые с помощью этого инструментария?
- Насколько сильно он зависит от версий программного обеспечения?
- И т.д. и т.п.
Все эти вопросы стоило решать ещё на этапе формулирования концепции инструментария, ну или по мере разработки инструментария.
Однако, в случае с «Lamp», этот инструмент универсален настолько, что на данный момент ни один из этих вопросов не может стать серьёзной проблемой в совместимости.
Весь создаваемый контент в исходном виде спокойно передаётся в Maya Binary и Maya ASCII форматах, а также в FBX и OBJ в производственном виде. Ограничения по версии – любая Maya, начиная от 2019 года (вне зависимости от патча) и новее.
Заключение
Разработка проприетарных инструментов – сложный и трудоёмкий процесс, который подразумевает общее понимание всех потребностей аниматоров, моделлеров, риггеров, художников по текстурам, художников по освещению и даже композеров. Ведь именно потребность в той или иной функциональности и вынуждает прибегать к решениями на базе собственных разработок.
А эти разработки, в свою очередь, создадут новые подходы в реализации тех или иных вещей в рамках анимационный фильмов или визуальных эффектов для игрового кино, что в конечном счёте может привнести новшества в сферу компьютерной графики и, как следствие, развить её.
Поэтому не бойтесь прибегать к разработке собственных решений для совершенствования ваших производственных задач, будь то анимация, моделирование или визуальные эффекты.
#Maya #Lamp #cgi #анимация #3d моделирование #инструменты анимации