RedHelium RedHelium

Jusper, Планируется в стим, но под издательством кого-нибудь. На счёт портирования на мобильные платформы пока не планировал

Jusper Jusper

RedHelium,

Игра планируется на стим? Если на телефон, то пост-эффекты будут лагать как сволочь)

RedHelium RedHelium

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

Jusper Jusper

Я большую разницу в работе со светом.
Не понимаю, наверное это еще постэффекты.

alexprey alexprey

А вот и результаты первого забега.

...
Dreaman Dreaman

TheDarkestRed,

Красивый и атмосферный получился :)

RedHelium RedHelium

alexprey, Спасибо, рад стараться :)

TheDarkestRed TheDarkestRed

Концепт арт лесной локации The Darkest Red 🎮 🌲 🌘

...
id66243826 id66243826

Первый трейлер игры, больше похоже на нарезку но все же =) Так же было выпущено обновление, и теперь есть возможность покупать персонажей.
Решил немного разнообразить механики, добавлены двери и ключи,...

...
alexprey alexprey

RedHelium, стиль необычайно хорош)

RedHelium RedHelium

Вновь взялся за свой проект под названием "Stalkmech". Понемногу начал перерабатывать уровни, а также интерфейс.
Моя группа ВК: https://vk.com/redheliumgames

Jusper Jusper

Закрепили с GenElCon успех боем на островной карте.

  • Против нас были: Турция и Россия (на сложности Невозможный)
  • Время ненападения: Отсутствует
  • ...
ruggaraxe ruggaraxe

alexprey, будем ждать фидбэк! Я надеюсь вы заметите множество улучшений! 😎

alexprey alexprey

Ура! Обязательно поиграем. Но блиииннн... Опять пауки... Арахнофобия и в играх не дает покоя 😂
Режимы это круто, мне не хватало лайт версия для побродить!

Jusper Jusper

alexprey,

надеюсь в мою хату завезут нормальный интернет и у меня получится постримить :D

Jusper Jusper

Перенес в проект, вместо раздела game-design. Завтра заценим, че как :)

alexprey alexprey

ruggaraxe, это вообще одна из моих первых игр, после дума конечно же 😂😂😂

Сейчас в стиме по скидосу, прикупил,надеюсь свезет и поучавствую в подобной движухе)

Jusper Jusper

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

ruggaraxe ruggaraxe

Крутяк! 15 лет назад была любимой стратегией. 3 часть выглядит круто, стиль такой же как и во всех первых частях.

Логотип проекта Unity

#1 Краткая теория

Краткая теория шейдеров

В этой статье я хочу описать основные моменты, которые стоит понимать, что бы начать писать шейдеры в Unity. Я затрону всё очень поверхностно, постараюсь выцепить только самое важное и объяснить на пальцах. Но упрощение влечет за собой неточность. Так что всё будет описано так, чтоб увидеть только вершину айсберга. Для тех-же, кто захочет нырнуть глубже,по каждой затронутой в статье теме ,в разделе "Дополнительный материал", будут спойлеры, содержащие ссылки на более подробное описание данной темы. Эта статья является моей дебютной, до этого никогда не писал, так что прошу не судить строго. Ну, начнем.

3D модель

Думаю, мы тут все прекрасно знаем, что такое 3D модель и из чего она состоит.
Но, на всякий случай, я хочу уточнить два момента, важных для нас:

  1. Вершина.Каждая вершина имеет свои координаты, а так же нормаль. Вершины объединены в полигоны при помощи рёбер, а полигоны, в свою очередь, образуют полигональную сетку(mesh).
  2. Текстура. Текстура - это простое изображение, которое расположено на модели в соответствии с uv координатами.
#1 Краткая теория — Unity — DevTribe: инди-игры, разработка, сообщество

UV координаты - соответствие между координатами на поверхности трёхмерного объекта (X, Y, Z) и координатами на текстуре (U, V). Значения U и V обычно изменяются от 0 до 1. Т.е. у каждой вершины модели есть свои соответствующие координаты на текстуре. Почему их только 2 ? Это просто. U соответствует X на координатной плоскости текстуры, V соответствует Y.

#1 Краткая теория — Unity — DevTribe: инди-игры, разработка, сообщество

Шейдеры

Шейдер - это программа, выполняющаяся на графическом процессоре видеокарты (GPU). На вход шейдера подаются входные данные, содержащие информацию о координатах вершин, полигонах,нормалях, освещении, цвете вершин, UV(текстурных координатах) и т.д.. Задача шейдера принять эти данные, обработать, и подать на выход конечный результат.

Схематично работу шейдера можно описать так:

  1. Прием входных данных
  2. Обработка данных
  3. Вывод конечного результата ( изображения )
  4. Ожидание следующих данных на вход

Также очень важно то, что шейдер выполняется для каждой отдельной вершины/пикселя отдельно! При этом он имеет информацию только о той вершине/пикселе которую сейчас обрабатывает. Т.е. во время написания шейдера мы не знаем, какого цвета соседняя вершина/пиксель.


Пиксельный и вертексный шейдеры

Вертексный шейдер - шейдер, обрабатывающий данные о вершине и затем передающий их в пиксельный шейдер. Какие данные шейдер передаст мы можем задать сами, но, мы должны обязательно передать(вернуть значение) координаты текущей вершины (x,y,z). Вертексный шейдер выполняется раньше, чем пиксельный, а затем, из него передаются данные в пиксельный шейдер.

Т.к. пикселей значительно больше, чем вершин, очевидно, что пиксельный шейдер выполняется большее количество раз, чем вертексный. Так же стоит понимать, что после передачи вертексным шейдером данных о вершине, эти данные интерполируются(сглаживаются) для каждого конкретного пикселя. Т.е. если пиксель стоит ровно между вершинами A(черная) и B(белая), цвет этого пикселя будет высчитан как средний от этих двух вершин(серый), и так для каждого параметра.

Пиксельный шейдер - шейдер, принимающий интерполированные данные от вертексного шейдера, и на их основе вычисляющий цвет для каждого отдельного пикселя. Опять-же, мы можем назначить, какие данные нужно будет передать пиксельному шейдеру, но мы обязательно должны вернуть цвет.


Итак, теперь мы знаем, что такое вектексный и пиесельный шейдер. Давайте немного усложним наш алгоритм работы шейдера:

  1. Прием входных данных
  2. Обработка их на ветрексном шейдере
  3. Интерполяция данных
  4. Передача данных пиксельному шейдеру
  5. Обработка данных на пиксельном шейдере
  6. Вывод конечного результата(изображения)

Заранее скажу, что есть еще 2 вида шейдеров: геометрические (работают с целыми примитивами модели) и поверхностные/surface (упрощенный вид шейдера в Unity 3D, в основном использующийся для работы с освещением).

Языки программирования шейдеров

  • GLSL - высокоуровневый ЯП для OpenGL
  • HLSL - высокоуровневый ЯП для DirectX
  • CG - высокоуровневый ЯП, в зависимости от ситуации компилируется под HLSL/GLSL. Используется в юнити. То что нужно для нас.

Язык программирования CG

Язык программирования CG - это высокоуровневый язык программирования, разработанный компанией Nvidia для программирования пиксельных и вертексных шейдеров.

Типы переменных в CG

Простые

  • float - числовая переменная с плавающей запятой (32бита)
  • half - числовая переменная с плавающей запятой (16 бит )
  • fixed - числовая переменная с плавающей запятной (12 бит)
  • int - целочисленные числа (32 бита)
  • bool - логическая (1 бит )

Векторные

  • float2, float3, float4
  • half2, half3, half4
  • fixed2, fixed3, fixed4
2D,3D и 4D векторы

Матрицы

  • float2x2, float3x3, float4x4

Текстурные

  • sampler2D - 2D текстура (существуют и 3D текстуры -; )
  • samplerCUBE - кубическая текстура (используется для отражения)

Для того, что бы указать, что переменная внешняя, спереди к ней добавляется ключевое слово uniform.

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

Основные функции CG

Геометрические

  • sin / asin - синус / арксинус
  • cos / acos - косинус / арккосинус
  • tan / atan / atan2 - тангенс, арктангенс, арктангенс от двух аргументов
  • dot - скалярное умножение векторов
  • cross - векторное умножение векторов
  • length - длинна ветора
  • reflect - вектор отражения
  • normalize - возвращает нормализованный вектор
  • degrees / radians - переводит радианы в градусы / градусы в радианы
  • distance - дистанция между двумя точками

Алгебраические

  • mul - перемножение матрицы на вектор и наоборот
  • pow - возведение в степень
  • lerp - линейная интерполяция
  • exp - экспонента в степени
  • sqrt - корень
  • log - логарифм

Физические

  • refract - преломление по аргументу

Остальные

  • min / max - возвращает

минимальное/максимальное значение каждого аргумента

  • clip - отрезает пиксели
  • clamp - устанавливает рамки для возвращаемого числа
  • saturate - устанавливает рамки для числа от 0 до 1
  • tex2D - возвращает цвет пикселя из текстуры по UV координатам
  • texCUBE -возвращает цвет пикселя из кубической текстуры по вектору
P.S. для подробного описания функции кликните на нее P.S2. цвет представляет собой переменную float4 / half4 / fixed4 (Red, Green, Blue, Alpha), причем каждая составляющая цвета в пределах от 0 до 1.

Model View Projection координаты

А теперь давайте разберемся, как рендерится наша модель на экран. К большому сожалению, наш экран работает в 2D режиме. Он умеет выводить нам 2D изображения. Т.е. нашей задачей является сделать проекцию объемного мира на плоский экран. Эта задача так-же стоит и перед художниками: изобразить объем на плоской бумаге. (Если не понятно о чем идет речь, посмотрите и пересмотрите потом еще раз это видео).
Причем делается это каждый кадр,чтобы было ощущение, что в мониторе мы перемешаемся в 3D пространстве.

Начнем с начала, с модели. Точнее, с вершины этой модели. Что мы о ней знаем? Только ее координаты (x,y,z). Причем эти координаты локальные. Т.е. они известны нам в системе координат, которая построена относительно модели.

локальные — #1 Краткая теория — Unity — DevTribe: инди-игры, разработка, сообщество
локальные

Нам нужно расположить эти координаты на экран так, что бы была проекция 3D мира на 2D экран. Тут нам помогут матрицы. Если кратко, то для того, что бы перевести координаты из одной системы координат в другую, нам нужно перемножить эти координаты на специальную матрицу (перемножение вектора на матрицу дает вектор). Вот, например, для того, что бы делать какие-нибудь расчеты в мировых координатах (координаты вершины в "мировом пространстве"), нам нужно перевести объектные координаты вершины в мировые. Для этого умножим объектные координаты на "мировую матрицу" (4x4 WorldMatrix)

Формула для расчета мировых координат
 (x,y,z) * WorldMatrix
мировые — #1 Краткая теория — Unity — DevTribe: инди-игры, разработка, сообщество
мировые

Теперь наши координаты стали мировыми и мы точно знаем, где в игровом мире расположена данная вершина. Это значит, что мы можем рассчитать освещение, тень, блики, и прочее. В этих же координатах расположены и все остальные игровые объекты. Но нам не достаточно знания одних мировых координат для того, что бы сделать проекцию модели на экран. Более того, мы даже не знаем, попадает ли наша модель в поле видимости камеры.

Следующим шагом для нас станет перевод мировых координат в видовые(система координат относительно камеры).Делается это так-же, путем умножения мировых координат на "матрицу вида" ( 4x4 ViewMatrix)
В итоге у нас:

(x,y,z,) * WorldMatrix * ViewMatrix

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

Передняя сторона куба, которая ближе к нам, больше, чем задняя сторона. Хотя, на самом деле, тут нет никакой передней и задней стороны, ведь это просто плоский рисунок, но с помощью проекции у нас создалось впечатление, что мы смотрим на объемное изображение. То-же должно происходить и у нас. Мы должны сделать проекцию. Делается это, а я думаю вы уже догадались, путем умножение координат камеры на матрицу проекции (4x4 ProjectionMatrix). И вот конечный результат, который можно вывести:

Формула преобразования 3D координат в экранные
(x,y,z) * WorldMatrix * ViewMatrix * ProjectionMatrix 

Все матрицы (World, View, Projection) заданы в движке Unity. А так-же есть сразу результат перемножения трех матриц - UNITY_MATRIX_MVP. Все эти действия, кстати, выполняются в вертексном шейдере.

Я уверен что многим всё-таки это не очень-то понятно.

Для тех, кому нужны детальные объяснения, как это работает

СЕМАНТИКА

Еще один важный вопрос, который стоит затронуть, это семантика входящих/выходящих данных в шейдере. Семантика в шейдере определяет, какой тип данных мы хотим получить на вход или выход: POSITION (позиция), TEXCOORD (uv координаты), NORMAL (нормаль) и т.д. В пиксельном шейдере семантика определяет тип интерполированных данных, полученных из вертексного шейдера. Так как, например, данных о текстурных координатах может быть несколько, к семантике этих данных в конце добавляют в конце: TEXCOORD0, TEXCOORD1, TEXCOORD2

Основные типы семантики:

  • POSITION - позиция вершины в объектных координатах
  • NORMAL - вектор нормали
  • TEXCOORD0 - текстурные координаты
  • COLOR - цвет
  • TANGENT - касательная
  • SV_POSITION - то же, что и POSITION
  • SV_Target - то же, что и цвет

Цвет

В программирование шейдеров мы постоянно сталкиваемся с цветом, поэтому я кратенько затрону эту тему. Цвет, как ,наверное, многим известно, в компьютерной графике кодируется тремя основными цветами: красным, зеленым и синим (r,g,b). Для того чтобы задать цвет в CG, нужно использовать 4d (red, green, blue, alpha) векторы. Каждый компонент этого вектора лежит в отрезке от 0 до 1.

Операции с цветами

  • Сложение/вычитание - смешение цветов. Например, красный + зеленый = желтый. Получается, для того что-бы смешать цвета, нужно сложить/вычесть 2 вектора.
float4 red = float4(1,0,0,0)
float4 green = float4(0,1,0,0)
red+green = ( 1+0,0+1,0+0,0+0)  = (1,1,0,0).  
  • Умножение/деление цветов друг на друга - не скалярное умножение.

Просто умножаем аналогичные компоненты вектора друг на друга.

float4 white = float4(1,1,1,1) 
float4 green = float4(0,1,0,0) 
float4 ColorMult = white*green = (1*0,1*1,1*0,1*0) = (0,1,0,0). 
Отсюда можно сделать вывод, что умножение любого цвета на белый дает точно такой-же цвет, а умножение любого цвета на черный дает черный цвет.
  • Умножение/деление цвета на число - по сути просто

увеличение/уменьшение яркости цвета. Просто умножаем каждую компоненту
вектора на число.

float4 lessGreen = float4(0,0.5,0,0) 
float4 green = lessGreen*2 = (0*2,0.5*2,0*2,0*2) = (0,1,0,0) 

Дополнительный материал

  • Статья на хабре, кстати по программированию шейдеров на юнити, где хорошо описан процесс построения изображения
  • Старая, но тем не менее очень хорошая статья про шейдеры на русском языке. Я бы сказал, что она обязательна к прочтению для тех, кто хочет разобраться в шейдерах.
  • Интересная статья на хабре, тоже про шейдер на Unity, но теперь для террейна. Затронута теория. Советую к прочтению.

Смотрите также:


Комментарии



Приятно прочесть. Спасибо за статью.

Огромное спасибо за эту статью. Это очень ценно и информации по шейдерам крайне мало.

E.S., это только одна статья из всего цикла. В следующих частях разбирают разные типы шейдеров более детально

Справка