EN
Andrey Sokolov
Andrey Sokolov
725 subscribers
goals
17 of 500 paid subscribers
Когда я наберу 500 платных подписчиков, смогу больше времени уделять записи видео и разработке аддонов для Blender.
360.79 of $ 1 135 money raised
Донаты || Donates
37.59 of $ 568 money raised
Cделать аддон True Time Remapping бесплатным для всех желающих навсегда. Make True Time Remapping add-on free for everyone forever.
113.49 of $ 114 money raised
На дисковый накопитель 4Tb для хранения бэкапов курса «Blender Избушка».

Математика в 3Д ► 20. Lens Flares. Динамические боке

Этот урок будет посвящён созданию динамической системы боке. Наша задача сделать так, чтобы те самые Н-Гоны, которые мы рендерили ранее, располагались на линии между источником света и дополнительным контрольным объектом и равномерно меняли своё расположение при смещении либо камеры, либо источника света, либо контроллера. На словах звучит сложновато, но как только система будет собрана, вы поймёте, что имеется в виду, и вспомните, что неоднократно видели такой эффект.
Буду очень благодарен всем, кто решит стать платными подписчиками или разово задонатить на означенные цели.
Итак, поехали! В прошлый раз мы остановились на том, что привели в порядок ноды и перенесли расчеты из скрипта и драйверов на Геометрические Ноды ↓
Продолжаем. Наведёмся на рамочку, в которой собраны элементы боке ↓
Мы можем видеть повторяющиеся колонки одинаковых нодов со слегка отличающимися настройками. В программировании многократно повторяющийся код заменяют на функции: функция прописывается один раз, и её можно вызвать из любого места кода, точно зная, что она делает и даже не задумываясь как она устроена внутри. Это делает работу над кодом намного удобнее. В нодовых редакторах роль функций играют нод-группы. Они точно так же позволяют выполнять одни и те же действия многократно, не создавая каждый раз огромные ветки нодов, и таким образом делают дерево нодов более читаемым. В нашем случае вместо таких колонок логичнее использовать нод-группы. Это позволит, с одной стороны, увеличить количество элементов, не перегружая дерево нодов, а с другой - лучше проработать и саму повторяющуюся систему.
Для начала удалим все лишние колонки, и оставим одну, с которой и будем работать ↓
↑ Давайте вкратце вспомним, что здесь происходит. В самом верху мы подключаем элемент в цепь с помощью Math в режиме Add (сложение), предварительно отрегулировав его яркость с помощью Math в режиме Multiply (умножение). Сам элемент - это Image Texture, обычная картинка, содержащая белый Н-Гон на чёрном фоне, из числа тех, что мы рендерили в прошлых уроках. Ниже к ней через два корректирующих Vector Math подключаются текстурные координаты проекции источника света на плэйн. Vector Math в режиме Scale (масштабирование) изменяет размер элемента, а Vector Math в режиме Add (сложение) определяет его сдвиг относительно центра проекции.
Пока что этот сдвиг определяется на глаз, произвольно, поэтому, чтобы элементы боке располагались на одной линии, значения этого сдвига приходится подбирать вручную. Мне бы хотелось добавить дополнительный Empty объект, расположенный на плоскости плэйна, и сделать так, чтобы элементы боке располагались на линии между проекцией источника света на плэйн и этим новым объектом-гайдом, а нам оставалось бы только контролировать, где именно на этой линии они будут располагаться. Более того, мне бы хотелось сделать, чтобы при изменении расстояния между объектом-гайдом и проекцией источника света на плэйн положение элементов боке автоматически пересчитывалось и корректировалось.
Для начала добавим новый Empty объект в сцену. Выставляем курсор на плоскость плэйна, просто тыкнув по плэйну мышкой, и нажимаем Shift+A > Empty > Sphere
↑ Можно использовать и любой другой тип Empty, это влияет только на его внешний вид, но мне кажется, что сфера в данном случае удобнее всего. Теперь нам нужно сделать, чтобы этот Empty (давайте я его буду в дальнейшем называть Гайд, чтобы не переключать раскладку?) всегда находился на плоскости плэйна. Поэтому сначала привяжем Гайд к плэйну в качестве чайлда. Как вам такое, противники англицизмов? ))
Выбираем Гайд, удерживая Shift, в 3Д-вьюпорте выбираем плэйн ↓
Нажимаем Ctrl+P и выбираем во всплывающем меню пункт Object
Теперь при перемещении плэйна, гайд будет перемещаться вместе с ним. Плюс к этому, для удобства дальнейшего управления, я бы хотел сделать, чтобы гайд всегда оставался привязанным к плоскости плэйна, куда бы мы его ни перетаскивали. В этом нам поможет констрейнт Shrinkwrap.
Открываем вкладку с констрейнтами и с выделенным активным гайдом добавляем новый констрейнт Shrinkwrap
Указываем плэйн в качестве таргета в констрейнте, и теперь сдвинуть гайд за пределы плэйна уже не получится, что собственно нам и было нужно ↓
Логично предположить, что для расчетов нам понадобится позиция гайда. Поэтому переместимся в Геометрические ноды, продублируем один из нодов Object Info с помощью Shift+D... ↓
...и в качестве объекта выберем в нём гайд (в проекте он всё ещё называется Empty) ↓
Подключим объект к свободному входу, чтобы можно было назначать его прямо в модификаторе, и сразу же в N-панели, во вкладке Group переименуем вход в Guide, чтобы в дальнейшем, не заходя в ноды, точно знать, что за объект предполагается использовать в системе ↓
Также я переименую в Guide и сам нод Object Info, в N-панели, но уже во вкладке Node, в графе Label 
Давайте подумаем, каким образом мы можем перемещать элемент между проекцией источника света на плэйн и положением гайда на плэйне. Координаты проекции у нас уже есть, координаты гайда есть, как говорил Иван Васильевич, «Чего же тебе ещё надо?» ↓
До этого мы сдвигали текстурные координаты объекта-камеры на место проекции источника света на плэйн (координатную систему в точке А на точку В). А если из них вычесть вектор ВС, то они сместятся в точку С ↓
Соответственно, зная вектор BC мы можем перемещать текстурные координаты по линии BC с помощью простого вычитания, предварительно масштабируя вектор ВС с помощью простого умножения ↓
Для начала найдём вектор BC. Точку В у нас определяет вектор LF TC Offset, точку С - Object Info с координатами гайда. Используя Vector Math в режиме Subtract (вычитание), получаем вектор ВС, вычтя С из В ↓
Подключаем полученный вектор к свободному выходу, чтобы получить возможность использовать его в качестве атрибута в Shader Editor, и в настройках модификатора задаём ему название, которое будем там использовать. Я назвал его proj_guide_vector
Переименуем новый выход в N-панели, во вкладке Group, чтобы, открыв модификатор, можно было понять, какой атрибут и для чего здесь используется ↓
Перейдём в Shader Editor и сфокусируемся на рамке с текстурными координатами ↓
Сейчас одни и те же текстурные координаты используются для всех элементов. Оговорюсь, что мы могли бы скорректировать уже эту готовую систему, но поскольку для этого, в любом случае, пришлось бы снова два раза корректировать вращение системы координат, чтобы компенсировать вращение камеры (если вы уже не помните, что там происходит, ниже мы разберём это подробнее), то проще продублировать всю систему координат целиком. К тому же, так мы сможем поднести её поближе к самим элементам и впоследствии объединить вместе со всей системой боке в одну нод-группу. Выделяем всю рамочку TC Coordinates (и я таки снова забыл её переименовать) и дублируем с помощью Shift+D вместе со всеми нодами ↓
Переносим копию рамочки ближе к системе боке и подключаем в качестве текстурных координат ↓
Давайте сфокусируемся на ней и вспомним, что в ней происходит ↓
↑ Непосредственно сдвиг текстурных координат от объекта камеры на место проекции источника света на плэйн осуществляется в ноде Subtract (это Vector Math в режиме Subtract (вычитание)).
• Три красные нода это соответственно: 1) Текстурные координаты объекта камеры; 2) Вращение камеры; 3) Вектор сдвига текстурных координат.
• Верхний нод Mapping предварительно изменяет вращение системы координат, чтобы оно совпадало с вращением камеры - это нужно, чтобы сдвиг системы координат на место проекции происходил в правильном направлении.
• Нижний нод Mapping возвращает вращение системы координат после сдвига обратно. Для этого вращение камеры предварительно умножается на -1 с помощью нода Scale (это Vector Math в режиме Scale), а результат используется для параметра Rotation в нижнем ноде Mapping. Возможно, так разделение по функциональности будет нагляднее ↓
Продублируем один из нодов с атрибутами ↓
Скопируем в него название атрибута, возвращающего вектор BC ↓
Переименуем сам нод с атрибутом (я назвал его Guide Vector) и с помощью Vector Math в режиме Subtract (вычитание) вычтем этот вектор из текстурных координат объекта камеры, предварительно смещённых на место проекции источника света на плэйн ↓
Как можно заметить, положение элемента боке не соответствует положению гайда на плэйне. А должно. Однако, если вспомнить, то позже по ходу движения у нас была ещё дополнительная коррекция текстурных координат - корректировка размера с помощью Vector Math в режиме Scale и корректировка положения с помощью Vector Math в режиме Add
Избавимся от них. Чтобы сохранить линки, можно удалить ноды с помощью Ctrl+X
Однако, положение элемента вновь не совпадает с положением гайда. Что не так? ↓
На самом деле, если на минуту задуматься, всё именно так, как и должно быть: с положением гайда совпадает нижний правый край картинки с элементом.
Картинка растягивается между нулём и единицей системы координат по осям X и Y, а ноль системы координат типа Object, которая используется в нашей системе (Camera TC - это Texture Coordinate > Object объекта камеры), находится на месте точки Origin объекта. Таким образом, при использовании системы координат типа Object для картинок, картинка оказывается не в центре объекта а справа и сверху от центра. Чтобы переместить её в центр, нам нужно к полученной системе координат добавить 0.5 по осям X и Y. Тогда -0.5 в системе координат станет её новым нулём, 0.5 - её новой единицей, и центр картинки будет совпадать с центром объекта. Это можно сделать с помощью Vector Math в режиме Add (сложение), который я поместил в рамочку Compensate UV
Теперь, чтобы контролировать перемещение картинки с элементом по линии вектора BC (между гайдом и проекцией источника света на плэйн), мы можем использовать Vector Math > Scale (в жёлтой рамочке с надписью Offset) ↓
Таким образом мы регулируем длину вектора, на который смещаем систему координат. Этот вопрос решён (как мы сейчас убедимся, частично). И следующая задача - регулировка размера системы координат и, соответственно, размера элемента. Нам нужно осуществлять эту регулировку уже после того, как система координат переместилась на место проекции источника света на плэйн, то есть в зелёной рамочке Offset, после первого Subtract, с помощью Vector Math > Scale
Однако, если сейчас покрутить оба параметра Scale, то мы увидим, что изменение Scale в зелёной рамочке влечёт за собой не только изменение размера, но и дополнительное изменение смещения элемента. Это и логично: мы меняем масштаб всей системы координат целиком, и последующий вектор смещения вычитается из уже отмасштабированной системы, но при этом их метрические системы не совпадают. Для того, чтобы этого избежать, нам нужно домножить Scale, отвечающий за передвижение по линии вектора ВС, на то же число, которое мы используем для Scale, определяющего масштаб системы координат. Иными словами, Scale в жёлтой рамочке нужно домножить на значение Scale в зелёной рамочке.
Как это сделать? Давайте для начала подключим временные Value для первого и второго Scale. Они же нам позже пригодятся и для создания нод-группы ↓
Используем нод Math в режиме Multiply (умножение), чтобы для Scale в жёлтой рамочке использовалось его собственное предполагаемое оригинальное значение Scale, умноженное на значение Scale для масштаба системы координат↓
Теперь всё работает, в чём мы можем убедиться, выставив какие-то более подходящие для такого элемента значения ↓
Подготовим все ноды, включая саму текстуру боке, регулировку её яркости и подключение к основной цепочке нодов, а также всё что мы только что сделали, к добавлению в нод-группу (см. ниже):
• Вынесем все входящие параметры Value из рамочки наружу (Alt+P).
• Добавим отдельный параметр Value для регулировки прозрачности.
• Поместим в отдельную рамочку Input Attributes все входящие атрибуты:
  - текстурные координаты объекта камеры;
  - вращение камеры;
  - сдвиг системы координат на место проекции;
  - вектор от проекции до гайда.
• Переаранжируем по смыслу и переименуем ноды корректировки системы координат, сверху-вниз:
  Offset Static - нерегулируемый вручную сдвиг системы координат на место проекции (точнее было бы назвать Offset Automatic);
  Scale - масштабирование системы коодинат;
  Offset Dynamic - динамический (регулируемый) сдвиг системы координат вдоль вектора ВС ↓
Теперь кое-что о входящих атрибутах. Мне не нравится идея помещать какие-то элементы, которые могут меняться (например, если мы решим заменить названия атрибутов) внутрь нод-групп, где они будут скрыты, и их будет сложно найти впоследствии. Также мне не нравится идея делать нод-группу с 4-мя дополнительными входами для этих параметров, только чтобы этого избежать ↓
Я предлагаю следующее решение (в программировании такой подход относится к области паттернов проектирования). Каждый из нодов, содержащий ссылки на любые внешние атрибуты, объекты и т.д., упаковывается в отдельную нод-группу ↓
↑ В этой нод-группе нет ровным счётом ничего, никаких входов, только один нод с одним внешним атрибутом или объектом, значение которого используется для единственного выхода. Выходим с помощью Tab.
Название таких нод-групп будет начинаться с маркировки "IN - ", чтобы мы могли легко их находить в списке нод-групп, когда нам потребуется. Для всех таких нод-групп устанавливается щиток, чтобы сборщик мусора Блендер не удалил их при закрытии проекта, если они не будут нигде использованы ↓
То же самое мы проделываем со всеми остальными нодами, содержащими внешние атрибуты ↓
Если при подключении появляются дополнительные, неиспользуемые нами входы или выходы, удаляем всё лишнее в N-панели, во вкладке Group
На выходе cтавим щиток и переименовываем нод-группу по тому же принципу ↓
После того, как мы проделали это со всеми входящими атрибутами, у нас должно получиться 4 новые нод-группы ↓
На них же мы заменим входящие атрибуты и в общей системе координат, которая используется для остальных элементов ↓
Чтобы добавить нужные нод-группы используем Shift+A > Group и выбираем их из списка. Благодаря названиям, их легко найти ↓
Можно добавить одну нод-группу, продублировать её с помощью Shift+D нужное количество раз (для общей системы координат используются 3 атрибута), и в настройках нода выбрать нужную группу из списка ↓
Переподключим текстурные координаты камеры, вращение камеры и вектор сдвига координат из нод-групп ↓
А неиспользуемые больше ноды удалим. Всё работает точно так же ↓
И последний пункт. Сейчас, вероятно, станет понятно, в чём смысл этих действий. Создадим отдельную рамочку, сделаем её яркой, назовём INCOMING, и в неё также поместим ноды с нод-группами, содержащими входящие атрибуты, ни к чему их не подключая ↓
Теперь, когда мы надумаем каким-то образом поменять атрибуты: заменить в них объекты, поменять им названия или сделать с ними что-либо ещё - нам не надо будет шерстить всё дерево нодов в поисках, где эти атрибуты могли быть использованы, залезать внутрь групп, открывать скрытые ноды и так до конца и не быть уверенными, что где-то что-то мы могли пропустить. Вместо этого мы просто видим большую белую рамку INCOMING, заходим в нужную нод-группу, заменяем нужный атрибут - и он автоматически заменяется одновременно для всего дерева нодов, во всех местах, где он подключен с помощью этой нод-группы ↓
Теперь мы можем со спокойной душой упаковывать всю нашу систему боке вместе со входящими параметрами в нод-группу ↓
Нажимаем Ctrl+G - и группа создана ↓
Приводим хаос в порядок. Выставляем входы в правильный порядок: цвет, размер, сдвиг, прозрачность. Для прозрачности (Alpha) выставляем минимальное значение на 0, максимальное - на 1. Добавляем необходимое количество перенаправляющих точек Reroute 
Выходим из группы (Tab), активируем значок щитка, называем её, например, LF Bokeh (Lens Flares Bokeh). В английском языке у боке h на конце. Такое, знаете ли с придыханием, бокэххх (шучу, если что) 
Удаляем временные Value и получаем маленькую компактную группу со всем необходимым - и боооооольшую бокеину. Так можно говорить - "бокеину"? Имеется в виду очень крупная (-ое, -ый?) боке ↓
Чтобы они не были такими при создании группы по умолчанию, зайду в настройки нод-группы (Tab), и в N-панели во вкладке Group укажу, чтобы значение параметра Scale по умолчанию (Default)  было равно 3 ↓
А значение Alpha - 0.5 (это не минус, а тире). И те же значения установлю у уже созданной и используемой нод-группы. Теперь Н-гон выглядит уже не так жутко ↓
Выйдем из нод-группы с помощью Tab. Так сейчас выглядит дерево нодов ↓
Добавим 10 копий нод-группы боке, разместим их одну под другой и последовательно соединим линками (выход Color ко входу Color). Удобнее всего с помощью Shift+D продублировать группу один раз, не подтверждая действие левой кнопкой мыши во время перетаскивания нажать Y, чтобы она перетаскивалась только по вертикали, разместить её под первой группой, подтвердить расположение левой кнопкой мыши, а после этого нажать несколько раз Shift+R, чтобы последнее действие повторилось несколько раз. Соединять группы линками удобнее всего, удерживая Alt, правой кнопкой мыши - тогда не обязательно целиться в конкретные входы и выходы, Блендер соединит их автоматически ↓
Результат подключаем в рамку COLOR, и пока что это просто десяток одинаковых элементов одного и того же размера, находящихся в одном и том же месте и наложенных поверх друг друга ↓
Теперь можно рандомизировать им параметры и посмотреть, как они будут себя вести, когда мы будем перемещать гайд по плоскости плэйна. В первый раз можно сделать это вручную, чтобы оценить, сколько времени это может занять. Тем более, что других вариантов пока и нет ↓
Но в дальнейшем можно будет написать скрипт, который добавит в N-панель нужные нам параметры, с помощью которых можно будет автоматически добавлять столько копий нод-группы, сколько мы укажем (и сколько потянет компьютер), и автоматически рандомизировать их параметры в указываемых диапазонах значений. Да, это не будет иметь прямого отношения к математике, но я так и не придумал, как без вреда для слитности и логичности повествования разъединить уроки по пайтон от уроков по математики, поэтому намереваюсь включить этот процесс в эту серию уроков.
Вы видите эти уроки, благодаря тем, кто забирает их к себе на стенки, рассказывает друзьям, знакомым, в сообществах, пабликах, чатах, коммьюнити. Без их поддержки развитие проекта было бы невозможным, и я благодарен каждому.
Со своей стороны выражаю большую благодарность спонсорам. Вы даёте мне возможность продолжать.
avatar
Когда то я смотрел на это и думал "Как же это сложно выглядит, хочу это сделать". А вот теперь я закончил этот курс. И грустно мне от того, что я его закончил. Осталось ощущение того, что я закрываю хорошую книгу. Что ж, хорошо что осталась еще избушка, туманность и галактика.

Subscription levels

1-й уровень

$ 2,27 per month
1-й уровень

2-й уровень

$ 5,7 per month
2-й уровень

3-й уровень

$ 11,4 per month
3-й уровень

4-й уровень

$ 22,7 per month
4-й уровень

5-й уровень

$ 57 per month
5-й уровень

Максимальная поддержка

$ 114 per month
Максимальная поддержка
Go up