Egy tetszőleges grafika megjelenítése a képernyőn a mai programokkal szinte gyerekjáték. Legyen szó egy képről, vektorgrafikáról vagy 3D modellről, keretrendszerek tucatjai állnak rendelkezésre, amelyek a probléma nagy részének a megoldását a háttérben elvégzik.
Mindazonáltal, ha valami speciálisat - és főleg egyedit - kell a képernyőre kivarázsolni, akkor a legtöbb esetben még mindig a hardver alapszintjére kell visszanyúlni.
A shader programok segítségével, és némi fantáziával egyszerű elemekből felépített grafikát is fantasztikusan fel lehet turbózni. Ehhez persze türelem, és rengeteg tapasztalat kell, mint minden máshoz.
A blogban található shader-ek elkészítéséhez az nvdia ingyenesen letölthető fxcomposer programjának 2.5-ös verziója ajánlott, de bármely más shader editor is tökéletesen megfelel. A Composer használatához érdemes rögtön a manual-t is letölteni.
Installálás után első lépésben hozz létre egy új projektet (File/New).
A jelenleg teljesen üres projekthez minimum kell egy shader és egy modell.
Az első shader létrehozása: Create/Effect
A megjelenő menüben válaszd a HLSL FX-et, majd a Next gomb megnyomásával már előre beállított effektek közül lehet válogatni.
Egyenlőre válaszd a "empty" lehetőséget. File névnek tetszőlegesen találj ki valamit, pl: "01_basic.fx", majd kattints a next gombra.
A megjelenő panelen láthatod a létrehozásra kerülő effect nevét.
Ezzel el is készült a shader alapja.
Alapbeállítás esetén a bal felső "Materials" ablakban egy fehér kör látható. Ha mégsem, akkor a View/Materials ki/be kapcsolásával ez tetszőlegesen állíthatod.
A modell hozzáadás lényegesen egyszerűbb. Create/Plane
A jobb alsó sarokban, a "Render" ablakban láthatónak kell lennie az imént hozzáadott plane.
A fehér kört drag-drop használatával húzd rá a plane-re, aminek hatására az fehérre változik.
Ezzel a plane mostantól ezt a shadert használja, bármi változtatás esetén a plane követni fogja azt.
A shader kód középen látható, a kommentek kiszedése után így kell kinéznie:
float4x4 WorldViewProj : WorldViewProjection; float4 mainVS(float3 pos : POSITION) : POSITION{ return mul(float4(pos.xyz, 1.0), WorldViewProj); } float4 mainPS() : COLOR { return float4(1.0, 1.0, 1.0, 1.0); } technique technique0 { pass p0 { CullMode = None; VertexShader = compile vs_3_0 mainVS(); PixelShader = compile ps_3_0 mainPS(); } }
A fenti kód tartalmaz mindent, ami egy shader minimális működéséhez kell.
A modell térbeli elhelyezését, transzformációit pontosan tudnia kell a programnak, erre szolgál a
WorldViewProjection. Ez tulajdonképp 3 mátrix szorzata.
WorldViewProjection = World * View * Projection
A World határozza meg a modell eltolását, elforgatását, nagyítását.
A View mondja meg, hogy kamera hol található a térben és épp merre néz
A Projection határozza meg a látószöget, a torzítás valamint a legközelebbi és a legtávolabbi látható távolságot.
Ezt a paramétert az FXComposer automatikusan adja a shader részére. A Saját programodban ezt neked kell kiszámolnod. Ahhoz, hogy az FXComposer tudja, hogy neki ezt a paramétert adni kell, a programban ez muszáj jelezni.
float4x4 WorldViewProj : WorldViewProjection;
A float 4x4 egy mátrix-ot definiál, a WoldViewProj pedig tetszőleges változó elnevezés
Az ezt követő kettőspont és a WolrdViewProjection úgynevezett SEMANTICS.
Ez határozza meg, hogy egy adott változó/paraméter milyen koncepció alapján kerül felhasználásra.
Jelen esetben a composer ebből tudja, hogy ennek a változónak kell átadni a már előre kiszámított mátrixot.
Fontos megjegyezni, hogy ez a SEMANTICS csak az fxcomposer számára érthető.
Ha ez most elsőre nem világos, ne ragadj le itt, a legtöbb példában elegendő lesz, hogy ott van. Ettől függetlenül érdemes a neten pontosan utánaolvasni.
A shader két függvényből áll.
VertexShader: amely minden számítást egyszer végez el a modell összes vertexén.
PixelShader: amely minden pixelen, ahol a model látható lefut.
Ebből következik, hogy mindaz, amit ki lehet számolni a VertexShader-ben, célszerű ott megtenni, hiszen az jóval kevesebbszer fog valószínűleg lefutni, mint a pixelshader.
A VertexShader a modell pozícióját várja input paraméterként, amit a POSTION SEMATICS jelöl.
float3 pos : POSITION
És a shader kimenete a model egy vertexének a pozíciója. Ezt szintén a POSTION SEMATICS jelöli.
float4 mainVS(float3 pos : POSITION) : POSITION
A függvény kiszámítja a vertex pontos helyzetét, majd átadja PixelShader-nek.
A PixelShader visszatérési értéke az a szín, amit a képernyőn meg kell jeleníteni. Ez a COLOR SEMATICS jelöli
float4 mainPS() : COLOR
A függvény pedig jelen esetben egy teljesen fehér értékkel tér vissza.
return float4(1.0, 1.0, 1.0, 1.0);
Az RGB értékek 0-1 között tetszőlegesek lehetnek. Az utolsó paraméter az Alpha áttetszőség értéke.
Ezek a paraméter értékek tetszőlegesen változtathatóak.
pl: return float4(1.0, 0.0, 0.0, 1.0);
Ebben az esetben a plane piros színű lesz.
Minden változtatás után a programot le kell fordítani. Addig nem látható a hatása. Erre szolgál a Compille button vagy a Build/Compille utasítás.
Megjegyzés: Az utolsó paraméter (Alpha) értéke szintén tetszőleges lehet, de ez jelen esetben nem befolyásolja a plane áttetszőségét. Ahhoz, hogy ez megtörténjen további beállításokra van szükség.
A shader következő eleme a technique.
Egy shader tetszőleges számú technique-t tartalmazhat. Ez határozza meg a shader lefutáshoz szükséges opciókat. Pl. az áttetszőséget is itt lehet beállítani.
Minden techniqe tetszőleges számú pass elemet tartalmaz.
A pass határozza meg, hogy melyik VertexShader és melyik PixelShader függvényeket kell lefuttatni.
A CullMode = None; hatására a kirajzolandó plane minden irányból látható.
A plane kirajzolása vagy óramutató járásával megegyezik vagy ellentétes.
A render ablakban az ALT+bal egérgomb használatával lehet az aktuális nézetet változtatni.
Jelen esetben a plane mindkét oldala látható (no culling)
Jelen esetben a plane mindkét oldala látható (no culling)
A CullMode felveheti a "CW" és a "CCW" értékeket.
CullMode = CW; (ne felejtsd el lefordítani a shadert)
Ebben az esetben a plane egyik irányból nem látható.
Valós helyzetben célszerű CW vagy CCW értékre állítani, mert egy adott polygon nagy valószínűséggel úgyis csak az egyik irányból lesz látható.
A megjelenítendő szín kódból történő változtatása elég lassú folyamat. Amennyiben a plane-t zöld színnel szeretnénk kirajzolni, a megfelelő sort át kéne írni, majd újrafordítani az egész kódot.
Ennek egyszerűsítésére az alábbi változtatások szükségesek.
Add hozzá a következő sorokat a program elejéhez.
Add hozzá a következő sorokat a program elejéhez.
float4 customColor :Color < string UIName = "Diffuse Color"; > = {1.0, 1.0, 0.0, 1.0};
Illetve a PixelShader visszatérési értékét írd át az alábbira, majd fordítsd le:
return customColor;
A Jobb felső sarokban (default nézet) látható a properties ablak.
Az ablakban immáron látható egy Diffuse Color elem, ami egy színkiválasztót is tartalmaz. Válassz ki egy tetszőleges színt. Látható, hogy a render ablakban a plane realtime követi.
A Color SEMATICS jelzi az fxcomposer számára, hogy ez a változó egy színt tartalmaz.
A kacsacsőrökben elhelyezett string UIName = "Diffuse Color"; úgynevezett Annotation.
Ez szintén csak az fxComposer számára fontos. Jelen esetben megmondja, hogy a User Interface Panelen milyen névvel szerepeljen ez a változó.
A későbbiekben még számos Annotation használatára lesz példa, egyenlőre bőven elég, hogy a változót értelmesen olvasható névvel el lehet látni.
A leírásban található idegen szavak - főleg a sematics és az annotation - bővebb leírására érdemes a neten rákeresni. Gyakorlásképpen hozz létre még egy Color változót és a PixelShader visszatérési értéke legyen a kettőnek az összege.
Az alábbiakban látható a megoldás:
float4x4 WorldViewProj : WorldViewProjection; float4 customColor :Color < string UIName = "Diffuse Color"; > = {1.0, 1.0, 0.0, 1.0}; float4 newColor :Color < string UIName = "Another Color"; > = {1.0, 1.0, 0.0, 1.0}; float4 mainVS(float3 pos : POSITION) : POSITION{ return mul(float4(pos.xyz, 1.0), WorldViewProj); } float4 mainPS() : COLOR { return customColor + newColor; } technique technique0 { pass p0 { CullMode = none; VertexShader = compile vs_3_0 mainVS(); PixelShader = compile ps_3_0 mainPS(); } }
Nincsenek megjegyzések:
Megjegyzés küldése