Геймдев
#статьи

Уроки по Blender: структура объектов, оптимизация, скрипты Python

Разбираемся в более продвинутых понятиях и инструментах.

Андрей Соколов

Специалист по компьютерной графике, оптимизации и автоматизации проектов. Автор серии уроков по Blender.

Сохранитесь и подпишитесь: наш Telegram-канал «Чекпоинт» — уютное место, где мы рассказываем об играх и о том, как они создаются.

Год назад в рамках своего YouTube-канала Андрей записал подробный курс по Blender, в котором работает более 7 лет. Обучение начинается с основ, рассчитанных в первую очередь на новичков, но последующие уроки могут быть интересны и для продвинутых пользователей — в них Андрей затрагивает скрытые возможности софта. Сам материал записывался в версии программы 2.90.1, но знания актуальны как для ранних версий (от 2.80), так и для последней (3.0.0).

Делимся основными тезисами третьего и четвёртого видеоуроков, посвящённых структуре, оптимизации и рандомизации объектов через инструменты Blender и скрипты Python. В предыдущих уроках мы рассматривали интерфейс программы и простые операции, а также основы моделирования.

Третий урок по Blender от Андрея Соколова
Четвёртый урок по Blender от Андрея Соколова

Структура объектов

Как известно, при создании нового проекта в сцене по умолчанию появляется куб. Это объект со своими данными, которые можно увидеть, если кликнуть на стрелку рядом с объектом Cube в Структуре проекта (Outliner). Данные объекта Cube — это меш Cube (иконка зелёного треугольника). Объект и его меш — это разные элементы.

Отображение объекта и меша в коллекции сцены. Для наглядности объект подчёркнут оранжевым цветом, меш — зелёным. Коллаж: Леон Балбери для Skillbox Media

У объекта есть название и характеристики: положение, вращение, масштаб и размеры. Они находятся на панели Трансформация (Transform) в верхней вкладке Элемент (Item) — саму панель можно легко вызвать горячей клавишей N.

Вызов панели Трансформация (Transform)

Данные меша можно посмотреть в Режиме редактирования (Edit Mode): здесь во вкладке Трансформация — Элемент появятся новые данные, в том числе Медиана (Median). Эта характеристика отображает координаты среднего значения точек.

Координаты меша во вкладке Медиана (Median). Скриншот: Леон Балбери для Skillbox Media

Видоизменим и переместим меш во вьюпорте и обратим внимание на его координаты. Затем вернёмся в Объектный режим (Object Mode) и обнаружим, что координаты объекта остались прежними (во вьюпорте можно заметить его ориджин — оранжевую точку, которая отвечает за позицию и центр объекта). Так мы видим, что объект и меш — две разные структуры в Blender.

Объект и меш, перемещённый в сторону. Скриншот: Леон Балбери для Skillbox Media

Взаимоотношения объекта и меша

Теперь выясним, почему эта информация важна для пользователя. Для наглядности переименуем объект Cube в Cube object (двойной клик по названию в структуре проекта), а его меш — в Cube mesh. Эти элементы связаны между собой. Их отношения напоминают связь Parent — Child («‎родитель» — «ребёнок»), где Cube mesh будет «ребёнком» Cube object. При этом у объекта может быть одновременно только один «‎ребёнок», а меш может быть «ребёнком» и других объектов.

Создадим новый куб с помощью Shift + A. Как и в случае с первым кубом, у нового объекта будет свой меш. Но, перейдя во вкладку Настройки данных объекта (Object Data Properties), новый меш можно заменить на первый, который мы ранее переименовали в Cube mesh.

Замена меша у нового объекта. Скриншот: Леон Балбери для Skillbox Media

Таким образом, у двух объектов будет один и тот же меш (чуть ниже объясним, чем это полезно).

Примечание

На скриншоте два объекта после этой операции выглядят по-разному. Это связано с тем, что их позиция и настройки отличаются. Если убрать все изменения во вкладке Трансформация — Элемент, то получится два одинаковых куба.

Проведём ещё один эксперимент. Удалим предыдущие объекты, добавим новый куб и зададим его мешу новое название, например, cube mesh main. Он будет главным мешем для будущих операций.

Зайдём во вкладку Наложения вьюпорта (Viewport Overlays) — в первом уроке мы включали в ней ось Z, — и отметим галочкой пункт Статистика (Statistics). В левом верхнем углу появится информация о сцене.

Местоположение опции «Статистика» и список данных. Скриншот: Леон Балбери для Skillbox Media

Статистика показывает, что в сцене находится:

  • 3 Объекта (Objects) — 1/3 означает, что один из них выделен;
  • 8 Вершин (Vertices);
  • 12 Рёбер (Edges);
  • 6 Граней (Faces);
  • 12 Треугольников (Triangles).

При создании нового куба или его дублировании (Shift + D) количество всех показателей геометрии увеличится вдвое, поскольку меш объекта также продублируется. Но если заменить меш нового объекта на предыдущий (в данном случае cube mesh main), то показатели не увеличатся.

Комбинация клавиш Alt + D упрощает процесс — с её помощью можно сразу же создавать новый объект с исходным мешем. Таким способом вы можете быстро сгенерировать множество идентичных объектов, сохранив начальное количество полигонов.

Клонирование объектов через Alt + D

Эта операция значительно экономит время и ресурсы при просчёте сцены. Дело в том, что у каждого полигона существует множество внутренних характеристик: нормаль, шейдинг и прочие данные, которые не так очевидны на первый взгляд, но важны при рендеринге. Соответственно, графический движок должен просчитать все эти показатели для каждого полигона в сцене. При использовании одинаковых данных время расчёта значительно сокращается, даже если они принадлежат разным объектам.

Оптимизация масштабных сцен

Попробуем усложнить задачу: выделяем все объекты в сцене и копируем их через Alt + D несколько раз. Рекомендуем предварительно удалить или спрятать (H) камеру и источник света, чтобы случайно не создать их дубликаты.

Группа объектов, скопированная несколько раз. Скриншот: Леон Балбери для Skillbox Media

Статистика на скриншоте показывает, что в сцене 310 объектов. Выделяем все объекты — это можно сделать при помощи клавиши A или окружности (Circle Select), вызвав инструмент кнопкой С и увеличив радиус колёсиком мыши. Если применить к одному из выделенных объектов модификатор Подразделение поверхности (Subdivision Surface) — о нём мы узнали во втором уроке, — количество граней увеличится. При наложении модификатора на все объекты в сцене сумма полигонов может вырасти до полумиллиона. Сделать это быстро можно при помощи горячих клавиш: Ctrl + 1, Ctrl + 2, Ctrl + 3 и Ctrl + 4 — для разных уровней сглаживания. Таким образом эффект от использования одних и тех же мешей пропадает, так как при использовании модификаторов происходит полный пересчёт геометрии объекта.

Примечание

Применить модификатор ко всем объектам можно и вручную — для этого его необходимо наложить на активный объект, выделить все остальные (A), нажать Ctrl + L и в открывшемся меню выбрать Copy Modifiers.

Обратный процесс работает аналогичным способом: удалив на активном объекте модификатор и применив Copy Modifiers, вы скопируете настройки на все выделенные объекты.

Увеличение количества полигонов с помощью модификатора «Подразделение поверхности» (Subdivision Surface)

Однако аналогичная операция возможна и внутри объекта. Отменяем модификатор через Ctrl + Z и переходим в режим редактирования. Выделив все полигоны (А), открываем меню инструментов через ПКМ (или W, если на правую кнопку мыши у вас назначено выделение) и выбираем опцию Подразделить (Subdivide). В нижнем левом углу вьюпорта появится вкладка с одноимённым названием. Открываем её и выставляем значение Гладкость (Smoothness) на 1, а Количество разрезов (Number of Cuts) на 4.

Увеличение количества полигонов через режим редактирования (Edit Mode)

В итоге получается почти тот же результат, что и при использовании модификатора через Ctrl + 4, но при этом сцена содержит 150 полигонов. Даже если продолжить дублирование с помощью Alt + D, количество граней останется прежним.

Если бы у каждого из 2156 объектов был свой меш, эта сцена насчитывала бы около 1 млн полигонов. Скриншот: Леон Балбери для Skillbox Media
Продолжаем эксперимент дальше. Итог — 17 248 объектов, 150 граней

При этом можно выбрать любой объект, перейти в режим редактирования и изменить его на своё усмотрение, используя приёмы из второго урока. В этом случае все изменения будут автоматически применены и к остальным объектам, так как меш один и тот же.

Объекты после манипуляций в режиме редактирования (Edit Mode). Скриншот: Леон Балбери для Skillbox Media

А если один из объектов выделить в объектном режиме, то во вкладке Трансформация — Элемент ему можно задать уникальные параметры положения, вращения, масштабирования и размера по любой оси. В этом случае трансформация не затронет остальные объекты.

Трансформация одного объекта. Скриншот: Леон Балбери для Skillbox Media

Получается, что при создании масштабных сцен можно обойтись одним мешем. Даже при 17 248 объектах статистика показывает, что в сцене всего 150 полигонов. При использовании отдельных мешей для каждого объекта их было бы порядка 8 млн. Это пример оптимизации.

Данный приём аналогично работает и с целыми коллекциями (о них мы узнали в первом уроке). Предположим, у вас есть коллекция из восьми разных моделей домов, которые вы хотите продублировать. При обычном копировании полигонаж сцены будет расти в геометрической прогрессии. Однако если щёлкнуть правой кнопкой по коллекции и выбрать Экземпляр в сцену (Instance to Scene), то группа моделей продублируется. Ещё это можно сделать через меню Добавить (Shift + A) Экземпляр коллекции (Add — Collection Instance). При этом у вас останется ровно столько же полигонов, сколько было раньше.

Примечание

Имейте в виду, что коллекции могут накладываться одна на другую. Если на первый взгляд в сцене не прибавилось объектов, просто проверьте структуру проекта — скопированные коллекции отобразятся там.

Чтобы разбить продублированную коллекцию на отдельные объекты, необходимо её выделить, зайти в меню Применить (Ctrl + A) — Сделать экземпляры настоящими (Apply — Make Instances Real).

Более подробная инструкция от 25games

Экономия полигонов влияет не только на скорость работы в программе, но и на рендеринг. Это особенно важно при работе над анимацией — на рендере каждого кадра можно сэкономить до нескольких минут.

Теперь попробуем изменить объекты не по отдельности, а при помощи встроенных инструментов Blender и скриптов Python.

Рандомизация с помощью инструментов Blender

Возвращаемся в объектный режим и выделяем все объекты (на всякий случай ещё раз убедитесь, что не захватили камеру и источник света).

В Blender существует такая функция, как поиск команды (клавиша F3). В поисковике находим Случайную трансформацию (Randomize Transform) и выбираем появившийся пункт (если в сцене очень много объектов, то придётся немного подождать).

В левой нижней части экрана появится одноимённая вкладка — в ней можно рандомизировать положение, вращение и размер объектов по всем трём осям. Возьмём для примера пункт Вращение (Rotation): если в первом поле выставить максимальное значение 180, то у каждого из объектов будет свой угол разворота по оси X от 0° до 360° (от −180° до 180°). Проведём ещё один эксперимент и выставим Масштаб (Scale) на 5 — в этом случае каждый отдельный объект изменит масштаб на случайное значение от 1 до 5. Если в сцене много объектов, то придётся снова подождать.

Результат изменения вращения объектов по оси X (180°) и их масштаба (5). Скриншот: Леон Балбери для Skillbox Media

Как вы могли заметить, проблема этой операции в том, что при огромном количестве объектов сцена обрабатывается довольно долго. Возможности Python, встроенные в Blender, могут значительно ускорить процесс рандомизации.

Рандомизация с помощью Python

Возвращаемся на шаг назад, до того, как мы рандомизировали объекты при помощи Случайной трансформации (Randomize Transform). Для начала поместим в отдельную коллекцию только те объекты, которые мы хотим рандомизировать (в данном случае кубы). Переименуйте её, например, в Cubes — это название мы в дальнейшем сможем использовать в коде как идентификатор коллекции.

Чтобы открыть консоль Python, наведите курсор на нижний край окна вьюпорта и аккуратно потяните вверх. В новом окне нажмите на Тип редактора (Editor Type) и выберите Консоль Python (Python Console).

Вытягивание нового окна и выбор консоли Python

Рандомизация в Python происходит с помощью модуля random. Импортируем модуль в рабочее пространство с помощью команды import и нажимаем Enter для подтверждения строки. После подключения модуля в Blender программа сможет обращаться к его функционалу. Модуль random по умолчанию входит в ту версию Python, которая поставляется вместе с Blender, и после импортирования программа может обращаться к нему и его методам.

>>> import random
>>>

Модуль random — это большой класс со множеством методов и подклассов. Их можно посмотреть, набрав в строке random. (точка после названия модуля или класса даёт доступ к его внутренней иерархии) и нажав Tab (в версиях ранее 2.82a — Ctrl + Space).

>>> random.
           BPF
           LOG4
           NV_MAGICCONST
           RECIP_BPF
           Random(
           SG_MAGICCONST
           SystemRandom(
           TWOPI
           betavariate(
           choice(
           choices(
           expovariate(
           gammavariate(
           gauss(
           getrandbits(
           getstate(
           lognormvariate(
           normalvariate(
           paretovariate(
           randbytes(
           randint(                         ← нужный нам метод
           random(
           randrange(
           sample(
           seed(
           setstate(
           shuffle(
           triangular(
           uniform(
           vonmisesvariate(
           weibullvariate(

Примечание

Также Tab/Ctrl + Space работает как автозаполнение, с помощью которого можно быстрее вводить команды. Например, написав obj и нажав Tab, вы увидите, что программа выведет слово object.

Сейчас нам потребуется метод randint(). Если ввести в консоли random.randint() и нажать Tab (в версиях ранее 2.82a — Ctrl + Space), то отобразится техническая информация об этом методе.

>>> random.randint(
randint(self, a, b)
Return random integer in range [a, b], including both end points

Здесь говорится, что метод выдаёт случайное целое число в заданном диапазоне, включая крайние его значения. Попробуем ввести в скобках через запятую значения 0 и 100 и нажмём Enter.

>>> random.randint(0,100)
39

Метод выдал число 39 (у вас может быть другой результат). Если обновить команду при помощи клавиши ↑ (вверх) и вновь нажать Enter, сгенерируется другое число в пределах между 0 и 100. Каждый раз при вводе команды оно будет меняться. Конечно, возможны и повторы, так как при случайном алгоритме результат непредсказуем.

Благодаря методу randint() мы можем присваивать объектам в Blender случайные значения масштаба и других параметров. Чтобы получить доступ к объектам, нам потребуется модуль bpy. В отличие от random он автоматически импортируется в консоль Python при запуске, поэтому добавлять его отдельно через команду import не нужно.

>>> bpy.
        app
        context
        data
        msgbus
        ops
        path
        props
        types
        utils

Модуль bpy включает в себя всё, что помогает пользователю взаимодействовать с интерфейсом Blender. Например, app включает всё, что касается взаимодействия с приложением, а context — всё, что связано с текущими элементами (активный объект, сцена, окно и так далее).

Нам потребуется класс data. Он содержит все данные текущего проекта в Blender, которые также можно посмотреть в Файле Blender (Blender File): информацию о коллекциях, объектах, камерах, источниках освещения, мешах и так далее.

Расположение вкладки «Файл Blender». Чтобы вернуться к предыдущему меню, выберите «Слой визуализации» (View Layer). Скриншот: Леон Балбери для Skillbox Media

Чтобы получить информацию об объектах (именно объектах, а не мешах), набираем в строке путь до класса, в котором они находятся (objects).

>>> bpy.data.objects

Если после этого нажать Tab (в версиях ранее 2.82a — Ctrl + Space), программа выдаст огромный список имён всех объектов в проекте. Чтобы найти конкретный объект, после указания пути до класса нужно поставить квадратные скобки и внутри в кавычках (двойных “” или одинарных ‘’) вписать его точное название.

Примечание

При указании имени важно соблюдать регистр (прописные и строчные буквы), например, “Cube” и “cube” — это совершенно разные объекты.

Если объект с таким именем существует, то при нажатии Enter он отобразится в строке. Если нет — программа выдаст ошибку.

>>> bpy.data.objects['Куб']
bpy.data.objects['Куб']

Далее настраиваем цикл перебора объектов, который выполняется командой for. Для этого используется следующая конструкция: for название_переменной in список_объектов. В данном случае:

>>> for object in bpy.data.objects:

Буквально это можно перевести как «для каждого объекта из всех объектов в проекте:». Обратите внимание, что эта конструкция заканчивается двоеточием. В данном случае object — это имя переменной (вместо object можно вписать и другое слово — в остальном коде будет отвечать именно за эту переменную), в которую будет поочерёдно подставляться каждый объект из класса bpy.data.objects. С каждым из подставленных объектов можно производить те или иные действия.

Примечание

Слово object в Python зарезервировано и имеет ключевое значение в коде. Когда мы называем им переменную, доступ к изначальному значению в рамках исполняемой программы утрачивается. Поэтому по возможности лучше использовать в качестве имён переменных другие слова или сокращения: ob, obj и так далее.

Вводим for object in bpy.data.objects: и нажимаем Enter. Обратите внимание, что в начале следующей строки автоматически появился отступ. Отступ говорит программе, что эта строка относится к телу цикла и будет выполняться для каждого объекта. Зададим переменную, в которой будет подставляться рандомное значение:

scale = random.randint(5, 100)/100

scale — имя переменной (можно вписать любое слово, которое мы будем использовать в дальнейшем в значении данной переменной);

random.randint — модуль random и его метод randint, рассмотренные выше;

(5, 100) — диапазон случайных значений;

/100 — коррекция результата, полученного при выполнении метода randint(), — результат делится на 100.

Для нашей задачи необходимо задать диапазон случайных значений примерно от 0 до 1. Поскольку метод randint принимает и выдаёт только целые числа, мы зададим диапазон от 5 до 100 и поделим случайное значение на 100. В итоге у нас получается число между 0,05 и 1 (5/100 = 0,05 и 100/100 = 1).

Следующая задача — назначить полученное значение в качестве размера объекта. Подтверждаем предыдущую строку через Enter. Обратите внимание: в начале новой строки сохраняется такой же отступ, и это означает, что мы продолжаем описывать тело цикла. Набираем следующую команду:

…     object.scale = (scale, scale, scale)

object — переменная, которую мы использовали в конструкции for object in bpy.data.objects: и которая теперь обозначает каждый из объектов в сцене.

Имейте в виду, что значение scale прописано в скобках три раза через запятую. Ранее на панели Трансформация (Transform) вы могли заметить, что Масштаб (Scale) каждого объекта рассчитывается по трём осям: X, Y, Z. Поэтому команда object.scale = scale не сработает, так как в ней будет задано только одно значение (а их должно быть три). Чтобы задать значение переменной scale для всех осей, прописываем её в скобках три раза через запятые: object.scale = (scale, scale, scale).

Подтверждаем строку, удаляем отступы в начале следующей, поскольку дополнительных команд у нас не будет, и ещё раз нажимаем Enter. Немного ждём и получаем результат!

Полученный результат. Скриншот: Леон Балбери для Skillbox Media

Все объекты в сцене стали разного размера. Если повторно выполнить прописанный нами цикл перебора (просто скопировав три строки), то масштаб объектов снова случайно изменится и сцена будет выглядеть иначе.

Легко заметить, что этот процесс происходит гораздо быстрее, чем при использовании Случайной трансформации (Randomize Transform). Чтобы засечь точное время обработки, напишем новый скрипт на основе предыдущего.

Ещё раз разделим окно вьюпорта, наведя курсор на верхний правый угол и потянув его влево. В новом окне меняем тип редактора на Редактор текста (Text Editor) — в нём нужный нам скрипт прописать будет легче, чем в консоли Python.

Нажимаем +Создать (+New). Перед тем, как копировать команды, прописанные в предыдущем шаге, нам нужно заново импортировать необходимые модули — текстовый редактор «‎не знает» операции, которые мы проводили в консоли Python. Импортируем модули с помощью команды import через запятую:

import bpy, random, time

Ещё раз пройдёмся по модулям: bpy отвечает за взаимодействие с интерфейсом Blender, random поможет сгенерировать случайное число, time — засечь время операции. Обратите внимание, что в отличие от консоли Python, где часть модулей импортируется автоматически при запуске (например, bpy), в текстовом редакторе все модули необходимо добавлять вручную.

Далее через одну пустую строку мы пропишем функцию для выполнения определённой части кода. Функция — это часть кода, которую можно вызывать многократно. Признак функции — круглые скобки в конце. Перед тем, как использовать функцию в коде, её надо определить. Для этого используем следующую конструкцию:

import bpy, random, time

def random_scale():

def (от англ. define, «определить») — указывает, что начинается определение функции;

random_scale — название функции (пишется английскими и желательно строчными буквами, без пробелов и слешей);

() — часть синтаксиса функции; скобки могут оставаться пустыми или содержать некие параметры, которые обычно используются в теле функции;

: — указывает на то, что далее идёт тело функции.

После того как вы нажмёте Enter, редактор автоматически сделает отступ. Также его можно сделать, нажав клавишу Tab или четыре пробела. Отступы в Python очень важны — они означают, что все строки с одинаковым отступом относятся к одному и тому же блоку кода (телу функции, циклу и так далее).

В следующей строке перед основной частью функции мы засечём время. Для этого зададим переменную t1 и с помощью = присвоим ей значение текущего времени, используя метод perf_counter() из модуля time:

import bpy, random, time

 def random_scale():
    t1 = time.perf_counter()

Метод — это готовая функция в рамках класса. Доступ к нему можно получить, указав название класса, к которому он относится, и через точку — имя самого метода. Обратите внимание, что def требуется только тогда, когда функцию нужно определить. Для вызова уже существующей функции достаточно прописать её имя с круглыми скобками в конце.

Теперь скопируем и вставим цикл, отвечающий за рандомизацию масштаба всех объектов, который мы прописали ранее в консоли:

import bpy, random, time

def random_scale():
    t1 = time.perf_counter()
    for object in bpy.data.objects:
       scale = random.randint(5,100)/100
         object.scale = (scale, scale, scale)

Важно убрать лишние точки, которые автоматически скопировались из консоли, и правильно расставить все отступы, как показано на скриншоте (тело цикла обособляется новым отступом). Следующая после цикла строка с t2 фиксирует время на момент, когда функция была выполнена.

import bpy, random, time

def random_scale():
    t1 = time.perf_counter()
    for object in bpy.data.objects:
         scale = random.randint(5,100)/100
         object.scale = (scale, scale, scale)
    t2 = time.perf_counter()

Теперь, чтобы посчитать длительность всего процесса, нам нужно из значения t2 вычесть t1 и отобразить где-то полученный результат. Для этого используем команду print() — это встроенный метод Python, с помощью которого можно выводить текстовую и числовую информацию на Системную консоль (не путать с консолью Python!). Её можно найти во вкладке Окно — Показать/скрыть системную консоль (Window — Toggle System Console).

Этот вариант подходит для пользователей Windows. Если у вас macOS/Linux, то Blender необходимо запустить из терминала, указав в нём полный путь до blender-launcher.exe. После этого терминал будет использоваться в качестве системной консоли.

Как запустить Blender из терминала на macOS. Мини-гайд от Hollowpixel

Чтобы вывести в консоли разницу во времени между началом и окончанием работы функции, производим вычисление в скобках:

import bpy, random, time

def random_scale():
    t1 = time.perf_counter()
  for object in bpy.data.objects:
         scale = random.randint(5,100)/100
         object.scale = (scale, scale, scale)
    t2 = time.perf_counter()
    print(t2-t1)

Сейчас функция существует только в виде инструкции и при запуске скрипта не сработает сама по себе. Для выполнения её нужно вызвать. Отделяем написанную функцию пустой строкой и в следующей строке копируем название функции random_scale() — без слова def, каких-либо отступов и двоеточия, но с круглыми скобками на конце. Это и будет вызов функции, которую мы определили ранее.

Теперь при запуске скрипта каждому объекту в сцене будет назначаться рандомное значение параметра scale, а в системной консоли — выводиться информация о времени, затраченном на выполнение операции. Остаётся только запустить скрипт кнопкой (в верхнем правом углу редактора) или комбинацией клавиш Alt P.

import bpy, random, time

def random_scale():
    t1 = time.perf_counter()
    for object in bpy.data.objects:
         scale = random.randint(5,100)/100
         object.scale = (scale, scale, scale)
    t2 = time.perf_counter()
    print(t2-t1)
    
random_scale()

После этого заходим в системную консоль и смотрим результаты — в нашем случае выполнение функции заняло 0,34 секунды:

Примечание

Конкретно этот скрипт работает для всех объектов в проекте. Помните, как в начале главы мы назвали коллекцию с кубами Cubes? Чтобы изменить объекты только в ней, фрагмент bpy.data.objects: необходимо заменить на bpy.data.collections[‘Cubes’].objects:, где ‘Cubes’ — название нужной коллекции.

Подведём итоги. Благодаря Python мы рандомизировали масштаб 17 248 объектов всего за треть секунды. Таким образом, базовые навыки программирования позволяют оптимизировать процессы и выполнять некоторые операции гораздо быстрее, чем через инструменты Blender.

В четвёртой части руководства мы познакомимся с основами анимации и рассмотрим несколько способов её воспроизведения.

Проверьте свой английский. Бесплатно ➞
Нескучные задания: small talk, поиск выдуманных слов — и не только. Подробный фидбэк от преподавателя + персональный план по повышению уровня.
Пройти тест
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована