Автор Тема: Шейдеры в Unity  (Прочитано 7730 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Ноябрь 15, 2013, 12:05:52 pm
Прочитано 7730 раз

Mimi Neko

  • Администратор
  • Старожил форума

  • Оффлайн
  • *****

  • 2453
  • Репутация:
    153
    • Просмотр профиля
Шейдеры в Unity
источник
Автор: pax

Шейдеры в Unity пишутся на специальном языке, который называется ShaderLab. Язык этот не сложный и в этой статье я его попытаюсь описать.
 Конечно большая часть этого урока – содержание справки Unity, но так как у многих проблемы с английским – этот урок будет полезным.

Синтаксис шейдера на языке ShaderLab
// Блок Shader – коневой блок
// он является контейнером для описания шейдера
// через пробел в кавычках указывается имя шейдера
Shader "Имя_шейдера" {

    // Блок параметров, которые пользователь может визуально
    // настраивать в инспекторе, при выборе данного шейдера
    // для материала. Все параметры, описанные в блоке Properties
    // в остальных местах шейдера должны применяться
    // в квадратных скобках.
    Properties {
       // Список параметров
       // например, следующая строка описывает параметр _Color
       // отображаемый в инспекторе как "Main Color" типа
       // Color с начальным значением (1,.5,.5,1):
        _Color ("Main Color", Color) = (1,.5,.5,1)

       // Unity не поддерживает отображение типа Matrix4x4
       // но не смотря на это его можно передавать в шейдер
       // программным путем.
       //
        _SpecColor ("Spec Color", Color) = (1,1,1,1)
        _Emission ("Emmisive Color", Color) = (0,0,0,0)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }

    // SubShader – контейнер, определяющий технику
    // визуализации материала.
    // Блоков SubShader может быть много, Unity выбирает
    // первый подходящий шейдер для видеокарты пользователя
    SubShader {

        // Pass – блок, описывающий один проход визуализации
        // для сложных материалов таких проходов может быть несколько
        Pass {

            // Блок Material назначает параметры материала,
            // которые будут использованы при расчете освещения.
            // например, в данном примере устанавливаются все
            // параметры, необходимые для полноценного вершинного
            // освещения.
            Material {
                Diffuse [_Color]
                Ambient [_Color]
                Shininess [_Shininess]
                Specular [_SpecColor]
                Emission [_Emission]
            }

            // Директива Lighting On|Off определяет
            // использование освещения.
            // Для того чтобы установленные значения блока
            // Material имели силу – освещение должно быть включено
            Lighting On

            // Директива SeparateSpecular определяет, стоит ли
            // добавлять зеркальную (бликовую) составляющую в
            // конце прохода. Чтобы директива имела силу –
            // освещения должно быть включено (Lighting On)
            SeparateSpecular On

            // дополнительные директивы будут описвны ниже

            // Блок SetTexture устанавливает текстуру и метод
            // ее наложения. После названия блока SetTexture
            // в квадратных скобках передается имя параметра,
            // указанного в блоке Properties.
            // Внутри блока может присутствовать от одной
            // до трех команд (Combine, Matrix и ConstantColor).
            // Количество текстурных слотов у разных видеокарт
            // разное, так что количество блоков SetTexture
            // должно выбираться в зависимости от того, какие
            // видеокарты Вы хотите поддерживать. Например,
            // видеокарты NVIDIA TNT2, GeForce 256, GeForce 2,
            // GeForce 4MX имеют 2 текстурных блока, а такие как
            // ATI Radeon 9500 и выше – 4 для D3D и 6-8 для OpenGL
            SetTexture [_MainTex] {

                // Возможности команды Combine можно посмотреть
                // в справке, замечу, что расчет альфы и цвета
                // можно разделить. Формулы комбинации цветов
                // записываются в это случае через запятую.
                Combine texture * primary DOUBLE, texture * primary
            }
        }
    }

    // Директива Fallback определяет то, как поведет себя Unity,
    // если ни одна из техник, определенных в блоках SubShader
    // не поддерживается видеокартой.
    // Имеется две формы записи директивы:
    // Fallback Off – отключает любые предупреждения о том, что
    // ни один из SubShader не поддерживается
    // Fallback "имя_шейдера" – передает все параметры (Properties)
    // и управление другому шейдеру.
    Fallback "Имя_другого_шейдера"
}

Файл шейдера должен иметь кодировку ASCII.

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


 Как и обещал, привожу список основных директив блока Pass:
Cull Back | Front | Off
 Устанавливает тип куллинга полигонов.
ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)
 Устанавливает режим теста глубины.
ZWrite On | Off
 Устанавливает режим записи глубины.
Fog { блок описания тумана }
 Устанавливает параметры тумана.
AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue
 Включает альфатест.
Blend SourceBlendMode DestBlendMode
 Устанавливает режим альфасмешивания.
Color Color value
 Устанавливает цвет, если вершинное освещение отключено.
ColorMask RGB | A | 0 | любая комбинация R, G, B, A
 Маска записи цвета. ColorMask 0 выключает рендеринг для всех цветовых каналов.
Offset OffsetFactor , OffsetUnits
 Устанавливает офсет (смещение) глубины.
ColorMaterial AmbientAndDiffuse | Emission
 Использует цвета вершин для расчета освещения.

Шейдерные программы
 Так же существует возможность применять шейдерные программы, написанные на языке Cg для сложных материалов, в которых необходимы специфические расчеты. Для этого вместо или внутри блока Pass необходимо использовать блок CGPROGRAM
CGPROGRAM
// директивы компиляции:
#pragma vertex vert
#pragma fragment frag

// Cg код

ENDCG

#pragma vertex и #pragma fragment определяют соответственно вершинную и фрагментную функции. Существует так же #pragma target, значениями которой могут быть default и 3.0. В первом случае для компиляции используются vs 1.1 и ps 2.0, во втором – vs 3.0 и ps 3.0. При компиляции для 3.0 – обе директивы #pragma vertex и #pragma fragment должны присутствовать.

 Подробнее об этом ShaderPrograms

 В Unity 3 появились новые возможности для реализации шейдеров – Surface Shaders. Используя эти возможности можно облегчить себе жизнь при написании шейдеров на языке Cg. Подробнее - SurfaceShaders, примеры таких шейдеров.

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

Более углубленно ShaderLab можно изучить читая справку

 UPD: Так же хорошей практикой будет разбор встроенных шейдеров юнити:
 Скачать исходники шейдеров Unity3d
« Последнее редактирование: Июнь 21, 2015, 23:28:56 pm от Mimi Neko »

Ноябрь 15, 2013, 12:30:54 pm
Ответ #1

Mimi Neko

  • Администратор
  • Старожил форума

  • Оффлайн
  • *****

  • 2453
  • Репутация:
    153
    • Просмотр профиля
Writing Surface Shaders (Написание шейдеров поверхности)
Перевод страницы из официального мануала "Writing Surface Shaders"


Достаточно сложно написать шейдер, который бы взаимодействовал с источниками освещения. Существуют различные источники освещения, различные настройки теней, различные типы рендринга (ускоренный и замедленный рендринг). Задача шейдера заключается в совокупной обработке всех этих сложных свойств.
Шейдер поверхности в Unity - это особый метод генерации кода, который позволяет очень просто написать шейдер, чем использовать шейдерные программы. Шейдер поверхности генерирует написанный вами код  Cg/HLSL.
Для примера см. Surface Shader Examples и Surface Shader Custom Lighting Examples.

Как работает шейдер поверхности
Определим "функцию поверхности" (“surface function”), которая будет использовать любую UV-развертку или какие-то данные как входящие данные, и заполним выходящую структуру SurfaceOutput. SurfaceOutput в основном описывает свойства поверхностей (цвет отражения, карта нормалей, эмиссия, зеркальность и т.д.). Этот код пишется на языках Cg/HLSL.

Компилятор шейдера поверхности определяет необходимые входные данные, а также данные, которые получаются на выходе и т.д., затем генерирует вершинные и пиксельные шейдеры (vertex&pixel shaders), а также определяет проходы для ускоренного и замедленного рендринга.

Стандартная структура исходящих данных шейдера поверхности выглядит так:
struct SurfaceOutput {
    half3 Albedo;
    half3 Normal;
    half3 Emission;
    half Specular;
    half Gloss;
    half Alpha;
};



Основные параметры шейдера поверхности

Шейдер поверхности, как и любой другой шейдер, пишется внутри блока CGPROGRAM..ENDCG. Отличия заключаются в:
- шейдер поверхности должен быть написан внутри блока SubShader  (Сабшейдера), но не внутри Pass (Блока Проходов). Шейдер поверхности сам компилирует необходимые проходы.
- используется директива #pragma surface ... для  того, чтобы определить шейдер поверхностей.


Директива #pragma surface записывается таким образом:
#pragma surface surfaceFunction lightModel [optionalparams]


Требуемые параметры:

surfaceFunction – определяет, в какой функции Cg, находится код шейдера поверхности.

Функция должна иметь форму типа void surf  (Input IN, inout SurfaceOutput),
где Input – структура, которую мы определили. Input должен содержать координаты текстур и дополнительные автоматические переменные, необходимые для работы функции поверхности.

lightModel – использование одной из встроенных моделей освещения (Lambert (diffuse) и BlinnPhong (specular)). Чтобы написать собственный источник света см. Custom Lighting Models.


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

alpha – Режим смешивания альфа-канала. Используется для полупрозрачных шейдеров.

alphatest:VariableName – Режим тестирования альфа-канала. Используется для transparent-cutout шейдеров. Пороговое значение задается во float переменной с VariableName.

vertex:VertexFunction – функция модификации вершин. Для примера см. шейдер Tree Bark.

finalcolor:ColorFunction – функция модификации конечного цвета. См. Surface шейдер.

exclude_path:prepass или exclude_path:forward – не генерирует проходы для  rendering path.

addshadow – добавляет тени и проходы для них. Используется при модификации вершин.

dualforward – использует dual lightmaps  (двойной лайтмап) в forward  rendering path (ускоренном типе рендринга) .

fullforwardshadows – поддерживает все виды теней в Forward rendering path.

decal:add - добавляет decal shader (т.е. terrain AddPass).

decal:blend - полупрозрачный decal shader.

softvegetation - ренедрит surface shader при включённом режиме Soft Vegetation.

noambient – не применяет окружающего освещения или  spherical harmonics lights.

novertexlights – не применяет spherical harmonics или per-vertex lights в Forward rendering.

nolightmap – отключает поддержку лайтмапа в шейдере (уменьшает размер шейдера).

nodirlightmap – отключает поддержку directional lightmaps в шейдере (делает шейдер меньше)

noforwardadd – отключает дополнительные проходы в Forward rendering. Шейдер поддерживает один полный directional light со всеми другими источниками света подсчитываемыми   через per-vertex/SH. Также уменьшает размер шейдера.

approxview – Для некоторых шейдеров рассчитывает освещение вершин вместо попиксельного освещения. Это ускоряет процесс рендернига. Когда камера находится близко к поверхности, то попиксельное освещение рассчитывается не совсем корректно.

halfasview – в функции освещения вместо view-direction рассчитывает half-direction вектор. Вектор half-direction рассчитывается попиксельно. Работает быстрее, но не совсем корректно.



Внутри блока CGPROGRAM можно прописать #pragma debug, чтобы компилятор выдал комментарии по поводу вашего кода. В инспекторе можно открыть код шейдера, нажав Open Compiled Shade.


Входные данные для шейдера поверхности
Структура входных данных Input в основном содержит любые координаты текстур необходимые шейдеру. Координатам текстур можно дать имя "uv", которое прописывается после названия текстуры (или используйте  "uv2", чтобы добавить вторую координату текстуры).


Дополнительные параметры в структуре Input:

float3 viewDir - рассчитывает view direction (направление взгляда, от вершины к наблюдателю) для расчета Parallax effects, rim lighting м и т.д.

float4 with COLOR semantic - рассчитывает интерполированный цвет вершин.

float4 screenPos – определяет координаты для эффекта отражения. Например, как  шейдер WetStreet в Dark Unity.

float3 worldPos – рассчитывает позицию в мировой системе координат.

float3 worldRefl – рассчитывает отражение вектора в мировой системе координат, при условии, что шейдер поверхности не прописан в o.Normal. Например, как в шейдере Reflect-Diffuse.

float3 worldNormal - рассчитывает нормаль в мироввой системе координат, при условии, что шейдер поверхности не прописан в o.Normal.

float3 worldRefl; INTERNAL_DATA – рассчитывает вектор отражения в мировой системе координат, при условии, что шейдер поверхности не прописан в o.Normal. Используйте WorldReflectionVector (IN, o.Normal) для того, чтобы получить вектор отражения, основанный на попиксельном освещении карты нормалей.

float3 worldNormal; INTERNAL_DATA – рассчитывает нормаль в мировой системе координат, при условии, что шейдер поверхности не прописан в o.Normal. Используйте WorldReflectionVector (IN, o.Normal) для того, чтобы получить вектор отражения, основанный на попиксельном освещении карты нормалей.
« Последнее редактирование: Июнь 21, 2015, 18:32:19 pm от Mimi Neko »

Ноябрь 15, 2013, 12:32:11 pm
Ответ #2

Mimi Neko

  • Администратор
  • Старожил форума

  • Оффлайн
  • *****

  • 2453
  • Репутация:
    153
    • Просмотр профиля
« Последнее редактирование: Ноябрь 27, 2013, 02:42:19 am от Mimi Neko »