Создание RenderMan (RSL) и Mantra (VEX) шэйдеров в Houdini
1. Введение
2. Surface шэйдеры - шэйдеры поверхности
3. Displace шэйдеры - шэйдеры смещения геометрии
4. Volume шэйдеры - шэйдеры объема
5. Light шэйдеры - шэйдеры света
6. Заключение/Список литературы
Введение
Несмотря на то, что за последние пару лет популярность Houdini среди русскоязычного населения заметно выросла, этот пакет для многих так и остаётся чем-то таинственным и загадочным, но, несомненно, очень крутым. Это происходит во многом потому, что для работы в нем часто требуются знания, неочевидно связанные непосредственно c Houdini.
Поэтому, просьба людей, впервые коснувшихся данной тематики, не удивляться тому, что в уроке о создании шэйдеров в Houdini речь по большему счёту пойдёт о RenderMan.
Две основные причины:
- архитектура Houdini ориентирована на работу с RenderMan-совместимыми рендерами;
- встроенный в Houdini рендер Mantra фактически является клоном RenderMan и бóльшая часть сведений о RenderMan так же справедлива и для Mantra.
RenderMan – стандарт описания трёхмерных данных для визуализации фотореалистичных изображений, разработан в 1987 году компанией PIXAR. RenderMan описывает компьютеру всё, что необходимо знать для рендеринга: трёхмерные объекты, источники света, камеры и т.д. Изначально RenderMan разрабатывался как интерфейс между любой программой моделирования и анимации и любой программой рендеринга.
Воплощением этого стандарта стала созданная PIXAR программа PhotoRealistic renderman – PRman, и, поскольку в дальнейшем далеко не все программы для рендеринга основывались на стандарте от PIXAR, многие стали отождествлять RenderMan и PRman, считая RenderMan рендерером. Несмотря на то, что RenderMan не стал стандартным интерфейсом для всех программ, было создано достаточно много RenderMan-совместимых программ (BMRT, 3Delight, Aqsis, PIXIE) и RenderMan-клонов (Gelato, Mantra).
Официальный сайт Pixar
Фильмография PRman
Несмотря на то, что в последнее время появилось множество современных решений использующих самые прогрессивные методы просчёта фотореалистичных изображений, построенных на технологиях raytrasing или pathtrasing, RenderMan является промышленным стандартом создания компьютерной графики и используется в большинстве продакшен студий на крупных и дорогих проектах.
Основные причины этого - скорость и гибкость.
За скорость в RenderMan отвечает техническая реализация в программах рендеринга (PRman, 3Delight, PIXIE) качественного и быстрого дисплэйсмента, эффектов Antiаliasing, Motion Blur, Depth of field. Технологии, оттачивающиеся уже более двух десятков лет, позволяют работать с огромным количеством данных эффективно используя ресурсы.
Гибкость – это в основном RSL – язык написания шэйдеров, который позволяет расширять возможности программы и добиваться получения практически любого необходимого эффекта.
Изучение данной тематики требует базовых знаний математики (курс начальной школы + немного тригонометрии и векторной алгебры), а так же знание основ программирования на C-подобных языках. И то и другое в общих чертах будет рассмотрено по мере возникновения необходимости. В заключении приведён список литературы, сайтов и форумов из которых можно получить более подробную информацию.
Важно: Данный урок требует некоторого знакомства с основными понятиями интерфейса Houdini:
Как работает RenderMan.
Принцип работы связки RenderMan рендер - программа для моделирования/анимации (пайплайн) выглядит так:
В программе для моделирования и анимации создаётся сцена. Объекты, источники света и камера, а также параметры сцены (разрешение конечного изображения, сэмплинг и прочие настройки рендера, назначенные шэйдеры и пути к текстурам) экспортируются в RIB-архив. Фактически RIB это фомат файла-сцены RenderMan. Дальнейший процесс выполняет программа-рендер
- считывает данные из RIB,
- удаляет лишние объекты, которые не попадают в область просчёта,
- выполняет вычисления displace шэйдеров
- удаляет невидимые участки поверхности
- выполняет вычисления surface и volume шэйдеров
- выдаёт финальную картинку.
Удобство работы во многом зависит от того как реализована интеграция интерфейса RenderMan в программе моделирования. Houdini, в отличие от других программ, в которых требуются плагины или скрипты для экспорта данных в RenderMan, разработана для работы с RenderMan-совместимыми рендерами, поэтому она не только имеет возможность экспортировать свои данные в RIB, но также на этапе создания сцены оперировать RenderManовскими примитывами и имеет интегрированную визуальную среду разработки VEX-builder, которую мы будем использовать для создания шэйдеров.
Так как мы будем использовать учебную версию Houdini которую можно скачать здесь, то рендерить примеры шэйдеров будем в Mantra (учебная версия не позволяет использовать внешние рендеры).
Mantra – клон RenderManа, но не RenderMan-совместимый рендер, и, несмотря на всю их похожесть некоторые различия всё же есть. Поэтому каждый пример будет рассматриваться как для RenderMan так и для Mantra.
Замечание: Шэйдеры для RenderMan пишутся на RSL, для Mantra на VEX. Это разные языки, но они имеют много общего. Во избежание путаницы, в дальнейшем говоря "шэйдеры для RenderMan" я подразумеваю RSL, "шэйдеры для Mantra" - соответственно VEX.
VEX-builber.
VEX-builder, при всей своей внешней похожести не является аналогом Hypershade в maya, Render tree в XSI или PIXAR Slim. VEX-builder - это инструмент программирования, который представляет переменные, функции и математические операции в виде нод. В таком подходе к созданию шэйдеров есть как достоинства так и недостатки.
Достоинства:
- наглядное представление данных
- создание шэйдера происходит отдновременно с созданием его графического интерфейса
- часто используемые функции и целые сети из узлов можно собирать в один хранящийся на жёстком диске узел (Digital asset) и использовать в дальнейшем как используются готовые шэйдеры в Hypershade или Slim
- компиляция шэйдеров производится средствами самого Houdini
- есть возможность использовать глобальные переменные Houdini и с самого начала разработки использовать возможности процедурной анимации, а так же использовать шэйдеры как контент для Digital Asset'ов.
К недостаткам можно отнести то, что для многих, знакомых с программированием, пользователей Houdini будет проще и быстрее написать код в виде текста. Но в тоже время VEX-builder позволяет использовать текстовый код – для этого есть нода Inline Code.
Что такое шэйдер.
Шэйдер - это программа, которая получает входные данные, обрабатывает их и возвращает некоторый результат. В RenderMan программы-шэйдеры запускаются во время редеринга и, обрабатывая данные хранящиеся в RIB, закрашивают поверхности или смещают их.
Когда рендерер просчитывает пиксель, он выпускает луч из этого пикселя, и там где луч пересекает поверхность, рендер вызывает соответствующие шейдеры для вычисления цвета пикселя. И так этот процесс повторяется для каждого пикселя, составляющего картинку.
Шейдеры работают с набором данных из сцены, называемым глобальными переменными, которые содержат определенную информацию, такую как точка пересечения луча с поверхностью или положение камеры. Такие переменные могут содержать в себе разные значения для разных точек поверхности.
Рисунок показывает процесс, происходящий после испускания луча в точку поверхности. Обратите внимание на глобальные переменные (P, N, и.т.д.) и на их направления.
В Houdini можно создавать 4 основных типа рендераман шэйдеров:
Surface – шэйдеры поверхности – вычисляют цвет и прозрачность поверхности (в Mantra ещё альфа и нормаль).
Displace – шэйдеры, вычисляющие положение точки поверхности, изменяющие геометрию – вычисляют положение точки и направление нормали в этой точке.
Volume – шэйдеры объёма – вычисляют цвет и прозрачность точки пространства (используются для атмосферных эффектов).
Light – шйэдеры света – отвечают за направление, цвет и интенсивность источников освещения.
Так же в Mantra есть ещё отдельные типы шэйдеров для теней и фотонов.
Шэйдеры для RenderMan пишутся на RSL – языке написания шэйдеров – очень похожем на С. VEX, на котором пишутся шэйдеры Mantra вцелом аналогичен RSL но имеет некотрые отличия в названиях функций и типах данных.
Код шэйдера представляет из себя следующее:
тип_шейдера имя_шейдера (
тип_параметра имя_параметра1 = значение_по_умолчанию1;
тип_параметра имя_параметра2 = значение_по_умолчанию2,
имя_параметра3 = значение_по_умолчанию3;
тип_параметра имя_параметра4 = значение_по_умолчанию4
)
{
тип_переменной имя_переменной1 = значение_переменной1;
тип_переменной имя_переменной2,
имя_переменной3 = значение_переменной3;
оператор__основного_кода;
имя_переменной2 = значение_переменной2;
оператор__основного_кода;
оператор__основного_кода;
/* комментарий
комментарий
комментарий */
код_возврата_значения;
код_возврата_значения;
}
Первая секция одержит тип (surface, light, displacement или volume), имя шэйдера и, в скобках, входные данные. Фигурными скобками ограничивается «тело» программы. В конце программа должна вернуть значения соответствующие типу шэйдера - обычно для этого нужно присвоить эти значения специальным переменным.
2. Surface шэйдеры
Surface шэйдеры предназначены для вычисления цвета и прозрачности текущей просчитываемой точки, определяемых переменными Oi и Ci.
Глобальные переменные используемые в Surface шэйдерах:
Cs, Os - переменные, содержащие цвет и прозрачность указанные пользователем при объявлении шэйдера в RIB файле
P - координата точки поверхности
dPdu, dPdv - "направления" поверхности
N, Ng - нормаль шэйдинга, и геометрическая нормаль
u,v - UV координаты
du, dv - изменение координат U и V
s,t - аналог UV координат для параметрических поверхностей
E - точка положения камеры
I - вектор, направленный от камеры к точке
Ci, Oi - переменные цвета и прозрачности которым присваивается результат работы шэйдера
С небольшими отличиями в названии те же переменные можно найти в шэйдере для Mantra:
Откройте Нoudini.
Удерживая клавишу Ctrl щелкните кнопку Sphere на полке Create в центре сцены появится примитив сфера. Оставьте её настройки по умолчанию.
Тип поверхности Primitive
обозначает, что поверхность объекта не строится из патчей или полигонов, а является параметрической , т.е. задаётся математической функцией, поэтому на рендере сфера будет идеально гладкой при любом приближении.
Затем установите камеру в положение, откуда будет светить лампочка. Нажмите с Ctrl на кнопку Point Light на полке Lights and Cameras – источник света появится в месте текущего положения камеры
Нажав на эту кнопку
Можно управлять источником света как камерой. Нажмите на эту кнопку ещё раз чтобы продолжить работать с обычной перспективной проекцией.
В принципе сцена готова – теперь для проверки работы шэйдера будем назначать его на эту сферу, смотреть на неё с разных сторон, а чтобы не забивать голову настройками рендера – рендерить кнопкой быстрого рендера в нижнем левом углу:
Рендериться будет в Mantra из текущего вида во вьюпорте (нажимая правой кнопкой мыши можно выбрать любой Output Driver, созданный в контексте out, в коммерческой версии там по умолчанию присутствует RenderMan).
В контексте SHOP создайте ноду Material.
Чтобы создать нужный оператор нужно удерживая указатель иыши над Network Pane вызвать Tool menu (клавиша TAB) и напечатать на клавиатуре первые 2-3 буквы нужного оператора.
Зайдите "внутрь" оператора (клавиша i) и создайте VOP RSL Surface SHOP. Соедините выход этой ноды с входом next ноды Suboutput. Вернитесь на уровень выше (клавиша u) и перетащите ноду material1 на объект во вьюпорте. Теперь любые шэйдеры собранные внутри ноды material1 и подключённые к соответствующему входу ноды Suboutput будут автоматически присваиваться шарику.
Входы для каждого типа шэйдеров имеют уникальный цвет:
Начнём с самого простого шэйдера.
surface constant()
{
Ci = Cs*Os;
Oi = Os;
}
surface - тип шэйдера
constant – имя шэйдера
() – скобки – в скобки заключаются входные параметры
{} – фигурные скобки обозначают начало и конец программы.
Ci – выходное значение цвета в точке, Oi – выходное значение прозрачности.
Ci, Oi – значения цвета и прозрачности, указывающиеся при вызове шэйдера из RIB (по умолчанию это белый цвет).
Зайдём в созданную ранее ноду rsl_vopsurface1. Пока внутри неё есть одна нода - output1, с двумя входами – Ci и Oi. Смотрим на код – чтобы получить нужный нам шэйдер constant – к входу Ci мы должны присоеденить произведение двух глобальных переменных – Cs и Os, а к входу Oi значение Os. Для получение доступа к глобальным переменным нужно создать ноду Global Variables
Os можно сразу соеденить с Oi.
Для получения Ci нужно перемножить Cs и Os – сделаем это нодой Multiply. Выход Multiply будет имеет значение нужное для Ci – соеденим их.
Для Mantra создадим VOP VEX Surface SHOP и повторим все предыдущие действия. Заметьте, что Output Surface шэйдера для Mantra выглядит иначе – Ci и Oi называются Cf и Of, а так же есть ещё три входа, Af - альфа (позволяет управлять альфой независимо от прозрачности), N - нормаль (даёт возможность создавать эффект bump в Surface шэйдере), F - данные для физически корректного движка.
Результат:
Поскольку мы не собираемся копаться в RIB файлах перед каждым рендером, нужно добавить шэйдеру возможность вручную вводить исходные значения.
Создайте две ноды Parametr.
Установите Parametr Type в Color.
Parametr Name и Parametr Label впишите Color для одной ноды и Opasity для второй.
Поднимитесь на уровень вверх и в параметрах шэйдера обратите внимание на появившиеся параметры Color и Opacity. Это и есть графический интерфес который мы создали для шэйдера. Имя под которым параметр будет фигурировать в интерфейсе задаётся в Parametr Label.
Вернитесь обратно в шэйдер и присоедините параметры вместо глобальных переменных Os и Cs.
Теперь мы можем задавать шэйдеру произвольные цвет и прозрачность.
Повторим то же самое для Mantra:
Результат (цвет задан в параметрах шэйдера):
В таком простом шэйдере мы пользовались только одним типом данных – обратите внимание, все входы и выходы здесь одинакового цвета. Это потому, что для каждого типа данных в VEX-builder используются уникальные цвета.
Integer – целые числа.
Float – числа с плавающей точкой.
Vector – направленный отрезок. Указывается координата конца этого отрезка, начало которого находится в начале координат. Представление этого типа данных имеет вид (x, y, z), где x, y и z это числа типа Float.
Normal - вектор, перпендикулярный касательной плоскости в точке. Это так же 3 числа Float через запятую.
Color – цвет – представлен группой из 3-х Float’ов – (r, g, b).
Point – точка – координата текущей точки – 3 числа типа float (x, y, z).
Замечание: Для Mantra все типы данных с тремя float (vector, color, normal, point) объединены под одним типом - vector и имеют один и тотже зелёный цвет.
Так же в этом шэйдере мы столкнулись с необходимостью выполнить математическую операцию "умножение". VEX-builder позволяет выполнять любые математические операции в нодовом представлении.
Большинство нод математических операций находятся в группе Combine:
Наиболее часто используемые операции:
* - умножение – перемножает любое количество подключенных к ней источников одного типа, или умножает произведение какого-то одного составного типа данных на какой-либо простой, например перемножить несколько color’ов, а затем умножить их на float. В Rsl шэйдерах мы не можем перемножать разные составные типы, например нельзя умножить цвет на точку:
От того какая нода подключена первой зависит тип данных на выходе ноды multiply.
+ - сложение - складывает входящие данные. Правила подключения входов такие же как и у ноды multiply.
/ - деление – работает так же как и предыдущие две, но первым всегда должно подключаться делимое, а затем делитель.
- - вычитание – работает аналогично делению.
Поскольку в шэйдерах для Mantra color, vector, point и normal – это один тип данных то их можно перемножать в одной ноде multiply, складывать в одной ноде add и т.д.
Итак, мы можем задать шэйдеру произвольный цвет и прозрачность, теперь добавим возможность использовать для цвета текстуру.
Вернитесь внутрь шэйдера. Отсоедините параметр Color но не удаляйте его - для более широкого функционала шэйдера было бы неплохо оставить возможность пользоваться как заданным цветом, так текстурой. Для использования текстуры в своем шэйдере содайте ноду с красноречивым названием Texture.
Всё необходимое для загрузки текстур из файла в этой ноде есть. Обратите внимание на настройки:
В RSL шэйдерах в меню Signature текстуру можно переключать из режима color во Float (используется только один канал текстуры). При использовании текстуры в шэйдерах для Mantra в меню Signature можно выбрать режим RGBA – из текстуры будут использоваться не только каналы цвета но и альфа-канал.
В этом режиме на выходе ноды texture будет другой тип данных – color4 (vector4 - mantra), поэтому для дальнейших математических операций с обычным трёхцветным color придется отделять альфа канал с помощью нод из группы Convert, примерно так:
Сейчас оставим простой RGB режим. Для того чтобы можно было переключаться между цветом и текстурой создайте ноду switch. Кликните Средней кнопкой на входе switcher и из появившегося меню выберете Create Paremetr. Параметр будет имеет тип Integer и от того какое число будет выбрано в интерфейсе шэйдера будет работать тот или другой вход ноды switch. Выходы от текстуры и параметра Color подключите во входы switcher’а input1 и input2. Так как у нас всего два варианта, в параметре переключателя вместо типа Integer можно выбрать Toggle – в интерфейсе это будет выглядеть как галка – on/off.
И для того чтобы выбирать файл для текстуры, создайте параметр для атрибута map ноды texture.
Замечание: при использовании текстур необходимо запомнить, что для рендера в RenderMan текстуры должны быть в его родном формате текстур - *.tex. Сконвертировать текстуру из своего формата в формат *.tex можно утилитой texmake входящей в состав RenderMan.
Для Mantra можно использовать практически любой тип изображений (включая *.tex).
Результат:
Теперь, когда мы знакомы с основными элементами для математических операций и для создания интерфейса, можно приступить к более сложным шэйдерам.
Шэйдер Constant не использует никаких данных сцены, таких как источники света и угол камеры.
Для начала заставим диффузную составляющую реагировать на свет.
Создайте новый шэйдер назовите его diffuse_.
Вот RSL код этого шэйдера:
surface diffuse_()
{
normal Nn = normalize(N);
Oi = Os;
Ci = Oi * Cs * diffuse(Nn);
}
Создайте ноду Global Variables.
Функция normalize выполняется нодой normalize, - создайте эту ноду и подключите к ней глобальную переменную N (эта функция приравнивает длину вектора к еденице сохраняя направление ).
При попытке найти ноду diffuse нас ожидает сюрприз: такой ноды в стандартной поставке Houdini нет, но это не значит, что мы не сможем воспользоваться этой функцией. На самом деле для далеко не всех RSL и VEX функций в VEX-builder есть соответствующие ноды (на Houdini слэнге VEX-операторы – VOP’ы). Здесь приходит на помощь нода Inline Code VOP.
Создайте эту ноду. Подсоедините к ней текущее значение переменной Nn – это нода normalize (полезно давать осмысленные имена нодам, например имена переменных, которые хранятся в этой ноде). Посмотрите на параметры ноды Inline Code:
В Output1 Type выберите color и задайте имя в поле Output1 Name (я использовал имя diff).
Теперь в поле Inline Vex Code напишите следующее:
$diff = diffuse($nvec);
$diff – только что созданный Output, знак доллара обозначает, что это переменная.
= - оператор присваивания – мы должны присвоить некоторое значение переменной $diff.
diffuse($nvec) – вызов функции diffuse с аргументом $nvec (в круглых скобках указываются аргументы - входные данные для функции). $nvec - значение являющееся результатом работы ноды Normalize, подключенной к Inline Code VOP - список все подключенных значений находится внижней части параметров этого оператора, а так же там указываются имена переменных для использования в Inline Vex Code.
; - строка с командой должна заканчиваться точкой с запятой.
Теперь создадим Multiply и перемножим Os, Cs и результат работы ноды Inline Code.
Присвоим результат Ci.
Результат:
Функция Diffuse это не "чёрный ящик", и при желании все вычисления внутри неё можно повторить, собрав свою функцию наделённую какими нибуть свойтвами, недоступными стандартной функции. Например работа diffuse() сводится к вычислению косинуса угла между направлением источника света и нормалью в точке:
Свет попадает в точку А перпендикулярно поверхности. В этой точке вектор -L и нормаль совпадают, т.е. угол между ними == 0. cos(0) == 1. Соответственно интенсивность источника света (пусть будеть 1) умножается на косинус получается что в точке А освещённость тоже равна 1. В точке "B" нормаль находится под углом 45 градусов к направлению освещения -L. cos(45) == 0.5. т.е. Освещённость этой точки будет 0,5 интенсивности источника света. Косинус угла вычисляется скалярным произведением еденичных векторов нормали и луча света - для получения еденичных веторов (длина которых равна 1) и нужны ноды Normalize.
Добавим возможность реагировать на Ambient освещение.
Ci = Os*Cs*(ambient()+diffuse(Nn));
Для этого добавим ноду ambient и сложим её значение с результатом с результатом вычисления Diffuse
Для того, чтобы увидеть реакцию поверхности на ambient освещение понадобиться создать источник света ambient light и задать ему цвет, отличный от чёрного.
Добавим два параметра Ka и Kd типа float для того, чтобы управлять интенсивностью диффузной и эмбиентной составляющей, а так же параметры цвета:
Установив значение, например, Kd =0 цвет diffuse, который на него умножается тоже станет равным нулю, а поскольку далее diffuse и ambient составляющие складываются, то значение 0 просто не будет оказывать какого-либо влияния на результат.
Собственно результат:
При желании можете добавить возможность использования текстур вместо цветовых параметров.
Следующим этапом будет добавление шэйдеру блика – specular. Specular, о котором пойдет речь не является физически корректным бликом, который в природе появляется на отражающих поверхностях и фактически является отражением самого яркого объекта (например окна или лампы). В данном случае это упрощённая математическая модель, которая рисует блики определённой формы в зависимости от положения источников света и камеры.
Кoд:
specular(Nf,V,roughness)
функция specular требует 3 аргумента:
Nf - это normalize(N) или faceforward(normalize(N), I ) (- в VEX faceforward называется frontface, так же называется соответствующая нода - frontface VOP).
Roughness – параметр float – будет регулировать жесткость блика.
V = -normalize(I);
Для получения V создайте ноду normalize.
Подключите к ней глобальную переменную I.
Создайте ноду Multiply и в первый вход подключите результат предыдущей ноды.
Нажмите средней кнопкой на втором входе ноды Multiply и выберите Create Constant.
В поле Float Default установите значение -1.
Теперь создайте ноду Inline Code и подключите к ней Nf и V, а также создайте параметр roughness:
Полученный specular можно добавить к diffuse и ambient составляющей присоединив его к ноде add.
Мы получили specular который в остальных программах обычно называют Blinn. Для получения блика типа Phong вместо функции specular в Inline Code нужно использовать функцию phong.
Добавим (умножением) к спекуляру параметр Ks для управления его интенсивностью:
Теперь подбирая значения Ks и Roughness можно получить, например, жесткий Glossy блик:
Замечание: обратите внимание, что функции specular и phong по-разному реагируют на параметр rougness поэтому будет удобно если для каждой из них будет выставлен соответствующий Float Range – границы в которых будет двигаться бегунок в интерфейсе.
Для specular подойдёт значение 0 1, для phong лучше использовать 0 100.
Для создания других типов бликов можно воспользоваться нодой Specular Functions (она уже содержит рассмотренные выше примеры, а так же Glossy и Anisotropic блики), либо собрать свою функцию Specular (о том как можно покопаться в функциях diffuse или specular и собрать свою с нуля можно прочитать в документации к PRman и в др. источниках которые будут указаны в заключительной части).
Чтобы придать блику цвет просто домножим его на параметр цвета или текстуру:
Говоря о создании Surface шэйдеров было бы неправильно обойти стороной рэйтрэйсовые функции – если такой материал как хром можно легко сымитировать используя карту отражения, то, например, стекло сделать фейком достаточно сложно.
Отражение.
Отражение – Reflection – сорздаётся функцией reflect:
reflect(I, Nn) – где I – глобальная переменная, а Nn = faceforward(normalize(N), I)
полный вызов функции выглядит так
trace(P, reflect(I, Nn))
Cначала получим Nn:
Обратите внимание на то, что функция faceforward в VEX называется fronface, так же называется нода реализующая её.
Далее соберите конструкцию trace(P, reflect(I, Nn)), и подключите к выходу Ci:
Для проверки работы рэйтрэйса создайте плоскость на которой лежит шар:
Аналогичным образом создаётся рефракция, только вместо функции reflect используется функция refract (при необходимости можно вынести параметр IOR подключив ноду parametr на вход eta):
IOR = 1.333
Атрибут angle ноды Ray trace регулирует «размытость» отражения или преломления, только не забывайте что Mantra и большинство RenderMan совместимых рендеров достаточно медленно просчитывают raytrace (в Mantra для этого лучше использовать Ray tracing engine).
Полученные отражение и преломление теперь можно добавить к основному шэйдеру, создав для них множители для управления интенсивностью.
Ещё один очень часто используемый рэйтрэйсовый эффект – Ambient Occlusion. И в RSL и в VEX это функция occlusion. Если вам достаточно её основного функционала то достаточно создать ноду Occlusion и использовать её:
Если необходимы дополнительные возможности, то лучше обратиться к документации по RSL и использовать Inline Code.
Для того, чтобы использовать окклюжен в собранном шэйдере его нужно умножить на остальные компоненты.
Абстрагируясь от программирования разработку Surface шэйдеров можно представить как создание компонент/составляющих (diffuse, specular и т.д.) которые в дальнейшем смешиваются (складываются, умножаются) для получения нужного окрашивания поверхности.
Таким образом можно создавать неограниченное количество блоков, каждый из которых будет реализовать тот или иной требуемый эффект и объединить их в самом шэйдере, или выводить их отдельно для сведения на композе. Сложение обычно используется когда нужно чтобы более тёмные цвета не оказывали влияния на картинку, умножение наоборот - как в случае с оклюженом используются более тёмные участки для создания эффекта мягких теней. Откройте Photoshop и посмотрите на список Blending режимов у слоёв - все они реализованы математическими операциями над цветами.
Паттерны.
Заканчивая разговор о Surface шэйдерах рассмотрим ещё одну очень важную возможность VEX и RSL – создание паттернов – параметрических цветных узоров, которые иногда называют «процедурными текстурами».
Паттерны – очень мощный и гибкий инструмент с огромной сферой применения и используются не только в Surface, но и во всех остальных шэйдерах. Паттерны не только не теряют детализацию при приближении и не только могут покрывать большие площади неповторяющимся рисунком, главное достоинство паттернов перед растровыми текстурами – параметризация, которая позволяет анимировать любое свойство текстуры.
Создание различных узоров и фракталов требует более глубоких навыков программирования, векторной алгебры и тригонометрии, поэтому здесь рассмотрим достаточно простые примеры (за дополнительной информацией – см. рекомендуемая литература). Создание каждого узора требует анализа необходимого рисунка, нахождение закономерностей и представление их в виде математических функций.
Окружность.
Окружность рисуется на двухмерной поверхности используя координаты параметрического пространства поверхности s-t (или u-v):
Окружность имеет радиус, координату центра.
Уравнение окружности ω (A; R) имеет вид (x – a)2 + (y – b)2 = R2, где a и b – координаты центра A окружности ω (A; R) .
Код шэйдера:
surface circle(
color inside = color (1, 1, 1);
color outside = color (1, 0, 0) ;
float radius = 0.3, scenter = 0.5, tcenter = 0.5;
)
{
float sdist, tdist, dist, circle;
sdist = s - scenter;
tdist = t - tcenter;
dist = sqrt(sdist*sdist + tdist*tdist);
circle = step( radius, dist );
Ci = mix( incolor, outcolor, circle);
}
Создайте полигональную плоскость (Ctrl + клик по кнопке Grid на полке Create), оставьте все значения по умолчанию, нажмите U чтобы войти в контекст ноды. Кликните правой кнопкой на выходе ноды grid1 и из появившегося списка выберите UV project. Убедитесь, что поля в разделе Transform выглядит так: Rotation 90 0 0, Scale 10 10 0.
В SHOP контексте создайте материал, в нем шэйдер VOP RSL Surface (для RenderMan) или VOP VEX Surface (для Mantra). Назовите его circle и примените материал к объекту.
Для сборки понадобятся функции
step – нода filterstep
Соберём шэйдер:
sdist = s - scenter;
tdist = t - tcenter;
dist = sqrt(sdist*sdist + tdist*tdist);
ind = step( radius, dist );
Ci = mix( incolor, outcolor, ind );
Установите значения параметров
inside = color (1, 1, 1);
outside = color (1, 0, 0) ;
radius = 0.3, scenter = 0.5, tcenter = 0.5;
Рендер:
Паттерн нарисовал окружность в каждом полигоне потому что после применения UVProject переменные s и t стали отдельными для каждого отдельного полигона. На объектах, имеющих U-V развёртку нужно использовать соответствующие переменные s и t. Создайте ноду UVCoords и возьмите переменные st из неё:
Рендер:
Поставив ключи на параметр radius, можно анимировать размер окружности – это можно использовать, например, при создании шэйдера роговицы глаза.
Шахматная доска:
Алгоритм следующий: делим ось s и t на несколько равных частей и поочерёдно закрашиваем их чёрным и белым цветом:
surface checker(
float srepeat = 2, trepeat = 2, soffset = 0.25, toffset = 0.25;
color color1 = color (0, 0, 0), color2 = color (1, 1, 1)
)
{
float ss = mod( srepeat * s - soffset, 1 );
float tt = mod( trepeat * t - toffset, 1 );
float chkrS = 1 - step( 0.25, ss ) + step( 0.75, ss );
float chkrT = 1 - step( 0.25, tt ) + step( 0.75, tt );
float chkr = abs(chkrS - chkrT);
Ci = mix( color1, color2, ind );
}
Создайте новый шэйдер, назовите его checker.
Для сборки понадобятся функции