Unity So erstellen Sie einen Shader

Shader ist ein kleines Skript, das mathematische Berechnungen und Algorithmen zur Berechnung der Farbe jedes gerenderten Pixels basierend auf der Lichteingabe und der Materialkonfiguration enthält.

Unity verwendet Shader, die in den folgenden Sprachen geschrieben sind:

  • Zum Schreiben der Shader-Programme selbst wird eine Programmiersprache namens HLSL verwendet.
  • Eine Unity-spezifische Sprache namens ShaderLab wird verwendet, um ein Shader-Objekt zu definieren, das als Container für die Shader-Programme fungiert.

Um einen Shader in Unity zu erstellen, führen Sie die folgenden Schritte aus:

Erstellen Sie einen Shader

  • Klicken Sie mit der rechten Maustaste auf die Projektansicht -> 'Create' -> 'Shader'

Abhängig von der Unity-Version, die Sie verwenden, können die Shader-Optionen unterschiedlich sein, aber hier ist, was jede der Optionen bedeutet:

  1. 'Standard Surface Shader': Dieser Shader ist für die Verwendung mit dem Unity's Physically Based Rendering (PBR)-System konzipiert. Es ermöglicht Entwicklern, Materialien zu erstellen, die realistisch auf Lichtverhältnisse reagieren. Es unterstützt verschiedene Rendering-Funktionen wie Normal Mapping, Glanzlichter und Reflexionen. Es handelt sich um einen vielseitigen Shader, der eine gute Balance zwischen Realismus und Leistung bietet.
  2. 'Unlit Shader': Wie der Name schon sagt, berücksichtigt ein unbeleuchteter Shader die Lichtverhältnisse nicht. Es wird häufig zum Rendern von Effekten verwendet, die keine realistische Beleuchtung erfordern, z. B. UI-Elemente, Partikelsysteme oder Spezialeffekte. Unbeleuchtete Shader sind in der Regel effizienter und können in Situationen nützlich sein, in denen eine vollständige Kontrolle über das Erscheinungsbild eines Objekts ohne Beleuchtungsberechnungen erforderlich ist.
  3. 'Image Effect Shader': Die Bildeffekt-Shader werden verwendet, um Nachbearbeitungseffekte-Effekte auf den gesamten Bildschirm oder bestimmte Renderziele anzuwenden. Sie ermöglichen es Entwicklern, das endgültig gerenderte Bild zu ändern, nachdem das Hauptrendering abgeschlossen ist. Beispiele für Bildeffekte sind Unschärfe, Farbkorrektur, Verzerrung oder stilisierte Filter. Sie können zur Verbesserung der visuellen Qualität oder zur Erzielung spezifischer künstlerischer Effekte eingesetzt werden.
  4. 'Compute Shader': Ein Compute-Shader ist eine Art Shader, der auf der GPU läuft, aber nicht direkt auf Pixeln arbeitet. Es wird für allgemeine Berechnungen mit parallelen Daten verwendet und ermöglicht Entwicklern die effiziente Durchführung komplexer Berechnungen oder Simulationen. Compute-Shader werden häufig für Aufgaben wie Physiksimulationen, prozedurale Generierung oder Datenverarbeitung verwendet.
  5. 'Ray Tracing Shader': Raytracing-Shader nutzen die Raytracing-Technologie, die das Verhalten von Licht im Vergleich zu herkömmlichen Rasterisierungstechniken genauer simuliert. Raytracing-Shader werden typischerweise verwendet, um in Echtzeitanwendungen äußerst realistische Beleuchtung, Reflexionen und Schatten zu erzielen. Sie erfordern leistungsstarke Hardware und werden häufig in grafikintensiven Bereichen wie Spielen oder Architekturvisualisierung eingesetzt.
  • Geben Sie nach Auswahl des Shaders einen beliebigen Namen ein und drücken Sie die Eingabetaste

Der neue Shader wird erstellt und kann in jedem Skripteditor geöffnet und an Ihre Bedürfnisse angepasst werden.

Standard '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"
}

Standard '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
        }
    }
}

Standard '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
        }
    }
}

Standard '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);
}

Standard '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);
}

Abschluss

Jeder Shader-Typ hat seine eigenen Stärken und Einsatzmöglichkeiten. Es ist wichtig, den geeigneten Shader basierend auf Ihren spezifischen Anforderungen und den visuellen Effekten auszuwählen, die Sie in Ihrem Projekt erzielen möchten.