Unity Jak utworzyć moduł cieniujący

Shader to mały skrypt zawierający obliczenia matematyczne i algorytmy obliczania koloru każdego renderowanego piksela w oparciu o oświetlenie wejściowe i konfigurację materiału.

Unity używa Shaderów napisanych w następujących językach:

  • Do pisania samych programów cieniujących używany jest język programowania zwany HLSL.
  • Język specyficzny dla Unity, zwany ShaderLab, jest używany do definiowania obiektu Shader, który działa jako kontener dla programów cieniujących.

Aby utworzyć moduł cieniujący w Unity, wykonaj poniższe czynności:

Utwórz moduł cieniujący

  • Kliknij prawym przyciskiem myszy widok projektu -> 'Create' -> 'Shader'

W zależności od używanej wersji Unity opcje modułu cieniującego mogą się różnić, ale oto znaczenie każdej z nich:

  1. 'Standard Surface Shader': Ten moduł cieniujący jest przeznaczony do współpracy z Unity's systemem renderowania opartego na fizyce (PBR). Pozwala programistom tworzyć materiały realistycznie reagujące na warunki oświetleniowe. Obsługuje różne funkcje renderowania, takie jak normalne mapowanie, odbicia lustrzane i odbicia. To wszechstronny moduł cieniujący zapewniający dobrą równowagę pomiędzy realizmem a wydajnością.
  2. 'Unlit Shader': Jak sama nazwa wskazuje, nieoświetlony moduł cieniujący nie bierze pod uwagę warunków oświetleniowych. Jest często używany do renderowania efektów, które nie wymagają realistycznego oświetlenia, takich jak elementy interfejsu użytkownika, systemy cząstek lub efekty specjalne. Nieoświetlone shadery są zazwyczaj bardziej wydajne i mogą być przydatne w sytuacjach, gdy wymagana jest pełna kontrola nad wyglądem obiektu bez żadnych obliczeń oświetlenia.
  3. 'Image Effect Shader': Shadery efektu obrazu służą do stosowania efektów post-processingu na całym ekranie lub określonych obiektach renderowania. Umożliwiają programistom modyfikowanie ostatecznego wyrenderowanego obrazu po zakończeniu głównego renderowania. Przykłady efektów obrazu obejmują rozmycie, gradację kolorów, zniekształcenie lub filtry stylizowane. Można je wykorzystać do podniesienia jakości wizualnej lub stworzenia określonych efektów artystycznych.
  4. 'Compute Shader': Moduł cieniujący obliczeniowy to rodzaj modułu cieniującego, który działa na GPU, ale nie działa bezpośrednio na pikselach. Służy do obliczeń ogólnego przeznaczenia na danych równoległych, umożliwiając programistom wydajne wykonywanie złożonych obliczeń lub symulacji. Moduły cieniujące obliczeniowe są powszechnie używane do zadań takich jak symulacje fizyki, generowanie procedur lub przetwarzanie danych.
  5. 'Ray Tracing Shader': Shadery wykorzystujące śledzenie promieni wykorzystują technologię śledzenia promieni, która dokładniej symuluje zachowanie światła w porównaniu z tradycyjnymi technikami rasteryzacji. Moduły cieniujące wykorzystujące śledzenie promieni są zwykle używane do uzyskiwania wysoce realistycznego oświetlenia, odbić i cieni w aplikacjach czasu rzeczywistego. Wymagają wydajnego sprzętu i często są wykorzystywane w dziedzinach intensywnie wykorzystujących grafikę, takich jak gry lub wizualizacje architektoniczne.
  • Po wybraniu modułu cieniującego wpisz dowolną nazwę i naciśnij Enter

Utworzony zostanie nowy Shader, który można otworzyć w dowolnym edytorze skryptów i zmodyfikować zgodnie z własnymi potrzebami.

Domyślny '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"
}

Domyślnie '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
        }
    }
}

Domyślnie '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
        }
    }
}

Domyślny '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);
}

Domyślny '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);
}

Wniosek

Każdy typ modułu cieniującego ma swoje mocne strony i zastosowania. Ważne jest, aby wybrać odpowiedni moduł cieniujący w oparciu o konkretne wymagania i efekty wizualne, które chcesz osiągnąć w swoim projekcie.

Sugerowane artykuły
Jak odtwarzać pliki wideo w Unity
Tworzenie efektu drgań aparatu w Unity
Implementowanie niestandardowej szybkości aktualizacji w Unity
Jak dodać efekt lunety snajperskiej w Unity
Tworzenie prostego systemu pocisków 2D w Unity
Jak wstrzymać grę w Unity
Metody na początku środowiska wykonawczego, które inicjują wartości w jedności