Ответ слушателю на вопрос по шейдерам.
Иногда, ответы слушателям на курсе, так сильно увлекают, что получаются целые статьи. Не могу удержаться и оставлю это здесь. Кому- нибудь окажется полезным.
Андрей, я тоже не являюсь программистом, но так получается, что многие художники начинают постепенно заниматься всё более специфическими задачами, что погружает их в изучение языков программирования. То есть математики- технари и художники идут друг другу на встречу. Математики изучают графику, а художники математику. Многие сознательно отказываются лезть в программирование. Так или иначе, программирование, помогает куда лучше понять механизмы компьютерной графики. Как там в "Экзистенции"- Бог, артист, механик. Я тоже нахожусь в процессе изучения, попутно стараюсь всё это переваривать, осмысливать, раскладывать по полочкам, фиксируя на видео. Вот и получаются эти курсы.
Шейдинг в Unity кросс- платформенный. Это означает, что шейдера написанные в Юнити будут работать на различных устройствах, использующих разные способы аппаратной отрисовки графики. Это D3D9, D3D10, D3D11, GLSL, HLSL- опенджиэлевские и директиксовые синтаксисы. CG язык более высокоуровневый и объединяет в себе более низкоуровневые структуры этих языков. Когда мы пишем на CG шейдер, то Юнити компилирует его в низкоуровневый шейдер, который могут понимать разные устройства. То есть нам не нужно писать конкретно на DX11 или HLSL отдельно. Юнити при компиляции, создаст шейдер содержащий инструкции для устройств, в каком случае и что будет отрисовываться на том или ином устройстве. Так что мы изучаем CG. CG был создан специально, чтобы было проще осваивать и понимать структуру шейдера.
Шейдерлаб- это ещё более высокоуровневый синтаксис, созданный чтобы писать как можно меньше. Ребята из Юнитеха, в частности Арас Працкявичус придумали этот синтаксис чтобы решать самые примитивные задачи. Смешивать текстуры, быстро добавлять что-то к имеющемуся шейдеру. Наличие синтаксиса шейдерлаба сбивает с толку всех кто начинает осваивать CG. Авторитетные шейдерописцы им не пользуются. Я редко использую элементы шейдерлаба в шейдерах. Иногда специфические вещи приходится вставлять, но он слишком высокоуровневый- это ограничение. Структура CG шейдера гибкая и основана на уровневом принципе.
Category{...} Может объединить все субшейдеры и назначать им одни и те же теги для отрисовки и смешивания. SubShader{...} это сам шейдер и есть. Он может быть один или несколько. Это значения не имеет. Важно сколько шейдер может обработать инструкций и сколько регистров может использоваться. Это определяется шейдерной моделью #define ShaderModel По умолчанию используется шейдерная модель ShaderModel2. Если инструкций больше, то шейдер при компиляции выдаст ошибку и попросит использовать более высокую шейдерную модель- ShaderModel3. Юнити может использовать все шейдерные модели вплоть до пятой. Далее, SubShader включает в себя пасы Pass{...}, их тоже может быть несколько. Каждый пасс- это отрисовка геометрии и текстур в буфер из которого результат попадает в следующий пасс или смешивается с результатом отрисовки следующего пасса. Внутри пасса размещается CGPROGRAM ...ENDCG - Это кусок в котором пишутся все расчёты производимые видеокартой. Здесь весь набор инструкций как и что отрисовывать. Это структура шейдера и есть. Сейчас пишу шейдер стекла и структура выглядит примерно так:
Shader "Custom/Glass" {
Properties {
//Здесь все переменные- Текстуры, значения ит.д.
}
Category{ // начало категории объединяющей все субшейдеры если их несколько.
SubShader {
Tags { "Queue" = "Transparent" "RenderType"="Transparent" } //В тегах назначаются обозначения последовательности и типа отрисовки геометрии
Pass{}//ЦВЕТ и ПРОЗРАЧНОСТЬ Задней поверхности. Отрисовывается только задняя часть геометрии с прозрачность, цветом и прочим.
GrabPass {}//ЗАХВАТ ДЛЯ ПРЕЛОМЛЕНИЯ, Результат отрисовки задней поверхности передающийся в расчёт рефракции.
Pass{}// ОТРИСОВКА ПЕРЕДНЕЙ ПОВЕРХНОСТИ, Здесь я размещаю расчёт рефракционного преломления и хроматическую аберацию.
Pass{}// ОТРИСОВКА ПЕРЕДНЕЙ ПОВЕРХНОСТИ ЦВЕТ И АЛЬФА, снова прозрачность, текстура и цвет, но фронтальной части геометрии.
Pass{}// ОТРИСОВКА ОТРАЖЕНИЙ ПЕРЕДНЕЙ ПОВЕРХНОСТИ, Здесь у меня весь расчёт фейкового отражения, френель и прочее.
} //конец субшейдера.
} //конец категории.
} //конец шейдера.
Таким образом, в категории один субшейдер, в субшейдере 4 пасса. В каждом пассе свой функционал. Почему так? Сначала отрисовывается задняя стенка стекла. Всё что за ней, смешивается с цветом стекла, текстурой и захватывается при помощи GrabPass в буфер. Оттуда передаётся по сути как обыкновенное, растеризованное изображение, в следующий пасс и уже там подвергается искажению, основываясь на нормали поверхности и расчёте UV координат. Здесь же расчитывается хроматическая аберация, расслаивающая картинку на цветовые составляющие. Результат совмещается и отдаётся пассом как готовое отрисованное изображение на экране. Третий пасс отрисовывает переднюю стенку стекла- прозрачность, цвет, текстуру и смешивает результат с результатом предидущего пасса, последний пасс накладывает карту отражений (кубмапу) на переднюю стенку стекла, здась же накладывается маска по френелю, чтобы стекло под разными углами вело себя по разному. В моём случае стекло должно быть не столько реалистичным, но иметь массу эффектов, которые я размещаю в пассы отрисовки передней и задней стенки. Каждый пасс я пишу в отдельном шейдере, тестирую, потом соединяю всё в один и дорабатываю. Такая вот рабочая задча.
Это структура шейдера.
Структура CG программы внутри пасса может быть воспроизведена посредством трёх видов шейдерных расчётов доступных в CG. Это СУРФЕЙСНЫЙ (поверхностный), ВЕРШИННЫЙ (геометрический, вертексный) и ФРАГМЕНТНЫЙ(пиксельный) шейдера. Сурфейсный шейдер более высокоуровневый и такой легче понимать и писать. Сурфейсный шейдер взаимодействует с моделью освещения. Это у меня всё есть в курсе. Дальше увидите. Я слишком углубляться не стал в курсе. Ну ладно. Писать такой проще, но такой шейдер здорово нагружает видеокарту расчётами освещения вместе с расчётами результатов. В общем, такой шейдер может здорово посадить FPS и по этому сурфейсный шейдинг лучше не использовать для мобильных устройств. Вертексные и фрагментные части шейдера самые низкоуровневые и для понимания и для написания самые сложные. Там больше писанины, а некоторые вещи настолько абстрактны, что даже поняв их потом трудно объяснить что это такое и как оно работает и почему именно так. Все три типа шейдерных подпрограмм сочетаются друг с другом. В одном пассе может быть только сурфейсный кусок, в другом только вертексный и фрагментный, вертексный и сурфейсный или все три сразу. Каждая из трёх подпрограмм взаимодействует с остальными при помощи входящих и исходящих данных. Не посредственно они не могут отдавать или принимать эти данные, по этому используются так называемые СТРУКТУРЫ struct{...}; . Структуры- это блоки содержащие типизированные данные с семантикой. К примеру:
struct vertexInput {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
У структуры есть название- vertexInput, она содержит набор из 4 элементов. Сначала тип, потом название данных и после двоеточия семантика. Семантика нужна для выделения регистра, чтобы видеокарта поняла, что цвет это цвет, нормаль это нормаль и так далее. Эта структура берёт всё это из геометрии. Всё что могут содержать вершины. Вершинная подпрограмма берёт эти данные и обрабатывает их складывая результаты в другую структуру но уже с другим названием. К примеру vertexOutput или обычно называют v2f (из вершин в фрагмент). Получается такая картина:
Входящие вертексные данные > Вертексная подпрограмма > Исходящие вертексные данные.
Структуры нужны как мостики или трубопроводы между блоками подпрограмм. Результат расчётов вертексной подпрограммы принимает фрагментный шейдер. Там происходит расчёт финального результата выводимый в виде пикселей на монитор. Это может быть и сурфейсная подпрограмма. Вот и всё. Это вкратце, но это всё многократно расписано и описано в документации, туториалах, много можно найти по шейдингу инфы. В общем это второе что нужно понять- как взаимодействуют шейдерные подпрограммы.
Третье что нужно для дальнейшего понимания- это алгебра и тригнометрия. Школьного курса вполне достаточно. Вектора, матрицы, простая математика. Вот и всё.
Где может использоваться. Для почти любого софта можно написать свою ноду, выполняющую то или иное действие. Для того-же Шейдер Форджа. Для МенталРея или другого рендера. Многие программы просто принимают какое-либо распространённое расширение текстового файла, где содержится код шейдера. Лайтвейв, на пример. Движки разумеется. Раньше, собственно, люди писали вообще всё с нуля. Весь двиг и шейдинг тоже, основываясь на каом нибудь фреймворке. Сейчас уже всё по другому. Много всего создано. Юнити- это среда разработки на основе DotNet2 (если не ошибаюсь). Отсюда использование языков C# и Java. Одна надстройка на основе другой, другая над третьей, а сверху приспосабливаются инструментальные плагины как четвёртая. Так, что сейчас вся работа программистов сводится к созданию таких надстроек над уже имеющимися программными тектоническими континентами- операционными системами, программами, фреймворками. Для разработчика графики это означает расширение функциональности инструментария используемого художниками, графического редактора, движка или приложения. Обычно это связано с игростроем, графическими интерфейсами приложений, кино и анимацией, куда реже- научные визуализации (медицина, инженерия). Сейчас, почти везде есть надстройки- редакторы, позволяющие использовать визуальное (нодовое) программирование. Houdini, Maya, Max, Lightwave. Все в разной степени могут это использовать, в основном для построения шейдинга материалов. Движковые редакторы, конечно тоже имеют такие надстройки. По сути, используя API и какой либо язык используемый данной средой, можно собрать любой редактор чего угодно, нодовый к примеру. Для Юнити полным полно таких редакторов. Они имеют открытый код и при желании можно вносить изменения в функциональность самого редактора. Переделать его или написать свой. Шейдер Фордж один из последних и самых удобных из тех что есть для Юнити. Мне как пользователю 3D софта, конечно проще было вязать вязанки из нод. Основным затруднением было продумывание того как и что должно происходить и как из набора кирпичиков, как в конструкторе собрать что-то осмысленное. Более или менее начало получаться, когда начал изучать ООП. Соответственно, полез с расспросами к программистам и они меня сразу застремали по полной. Все как один отвечали, что ДЕЙСТВИТЕЛЬНО СЕРБЁЗНЫЕ ВЕЩИ НУЖНО ТОЛЬКО ПИСАТЬ. Какое-то время я пытался вести дискуссии по поводу плюсов нодового программирования, но меня просто в серьёз не воспринимали- не дорос ещё, чтобы такие вещи понимать. Мне очень хотелось углубиться именно в работу с нодами. Просто хотелось, потому как в этом есть какая- то притягательная эстетика. Любой художник- правополушарный по мышлению и думать картинками узоров нод художнику более свойственно. Если это Grasshopper, то это вообще сказка! Я и сейчас пользуюсь нодами в разных пакетах, но уже крайне редко, только по необходимости.
Потом до меня начало доходить, что нода- это картинка, визуальное представление информации. Каждая нода- это контейнер содержащий подпрограмму, которая принимает какие-то данные, обрабатывает по сценарию заложенному в функционале этого сценария и возвращает данные как исходящие. Программа, получает карту того как собрать объект, текстуру, материал или шедер, собирает всё в один сценарий и компилирует результат. В Maya нет ничего в файле ma. Там только инструкции, как собрать сцену и всё содкржимое. Майя получает файл и конструирует сцену. Если сценарий конструирования сцены изменён, Майя его просто реконструирует. Короче, ложки на самом деле нет. По сути, Maya- это компилятор файла в формате ma или mb. Не более того. Было бы затруднительно, написать всю сцену в текстовом редакторе, хотя простую сцену с кубиком можно написать в блокноте и открыть в Майя. Вы увидите кубик. Майя, как редактор, как раз оперирует нодами. Результатом становится скомпилированный файл, который можно открыть в Майя и вновь воспроизвести сцену- геометрию, материалы, анимацию. Экспорт- это компиляция в другой формат. Есть такое, что программы скомпилировать не могут. Если взять формат Collada, то там, кроме геометрии, могут быть размещены куски кода содержащие шайдерные куски. Весьма низкоуровневые. Collada открытый текстовый формат и внутри файла можно вносить такие изменения, которые не получится вынести из 3D редактора при компиляции- экспорте. Только вручную и только в текстовом режиме. WebGL использует это и отдаёт видеокарте из текстового файла геометрию, ссылки на текстуры, шейдерную часть и всё это отрисовывается. Так что нужен только текстовый редактор и всё. Это другая крайность- оголтелый кодинг всего и вся чистый и беспощадный. Я туда полез, но вовремя одумался и вылез.
Разработчик оперирующий нодами, как дрессированная обезьяна, прото берёт кусок кода, копирует его и вставляет в определённое место. Бездумно, абсолютно не понимая как работает этот кусок кода. В наборе такого разраба ограниченный набор нод и набор ограничений того как он их может соединять в последовательность. Единственно что он может, это менять последовательность, разветвлять эту последовательность и в небольшом диапазоне менять сценарий подпрограммы находящейся в ноде. Этого достаточно, чтобы получить огромное разнообразие вариантов получения массивных комбащйнов для обработки данных, но по сути- это ограниченное пространство, ведь оно очень высокоуровневое. Другое дело, когда ты можешь создавать подпрограммы- ноды самостоятельно. В этом случае, ты приходишь к нодовому редактированию, исходя из оптимизации самого процесса разработки. Это кардинально другой уровень. Программист разрабатывает достаточно гибкие и мощные подпрограммы и компанует из них комбайны. В каких- то случаях это оказывается весьма осмысленно, даже для программистов. Это избавляет их от манипулирования огромными объёмами текстового кода, даже если это использование готовых библиотек. Хотя, в большинстве случаев этого не требуется. В любом случае, даже начальные навыки ООП, очень здорово помогают в использовании нодового редактирования где угодно. Это точно.