Shadery w Unity
Wstęp Potok renderowania w Unity korzysta z trzech podstawowych elementów: Trójwymiarowe modele Unity korzysta z modeli w formacie *.fbx (wspierane są też inne formaty ale są one konwertowane w tle do *.fbx) Materiały jest to interfejs pozwalający inicjalizować programy cieniowania odpowiednimi danymi (teksturami i właściwościami) Programy cieniujące skrypty przetwarzające wierzchołki i fragmenty w celu określenia koloru odpowiednich pikseli na ekranie
Dostępne jednostki cieniowania Surface Shader Wysokopoziomowy program cieniowania zalecany przy efektach korzystających ze świateł. Rozbijany jest później na serię jednostek cieniujących wierzchołki oraz fragmenty Vertex&Fragment Shaders Zgodnie z nazwą jednostki cieniowania odpowiedzialne za przetwarzanie wierzchołków i fragmentów Dostępne są również nowsze jednostki (geometry, hull i domain shader y) ale ich nie będziemy poruszać
Dostępne jednostki cieniowania cd. Fixed Function Shaders Przestarzałe rozwiązanie bazujące na stałym potoku renderowania Zbiór funkcji wykonujących podstawowe operacje (np. mieszanie kolorów, tekstur, wykorzystanie podstawowych modeli oświetlenia itp.)
ShaderLab wstęp Językiem wykorzystywanym w Unity do tworzenia programów cieniowania jest ShaderLab Na początku pliku zdefiniowana jest nazwa programu -> Shader MyShader Ciało programu zawiera: Sekcję z własnościami programu cieniowania -> Properties własności te można ustawiać z poziomu edytora Unity Shader "MyShader" Properties // SubShader CGPROGRAM // ENDCG SubShader Fallback "Diffuse"
ShaderLab wstęp cd. Zbiór sekcji z różnymi wersjami programu -> SubShader sprawdzając od góry uruchamiana jest pierwsza napotkana wersja, która może zostać wykonana na dostępnej karcie graficznej jeżeli żadna wersja nie może zostać wykonana, korzystając ze słowa kluczowego Fallback możemy wyznaczyć, inny (zastępczy) program cieniowania Kod programu (język GLSL/CG) znajduje się pomiędzy dyrektywami CGPROGRAM ENDCG Shader "MyShader" Properties // SubShader CGPROGRAM // ENDCG SubShader Fallback "Diffuse"
ShaderLab sekcja Properties Właściwości definiujemy w formacie: nazwa (etykieta, typ) = wartość_domyślna Podstawowe typy danych: 2D sampler2d (tekstura), domyślną wartością może być np. white, black, gray, bump (normal mapa) Cube samplercube (6 tekstur tworzących kostkę), Int, Float (Range) Color Vector (zawsze czterowymiarowy) Shader "MyShader" Properties _MyTexture ("My texture", 2D) = "white" _MyNormalMap ("My normal map", 2D) = "bump // Grey _MyInt ("My integer", Int) = 2 _MyFloat ("My float", Float) = 1.5 _MyRange ("My range", Range(0.0, 1.0)) = 0.5 _MyColor ("My colour", Color) = (1, 0, 0, 1) // (R, G, B, A) _MyVector ("My Vector4", Vector) = (0, 0, 0, 0) // (x, y, z, w)
ShaderLab sekcja SubShader Sekcja SubShader ma zazwyczaj następującą strukturę: Tagi i ustawienia programu cieniowania Kod programu w języku GLSL/CG (pomiędzy dyrektywami CGPROGRAM ENDCG) Dyrektywy kompilacji SubShader Tags "RenderType"="Opaque "Queue"="Geometry+1" "ForceNoShadowCasting"="True" LOD 200 Offset -1, -1 CGPROGRAM #pragma surface surf Lambert decal:blend sampler2d _MainTex; struct Input float2 uv_maintex; ; Deklaracje zmiennych globalnych Deklaracje struktur danych wejściowych i/lub wyjściowych Kod jednostek cieniowania void surf (Input IN, inout SurfaceOutput o) half4 c = tex2d (_MainTex, IN.uv_MainTex); o.albedo = c.rgb; o.alpha = c.a; ENDCG
ShaderLab sekcja SubShader Tagi i ustawienia programu cieniowania https://docs.unity3d.com/manual/sl-subshadertags.html Dokumentacja opisuje 7 podstawowych tagów: Dwa najważniejsze: Queue, RenderType Queue - określa kolejność wyświetlania na ekranie. Parametrem jest liczba. Istnieje kilka stałych takich jak: Background, Geometry, AlphaTest, Transparent, Overlay RenderType określa sposób wyświetlania wyniku. Z najważniejszych typów wyróżnić można: Opaque nieprzezroczysty, Transparent (pół)przezroczysty, TransparentCutout (pół)przezroczyste fragmenty są obcinane
ShaderLab sekcja SubShader Tagi i ustawienia programu cieniowania cd. Pozostałe: DisableBatching, ForceNoShadowCasting, IngoreProjector, CanUseSpriteAtlas, PreviewType Ustawienia mogą dotyczyć między innymi: Bufora głębi: Cull [Back Front Off], ZWrite [On Off], ZTest [Less Greater Equal ], Offset [Factor Units], Świateł: Lighting [On Off] Level of Details: LOD [liczba]
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Dyrektywy kompilacji Na podstawie tych dyrektyw karta graficzna określa, która sekcja SubShader powinna zostać wybrana Pozwalają określić wymaganą wersję OpenGL/DirectX Umożliwiają ograniczenie użyteczności materiału do określonych komponentów Unity (Renderer ów) Dyrektywy pozwalają wczytywać pliki biblioteczne Za pomocą dyrektyw deklaruje się jednostki cieniowania #include "UnityCG.cginc" #pragma surface surfacefunction lightmodel [optionalparams] #pragma vertex name #pragma fragment name #pragma geometry name #pragma hull name #pragma domain name #pragma target name #pragma only_renderers space_separated_names #pragma exclude_renderers space_separated_names #pragma multi_compile #pragma enable_d3d11_debug_symbols #pragma hardware_tier_variants renderer_name
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Deklaracje zmiennych globalnych Aby używać właściwości nie wystarczy zadeklarowanie ich w sekcji Properties Wymagana jest deklaracja zmiennych globalnych do których zostaną przypisane wartości nazwy muszą się zgadzać z nazwami w sekcji Properties Typy mogą być bardziej restrykcyjne np. ograniczenie wektorów do dwóch lub trzech wymiarów, zmniejszenie dokładności float a do half itp. Properties _MyTexture ("My texture", 2D) = "white" _MyNormalMap ("My normal map", 2D) = "bump" _MyInt ("My integer", Int) = 2 _MyFloat ("My float", Float) = 1.5 _MyRange ("My range", Range(0.0, 1.0)) = 0.5 _MyColor ("My colour", Color) = (1, 0, 0, 1) _MyVector ("My Vector4", Vector) = (0, 0, 0, 0) SubShader CGPROGRAM sampler2d _MyTexture, _MyNormalMap; int _MyInt; float _MyFloat, _MyRange; half4 _MyColor; float4 _MyVector; ENDCG
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Deklaracje struktur danych Istnieje możliwość zdefiniowania struktur danych wejściowych i wyjściowych z poszczególnych jednostek cieniujących Surface Shader y (https://docs.unity3d.com/manual/sl- SurfaceShaders.html) Istnieją trzy struktury danych wyjściowych: SurfaceOutput (standard z Unity 4 - materiały Diffuse lub Specular) SurfaceOutputStandard i SurfaceOutputStandard Specular (standard z Unity 5 materiały Standard) #pragma surface surf Lambert struct Input float4 color : COLOR; ; void surf (Input IN, inout SurfaceOutput o) o.albedo = 1; // 1 = (1,1,1,1) = white
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Deklaracje struktur danych cd. Dane wejściowe dla Surface Shader ów należy zdefiniować. Mogą zawierać: Koordynaty tekstury (zmienne zaczynające się na uv_ lub uv2_) Interpolowany kolor piksela (zmienna z wiązaniem : COLOR) pozycję na ekranie i w świecie Wektory odbicia i normalne #pragma surface surf Lambert struct Input float4 color : COLOR; ; void surf (Input IN, inout SurfaceOutput o) o.albedo = 1; // 1 = (1,1,1,1) = white
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Deklaracje struktur danych cd. Vertex & Fragment Shader y Dla tych jednostek cieniujących trzeba zdefiniować strukturę wejściową i wyjściową (dla Vertex Shader a mogą to być parametry wywołania) Przypisywanie wartości opiera się na wiązaniach jak TEXCOORD0, SV_POSITION itp. (listę dostępnych wiązań można znaleźć w dokumentacji) Vertex Shader zwraca strukturę, która jest wejściem do Fragment Shader a Fragment Shader zwraca obliczony kolor fragmentu (typ fixed4 powiązany z SV_Target) #pragma vertex vert #pragma fragment frag struct v2f float2 uv : TEXCOORD0; float4 pos : SV_POSITION; ; v2f vert (float4 vertex : POSITION, float2 uv : TEXCOORD0) v2f o; o.pos = UnityObjectToClipPos(vertex); o.uv = uv; return o; fixed4 frag (v2f i) : SV_Target return fixed4(i.uv, 0, 0);
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Kod jednostek cieniowania Przykłady (Surface Shader) Simple Diffuse tylko światło rozposzone Textured model z teksturą Bumped dodana normal mapa Rim poświata dookoła obiektu Sliced wycięta część fragmentów Cubemap dodane odbicie (z cubemap y) Details dodana druga tekstura z detalami VertexData wyświetlenie normalnych Normals Extrusion wyciągnięcie modelu wzdłuż normalnych Snow efekt pokrywy śnieżnej
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Kod jednostek cieniowania cd. Przykłady (Fragment Shader) VertexLit tylko tekstura, bez świateł SolidColor jednolity kolor UV kolory koordynatów tekstury Vpos wycięcie szachownicy w modelu Vface pokolorowanie front i back face ów Vertex1d przekształcenie współrzędnej w losowe kolory WrlSpN wyświetlenie normalnych (globalnych) Triplanar tekstura naniesiona z trzech kątów
ShaderLab sekcja SubShader Kod programu w języku GLSL/CG - Kod jednostek cieniowania cd. Przykłady (Fragment Shader) SkyRefl odbicie nieba na powierzchni obiektu ManyTex wiele tekstur naniesionych na obiekt ChBoard wzór szachownicy wygenerowany na obiekcie Diffuse światło rozproszone Ambient światło otoczenia ShadCast rzucanie cienia ShadRecv wyświetlenie cieni innych obiektów
ShaderLab sekcja SubShader Zaawansowane czas w jednostkach cieniujących Przykłady Falująca podłoga Wyciąganie wierzchołków wzdłuż normalnych zależnie od czasu Dostępne zmienne: _Time[4] = t/20, t, t*2, t*3 _SinTime[4] = sin(t/8), sin(t/4), sin(t/2), sin(t) gdzie t to aktualny czas
ShaderLab sekcja SubShader Zaawansowane programy cieniujące wykorzystujące wiele przejść Niektórych efektów nie da się uzyskać za pomocą pojedynczej sekwencji jednostek cieniowania Z tego powodu wprowadzony został mechanizm przejść (ang. Pass) Każde kolejne przejście może korzystać z danych wyjściowych poprzedniego przejścia zapisanych w odpowiednich buforach Przykładem wykorzystania jest użycie predefiniowanego przejścia GrabPass, które zwraca fragment obrazu zasłanianego przez nasz obiekt Pozwala stworzyć takie materiały jak szkło czy woda
Physically based rendering Model oświetlenia oparty na właściwościach fizycznych materiałów Kosztowniejszy od wcześniejszych podejść opartych o światło rozproszone (Diffuse) i odbicia lustrzane (Specular) Dający bardziej realistyczne efekty i więcej możliwości Unity dostarcza dwie wersje materiałów: lustrzaną i metaliczną
Physically based rendering Wersja metaliczna (metallic) Wersja metaliczna zawiera trzy parametry: Kolor bazowy materiału Poziom gładkości Poziom metaliczności
Physically based rendering Wersja lustrzana (specular) Wersja lustrzana zawiera trzy parametry: Kolor bazowy materiału Poziom gładkości Kolor odbicia lustrzanego
Substance (by Allegorithmic) Alternatywa do pisania zaawansowanych programów cieniujących ręcznie Substance Designer Produkt firmy Allegorithmic pozwalający na tworzenie materiałów za pomocą łączenia bloczków Możliwość eksportu materiału do silników gier takich jak Unity czy Unreal Engine 4
Substance (by Allegorithmic) Przykład materiałów generowanych dynamicznie Na podstawie parametrów generowane są tekstury oraz prostszy materiał, który z nich korzysta Parametry można modyfikować w czasie działania aplikacji (generacja nowej tekstury może być kosztowne) Parametry definiuje się tworząc substancję w Substance Designer ze
Materiały https://docs.unity3d.com/manual/sl-reference.html https://docs.unity3d.com/manual/graphicstutorials.html http://http.developer.nvidia.com/cg/ http://www.alanzucconi.com/2015/06/10/a-gentle-introduction-to-shaders-inunity3d/ https://blogs.unity3d.com/2015/02/18/working-with-physically-based-shadinga-practical-approach/ https://unity3d.com/learn/tutorials/topics/graphics https://www.allegorithmic.com/ https://github.com/podmuch/shadersoverview.git