IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

1. diel - XNA a HLSL - Prvý shader

V tomto seriáli sa pozrieme na to, ako písať shadery v jazyku HLSL (High Level Shader Language). V XNA to je jediný spôsob, ako shadery môžeme písať. Existujú aj ďalšie jazyky (napríklad pre OpenGL), ale tými sa tu zaoberať nebudeme. Viac menej ale všetko funguje a vyzerá rovnako, pokiaľ to nie je assembler :-)

Čo to je shader

Shader je krátky kus programu, ktorý beží na grafickej karte a nejakým spôsobom ovplyvňuje vykresľovanie trojuholníkov. Môžeme skrze ne naniesť textúru, pridať osvetlenie a ďalšie iné veci. So shader sme vlastne už pracovali BasicEffect nie je nič iné ako shader. Obsahuje základné vykresľovanie, budeme sa ho snažiť nahradiť naším vlastným.

Prvý shader

Ako základ by som asi použil piaty diel, kde máme rotujúce model. Bude sa pre našu vec celkom hodiť. Neobsahuje žiadny komplikovaný kód, ktorý by sa nám plietol. Najprv pridáme do projektu nový shader. Robí sa to podobne ako s pridávaním textúr. Akurát namiesto Add existing item vyberieme Add new item a v okne EffectFile. Ja som ho nazval PrvniShader. Vygeneruje sa nám prakticky celý hotový shader. Poďme sa na neho pozrieť. Prvé, čo skúsené oko zaujme, je, že je syntax vlastne céčkovská a taky že neexistuje zvýrazňovania. Budeme sa bez toho musieť zaobísť. Hneď hore nájdeme naše poznáme 3 matica:

float4x4 World;
float4x4 View;
float4x4 Projection;

Tých sa nezbavíme nikdy. Dátový typ float4x4 nám hovorí, že ide o maticu 4x4. Sú to takzvané parametre. Sú pre všetkých práve vykresľovanie vrcholy rovnaké. Ďalej nasledujú dve štruktúry. Kto nikdy o štruktúrach nepočul, tak je to taká "hlúpa" trieda:

struct VertexShaderInput{
    float4 Position : POSITION0;
};

Prvá štruktúra vyjadruje to, čo do shader vstupuje. Iste si spomínate na to, ako sme tvorili vlastné vertex a práve tá dáta z vertexu tu reprezentuje táto štruktúra. Float4 je vektor o 4-roch hodnotách. Za dvojbodkou potom nájdeme takzvanou sémantiku. Sémantika ako taká dáva onej zložke význam. V tomto prípade sa jedná o pozíciu vertexu. Máme aj ďalšie sémantiky, ale o tých sa budeme baviť neskôr. Druhá štruktúra:

struct VertexShaderOutput{
    float4 Position : POSITION0;
};

sa príliš od tej prvej nelíši. Vlastne vôbec. Hovorí nám informácie o výstupe. Opäť chceme, aby vystupovala pozície vertexu, avšak transformovaná. Ona transformácie sa deje hneď pod:

VertexShaderOutput VertexShaderFunction(VertexShaderInput input){
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    return output;
}

Tomuto úseku sa hovorí vertex shader. Alebo ak časť shader, ktorá pracuje s vertexy. Toto bude pre nás základné kód. Len pre predstavu sa v ňom odohráva transformácie z lokálnych súradníc na súradnice sveta (násobenie World maticou), potom sú súradnice prepočítané do tých ako ich vidí kamera (násobenie maticou View) a na záver transformované z 3D sveta na našu plochú obrazovku (násobenie maticou Projection). Funkcia mul, ako niektorým už došlo, slúži pre násobenie matíc. Ďalšie funkcie, ktorá nasleduje, je takzvaný pixel shader:

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0{
    return float4(1, 0, 0, 1);
}

Ten určuje, akú výslednú farbu bude mať práve opísaná pixel. V našom prípade to bude červená. Poradie farieb je nasledovné: červená, zelená, modrá a alfa alebo ak transparentnosť. Jednička znamená maximálny jas danej farby. Rozsah je od 0 do 1, nie teda ako zvyčajne býva od 0 do 255-tich. Iste si pamätáte, ako sme v bludisku odovzdávali farbu pre podlahy a tú sme práve museli prepočítať pomocou metódy ToVector3. Ideme ďalej, už nám zostáva len kúsok:

technique Technique1{
    pass Pass1{
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

Ešte než vysvetlím o čo sa jedná, dovolím si kus kódu, ktorý sme predtým pri používaní shaderov používali:

Effect.CurrentTechnique.Passes[0].Apply();

V jednom shader totiž môže byť niekoľko "techník", ktoré možno použiť pre vykresľovanie a každá môže mať niekoľko kôl. Väčšinou je to síce len jedno, ale napríklad také rozmazania obrazu sa musia vykonávať na dvakrát, raz vertikálne a druhýkrát horizontálne. Vo vnútri každého kola máme nadefinované, ktoré shadery sa majú použiť a pod akou verzií sa majú skompilovať. My si vystačíme s verziou 2, tá je podporovaná v režime Reach a pre náročnejších veci siahneme pre verziu 3. Tú možno použiť len pre Hi-def profil. Veľa rozdielov medzi nimi nie je. Iba v množstve príkazov, ktoré môžeme zadať a prípadne používať nejaké pokročilé funkcie. Tak by sa dal popísať základné shader.

Používame shader

Prvé, čo musíme urobiť, je si shader nahrať. Urobíme tak v metóde LoadContent:

Effect effect;
effect = Content.Load<Effect>("PrvniShader");

Máme efekt nahraný a pripravený na použitie. Aby ho bolo možné použiť pre vykresľovanie modelu, musíme ním nahradiť BasicEffect ktorý model teraz používa. Preto prejdeme všetky časti modelu a nastavíme im náš shader:

foreach (ModelMesh mesh in model.Meshes){
  foreach (ModelMeshPart part in mesh.MeshParts){
    part.Effect = effect;
  }
}

A už len stačí efekt použiť pri vykresľovaní. Najprv nastavíme spoločné parametre, nie je potreba nastavovať zakaždým znova:

effect.Parameters["View"].SetValue(Matrix.CreateLookAt(new Vector3(100, 150, 0), new Vector3(0, 0, 0), Vector3.Up));
effect.Parameters["Projection"].SetValue(Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDevice.DisplayMode.AspectRatio, 1, 1000));

A pre každú časť modelu nastaviť maticu World:

foreach (ModelMesh mesh in model.Meshes){
  foreach (ModelMeshPart part in mesh.MeshParts){
    part.Effect.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index]*rotace);
  }
  mesh.Draw();
}

Ako ste si všimli, parametre shader sú v kolekcii a pristupujeme k nim cez ich názov. Ak teraz hru pustíte uvidíte niečo takéhoto:

Použitie shader v HLSL v XNA - Tvorba shaderov v HLSL

Gratulujem. Napísali ste prvý shader. Nabudúce si doň pridáme textúru. Čakám na nápady, komentáre, otázky dole pod články ostatne ako vždy skoro márne.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 150x (1.58 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Všetky články v sekcii
Tvorba shaderov v HLSL
Preskočiť článok
(neodporúčame)
XNA a HLSL - Textúry
Článok pre vás napísal vodacek
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Vodáček dělá že umí C#, naplno se již pět let angažuje v projektu ŽvB. Nyní studuje na FEI Upa informatiku, ikdyž si připadá spíš na ekonomice. Není mu také cizí PHP a SQL. Naopak cizí mu je Java a Python.
Aktivity