3Dc: nagyobb részletesség
Egy számolási művelet általában egy nagyságrenddel gyorsabban zajlik le, mint egy memóriaművelet. Számoláshoz az adatokat speciális, nagyon gyorsan elérhető tárolóhelyekről (regiszterekből) olvassa ki (és írja be) a hardver. Sajnos ezek a gyors elérésű tárolók nagyon drágák és kicsi a kapacitásuk, nem fér el bennük az összes feldolgozandó adat, ezért van szükség nagy memóriákra, amelyek a kiszámolt eredményeket és a feldolgozásra váró adatokat tárolják. A memória írása vagy olvasása sokkal összetettebb művelet egy számolásnál: ki kell keresni a kívánt adat címét a memóriából, majd a címhez tartozó adatot (esetleg még további címen lévő adatot), ezt regiszterbe kell írni, majd az eredménnyel ugyanezt a folyamatot visszafelé eljátszani. A memóriaműveletek másik hátráltató tulajdonsága a véges memória-sávszélesség. Előfordulhat, hogy a sok párhuzamos írást/olvasást a memória csak késéssel tudja végrehajtani. Sávszélességet spórolhatunk kevesebb írással vagy olvasással (pl.Z-buffer technikák) vagy kevesebb adat mozgatásával (tömörítés). És ebben a pontban ütköznek a programozó és a hardver érdekei. A kóder szeretne minél részletesebb és nagyobb memóriát igénylő textúrákat használni, de ez a memória-sávszélesség rovására megy.
Az egyre nagyobb számolási teljesítménnyel rendelkező grafikus lapkáknál szinte adja magát a tömörítés ötlete: tömörítsük be az adatot, hogy kisebb legyen, ezt a kisebb adatot írjuk a memóriába, ha megint ki kell olvasni, akkor majd kitömörítjük. Az első ilyen tömörítési eljárást az S3 dolgozta ki a Savage sorozat megjelenésekor, ezzel próbálták kiküszöbölni a 64 bites memóriavezérlő hátrányait. Régi motorosok még emlékezhetnek az Unreal Tournamenthez mellékelt második CD-re, amelyen az S3-as kártyákhoz használható tömörített textúrák voltak, melyekkel akkoriban elképzelhetetlen képminőséget lehetett előcsalogatni.
Ma már minden videokártya ismeri a szokásos DXTC (DirectX texture Compression) eljárásokat, ezeknek egy bajuk van csak, a pontosságuk:
Látható, hogy a 3Dc sokkal jobb képminőséget biztosít, holott ugyanazt a 4:1 tömörítési arányt nyújtja mint a DXTC
Bump Mapping
Tipikusan nagy pontosságú textúrákat igényel a Bump Mapping eljárás, amivel finom domborzati mintákat lehet rácsalni a sima felületekre. Ennek a módszernek többféle megvalósítása létezik és nem éppen új keletű – már a DirectX 7-nek is a része volt. Eddig nem sokan próbálták bemutatni a szélesebb olvasóközönségnek, mi most belevágunk.
Az alapkérdés: mitől látszik egy felület domborúnak vagy egyenetlennek? Attól, hogy a fény nem egyenletesen verődik róla vissza, hanem az egyenetlenségeknek megfelelően szétszóródik. Ennek a szétszóródásnak a mértékét rögzíteni lehet egy ügyesen megszerkesztett textúrában, ezt szokták bump mapnek vagy normal mapnek nevezni. Tipikusan a map (térkép) jelzőt szokták használni olyan textúrákhoz, amelyek nem színt hanem valami más tulajdonságot kódolnak a pixel (vagy vertex) számításokhoz: vesszük a pixelünket, a térképekben kikeressük a megfelelő tulajdonságokat és ezekkel számolunk.
Szóval egy normal map a normálisok térképe. A normális az éppen aktuális képpont(ok)ról visszaverődő fény irányát segíti kiszámolni, valójában a pixelt/pixeleket tartalmazó sík egységnyi hosszúságú (ez még fontos lesz) tengelye. A fényforrás pozíciója és a tengely segítségével kiszámolható a fény beesési szöge a felületre. Ha nem tartozik fénytörési térkép (refraction map) a felülethez, akkor a beesési szöggel egyenlő szögben verődik vissza a fény a tengely túloldalán (beesési szög = visszaverődési szög az általános iskolai fizikában). Ezzel a módszerrel egy geometriailag sima felülethez többféle visszaverődési szög társítható, tehát a szétszóródott visszaverődések hatására egyenetlennek tűnik majd a felület.
Egyszerű bemutató volt a Bump Map működésére az NV40-es bemutató benzinkutas példa. Nézzük, hogyan lehet ügyes normal map-szerkesztéssel geometriai részletességet szimulálni:
1. A megjelenítéshez egy alacsony poligonszámú modellt hozunk létre.
2. Megcsináljuk a modell részletesebb verzióját nagyobb poligonszámmal. Ezt fogjuk használni a normal map generálásához, az elkészült 3D alkalmazásban már nem lesz rá szükség.
3. Egymásra helyezzük a két különböző részletességű modellt.
4. A felhasznált normal map felbontásának megfelelően a kisebb poligonszámú modell felületére merőlegeseket állítunk (fekete), ezek kimetszenek egy-egy pontot a nagyobb részletességű modellen.
+ + =
Normalmap-generálás
5. A részletesebb modell metszéspontjába szerkesztett érintő segítségével meg tudjuk szerkeszteni a metszésponthoz tartozó tengelyt a részletes modellen.
6. Ezt a tengelyt (piros) jegyezzük be a kevésbé részletes modell normal mapjába, ezáltal az egyszerűbb modellen az összetettebb fényvisszaverődése fog lejátszódni, egyenetlen hatást keltve.
+ =
Térjünk vissz a 3Dc-hez! A 4:1 tömörítési aránnyal négyszer olyan részletes normal mapet tudunk eltárolni ugyanakkora memóriaigénnyel, mint korábban, vagyis negyedakkora részletek is megjeleníthetőek. Az ATI állítása szerint ez a módszer akár korábbi játékokhoz is alkalmazható, hiszen csak a normal mapeket kell újragenerálni. Nézzük, mire számíthatunk a jövőben:
Serious Sam 2
A varangyos rücsök 3Dc-vel és hagyományos módszerrel – minél rondább, annál jobb :)
Mivel teljesen új tömörítési eljárásról van szó, most kitérünk a folyamat részletes leírására. Akit nem érdekelnek a technikai részletek, nyugodtan ugorhat néhány bekezdést a következő, új antialiasing technikát bemutató fejezetig.
Adott az eredeti 32 bit színmélységű normal map. Minden egyes pixel egy egységnyi hosszúságú vektor 3 koordinátáját tárolja 8/8/8 bites pontossággal (a 32 bitből az utolsó 8 szabadon marad). A vektor másik végpontját az éppen árnyékolni szánt pixel koordinátája adja. A tömörítés két részre osztható.
Mivel a normális egységnyi hosszúságú, egy 3D Pitagorasz-tétel segítségével a Z-koordináta kiszámítható az X és Y segítségével (lásd az ábrán). A fölöslegessé vált koordináta elhagyható, máris nyertünk 8 bitet minden pixelen. A kihasználatlan 8 bittel és a Z-koordináta kizárásával már 2:1 tömörítési aránynál tartunk. Eddig a folyamat veszteségmentes volt, vagyis a kép minőségromlás nélkül visszaállítható.
A második lépés már hordoz magában némi minőségcsökkenést. A tömöríteni kívánt textúrát 4×4 pixeles egységekre bontjuk és a továbbiakban minden egységet külön dolgozunk fel. A 16 pixelen megkeressük a legkisebb és a legnagyobb X és Y értékeket, ezek kiadnak egy-egy számtartományt. A tartományokon egymástól egyenlő távolságban felveszünk további hat értéket; így kapunk 8-8 X és Y koordináta értéket, melyeket beszámozunk 0-7 között. Megvizsgáljuk minden pixel (természetesen csak a 4×4-es blokkban) X és Y koordinátáját, hogy melyik kiszámolt pontunk áll hozzá a legközelebb a nyolcból, és a kiszámolt értékünk sorszámát írjuk be az X és Y koordináta helyére. A sorszám 0 és 7 között változhat, ezért elég 3 bit a leírásához, 2×8 bit helyett 2×3-at használunk fel. Ebben a pillanatban hoztunk be némi veszteséget az eljárásba: az eredeti értékek helyett az általunk kiszámoltakat használtuk, de a korábbi képen látható, hogy ez a veszteség sokkal kisebb, mint amivel eddig tömöríteni tudtunk.
Az eredeti 4×8 bit (felül), a tömörített 2×3 bit + maximumok és minimumok, valamint számolás
Összegezve: eredetileg 4×4-es pixelblokkot, pixelenként 4×8 bit információt, 4×4×4×8 bit = 512 biten tároltunk. A tömörítéssel pixelenként csak két darab 3 bites komponenst és az X és Y koordináta maximumát és minimumát (további 4× 8 bit) kell tárolni, 4×4×2×3 bit + 4× 8 bit = 128 biten, azaz 4:1 tömörítési arányt kaptunk.
A cikk még nem ért véget, kérlek, lapozz!