0 added
0 removed
Original
2026-01-01
Modified
2026-02-21
1
<p><a>#статьи</a></p>
1
<p><a>#статьи</a></p>
2
<ul><li>2 фев 2022</li>
2
<ul><li>2 фев 2022</li>
3
<li>0</li>
3
<li>0</li>
4
</ul><p>Разбираемся в более продвинутых понятиях и инструментах.</p>
4
</ul><p>Разбираемся в более продвинутых понятиях и инструментах.</p>
5
<p>Считает игры произведениями искусства и старается донести эту идею до широких масс. В свободное время стримит, рисует и часами зависает в фоторежимах.</p>
5
<p>Считает игры произведениями искусства и старается донести эту идею до широких масс. В свободное время стримит, рисует и часами зависает в фоторежимах.</p>
6
<p>Специалист по компьютерной графике, оптимизации и автоматизации проектов. Автор серии уроков по Blender.</p>
6
<p>Специалист по компьютерной графике, оптимизации и автоматизации проектов. Автор серии уроков по Blender.</p>
7
<p>Год назад в рамках своего<a>YouTube-канала</a>Андрей записал подробный<a>курс</a>по Blender, в котором работает более 7 лет. Обучение начинается с основ, рассчитанных в первую очередь на новичков, но последующие уроки могут быть интересны и для продвинутых пользователей - в них Андрей затрагивает скрытые возможности софта. Сам материал записывался в версии программы 2.90.1, но знания актуальны как для ранних версий (от 2.80), так и для последней (3.0.0).</p>
7
<p>Год назад в рамках своего<a>YouTube-канала</a>Андрей записал подробный<a>курс</a>по Blender, в котором работает более 7 лет. Обучение начинается с основ, рассчитанных в первую очередь на новичков, но последующие уроки могут быть интересны и для продвинутых пользователей - в них Андрей затрагивает скрытые возможности софта. Сам материал записывался в версии программы 2.90.1, но знания актуальны как для ранних версий (от 2.80), так и для последней (3.0.0).</p>
8
<p>Делимся основными тезисами третьего и четвёртого видеоуроков, посвящённых структуре, оптимизации и рандомизации объектов через инструменты Blender и скрипты Python. В предыдущих уроках мы рассматривали<a>интерфейс программы и простые операции</a>, а также<a>основы моделирования</a>.</p>
8
<p>Делимся основными тезисами третьего и четвёртого видеоуроков, посвящённых структуре, оптимизации и рандомизации объектов через инструменты Blender и скрипты Python. В предыдущих уроках мы рассматривали<a>интерфейс программы и простые операции</a>, а также<a>основы моделирования</a>.</p>
9
Третий урок по Blender от Андрея СоколоваЧетвёртый урок по Blender от Андрея Соколова<p>Как известно, при создании нового проекта в сцене по умолчанию появляется куб. Это объект со своими данными, которые можно увидеть, если кликнуть на стрелку рядом с <strong>объектом Cube</strong>в <strong>Структуре проекта</strong>(Outliner). Данные объекта Cube - это меш Cube (иконка зелёного треугольника).<strong>Объект</strong><strong>и его меш - это разные элементы.</strong></p>
9
Третий урок по Blender от Андрея СоколоваЧетвёртый урок по Blender от Андрея Соколова<p>Как известно, при создании нового проекта в сцене по умолчанию появляется куб. Это объект со своими данными, которые можно увидеть, если кликнуть на стрелку рядом с <strong>объектом Cube</strong>в <strong>Структуре проекта</strong>(Outliner). Данные объекта Cube - это меш Cube (иконка зелёного треугольника).<strong>Объект</strong><strong>и его меш - это разные элементы.</strong></p>
10
Отображение объекта и меша в коллекции сцены. Для наглядности объект подчёркнут оранжевым цветом, меш - зелёным. Коллаж: Леон Балбери для Skillbox Media<p>У <strong>объекта</strong>есть название и характеристики: положение, вращение, масштаб и размеры. Они находятся на панели<strong>Трансформация</strong>(Transform) в верхней вкладке<strong>Элемент</strong>(Item) - саму панель можно легко вызвать горячей клавишей<strong>N</strong>.</p>
10
Отображение объекта и меша в коллекции сцены. Для наглядности объект подчёркнут оранжевым цветом, меш - зелёным. Коллаж: Леон Балбери для Skillbox Media<p>У <strong>объекта</strong>есть название и характеристики: положение, вращение, масштаб и размеры. Они находятся на панели<strong>Трансформация</strong>(Transform) в верхней вкладке<strong>Элемент</strong>(Item) - саму панель можно легко вызвать горячей клавишей<strong>N</strong>.</p>
11
Вызов панели Трансформация (Transform)<p>Данные<strong>меша</strong>можно посмотреть в <strong>Режиме редактирования</strong>(Edit Mode): здесь во вкладке<strong>Трансформация - Элемент</strong>появятся новые данные, в том числе<strong>Медиана</strong>(Median). Эта характеристика отображает координаты<a>среднего значения точек</a>.</p>
11
Вызов панели Трансформация (Transform)<p>Данные<strong>меша</strong>можно посмотреть в <strong>Режиме редактирования</strong>(Edit Mode): здесь во вкладке<strong>Трансформация - Элемент</strong>появятся новые данные, в том числе<strong>Медиана</strong>(Median). Эта характеристика отображает координаты<a>среднего значения точек</a>.</p>
12
Координаты меша во вкладке Медиана (Median). Скриншот: Леон Балбери для Skillbox Media<p>Видоизменим и переместим меш во вьюпорте и обратим внимание на его координаты. Затем вернёмся в <strong>Объектный режим</strong>(Object Mode) и обнаружим, что координаты объекта остались прежними (во вьюпорте можно заметить его ориджин - оранжевую точку, которая отвечает за позицию и центр объекта). Так мы видим, что объект и меш - две разные структуры в Blender.</p>
12
Координаты меша во вкладке Медиана (Median). Скриншот: Леон Балбери для Skillbox Media<p>Видоизменим и переместим меш во вьюпорте и обратим внимание на его координаты. Затем вернёмся в <strong>Объектный режим</strong>(Object Mode) и обнаружим, что координаты объекта остались прежними (во вьюпорте можно заметить его ориджин - оранжевую точку, которая отвечает за позицию и центр объекта). Так мы видим, что объект и меш - две разные структуры в Blender.</p>
13
Объект и меш, перемещённый в сторону. Скриншот: Леон Балбери для Skillbox Media<p>Теперь выясним, почему эта информация важна для пользователя. Для наглядности переименуем объект<strong>Cube</strong>в <strong>Cube object</strong>(двойной клик по названию в структуре проекта), а его меш - в <strong>Cube mesh</strong>. Эти элементы связаны между собой. Их отношения напоминают связь<strong>Parent - Child</strong>("родитель" - "ребёнок"), где Cube mesh будет "ребёнком" Cube object. При этом у объекта может быть одновременно только один "ребёнок", а меш может быть "ребёнком" и других объектов.</p>
13
Объект и меш, перемещённый в сторону. Скриншот: Леон Балбери для Skillbox Media<p>Теперь выясним, почему эта информация важна для пользователя. Для наглядности переименуем объект<strong>Cube</strong>в <strong>Cube object</strong>(двойной клик по названию в структуре проекта), а его меш - в <strong>Cube mesh</strong>. Эти элементы связаны между собой. Их отношения напоминают связь<strong>Parent - Child</strong>("родитель" - "ребёнок"), где Cube mesh будет "ребёнком" Cube object. При этом у объекта может быть одновременно только один "ребёнок", а меш может быть "ребёнком" и других объектов.</p>
14
<p>Создадим новый куб с помощью<strong>Shift + A</strong>. Как и в случае с первым кубом, у нового объекта будет свой меш. Но, перейдя во вкладку<strong>Настройки данных объекта</strong>(Object Data Properties), новый меш можно заменить на первый, который мы ранее переименовали в Cube mesh.</p>
14
<p>Создадим новый куб с помощью<strong>Shift + A</strong>. Как и в случае с первым кубом, у нового объекта будет свой меш. Но, перейдя во вкладку<strong>Настройки данных объекта</strong>(Object Data Properties), новый меш можно заменить на первый, который мы ранее переименовали в Cube mesh.</p>
15
Замена меша у нового объекта. Скриншот: Леон Балбери для Skillbox Media<p>Таким образом, у двух объектов будет один и тот же меш (чуть ниже объясним, чем это полезно).</p>
15
Замена меша у нового объекта. Скриншот: Леон Балбери для Skillbox Media<p>Таким образом, у двух объектов будет один и тот же меш (чуть ниже объясним, чем это полезно).</p>
16
<p><strong>Примечание</strong></p>
16
<p><strong>Примечание</strong></p>
17
<p>На скриншоте два объекта после этой операции выглядят по-разному. Это связано с тем, что их позиция и настройки отличаются. Если убрать все изменения во вкладке Трансформация - Элемент, то получится два одинаковых куба.</p>
17
<p>На скриншоте два объекта после этой операции выглядят по-разному. Это связано с тем, что их позиция и настройки отличаются. Если убрать все изменения во вкладке Трансформация - Элемент, то получится два одинаковых куба.</p>
18
<p>Проведём ещё один эксперимент. Удалим предыдущие объекты, добавим новый куб и зададим его мешу новое название, например,<strong>cube mesh main</strong>. Он будет главным мешем для будущих операций.</p>
18
<p>Проведём ещё один эксперимент. Удалим предыдущие объекты, добавим новый куб и зададим его мешу новое название, например,<strong>cube mesh main</strong>. Он будет главным мешем для будущих операций.</p>
19
<p>Зайдём во вкладку<strong>Наложения вьюпорта</strong>(Viewport Overlays) - в <a>первом уроке</a>мы включали в ней ось Z, - и отметим галочкой пункт<strong>Статистика</strong>(Statistics). В левом верхнем углу появится информация о сцене.</p>
19
<p>Зайдём во вкладку<strong>Наложения вьюпорта</strong>(Viewport Overlays) - в <a>первом уроке</a>мы включали в ней ось Z, - и отметим галочкой пункт<strong>Статистика</strong>(Statistics). В левом верхнем углу появится информация о сцене.</p>
20
Местоположение опции "Статистика" и список данных. Скриншот: Леон Балбери для Skillbox Media<p>Статистика показывает, что в сцене находится:</p>
20
Местоположение опции "Статистика" и список данных. Скриншот: Леон Балбери для Skillbox Media<p>Статистика показывает, что в сцене находится:</p>
21
<ul><li>3<strong>Объекта</strong>(Objects) - 1/3 означает, что один из них выделен;</li>
21
<ul><li>3<strong>Объекта</strong>(Objects) - 1/3 означает, что один из них выделен;</li>
22
<li>8<strong>Вершин</strong>(Vertices);</li>
22
<li>8<strong>Вершин</strong>(Vertices);</li>
23
<li>12<strong>Рёбер</strong>(Edges);</li>
23
<li>12<strong>Рёбер</strong>(Edges);</li>
24
<li>6<strong>Граней</strong>(Faces);</li>
24
<li>6<strong>Граней</strong>(Faces);</li>
25
<li>12<strong>Треугольников</strong>(Triangles).</li>
25
<li>12<strong>Треугольников</strong>(Triangles).</li>
26
</ul><p>При создании нового куба или его дублировании (<strong>Shift + D</strong>) количество всех показателей геометрии увеличится вдвое, поскольку меш объекта также продублируется. Но если заменить меш нового объекта на предыдущий (в данном случае<strong>cube mesh main</strong>), то показатели не увеличатся.</p>
26
</ul><p>При создании нового куба или его дублировании (<strong>Shift + D</strong>) количество всех показателей геометрии увеличится вдвое, поскольку меш объекта также продублируется. Но если заменить меш нового объекта на предыдущий (в данном случае<strong>cube mesh main</strong>), то показатели не увеличатся.</p>
27
<p>Комбинация клавиш<strong>Alt + D</strong>упрощает процесс - с её помощью можно сразу же создавать новый объект с исходным мешем. Таким способом вы можете быстро сгенерировать множество идентичных объектов, сохранив начальное количество полигонов.</p>
27
<p>Комбинация клавиш<strong>Alt + D</strong>упрощает процесс - с её помощью можно сразу же создавать новый объект с исходным мешем. Таким способом вы можете быстро сгенерировать множество идентичных объектов, сохранив начальное количество полигонов.</p>
28
Клонирование объектов через Alt + D<p><strong>Эта операция значительно экономит время и ресурсы при просчёте сцены.</strong>Дело в том, что у каждого полигона существует множество внутренних характеристик: нормаль, шейдинг и прочие данные, которые не так очевидны на первый взгляд, но важны при рендеринге. Соответственно, графический движок должен просчитать все эти показатели для каждого полигона в сцене. При использовании одинаковых данных время расчёта значительно сокращается, даже если они принадлежат разным объектам.</p>
28
Клонирование объектов через Alt + D<p><strong>Эта операция значительно экономит время и ресурсы при просчёте сцены.</strong>Дело в том, что у каждого полигона существует множество внутренних характеристик: нормаль, шейдинг и прочие данные, которые не так очевидны на первый взгляд, но важны при рендеринге. Соответственно, графический движок должен просчитать все эти показатели для каждого полигона в сцене. При использовании одинаковых данных время расчёта значительно сокращается, даже если они принадлежат разным объектам.</p>
29
<p>Попробуем усложнить задачу: выделяем все объекты в сцене и копируем их через<strong>Alt + D</strong>несколько раз. Рекомендуем предварительно удалить или спрятать (<strong>H</strong>) камеру и источник света, чтобы случайно не создать их дубликаты.</p>
29
<p>Попробуем усложнить задачу: выделяем все объекты в сцене и копируем их через<strong>Alt + D</strong>несколько раз. Рекомендуем предварительно удалить или спрятать (<strong>H</strong>) камеру и источник света, чтобы случайно не создать их дубликаты.</p>
30
Группа объектов, скопированная несколько раз. Скриншот: Леон Балбери для Skillbox Media<p>Статистика на скриншоте показывает, что в сцене 310 объектов. Выделяем все объекты - это можно сделать при помощи клавиши<strong>A</strong>или<strong>окружности</strong>(Circle Select), вызвав инструмент кнопкой<strong>С</strong>и увеличив радиус колёсиком мыши. Если применить к одному из выделенных объектов модификатор<strong>Подразделение поверхности</strong>(Subdivision Surface) - о нём мы узнали во <a>втором уроке</a>, - количество граней увеличится. При наложении модификатора на все объекты в сцене сумма полигонов может вырасти до полумиллиона. Сделать это быстро можно при помощи горячих клавиш:<strong>Ctrl + 1, Ctrl + 2, Ctrl + 3</strong>и <strong>Ctrl + 4</strong> - для разных уровней сглаживания. Таким образом эффект от использования одних и тех же мешей пропадает, так как при использовании модификаторов происходит полный пересчёт геометрии объекта.</p>
30
Группа объектов, скопированная несколько раз. Скриншот: Леон Балбери для Skillbox Media<p>Статистика на скриншоте показывает, что в сцене 310 объектов. Выделяем все объекты - это можно сделать при помощи клавиши<strong>A</strong>или<strong>окружности</strong>(Circle Select), вызвав инструмент кнопкой<strong>С</strong>и увеличив радиус колёсиком мыши. Если применить к одному из выделенных объектов модификатор<strong>Подразделение поверхности</strong>(Subdivision Surface) - о нём мы узнали во <a>втором уроке</a>, - количество граней увеличится. При наложении модификатора на все объекты в сцене сумма полигонов может вырасти до полумиллиона. Сделать это быстро можно при помощи горячих клавиш:<strong>Ctrl + 1, Ctrl + 2, Ctrl + 3</strong>и <strong>Ctrl + 4</strong> - для разных уровней сглаживания. Таким образом эффект от использования одних и тех же мешей пропадает, так как при использовании модификаторов происходит полный пересчёт геометрии объекта.</p>
31
<p><strong>Примечание</strong></p>
31
<p><strong>Примечание</strong></p>
32
<p>Применить модификатор ко всем объектам можно и вручную - для этого его необходимо наложить на активный объект, выделить все остальные (<strong>A</strong>), нажать<strong>Ctrl + L</strong>и в открывшемся меню выбрать<strong>Copy Modifiers.</strong></p>
32
<p>Применить модификатор ко всем объектам можно и вручную - для этого его необходимо наложить на активный объект, выделить все остальные (<strong>A</strong>), нажать<strong>Ctrl + L</strong>и в открывшемся меню выбрать<strong>Copy Modifiers.</strong></p>
33
<p>Обратный процесс работает аналогичным способом: удалив на активном объекте модификатор и применив Copy Modifiers, вы скопируете настройки на все выделенные объекты.</p>
33
<p>Обратный процесс работает аналогичным способом: удалив на активном объекте модификатор и применив Copy Modifiers, вы скопируете настройки на все выделенные объекты.</p>
34
Увеличение количества полигонов с помощью модификатора "Подразделение поверхности" (Subdivision Surface)<p>Однако аналогичная операция возможна и внутри объекта. Отменяем модификатор через<strong>Ctrl + Z</strong>и переходим в режим редактирования. Выделив все полигоны (<strong>А</strong>), открываем меню инструментов через<strong>ПКМ</strong>(или<strong>W</strong>, если на правую кнопку мыши у вас назначено выделение) и выбираем опцию<strong>Подразделить</strong>(Subdivide). В нижнем левом углу вьюпорта появится вкладка с одноимённым названием. Открываем её и выставляем значение<strong>Гладкость</strong>(Smoothness) на 1, а <strong>Количество разрезов</strong>(Number of Cuts) на 4.</p>
34
Увеличение количества полигонов с помощью модификатора "Подразделение поверхности" (Subdivision Surface)<p>Однако аналогичная операция возможна и внутри объекта. Отменяем модификатор через<strong>Ctrl + Z</strong>и переходим в режим редактирования. Выделив все полигоны (<strong>А</strong>), открываем меню инструментов через<strong>ПКМ</strong>(или<strong>W</strong>, если на правую кнопку мыши у вас назначено выделение) и выбираем опцию<strong>Подразделить</strong>(Subdivide). В нижнем левом углу вьюпорта появится вкладка с одноимённым названием. Открываем её и выставляем значение<strong>Гладкость</strong>(Smoothness) на 1, а <strong>Количество разрезов</strong>(Number of Cuts) на 4.</p>
35
Увеличение количества полигонов через режим редактирования (Edit Mode)<p>В итоге получается почти тот же результат, что и при использовании модификатора через<strong>Ctrl + 4</strong>, но при этом сцена содержит 150 полигонов. Даже если продолжить дублирование с помощью<strong>Alt + D</strong>, количество граней останется прежним.</p>
35
Увеличение количества полигонов через режим редактирования (Edit Mode)<p>В итоге получается почти тот же результат, что и при использовании модификатора через<strong>Ctrl + 4</strong>, но при этом сцена содержит 150 полигонов. Даже если продолжить дублирование с помощью<strong>Alt + D</strong>, количество граней останется прежним.</p>
36
Если бы у каждого из 2156 объектов был свой меш, эта сцена насчитывала бы около 1 млн полигонов. Скриншот: Леон Балбери для Skillbox MediaПродолжаем эксперимент дальше. Итог - 17 248 объектов, 150 граней<p>При этом можно выбрать любой объект, перейти в режим редактирования и изменить его на своё усмотрение, используя приёмы из <a>второго урока</a>. В этом случае все изменения будут автоматически применены и к остальным объектам, так как меш один и тот же.</p>
36
Если бы у каждого из 2156 объектов был свой меш, эта сцена насчитывала бы около 1 млн полигонов. Скриншот: Леон Балбери для Skillbox MediaПродолжаем эксперимент дальше. Итог - 17 248 объектов, 150 граней<p>При этом можно выбрать любой объект, перейти в режим редактирования и изменить его на своё усмотрение, используя приёмы из <a>второго урока</a>. В этом случае все изменения будут автоматически применены и к остальным объектам, так как меш один и тот же.</p>
37
Объекты после манипуляций в режиме редактирования (Edit Mode). Скриншот: Леон Балбери для Skillbox Media<p>А если один из объектов выделить в объектном режиме, то во вкладке<strong>Трансформация</strong><strong>- Элемент</strong>ему можно задать уникальные параметры положения, вращения, масштабирования и размера по любой оси. В этом случае трансформация не затронет остальные объекты.</p>
37
Объекты после манипуляций в режиме редактирования (Edit Mode). Скриншот: Леон Балбери для Skillbox Media<p>А если один из объектов выделить в объектном режиме, то во вкладке<strong>Трансформация</strong><strong>- Элемент</strong>ему можно задать уникальные параметры положения, вращения, масштабирования и размера по любой оси. В этом случае трансформация не затронет остальные объекты.</p>
38
Трансформация одного объекта. Скриншот: Леон Балбери для Skillbox Media<p>Получается, что при создании масштабных сцен можно обойтись одним мешем. Даже при 17 248 объектах статистика показывает, что в сцене всего 150 полигонов. При использовании отдельных мешей для каждого объекта их было бы порядка 8 млн. Это пример<strong>оптимизации</strong>.</p>
38
Трансформация одного объекта. Скриншот: Леон Балбери для Skillbox Media<p>Получается, что при создании масштабных сцен можно обойтись одним мешем. Даже при 17 248 объектах статистика показывает, что в сцене всего 150 полигонов. При использовании отдельных мешей для каждого объекта их было бы порядка 8 млн. Это пример<strong>оптимизации</strong>.</p>
39
<p>Данный приём аналогично работает и с целыми коллекциями (о них мы узнали в <a>первом уроке</a>). Предположим, у вас есть коллекция из восьми разных моделей домов, которые вы хотите продублировать. При обычном копировании полигонаж сцены будет расти в геометрической прогрессии. Однако если щёлкнуть правой кнопкой по коллекции и выбрать<strong>Экземпляр в сцену</strong>(Instance to Scene), то группа моделей продублируется. Ещё это можно сделать через меню<strong>Добавить</strong>(<strong>Shift + A</strong>)<strong>-</strong><strong>Экземпляр коллекции</strong>(Add - Collection Instance). При этом у вас останется ровно столько же полигонов, сколько было раньше.</p>
39
<p>Данный приём аналогично работает и с целыми коллекциями (о них мы узнали в <a>первом уроке</a>). Предположим, у вас есть коллекция из восьми разных моделей домов, которые вы хотите продублировать. При обычном копировании полигонаж сцены будет расти в геометрической прогрессии. Однако если щёлкнуть правой кнопкой по коллекции и выбрать<strong>Экземпляр в сцену</strong>(Instance to Scene), то группа моделей продублируется. Ещё это можно сделать через меню<strong>Добавить</strong>(<strong>Shift + A</strong>)<strong>-</strong><strong>Экземпляр коллекции</strong>(Add - Collection Instance). При этом у вас останется ровно столько же полигонов, сколько было раньше.</p>
40
<p><strong>Примечание</strong></p>
40
<p><strong>Примечание</strong></p>
41
<p>Имейте в виду, что коллекции могут накладываться одна на другую. Если на первый взгляд в сцене не прибавилось объектов, просто проверьте структуру проекта - скопированные коллекции отобразятся там.</p>
41
<p>Имейте в виду, что коллекции могут накладываться одна на другую. Если на первый взгляд в сцене не прибавилось объектов, просто проверьте структуру проекта - скопированные коллекции отобразятся там.</p>
42
<p>Чтобы разбить продублированную коллекцию на отдельные объекты, необходимо её выделить, зайти в меню<strong>Применить (Ctrl + A) - Сделать экземпляры настоящими</strong>(Apply - Make Instances Real).</p>
42
<p>Чтобы разбить продублированную коллекцию на отдельные объекты, необходимо её выделить, зайти в меню<strong>Применить (Ctrl + A) - Сделать экземпляры настоящими</strong>(Apply - Make Instances Real).</p>
43
Более подробная инструкция от 25games<p><strong>Экономия полигонов влияет не только на скорость работы в программе, но и на рендеринг.</strong>Это особенно важно при работе над анимацией - на рендере каждого кадра можно сэкономить до нескольких минут.</p>
43
Более подробная инструкция от 25games<p><strong>Экономия полигонов влияет не только на скорость работы в программе, но и на рендеринг.</strong>Это особенно важно при работе над анимацией - на рендере каждого кадра можно сэкономить до нескольких минут.</p>
44
<p>Теперь попробуем изменить объекты не по отдельности, а при помощи встроенных инструментов Blender и скриптов Python.</p>
44
<p>Теперь попробуем изменить объекты не по отдельности, а при помощи встроенных инструментов Blender и скриптов Python.</p>
45
<p>Возвращаемся в объектный режим и выделяем все объекты (на всякий случай ещё раз убедитесь, что не захватили камеру и источник света).</p>
45
<p>Возвращаемся в объектный режим и выделяем все объекты (на всякий случай ещё раз убедитесь, что не захватили камеру и источник света).</p>
46
<p>В Blender существует такая функция, как поиск команды (клавиша<strong>F3</strong>). В поисковике находим<strong>Случайную трансформацию</strong>(Randomize Transform) и выбираем появившийся пункт (если в сцене очень много объектов, то придётся немного подождать).</p>
46
<p>В Blender существует такая функция, как поиск команды (клавиша<strong>F3</strong>). В поисковике находим<strong>Случайную трансформацию</strong>(Randomize Transform) и выбираем появившийся пункт (если в сцене очень много объектов, то придётся немного подождать).</p>
47
<p>В левой нижней части экрана появится одноимённая вкладка - в ней можно рандомизировать положение, вращение и размер объектов по всем трём осям. Возьмём для примера пункт<strong>Вращение</strong>(Rotation): если в первом поле выставить максимальное значение 180, то у каждого из объектов будет свой угол разворота по оси X от 0° до 360° (от -180° до 180°). Проведём ещё один эксперимент и выставим<strong>Масштаб</strong>(Scale) на 5 - в этом случае каждый отдельный объект изменит масштаб на случайное значение от 1 до 5. Если в сцене много объектов, то придётся снова подождать.</p>
47
<p>В левой нижней части экрана появится одноимённая вкладка - в ней можно рандомизировать положение, вращение и размер объектов по всем трём осям. Возьмём для примера пункт<strong>Вращение</strong>(Rotation): если в первом поле выставить максимальное значение 180, то у каждого из объектов будет свой угол разворота по оси X от 0° до 360° (от -180° до 180°). Проведём ещё один эксперимент и выставим<strong>Масштаб</strong>(Scale) на 5 - в этом случае каждый отдельный объект изменит масштаб на случайное значение от 1 до 5. Если в сцене много объектов, то придётся снова подождать.</p>
48
Результат изменения вращения объектов по оси X (180°) и их масштаба (5). Скриншот: Леон Балбери для Skillbox Media<p>Как вы могли заметить, проблема этой операции в том, что при огромном количестве объектов сцена обрабатывается довольно долго. Возможности Python, встроенные в Blender, могут значительно ускорить процесс рандомизации.</p>
48
Результат изменения вращения объектов по оси X (180°) и их масштаба (5). Скриншот: Леон Балбери для Skillbox Media<p>Как вы могли заметить, проблема этой операции в том, что при огромном количестве объектов сцена обрабатывается довольно долго. Возможности Python, встроенные в Blender, могут значительно ускорить процесс рандомизации.</p>
49
<p>Возвращаемся на шаг назад, до того, как мы рандомизировали объекты при помощи<strong>Случайной трансформации</strong>(Randomize Transform). Для начала поместим в отдельную коллекцию только те объекты, которые мы хотим рандомизировать (в данном случае кубы). Переименуйте её, например, в <strong>Cubes</strong> - это название мы в дальнейшем сможем использовать в коде как идентификатор коллекции.</p>
49
<p>Возвращаемся на шаг назад, до того, как мы рандомизировали объекты при помощи<strong>Случайной трансформации</strong>(Randomize Transform). Для начала поместим в отдельную коллекцию только те объекты, которые мы хотим рандомизировать (в данном случае кубы). Переименуйте её, например, в <strong>Cubes</strong> - это название мы в дальнейшем сможем использовать в коде как идентификатор коллекции.</p>
50
<p>Чтобы открыть консоль Python, наведите курсор на нижний край окна вьюпорта и аккуратно потяните вверх. В новом окне нажмите на <strong>Тип редактора</strong>(Editor Type) и выберите<strong>Консоль Python</strong>(Python Console).</p>
50
<p>Чтобы открыть консоль Python, наведите курсор на нижний край окна вьюпорта и аккуратно потяните вверх. В новом окне нажмите на <strong>Тип редактора</strong>(Editor Type) и выберите<strong>Консоль Python</strong>(Python Console).</p>
51
Вытягивание нового окна и выбор консоли Python<p>Рандомизация в Python происходит с помощью модуля<strong>random</strong>. Импортируем модуль в рабочее пространство с помощью команды<strong>import</strong>и нажимаем<strong>Enter</strong>для подтверждения строки. После подключения модуля в Blender программа сможет обращаться к его функционалу. Модуль<strong>random</strong>по умолчанию входит в ту версию Python, которая поставляется вместе с Blender, и после импортирования программа может обращаться к нему и его методам.</p>
51
Вытягивание нового окна и выбор консоли Python<p>Рандомизация в Python происходит с помощью модуля<strong>random</strong>. Импортируем модуль в рабочее пространство с помощью команды<strong>import</strong>и нажимаем<strong>Enter</strong>для подтверждения строки. После подключения модуля в Blender программа сможет обращаться к его функционалу. Модуль<strong>random</strong>по умолчанию входит в ту версию Python, которая поставляется вместе с Blender, и после импортирования программа может обращаться к нему и его методам.</p>
52
>>> import random >>><p>Модуль<strong>random</strong> - это большой класс со множеством методов и подклассов. Их можно посмотреть, набрав в строке<strong>random.</strong>(точка после названия модуля или класса даёт доступ к его внутренней иерархии) и нажав<strong>Tab</strong>(в версиях ранее 2.82a -<strong>Ctrl + Space</strong>).</p>
52
>>> import random >>><p>Модуль<strong>random</strong> - это большой класс со множеством методов и подклассов. Их можно посмотреть, набрав в строке<strong>random.</strong>(точка после названия модуля или класса даёт доступ к его внутренней иерархии) и нажав<strong>Tab</strong>(в версиях ранее 2.82a -<strong>Ctrl + Space</strong>).</p>
53
>>> 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(<p><strong>Примечание</strong></p>
53
>>> 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(<p><strong>Примечание</strong></p>
54
<p>Также<strong>Tab/Ctrl + Space</strong>работает как автозаполнение, с помощью которого можно быстрее вводить команды. Например, написав obj и нажав Tab, вы увидите, что программа выведет слово object.</p>
54
<p>Также<strong>Tab/Ctrl + Space</strong>работает как автозаполнение, с помощью которого можно быстрее вводить команды. Например, написав obj и нажав Tab, вы увидите, что программа выведет слово object.</p>
55
<p>Сейчас нам потребуется метод<strong>randint ()</strong>. Если ввести в консоли<strong>random.randint ()</strong>и нажать<strong>Tab</strong>(в версиях ранее 2.82a -<strong>Ctrl + Space</strong>), то отобразится техническая информация об этом методе.</p>
55
<p>Сейчас нам потребуется метод<strong>randint ()</strong>. Если ввести в консоли<strong>random.randint ()</strong>и нажать<strong>Tab</strong>(в версиях ранее 2.82a -<strong>Ctrl + Space</strong>), то отобразится техническая информация об этом методе.</p>
56
>>> random.randint( randint(self, a, b) Return random integer in range [a, b], including both end points<p>Здесь говорится, что метод выдаёт случайное целое число в заданном диапазоне, включая крайние его значения. Попробуем ввести в скобках через запятую значения 0 и 100 и нажмём<strong>Enter</strong>.</p>
56
>>> random.randint( randint(self, a, b) Return random integer in range [a, b], including both end points<p>Здесь говорится, что метод выдаёт случайное целое число в заданном диапазоне, включая крайние его значения. Попробуем ввести в скобках через запятую значения 0 и 100 и нажмём<strong>Enter</strong>.</p>
57
>>> random.randint(0,100) 39<p>Метод выдал число 39 (у вас может быть другой результат). Если обновить команду при помощи клавиши ↑ (вверх) и вновь нажать<strong>Enter</strong>, сгенерируется другое число в пределах между 0 и 100. Каждый раз при вводе команды оно будет меняться. Конечно, возможны и повторы, так как при случайном алгоритме результат непредсказуем.</p>
57
>>> random.randint(0,100) 39<p>Метод выдал число 39 (у вас может быть другой результат). Если обновить команду при помощи клавиши ↑ (вверх) и вновь нажать<strong>Enter</strong>, сгенерируется другое число в пределах между 0 и 100. Каждый раз при вводе команды оно будет меняться. Конечно, возможны и повторы, так как при случайном алгоритме результат непредсказуем.</p>
58
<p>Благодаря методу<strong>randint ()</strong>мы можем присваивать объектам в Blender случайные значения масштаба и других параметров. Чтобы получить доступ к объектам, нам потребуется модуль<strong>bpy</strong>. В отличие от <strong>random</strong>он автоматически импортируется в консоль Python при запуске, поэтому добавлять его отдельно через команду<strong>import</strong>не нужно.</p>
58
<p>Благодаря методу<strong>randint ()</strong>мы можем присваивать объектам в Blender случайные значения масштаба и других параметров. Чтобы получить доступ к объектам, нам потребуется модуль<strong>bpy</strong>. В отличие от <strong>random</strong>он автоматически импортируется в консоль Python при запуске, поэтому добавлять его отдельно через команду<strong>import</strong>не нужно.</p>
59
>>> bpy. app context data msgbus ops path props types utils<p>Модуль<strong>bpy</strong>включает в себя всё, что помогает пользователю взаимодействовать с интерфейсом Blender. Например,<strong>app</strong>включает всё, что касается взаимодействия с приложением, а <strong>context</strong> - всё, что связано с текущими элементами (активный объект, сцена, окно и так далее).</p>
59
>>> bpy. app context data msgbus ops path props types utils<p>Модуль<strong>bpy</strong>включает в себя всё, что помогает пользователю взаимодействовать с интерфейсом Blender. Например,<strong>app</strong>включает всё, что касается взаимодействия с приложением, а <strong>context</strong> - всё, что связано с текущими элементами (активный объект, сцена, окно и так далее).</p>
60
<p>Нам потребуется класс<strong>data</strong>. Он содержит все данные текущего проекта в Blender, которые также можно посмотреть в <strong>Файле Blender</strong>(Blender File): информацию о коллекциях, объектах, камерах, источниках освещения, мешах и так далее.</p>
60
<p>Нам потребуется класс<strong>data</strong>. Он содержит все данные текущего проекта в Blender, которые также можно посмотреть в <strong>Файле Blender</strong>(Blender File): информацию о коллекциях, объектах, камерах, источниках освещения, мешах и так далее.</p>
61
Расположение вкладки "Файл Blender". Чтобы вернуться к предыдущему меню, выберите "Слой визуализации" (View Layer). Скриншот: Леон Балбери для Skillbox Media<p>Чтобы получить информацию об объектах (именно объектах, а не мешах), набираем в строке путь до класса, в котором они находятся (objects).</p>
61
Расположение вкладки "Файл Blender". Чтобы вернуться к предыдущему меню, выберите "Слой визуализации" (View Layer). Скриншот: Леон Балбери для Skillbox Media<p>Чтобы получить информацию об объектах (именно объектах, а не мешах), набираем в строке путь до класса, в котором они находятся (objects).</p>
62
>>> bpy.data.objects<p>Если после этого нажать<strong>Tab</strong>(в версиях ранее 2.82a -<strong>Ctrl + Space</strong>), программа выдаст огромный список имён всех объектов в проекте. Чтобы найти конкретный объект, после указания пути до класса нужно поставить квадратные скобки и внутри в кавычках (двойных "" или одинарных ‘’) вписать его точное название.</p>
62
>>> bpy.data.objects<p>Если после этого нажать<strong>Tab</strong>(в версиях ранее 2.82a -<strong>Ctrl + Space</strong>), программа выдаст огромный список имён всех объектов в проекте. Чтобы найти конкретный объект, после указания пути до класса нужно поставить квадратные скобки и внутри в кавычках (двойных "" или одинарных ‘’) вписать его точное название.</p>
63
<p><strong>Примечание</strong></p>
63
<p><strong>Примечание</strong></p>
64
<p>При указании имени важно соблюдать регистр (прописные и строчные буквы), например, "Cube" и "cube" - это совершенно разные объекты.</p>
64
<p>При указании имени важно соблюдать регистр (прописные и строчные буквы), например, "Cube" и "cube" - это совершенно разные объекты.</p>
65
<p>Если объект с таким именем существует, то при нажатии<strong>Enter</strong>он отобразится в строке. Если нет - программа выдаст ошибку.</p>
65
<p>Если объект с таким именем существует, то при нажатии<strong>Enter</strong>он отобразится в строке. Если нет - программа выдаст ошибку.</p>
66
>>> bpy.data.objects['Куб'] bpy.data.objects['Куб']<p>Далее настраиваем цикл перебора объектов, который выполняется командой<strong>for</strong>. Для этого используется следующая конструкция:<strong>for</strong><em>название_переменной</em><strong>in</strong><em>список_объектов.</em>В данном случае:</p>
66
>>> bpy.data.objects['Куб'] bpy.data.objects['Куб']<p>Далее настраиваем цикл перебора объектов, который выполняется командой<strong>for</strong>. Для этого используется следующая конструкция:<strong>for</strong><em>название_переменной</em><strong>in</strong><em>список_объектов.</em>В данном случае:</p>
67
>>> for object in bpy.data.objects:<p>Буквально это можно перевести как "<strong>для каждого объекта из всех объектов в проекте:</strong>". Обратите внимание, что эта конструкция заканчивается двоеточием. В данном случае<strong>object</strong> - это имя переменной (вместо object можно вписать и другое слово - в остальном коде будет отвечать именно за эту переменную), в которую будет поочерёдно подставляться каждый объект из класса<strong>bpy.data.objects</strong>. С каждым из подставленных объектов можно производить те или иные действия.</p>
67
>>> for object in bpy.data.objects:<p>Буквально это можно перевести как "<strong>для каждого объекта из всех объектов в проекте:</strong>". Обратите внимание, что эта конструкция заканчивается двоеточием. В данном случае<strong>object</strong> - это имя переменной (вместо object можно вписать и другое слово - в остальном коде будет отвечать именно за эту переменную), в которую будет поочерёдно подставляться каждый объект из класса<strong>bpy.data.objects</strong>. С каждым из подставленных объектов можно производить те или иные действия.</p>
68
<p><strong>Примечание</strong></p>
68
<p><strong>Примечание</strong></p>
69
<p>Слово object в Python зарезервировано и имеет ключевое значение в коде. Когда мы называем им переменную, доступ к изначальному значению в рамках исполняемой программы утрачивается. Поэтому по возможности лучше использовать в качестве имён переменных другие слова или сокращения: ob, obj и так далее.</p>
69
<p>Слово object в Python зарезервировано и имеет ключевое значение в коде. Когда мы называем им переменную, доступ к изначальному значению в рамках исполняемой программы утрачивается. Поэтому по возможности лучше использовать в качестве имён переменных другие слова или сокращения: ob, obj и так далее.</p>
70
<p>Вводим<strong>for object in bpy.data.objects:</strong>и нажимаем<strong>Enter</strong>. Обратите внимание, что в начале следующей строки автоматически появился отступ. Отступ говорит программе, что эта строка относится к телу цикла и будет выполняться для каждого объекта. Зададим переменную, в которой будет подставляться рандомное значение:</p>
70
<p>Вводим<strong>for object in bpy.data.objects:</strong>и нажимаем<strong>Enter</strong>. Обратите внимание, что в начале следующей строки автоматически появился отступ. Отступ говорит программе, что эта строка относится к телу цикла и будет выполняться для каждого объекта. Зададим переменную, в которой будет подставляться рандомное значение:</p>
71
… scale = random.randint(5, 100)/100<p><strong>scale</strong> - имя переменной (можно вписать любое слово, которое мы будем использовать в дальнейшем в значении данной переменной);</p>
71
… scale = random.randint(5, 100)/100<p><strong>scale</strong> - имя переменной (можно вписать любое слово, которое мы будем использовать в дальнейшем в значении данной переменной);</p>
72
<p><strong>random.randint</strong> - модуль<strong>random</strong>и его метод<strong>randint</strong>, рассмотренные выше;</p>
72
<p><strong>random.randint</strong> - модуль<strong>random</strong>и его метод<strong>randint</strong>, рассмотренные выше;</p>
73
<p><strong>(5, 100)</strong> - диапазон случайных значений;</p>
73
<p><strong>(5, 100)</strong> - диапазон случайных значений;</p>
74
<p><strong>/100</strong> - коррекция результата, полученного при выполнении метода<strong>randint ()</strong>, - результат делится на 100.</p>
74
<p><strong>/100</strong> - коррекция результата, полученного при выполнении метода<strong>randint ()</strong>, - результат делится на 100.</p>
75
<p>Для нашей задачи необходимо задать диапазон случайных значений примерно от 0 до 1. Поскольку метод<strong>randint</strong>принимает и выдаёт только целые числа, мы зададим диапазон от 5 до 100 и поделим случайное значение на 100. В итоге у нас получается число между 0,05 и 1 (5/100 = 0,05 и 100/100 = 1).</p>
75
<p>Для нашей задачи необходимо задать диапазон случайных значений примерно от 0 до 1. Поскольку метод<strong>randint</strong>принимает и выдаёт только целые числа, мы зададим диапазон от 5 до 100 и поделим случайное значение на 100. В итоге у нас получается число между 0,05 и 1 (5/100 = 0,05 и 100/100 = 1).</p>
76
<p>Следующая задача - назначить полученное значение в качестве размера объекта. Подтверждаем предыдущую строку через<strong>Enter</strong>. Обратите внимание: в начале новой строки сохраняется такой же отступ, и это означает, что мы продолжаем описывать тело цикла. Набираем следующую команду:</p>
76
<p>Следующая задача - назначить полученное значение в качестве размера объекта. Подтверждаем предыдущую строку через<strong>Enter</strong>. Обратите внимание: в начале новой строки сохраняется такой же отступ, и это означает, что мы продолжаем описывать тело цикла. Набираем следующую команду:</p>
77
… object.scale = (scale, scale, scale)<p><strong>object</strong> - переменная, которую мы использовали в конструкции<strong>for</strong><strong>object</strong><strong>in bpy.data.objects:</strong>и которая теперь обозначает каждый из объектов в сцене.</p>
77
… object.scale = (scale, scale, scale)<p><strong>object</strong> - переменная, которую мы использовали в конструкции<strong>for</strong><strong>object</strong><strong>in bpy.data.objects:</strong>и которая теперь обозначает каждый из объектов в сцене.</p>
78
<p>Имейте в виду, что значение<strong>scale</strong>прописано в скобках три раза через запятую. Ранее на панели<strong>Трансформация</strong>(Transform) вы могли заметить, что<strong>Масштаб</strong>(Scale) каждого объекта рассчитывается по трём осям: X, Y, Z. Поэтому команда object.scale = scale не сработает, так как в ней будет задано только одно значение (а их должно быть три). Чтобы задать значение переменной scale для всех осей, прописываем её в скобках три раза через запятые:<strong>object.scale = (scale, scale, scale)</strong>.</p>
78
<p>Имейте в виду, что значение<strong>scale</strong>прописано в скобках три раза через запятую. Ранее на панели<strong>Трансформация</strong>(Transform) вы могли заметить, что<strong>Масштаб</strong>(Scale) каждого объекта рассчитывается по трём осям: X, Y, Z. Поэтому команда object.scale = scale не сработает, так как в ней будет задано только одно значение (а их должно быть три). Чтобы задать значение переменной scale для всех осей, прописываем её в скобках три раза через запятые:<strong>object.scale = (scale, scale, scale)</strong>.</p>
79
<p>Подтверждаем строку, удаляем отступы в начале следующей, поскольку дополнительных команд у нас не будет, и ещё раз нажимаем<strong>Enter.</strong>Немного ждём и получаем результат!</p>
79
<p>Подтверждаем строку, удаляем отступы в начале следующей, поскольку дополнительных команд у нас не будет, и ещё раз нажимаем<strong>Enter.</strong>Немного ждём и получаем результат!</p>
80
Полученный результат. Скриншот: Леон Балбери для Skillbox Media<p>Все объекты в сцене стали разного размера. Если повторно выполнить прописанный нами цикл перебора (просто скопировав три строки), то масштаб объектов снова случайно изменится и сцена будет выглядеть иначе.</p>
80
Полученный результат. Скриншот: Леон Балбери для Skillbox Media<p>Все объекты в сцене стали разного размера. Если повторно выполнить прописанный нами цикл перебора (просто скопировав три строки), то масштаб объектов снова случайно изменится и сцена будет выглядеть иначе.</p>
81
<p>Легко заметить, что этот процесс происходит гораздо быстрее, чем при использовании<strong>Случайной трансформации</strong>(Randomize Transform). Чтобы засечь точное время обработки, напишем новый скрипт на основе предыдущего.</p>
81
<p>Легко заметить, что этот процесс происходит гораздо быстрее, чем при использовании<strong>Случайной трансформации</strong>(Randomize Transform). Чтобы засечь точное время обработки, напишем новый скрипт на основе предыдущего.</p>
82
<p>Ещё раз разделим окно вьюпорта, наведя курсор на верхний правый угол и потянув его влево. В новом окне меняем тип редактора на <strong>Редактор текста</strong>(Text Editor) - в нём нужный нам скрипт прописать будет легче, чем в консоли Python.</p>
82
<p>Ещё раз разделим окно вьюпорта, наведя курсор на верхний правый угол и потянув его влево. В новом окне меняем тип редактора на <strong>Редактор текста</strong>(Text Editor) - в нём нужный нам скрипт прописать будет легче, чем в консоли Python.</p>
83
<p>Нажимаем<strong>+Создать</strong>(+New). Перед тем, как копировать команды, прописанные в предыдущем шаге, нам нужно заново импортировать необходимые модули - текстовый редактор "не знает" операции, которые мы проводили в консоли Python. Импортируем модули с помощью команды<strong>import</strong>через запятую:</p>
83
<p>Нажимаем<strong>+Создать</strong>(+New). Перед тем, как копировать команды, прописанные в предыдущем шаге, нам нужно заново импортировать необходимые модули - текстовый редактор "не знает" операции, которые мы проводили в консоли Python. Импортируем модули с помощью команды<strong>import</strong>через запятую:</p>
84
import bpy, random, time<p>Ещё раз пройдёмся по модулям:<strong>bpy</strong>отвечает за взаимодействие с интерфейсом Blender,<strong>random</strong>поможет сгенерировать случайное число,<strong>time</strong> - засечь время операции. Обратите внимание, что в отличие от консоли Python, где часть модулей импортируется автоматически при запуске (например,<strong>bpy</strong>), в текстовом редакторе все модули необходимо добавлять вручную.</p>
84
import bpy, random, time<p>Ещё раз пройдёмся по модулям:<strong>bpy</strong>отвечает за взаимодействие с интерфейсом Blender,<strong>random</strong>поможет сгенерировать случайное число,<strong>time</strong> - засечь время операции. Обратите внимание, что в отличие от консоли Python, где часть модулей импортируется автоматически при запуске (например,<strong>bpy</strong>), в текстовом редакторе все модули необходимо добавлять вручную.</p>
85
<p>Далее через одну пустую строку мы пропишем функцию для выполнения определённой части кода.<strong>Функция - это часть кода, которую можно вызывать многократно.</strong>Признак функции - круглые скобки в конце. Перед тем, как использовать функцию в коде, её надо определить. Для этого используем следующую конструкцию:</p>
85
<p>Далее через одну пустую строку мы пропишем функцию для выполнения определённой части кода.<strong>Функция - это часть кода, которую можно вызывать многократно.</strong>Признак функции - круглые скобки в конце. Перед тем, как использовать функцию в коде, её надо определить. Для этого используем следующую конструкцию:</p>
86
import bpy, random, time def random_scale():<p><strong>def</strong>(от англ.<em>define, "определить"</em>) - указывает, что начинается определение функции;</p>
86
import bpy, random, time def random_scale():<p><strong>def</strong>(от англ.<em>define, "определить"</em>) - указывает, что начинается определение функции;</p>
87
<p><strong>random_scale</strong> - название функции (пишется английскими и желательно строчными буквами, без пробелов и слешей);</p>
87
<p><strong>random_scale</strong> - название функции (пишется английскими и желательно строчными буквами, без пробелов и слешей);</p>
88
<p><strong>()</strong> - часть синтаксиса функции; скобки могут оставаться пустыми или содержать некие параметры, которые обычно используются в теле функции;</p>
88
<p><strong>()</strong> - часть синтаксиса функции; скобки могут оставаться пустыми или содержать некие параметры, которые обычно используются в теле функции;</p>
89
<p><strong>:</strong> - указывает на то, что далее идёт тело функции<em>.</em></p>
89
<p><strong>:</strong> - указывает на то, что далее идёт тело функции<em>.</em></p>
90
<p>После того как вы нажмёте<strong>Enter</strong>, редактор автоматически сделает отступ. Также его можно сделать, нажав клавишу<strong>Tab</strong>или четыре пробела.<strong>Отступы в Python очень важны - они означают, что все строки с одинаковым отступом относятся к одному и тому же блоку кода (телу функции, циклу и так далее).</strong></p>
90
<p>После того как вы нажмёте<strong>Enter</strong>, редактор автоматически сделает отступ. Также его можно сделать, нажав клавишу<strong>Tab</strong>или четыре пробела.<strong>Отступы в Python очень важны - они означают, что все строки с одинаковым отступом относятся к одному и тому же блоку кода (телу функции, циклу и так далее).</strong></p>
91
<p>В следующей строке перед основной частью функции мы засечём время. Для этого зададим переменную<strong>t1</strong>и с помощью<strong>=</strong>присвоим ей значение текущего времени, используя метод<strong>perf_counter ()</strong>из модуля<strong>time</strong>:</p>
91
<p>В следующей строке перед основной частью функции мы засечём время. Для этого зададим переменную<strong>t1</strong>и с помощью<strong>=</strong>присвоим ей значение текущего времени, используя метод<strong>perf_counter ()</strong>из модуля<strong>time</strong>:</p>
92
import bpy, random, time def random_scale(): t1 = time.perf_counter()<p><strong>Метод - это готовая функция в рамках класса.</strong>Доступ к нему можно получить, указав название класса, к которому он относится, и через точку - имя самого метода. Обратите внимание, что<strong>def</strong>требуется только тогда, когда функцию нужно определить. Для вызова уже существующей функции достаточно прописать её имя с круглыми скобками в конце.</p>
92
import bpy, random, time def random_scale(): t1 = time.perf_counter()<p><strong>Метод - это готовая функция в рамках класса.</strong>Доступ к нему можно получить, указав название класса, к которому он относится, и через точку - имя самого метода. Обратите внимание, что<strong>def</strong>требуется только тогда, когда функцию нужно определить. Для вызова уже существующей функции достаточно прописать её имя с круглыми скобками в конце.</p>
93
<p>Теперь скопируем и вставим цикл, отвечающий за рандомизацию масштаба всех объектов, который мы прописали ранее в консоли:</p>
93
<p>Теперь скопируем и вставим цикл, отвечающий за рандомизацию масштаба всех объектов, который мы прописали ранее в консоли:</p>
94
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)<p>Важно убрать лишние точки, которые автоматически скопировались из консоли, и правильно расставить все отступы, как показано на скриншоте (тело цикла обособляется новым отступом). Следующая после цикла строка с <strong>t2</strong>фиксирует время на момент, когда функция была выполнена.</p>
94
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)<p>Важно убрать лишние точки, которые автоматически скопировались из консоли, и правильно расставить все отступы, как показано на скриншоте (тело цикла обособляется новым отступом). Следующая после цикла строка с <strong>t2</strong>фиксирует время на момент, когда функция была выполнена.</p>
95
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()<p>Теперь, чтобы посчитать длительность всего процесса, нам нужно из значения<strong>t2</strong>вычесть<strong>t1</strong>и отобразить где-то полученный результат. Для этого используем команду<strong>print ()</strong> - это встроенный метод Python, с помощью которого можно выводить текстовую и числовую информацию на <strong>Системную консоль</strong>(не путать с консолью Python!). Её можно найти во вкладке<strong>Окно</strong><strong>- Показать/скрыть системную консоль</strong>(Window - Toggle System Console).</p>
95
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()<p>Теперь, чтобы посчитать длительность всего процесса, нам нужно из значения<strong>t2</strong>вычесть<strong>t1</strong>и отобразить где-то полученный результат. Для этого используем команду<strong>print ()</strong> - это встроенный метод Python, с помощью которого можно выводить текстовую и числовую информацию на <strong>Системную консоль</strong>(не путать с консолью Python!). Её можно найти во вкладке<strong>Окно</strong><strong>- Показать/скрыть системную консоль</strong>(Window - Toggle System Console).</p>
96
<p><strong>Этот вариант подходит для пользователей Windows</strong>. Если у вас macOS/Linux, то Blender необходимо запустить из терминала, указав в нём полный путь до blender-launcher.exe. После этого терминал будет использоваться в качестве системной консоли.</p>
96
<p><strong>Этот вариант подходит для пользователей Windows</strong>. Если у вас macOS/Linux, то Blender необходимо запустить из терминала, указав в нём полный путь до blender-launcher.exe. После этого терминал будет использоваться в качестве системной консоли.</p>
97
Как запустить Blender из терминала на macOS. Мини-гайд от Hollowpixel<p>Чтобы вывести в консоли разницу во времени между началом и окончанием работы функции, производим вычисление в скобках:</p>
97
Как запустить Blender из терминала на macOS. Мини-гайд от Hollowpixel<p>Чтобы вывести в консоли разницу во времени между началом и окончанием работы функции, производим вычисление в скобках:</p>
98
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)<p>Сейчас функция существует только в виде инструкции и при запуске скрипта не сработает сама по себе. Для выполнения её нужно вызвать. Отделяем написанную функцию пустой строкой и в следующей строке копируем название функции<strong>random_scale ()</strong> - без слова<strong>def</strong>, каких-либо отступов и двоеточия, но с круглыми скобками на конце. Это и будет вызов функции, которую мы определили ранее.</p>
98
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)<p>Сейчас функция существует только в виде инструкции и при запуске скрипта не сработает сама по себе. Для выполнения её нужно вызвать. Отделяем написанную функцию пустой строкой и в следующей строке копируем название функции<strong>random_scale ()</strong> - без слова<strong>def</strong>, каких-либо отступов и двоеточия, но с круглыми скобками на конце. Это и будет вызов функции, которую мы определили ранее.</p>
99
<p>Теперь при запуске скрипта каждому объекту в сцене будет назначаться рандомное значение параметра<strong>scale</strong>, а в системной консоли - выводиться информация о времени, затраченном на выполнение операции. Остаётся только запустить скрипт кнопкой<strong>▷</strong>(в верхнем правом углу редактора) или комбинацией клавиш<strong>Alt</strong><strong>+</strong><strong>P</strong>.</p>
99
<p>Теперь при запуске скрипта каждому объекту в сцене будет назначаться рандомное значение параметра<strong>scale</strong>, а в системной консоли - выводиться информация о времени, затраченном на выполнение операции. Остаётся только запустить скрипт кнопкой<strong>▷</strong>(в верхнем правом углу редактора) или комбинацией клавиш<strong>Alt</strong><strong>+</strong><strong>P</strong>.</p>
100
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()<p>После этого заходим в системную консоль и смотрим результаты - в нашем случае выполнение функции заняло 0,34 секунды:</p>
100
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()<p>После этого заходим в системную консоль и смотрим результаты - в нашем случае выполнение функции заняло 0,34 секунды:</p>
101
<p><strong>Примечание</strong></p>
101
<p><strong>Примечание</strong></p>
102
<p>Конкретно этот скрипт работает для всех объектов в проекте. Помните, как в начале главы мы назвали коллекцию с кубами<strong>Cubes</strong>? Чтобы изменить объекты только в ней, фрагмент<strong>bpy.data.objects:</strong>необходимо заменить на <strong>bpy.data.collections[‘Cubes’].objects:</strong>, где ‘Cubes’ - название нужной коллекции.</p>
102
<p>Конкретно этот скрипт работает для всех объектов в проекте. Помните, как в начале главы мы назвали коллекцию с кубами<strong>Cubes</strong>? Чтобы изменить объекты только в ней, фрагмент<strong>bpy.data.objects:</strong>необходимо заменить на <strong>bpy.data.collections[‘Cubes’].objects:</strong>, где ‘Cubes’ - название нужной коллекции.</p>
103
<p>Подведём итоги. Благодаря Python мы рандомизировали масштаб 17 248 объектов всего за треть секунды. Таким образом, базовые навыки программирования позволяют оптимизировать процессы и выполнять некоторые операции гораздо быстрее, чем через инструменты Blender.</p>
103
<p>Подведём итоги. Благодаря Python мы рандомизировали масштаб 17 248 объектов всего за треть секунды. Таким образом, базовые навыки программирования позволяют оптимизировать процессы и выполнять некоторые операции гораздо быстрее, чем через инструменты Blender.</p>
104
<p>В четвёртой части руководства мы познакомимся с основами анимации и рассмотрим несколько способов её воспроизведения.</p>
104
<p>В четвёртой части руководства мы познакомимся с основами анимации и рассмотрим несколько способов её воспроизведения.</p>
105
<p><strong>Читайте остальные статьи из серии:</strong></p>
105
<p><strong>Читайте остальные статьи из серии:</strong></p>
106
<a>Практический курс: "Blender.Design" Узнать про курс</a>
106
<a>Практический курс: "Blender.Design" Узнать про курс</a>