Unity Як створити шейдер

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

Unity використовує шейдери, написані такими мовами:

  • Для написання самих шейдерних програм використовується мова програмування під назвою HLSL.
  • Спеціальна мова Unity під назвою ShaderLab використовується для визначення об’єкта Shader, який діє як контейнер для програм shader.

Щоб створити шейдер у Unity, виконайте наведені нижче дії.

Створіть шейдер

  • Клацніть правою кнопкою миші на вікні проекту -> 'Create' -> 'Shader'

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

  1. 'Standard Surface Shader': Цей шейдер розроблений для роботи з Unity's системою фізичного відтворення (PBR). Це дозволяє розробникам створювати матеріали, які реалістично реагують на умови освітлення. Він підтримує різні функції візуалізації, як-от звичайне відображення, віддзеркалення та відображення. Це універсальний шейдер, який забезпечує хороший баланс між реалістичністю та продуктивністю.
  2. 'Unlit Shader': Як випливає з назви, неосвітлений шейдер не враховує умови освітлення. Його часто використовують для відтворення ефектів, які не потребують реалістичного освітлення, наприклад елементів інтерфейсу користувача, систем частинок або спеціальних ефектів. Неосвітлені шейдери зазвичай більш ефективні та можуть бути корисними в ситуаціях, коли потрібен повний контроль над зовнішнім виглядом об’єкта без будь-яких розрахунків освітлення.
  3. 'Image Effect Shader': Шейдери ефект зображення використовуються для застосування ефектів постобробки до всього екрана або певних цілей візуалізації. Вони дозволяють розробникам змінювати остаточне відтворене зображення після завершення основного відтворення. Приклади ефектів зображення включають розмиття, градацію кольорів, спотворення або стилізовані фільтри. Їх можна використовувати для покращення візуальної якості або створення специфічних художніх ефектів.
  4. 'Compute Shader': Обчислювальний шейдер — це тип шейдера, який працює на GPU, але не працює безпосередньо з пікселями. Він використовується для обчислень загального призначення з паралельними даними, що дозволяє розробникам ефективно виконувати складні обчислення або симуляції. Обчислювальні шейдери зазвичай використовуються для таких завдань, як фізичне моделювання, процедурна генерація або обробка даних.
  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
Створення GrabPack в Unity за мотивами Poppy Playtime
Створення ефекту Bullet Time в Unity
Реалізація кінетичних взаємодій в єдності
Реалізація об’єктного пулу в Unity
Створення гри-головоломки в Unity