Unity איך ליצור Shader

Shader הוא סקריפט קטן המכיל חישובים מתמטיים ואלגוריתמים לחישוב הצבע של כל פיקסל שעובד, בהתבסס על קלט התאורה ותצורת החומר.

Unity משתמש ב-Shaders הכתובים בשפות הבאות:

  • שפת תכנות בשם HLSL משמשת לכתיבת תוכניות ההצללה עצמן.
  • שפה ספציפית ל-Unity הנקראת ShaderLab משמשת להגדרת אובייקט Shader, שפועל כמיכל לתוכניות הצללה.

כדי ליצור הצללה ב-Unity, בצע את השלבים הבאים:

צור Shader

  • לחץ לחיצה ימנית על תצוגת הפרויקט -> 'Create' -> 'Shader'

בהתאם לגרסת Unity שבה אתה משתמש, אפשרויות ה-Shader עשויות להיות שונות, אבל הנה המשמעות של כל אחת מהאפשרויות:

  1. 'Standard Surface Shader': הצללה זו תוכננה לעבוד עם מערכת העיבוד הפיזי (PBR) של Unity. זה מאפשר למפתחים ליצור חומרים המגיבים לתנאי תאורה בצורה מציאותית. הוא תומך בתכונות רינדור שונות כמו מיפוי רגיל, הדגשות מרהיבות והשתקפויות. זהו מכשיר הצללה רב-תכליתי המספק איזון טוב בין ריאליזם לביצועים.
  2. 'Unlit Shader': כפי שהשם מרמז, הצללה לא מוארת אינה מתחשבת בתנאי תאורה. הוא משמש לעתים קרובות לעיבוד אפקטים שאינם זקוקים לתאורה מציאותית, כגון רכיבי ממשק משתמש, מערכות חלקיקים או אפקטים מיוחדים. הצללים לא מוארים הם בדרך כלל יעילים יותר ויכולים להיות שימושיים במצבים שבהם זה דורש שליטה מלאה על המראה של אובייקט ללא כל חישובי תאורה.
  3. 'Image Effect Shader': הצללות אפקט תמונה משמשות להחלת אפקטים של פוסט-עיבוד על כל המסך או על יעדי רינדור ספציפיים. הם מאפשרים למפתחים לשנות את התמונה המעובדת הסופית לאחר השלמת העיבוד הראשי. דוגמאות לאפקטים של תמונה כוללות טשטוש, דירוג צבע, עיוות או פילטרים מסוגננים. ניתן להשתמש בהם כדי לשפר את האיכות החזותית או ליצור אפקטים אמנותיים ספציפיים.
  4. 'Compute Shader': הצללה ממוחשבת היא סוג של הצללה שפועלת על ה-GPU אך אינה פועלת על פיקסלים ישירות. הוא משמש לחישובים למטרות כלליות על נתונים מקבילים, ומאפשר למפתחים לבצע חישובים מורכבים או סימולציות ביעילות. הצללות מחשוב משמשות בדרך כלל למשימות כמו הדמיות פיזיקה, יצירת פרוצדורות או עיבוד נתונים.
  5. 'Ray Tracing Shader': הצללים למעקב אחר קרניים משתמשים בטכנולוגיית מעקב אחר קרניים, המדמה את התנהגות האור בצורה מדויקת יותר בהשוואה לטכניקות רסטר מסורתיות. הצללים למעקב אחר קרני משמשים בדרך כלל להשגת תאורה, השתקפויות וצללים מציאותיים ביותר ביישומים בזמן אמת. הם דורשים חומרה רבת עוצמה ומשמשים לעתים קרובות בתחומים עתירי גרפיקה כמו משחקים או הדמיה ארכיטקטונית.
  • לאחר בחירת הצללה, הקלד כל שם והקש Enter

ה-Shader החדש נוצר וניתן לפתוח אותו בכל עורך סקריפט ולשנות אותו כך שיתאים לצרכים שלך.

ברירת מחדל '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);
}

סיכום

לכל סוג הצללה יש חוזקות ושימושים משלו. חשוב לבחור את ההצללה המתאים על סמך הדרישות הספציפיות שלך והאפקטים החזותיים שאתה שואף להשיג בפרויקט שלך.