Unity: как создать шейдер

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

Unity использует шейдеры, написанные на следующих языках:

  • Язык программирования под названием HLSL используется для написания самих программ шейдеров.
  • Специальный для Unity язык под названием ShaderLab используется для определения объекта Shader, который действует как контейнер для программ шейдера.

Чтобы создать шейдер в формате Unity, выполните следующие действия:

Создать шейдер

  • Щелкните правой кнопкой мыши представление проекта -> 'Create' -> 'Shader'

В зависимости от используемой вами версии Unity параметры шейдера могут различаться, но вот что означает каждый из параметров:

  1. 'Standard Surface Shader': Этот шейдер предназначен для работы с Unity's системой физически основанного рендеринга (PBR). Это позволяет разработчикам создавать материалы, которые реалистично реагируют на условия освещения. Он поддерживает различные функции рендеринга, такие как отображение нормалей, зеркальные блики и отражения. Это универсальный шейдер, обеспечивающий хороший баланс между реализмом и производительностью.
  2. 'Unlit Shader': Как следует из названия, неосвещенный шейдер не учитывает условия освещения. Его часто используют для рендеринга эффектов, не требующих реалистичного освещения, таких как элементы пользовательского интерфейса, системы частиц или специальные эффекты. Шейдеры без освещения обычно более эффективны и могут быть полезны в ситуациях, когда требуется полный контроль над внешним видом объекта без каких-либо расчетов освещения.
  3. 'Image Effect Shader': Шейдеры image effect используются для применения эффектов постобработки ко всему экрану или определенным объектам рендеринга. Они позволяют разработчикам изменять окончательно визуализированное изображение после завершения основного рендеринга. Примеры эффектов изображения включают размытие, цветокоррекцию, искажение или стилизованные фильтры. Их можно использовать для улучшения визуального качества или создания особых художественных эффектов.
  4. 'Compute Shader': Вычислительный шейдер — это тип шейдера, который работает на графическом процессоре, но не работает с пикселями напрямую. Он используется для вычислений общего назначения с параллельными данными, позволяя разработчикам эффективно выполнять сложные вычисления или моделирование. Вычислительные шейдеры обычно используются для таких задач, как физическое моделирование, процедурная генерация или обработка данных.
  5. 'Ray Tracing Shader': Шейдеры с трассировкой лучей используют технологию трассировки лучей, которая имитирует поведение света более точно по сравнению с традиционными методами растеризации. Шейдеры с трассировкой лучей обычно используются для достижения очень реалистичного освещения, отражений и теней в приложениях реального времени. Они требуют мощного оборудования и часто используются в областях с интенсивным использованием графики, таких как игры или архитектурная визуализация.
  • После выбора шейдера введите любое имя и нажмите Enter.

Новый шейдер создан, его можно открыть в любом редакторе сценариев и изменить в соответствии с вашими потребностями.

По умолчанию 'Standard Surface Shader':

Shader "Custom/NewSurfaceShader"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

По умолчанию 'Unlit Shader':

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

По умолчанию 'Image Effect Shader':

Shader "Hidden/NewImageEffectShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                // just invert the colors
                col.rgb = 1 - col.rgb;
                return col;
            }
            ENDCG
        }
    }
}

По умолчанию 'Compute Shader':

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    // TODO: insert actual code here!

    Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}

По умолчанию 'Ray Tracing Shader':

RWTexture2D<float4> RenderTarget;

#pragma max_recursion_depth 1

[shader("raygeneration")]
void MyRaygenShader()
{
    uint2 dispatchIdx = DispatchRaysIndex().xy;
   
    RenderTarget[dispatchIdx] = float4(dispatchIdx.x & dispatchIdx.y, (dispatchIdx.x & 15)/15.0, (dispatchIdx.y & 15)/15.0, 0.0);
}

Заключение

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

Рекомендуемые статьи
Как заставить объект следовать за курсором мыши в Unity
Как воспроизводить видеофайлы в Unity
Как добавить эффект снайперского прицела в Unity
Создание GrabPack в Unity, вдохновленное Poppy Playtime
Создание эффекта Bullet Time в Unity
Использование контроллера Runtime Animator в Unity
Реализация пула объектов в Unity