Klasszikus árnyéktérképek dióhéjban. Dev Blog 4: Új Combat Arms grafikus funkciók

A fénynek három fő jellemzője van: fényesség (Multiplier), szín (Color) és az általa megvilágított tárgyakról vetett árnyékok (Shadows).

Amikor fényforrásokat helyez el egy jelenetben, ügyeljen a színükre. A nappali fényforrások kék árnyalatúak, de mesterséges fényforrás létrehozásához sárgás színűt kell adni.

Azt is figyelembe kell venni, hogy az utcai fényt szimuláló forrás színe a napszaktól függ. Ezért, ha a jelenet témája az esti idő, a világítás a nyári naplemente vöröses árnyalataiban lehet.

Különböző megjelenítők kínálnak saját árnyékgeneráló algoritmusokat. A tárgyról vetett árnyék sok mindent elárul – milyen magasan van a talaj felett, milyen a felület szerkezete, amelyre az árnyék esik, milyen forrásból világít a tárgy stb.

Emellett az árnyék kiemelheti az előtér és a háttér kontrasztját, valamint „kiadhat” egy olyan tárgyat, amely nem a virtuális kamera lencséjének látóterében van.

A tárgy által vetett árnyék alakjától függően a jelenet valósághűnek (6.6. ábra) vagy nem egészen hihetőnek tűnhet (6.7. ábra).

Ahogy fentebb említettük, egy valódi fénysugár nagyszámú visszaverődésen és fénytörésen megy keresztül, így a valódi árnyékok szélei mindig elmosódottak. A háromdimenziós grafikában egy speciális kifejezést használnak az ilyen árnyékok jelölésére - lágy árnyékok.

A lágy árnyékok elérése meglehetősen nehéz. Sok renderer úgy oldja meg a lágy árnyékok problémáját, hogy a 3ds max 7 interfészéhez egy nem pontszerű fényforrást ad, amely téglalap alakú vagy más alakú. Egy ilyen forrás nem egy pontból bocsát ki fényt, hanem a felszín minden pontjából. Ebben az esetben minél nagyobb a fényforrás területe, annál lágyabbak az árnyékok rendereléskor.

Különféle megközelítések léteznek az árnyékok megjelenítésére: árnyéktérkép (Shadow Map), nyomkövetés (Raytraced) és globális megvilágítás (Global Illumination) használata. Tekintsük őket sorrendben.

Rizs. 6.6. Objektum lágy árnyékokkal

Rizs. 6.7. Kemény árnyékokkal rendelkező objektum

Rizs. 6.8. A beállítások görgetése Shadow Map Parameters (Az árnyéktérkép paraméterei) a fényforráshoz

Az árnyéktérkép használatával homályos árnyékokat kaphat

homályos élekkel. A Shadow Map (Shadow map) fő beállítás az árnyéktérkép mérete (Size (Size) paraméter) a Shadow Map Params (Shadow map paraméterek) beállításában (6.8. ábra). Ha a térkép méretét csökkentjük, a keletkező árnyékok tisztasága is csökken.

A nyomkövetési módszer lehetővé teszi, hogy tökéletesen formázott árnyékokat kapjunk, amelyek azonban éles körvonaluk miatt természetellenesnek tűnnek. A nyomkövetés az egyes fénysugarak útjainak nyomon követése a fényforrástól a kamera lencséjéig, figyelembe véve azok visszaverődését a jelenetben lévő tárgyakról és fénytörésüket átlátszó közegben. A nyomkövetési módszert gyakran használják olyan jelenetek renderelésére, amelyek tükröződnek.

A 3ds max 5-től kezdődően az Area Shadows módszert használják lágy árnyékok előállítására, amely egy kissé módosított nyomkövetési módszeren alapul. Az Area Shadows (árnyékeloszlás) lehetővé teszi az árnyékok kiszámítását az objektumról, mintha nem egy fényforrás lenne a jelenetben, hanem pontszerű fényforrások csoportja, egyenletesen elosztva egy adott területen.

Bár a sugárkövetés pontosan reprodukálja a generált árnyékok finom részleteit, nem ideális rendereléshez, mivel az eredményül kapott árnyékok kemény szélűek.

A globális megvilágítási módszer (Radiosity) lehetővé teszi, hogy lágy árnyékokat érjen el a végső képen. Ez a módszer a világítás nyomkövetésének alternatívája. Ha a nyomkövetési módszer a jelenetnek csak azokat a részeit jeleníti meg, amelyeket a fénysugarak érnek, akkor a globális megvilágítási módszer az egyes képpontok elemzése alapján kiszámítja a fény szóródását a jelenet meg nem világított vagy árnyékolt részein. Ez figyelembe veszi a fénysugarak összes visszaverődését a jelenetben.

A Global Illumination lehetővé teszi, hogy valósághű képet kapjunk, de a renderelési folyamat erősen leterheli a munkaállomást, és ráadásul sok időt vesz igénybe. Ezért bizonyos esetekben célszerű olyan világítási rendszert használni, amely szimulálja a szórt fény hatását. Ebben az esetben a fényforrásokat úgy kell elhelyezni, hogy helyzetük egybeessen a közvetlen fényhatás helyeivel. Az ilyen forrásoknak nem szabad árnyékot létrehozniuk, és alacsony fényerővel kell rendelkezniük. Ez a módszer természetesen nem hoz létre olyan valósághű képet, mint a valódi globális megvilágítási módszerrel. Az egyszerű geometriájú jeleneteknél azonban jól jöhet.

A globális megvilágítás kiszámítására többféle algoritmus létezik, a visszavert fény kiszámításának egyik módszere a fotonkövetés (Photon Mapping). Ez a módszer magában foglalja a globális megvilágítás kiszámítását egy úgynevezett fotontérkép létrehozása alapján. A fotontérkép a helyszín megvilágítására vonatkozó, nyomkövetéssel gyűjtött információ.

A fotonkövetési módszer előnye, hogy a fotontérképként elmentett fotonkövetési eredmények később felhasználhatók globális megvilágítási effektus létrehozására 3D animációs jelenetekben. A fotonkövetéssel számított globális megvilágítás minősége a fotonok számától, valamint a nyomkövetés mélységétől függ. A fotonkövetés segítségével a maró hatást is kiszámíthatja (a maró hatásról bővebben a 7. fejezet „Általános tudnivalók a vizualizációról a 3D grafikában” című fejezetében olvashat).

A szabványos fényforrások közül három fényforrás (nevezetesen a Spot, a Direct és az Omni) teszi lehetővé a renderelni kívánt árnyékok típusának kiválasztását. Ha a szabványos Default Scanline Renderer-t (DSR) használjuk, akkor a következőkre leszünk kíváncsiak: Advanced ray-traced shadows, Area shadows, Ray-traced shadows, Shadow maps.

Árnyéktípus kiválasztásakor az IS paraméter görgetései között megjelenik egy árnyékparaméter-kiterjesztés, amelynek neve a típus nevével kezdődik.

árnyéktérkép

A számított erőforrásokhoz a legegyszerűbb és igénytelen árnyéktípus.

  1. A térkép mérete, amelyen az árnyék alapul. Minél nagyobb a térkép, annál jobb a kiszámított árnyék. Jobb, ha 2 n-es rendszámokat használunk
  2. Az árnyék szélének elmosása. A paraméter növelése lehetővé teszi, hogy kis térképfelbontás mellett megszabaduljon a szél szaggatott szélétől
  3. A Bias érték vezérléséért felelős paraméter. Alapértelmezés szerint letiltva (a legtöbb esetben a legjobb eredmény). Animáció esetén az opció engedélyezése segíthet.
  4. Ha le van tiltva, akkor a fény áthalad a felületen, ha a normálokkal ellentétes sokszögeket talál. Az opció engedélyezése lehetővé teszi a megfelelő árnyékok megjelenítését

Az 1. ábrán a képek felső sora jól mutatja az árnyék minőségének változását a Size paraméter növekedésével. Még a térkép méretének jelentős növelése sem oldja meg az árnyék szaggatott széleinek problémáját, bár az árnyék rajzolása minden bizonnyal bonyolultabbá válik.

A második sorban mindhárom esetben a térkép mérete változatlan marad, de a Sample Range paraméter változik. Fokozatosan növelve az árnyék szélének elmosásával megszabadultunk a szaggatottságtól.

1. ábra Árnyéktérkép típusú árnyék minőségének megváltoztatása különböző paraméterekkel

Ray Traced Shadows

Az ilyen típusú árnyékok kiszámítása nyomkövetési algoritmus alapján történik. Éles széleik vannak, és szinte lehetetlen beállítani.

A Ray-Traced Shadow pontosabb, mint az Árnyéktérkép. Ezen kívül képesek figyelembe venni az objektum átlátszóságát, ugyanakkor „száraz” és tiszta, ami a legtöbb esetben nem tűnik túl természetesnek. A Ray-Traced Shadow igényesebb a számítógépes erőforrásokkal szemben, mint a Shadow Map.

  1. Az objektum távolsága a vetett árnyéktól
  2. A nyomkövetési mélység az árnyék kialakulásáért felelős paraméter. Ennek az értéknek a növelése jelentősen megnövelheti a renderelési időt.

Az Omni típusú IC-kkel rendelkező Ray-Traced Shadows megjelenítése tovább tart, mint a Ray-Traced Shadows + Spot (vagy Directional) esetén

2. ábra Sugárkövető árnyékok átlátszatlan és átlátszó objektumokból

Advanced Ray Traced Shadows

Az ilyen típusú árnyékok nagyon hasonlítanak a Ray-Traced Shadowshoz, de ahogy a neve is sugallja, fejlettebb beállításokkal rendelkeznek, amelyek lehetővé teszik, hogy természetesebb és helyesebb számításokat kapjon.

  1. Árnyékgenerálási módszer
    Egyszerű - egyetlen sugár elhagyja az IS-t. A Shadow nem támogat semmilyen élsimítást és minőségi beállítást
    1-Pas Antialias - sugárnyaláb kibocsátását utánozzák. Sőt, minden megvilágított felületről ugyanannyi sugárzás verődik vissza (a sugarak számát az Árnyék minősége szabályozza).
    2-Pas Antialias - Hasonlóképpen, de két sugarat bocsátanak ki.
  2. Ha le van tiltva, akkor a fény áthalad a felületen, ha a normálokkal ellentétes sokszögeket talál. Az opció engedélyezése lehetővé teszi a megfelelő árnyékok megjelenítését
  3. A megvilágított felület által kibocsátott sugarak száma
  4. A megvilágított felület által kibocsátott másodlagos sugarak száma
  5. A sugár (pixelben) az árnyék szélének elmosásához. A paraméter növelése javítja az elmosódás minőségét. Ha apró részletek elvesznek az élek elmosásakor, javítsa ki ezt az esetet az Árnyék integritásának növelésével
  6. Az objektum távolsága a vetett árnyéktól
  7. A sugarak véletlenszerűségét szabályozó paraméter. Kezdetben a sugarak egy szigorú rács mentén irányulnak, ami kellemetlen műtermékeket okozhat. A káosz hozzáadásával az árnyék természetesebbnek tűnik.
    Az ajánlott értékek 0,5-1,0. A lágyabb árnyékokhoz azonban nagyobb remegési mennyiségre van szükség.

Terület árnyékai

Ez az árnyéktípus lehetővé teszi a fényforrás méreteinek figyelembevételét, így természetes kiterjesztett árnyékokat kaphat, amelyek "hasadnak" és elmosódnak, ahogy távolodnak a tárgytól. A 3dsMax számos árnyék "minta" (minta) összekeverésével szerez ilyen árnyékokat. Minél több "minta" és jobb a keverés, annál jobb a számított árnyék.

  1. Egy képzeletbeli fényforrás alakja, amely lehetővé teszi az árnyék természetének meghatározását.
    Egyszerű - egyetlen sugár elhagyja az IS-t. Az árnyék nem támogat semmilyen élsimítást és minőségi beállítást.
    Téglalap fény t - egy téglalap alakú terület fénykibocsátását szimulálja.
    lemez fénye - Az IC úgy viselkedik, mintha lemez formáját öltötte volna.
    doboz fénye – egy köbös IC utánzata.
    Gömbfény t egy gömb alakú IC utánzata.
  2. Ha le van tiltva, akkor a fény áthalad a felületen, ha a normálokkal ellentétes sokszögeket talál. Az opció engedélyezése lehetővé teszi a megfelelő árnyékok megjelenítését.
  3. Szabályozza a kibocsátott sugarak számát (nem lineáris). Minél nagyobb a szám, annál több sugár, annál jobb az árnyék minősége.
  4. Az árnyék minőségéért felelős paraméter. A racionális számításhoz mindig állítson be egy nagyobb számot, mint az Árnyék integritása.
  5. A sugár (pixelben) az árnyék szélének elmosásához. A paraméter növelése javítja az elmosódás minőségét. Ha apró részletek elvesznek az élek elmosásakor, javítsa ki ezt az esetet az Árnyék integritásának növelésével.
  6. A tárgy távolsága a vetett árnyéktól.
  7. A sugarak véletlenszerűségét szabályozó paraméter. Kezdetben a sugarak egy szigorú rács mentén irányulnak, ami kellemetlen műtermékeket okozhat. A káosz bevezetése természetesebbé teszi az árnyék képét.
  8. Képzeletbeli forrásdimenziók. Hossz – hossz, Szélesség – szélesség, Magasság (csak a Box Light és Sphere Light esetén aktív) – magasság.

Vessünk egy pillantást a 3. ábrára. Az első töredéken. Az árnyék több "mintája" egymásra kerül, minden keveredés nélkül. A második töredéken már keveredtek (Jitter Amount 0.0-ról 6.0-ra változott). A vegyes "mintákat" természetesebb árnyéknak tekintik, de minősége sok kívánnivalót hagy maga után. A harmadik töredék kiváló minőségű árnyékot mutat (A Shadow Integrity és Shadow Quality egyedi értékről 8-ra, illetve 10-re változott).

A második sor a 3. ábrán. szemlélteti, hogyan változik az árnyék természete, ha növeljük a képzeletbeli forrás méreteit. Ebben az esetben van egy képzeletbeli Rectangle Light típusú (lapos téglalap alakú) forrásunk. A forrásterület növekedésével az árnyék elmosódása növekszik.

3. ábra Az Area Shadow típusú árnyék minőségének megváltoztatása különböző paraméterekkel

Egyes paraméterértékek tájékoztató jellegűek, de mindennek csak a képzelet szab határt. A legjobb módja annak, hogy megtudja, a kísérletezés. Ne féljen kísérletezni a fénnyel. Fogja meg a jövő képének hangulatát, és adja át magát a beállításoknak.

A 4. ábrán. egy sakkló, amelynek anyaga egyszerű fa eljárási textúra. Három különböző színben színezett fényforrás. Egyszerű rendezés, ennek ellenére a figura jól néz ki.

4. ábra Sakkfigura "lovag". Tárgyvizualizáció

Összegzés

A világítás az egyik legfontosabb lépés a 3D-s jelenetekben. Első pillantásra úgy tűnhet, hogy az óra száraz információi nem alkalmazhatók az alkotómunkára. Kellő találékonysággal és szorgalommal azonban hihetetlen eredményeket lehet elérni. Végül is minden digitális kép csak nullák és egyesek halmaza, a 3dsMax pedig csak a következő eszköz, akár egy ceruza vagy egy ecset.

Az eredeti árnyékleképezési algoritmust nagyon régen találták fel. Működési elve a következő:
  1. A jelenetet a fényforrás helyzetéből textúrába (árnyéktérképbe) rajzoljuk. Itt fontos megjegyezni, hogy a különböző típusú fényforrások esetében minden egy kicsit másképp történik.
    Az irányított fényforrásoknak (bizonyos közelítésben a napfénynek is nevezhetjük) nincs térbeli pozíciójuk, azonban az árnyéktérkép kialakításához ezt a pozíciót kell kiválasztani. Általában a megfigyelő pozíciójához van kötve, így azok a tárgyak, amelyek közvetlenül a megfigyelő látóterében vannak, beleesnek az árnyéktérképbe. Rendereléskor ortográfiai vetületet használunk.
    A vetítési fényforrások (átlátszatlan ernyős lámpák, spotlámpák) bizonyos pozícióval rendelkeznek a térben, és korlátozzák a fény terjedését bizonyos irányokban. Ebben az esetben az árnyéktérkép megjelenítésekor a szokásos perspektivikus vetítési mátrixot használják.
    A körsugárzó fényforrások (például izzólámpa), bár a térben meghatározott pozícióval rendelkeznek, minden irányba terjesztik a fényt. Az árnyékok ilyen fényforrásból történő helyes felépítéséhez kocka textúrákat (kockatérképeket) kell használnia, ami általában azt jelenti, hogy a jelenetet hatszor kell árnyéktérképbe rajzolni. Nem minden játék engedhet meg magának dinamikus árnyékokat ilyen fényből, és nem minden játéknak van rá szüksége. Ha érdekel, hogyan működik ez a megközelítés, van egy téma ebben a témában.
    Ezen kívül létezik az árnyékleképező algoritmusok alosztálya (LiSPSM , TSM , PSM stb.), amelyek nem szabványos vetítési nézetmátrixokat használnak az árnyékok minőségének javítására és az eredeti megközelítés hiányosságainak kiküszöbölésére.
    Bárhogyan is készül az árnyéktérkép, az algoritmus bonyolultabb változataiban változatlanul tartalmazza a fényforrás és a legközelebbi látható (a fényforrás helyzetétől számított) pont távolságát vagy ennek függvényét.
  2. A jelenetet a fő kamerából rajzoljuk. Annak megértéséhez, hogy bármely objektum pontja árnyékban van-e, elegendő ennek a pontnak a koordinátáit az árnyéktérkép terébe fordítani, és összehasonlítani. Az árnyéktérkép terét a nézet-vetítés mátrix határozza meg, amelyet ennek a térképnek a kialakításánál használtunk. Az objektumpont koordinátáinak lefordításával ebbe a térbe, és a koordinátákat a tartományból konvertálva [-1;-1] ban ben , megkapjuk a textúra koordinátáit. Ha a kapott koordináták a tartományon kívül esnek , akkor ez a pont nem szerepel az árnyéktérképen, és árnyékolatlannak tekinthető. Az árnyéktérképből a kapott textúrakoordináták alapján kiválasztva megkapjuk a távolságot a fényforrás és a hozzá legközelebb eső objektum pontja között. Ha ezt a távolságot összehasonlítjuk az aktuális pont és a fényforrás távolságával, akkor a pont árnyékban van, ha az árnyéktérképen látható érték kisebb. Ez logikai szempontból nagyon egyszerű, ha az árnyéktérképen kisebb az érték, akkor ezen a ponton van valami tárgy, ami közelebb van a fényforráshoz, és ennek az árnyékában vagyunk.
Az árnyékleképezés messze a leggyakoribb algoritmus a dinamikus árnyékok megjelenítésére. Az algoritmus egyik vagy másik módosításának megvalósítása szinte minden grafikus motorban megtalálható. Ennek az algoritmusnak az a fő előnye, hogy gyors árnyékképzést tesz lehetővé tetszőlegesen összetett geometriai objektumokból. Ugyanakkor az algoritmus sokféle változatának megléte nagyrészt annak hiányosságaira vezethető vissza, ami nagyon kellemetlen grafikai műtermékekhez vezethet. Az alábbiakban a PPSM-re jellemző problémákat és azok leküzdésének módjait tárgyaljuk.

Párhuzamos osztott árnyékleképezés

Vegye figyelembe a következő problémát: dinamikus árnyékokat kell rajzolni olyan tárgyakról, amelyek jelentős távolságra vannak a lejátszótól anélkül, hogy befolyásolnák a közeli objektumok árnyékait. Korlátozzuk magunkat az irányított napfényre.
Ez a fajta feladat különösen a szabadtéri játékokban lehet aktuális, ahol bizonyos helyzetekben a játékos több száz méterrel látja maga előtt a tájat. Ugyanakkor minél távolabbra akarjuk látni az árnyékot, annál több hely kerüljön az árnyéktérképbe. Az árnyéktérképen lévő objektumok megfelelő felbontásának megőrzése érdekében kénytelenek vagyunk magának a térképnek a felbontását növelni, ami először a teljesítmény csökkenéséhez vezet, majd a renderelési cél maximális méretének korlátjába ütközünk. Ennek eredményeként a teljesítmény és az árnyékminőség között egyensúlyozva jól markáns aliasing hatású árnyékokat kapunk, amit még az elmosódás is rosszul takar. Nyilvánvaló, hogy egy ilyen megoldás nem tud minket kielégíteni.
Ennek a problémának a megoldására kidolgozhatunk egy vetületi mátrixot úgy, hogy a játékoshoz közeli objektumok nagyobb területet kapjanak az árnyéktérképen, mint a távolabbi objektumok. Ez a fő gondolata a Perspective Shadow Mapping (PSM) algoritmusnak és számos más algoritmusnak. Ennek a megközelítésnek az a fő előnye, hogy gyakorlatilag nem változtattunk a jelenet megjelenítési folyamatán, csupán a nézet-vetítés mátrix számítási módja változott. Ez a megközelítés könnyen beépíthető egy meglévő játékba vagy motorba anélkül, hogy az utóbbin jelentős módosításokat kellene végezni. Az ilyen megközelítések fő hátránya a peremfeltételek. Képzeljünk el egy olyan helyzetet, amikor napnyugtakor árnyékokat rajzolunk a Napból. Ahogy a Nap közelebb kerül a horizonthoz, az árnyéktérképen látható objektumok nagymértékben átfedik egymást. Ebben az esetben egy atipikus vetítési mátrix súlyosbíthatja a helyzetet. Más szóval, a PSM osztályú algoritmusok bizonyos helyzetekben jól működnek, például amikor a játék árnyékokat húz a zenithez közeli "rögzített napról".
A PSSM algoritmus egy alapvetően eltérő megközelítést javasol. Egyesek számára ez az algoritmus Cascaded Shadow Mapping (CSM) néven ismert. Formálisan ezek különböző algoritmusok, még azt is mondhatnám, hogy a PSSM a CSM speciális esete. Ebben az algoritmusban javasolt a fő kamera láthatósági piramisának (frustum) felosztása szegmensekre. PSSM esetén - a közeli és távoli vágási síkkal párhuzamos határokkal, CSM esetén - az elválasztás típusa nincs szigorúan szabályozva. Minden szegmenshez ( hasított az algoritmus terminológiájában) saját árnyéktérképet készít. Az alábbi ábrán látható egy példa a szétválasztásra.


Az ábrán a láthatósági piramis 3 szegmensre való felosztása látható. A szegmensek mindegyike határolókerettel van megjelölve (a 3D térben lesz egy doboz, egy határoló doboz). A tér ezen korlátozott részeinek mindegyikéhez saját árnyéktérkép készül. A figyelmes olvasó megjegyzi, hogy itt tengelyhez igazított határolódobozokat használtam. Használhat nem igazítottakat is, ez tovább bonyolítja az objektumvágó algoritmust, és némileg megváltoztatja a nézetmátrix kialakításának módját a fényforrás helyzetéből. Mivel a láthatósági piramis tágul, a kamerához közelebb eső szegmensek területe lényegesen kisebb lehet, mint a távolabbiak területe. Ugyanazzal az árnyéktérkép felbontással ez nagyobb felbontást jelent a közeli objektumok árnyékai számára. A GPU Gems 3 fent említett cikkében a következő sémát javasoljuk a láthatósági piramis hasadási távolságának kiszámításához:



ahol én– partíciós index, m- partíciók száma, n a közeli vágási sík távolsága, f a távoli vágási sík távolsága, λ az az együttható, amely meghatározza a logaritmikus és az egyenletes particionálási skála közötti interpolációt.

Általános a megvalósításban
A Direct3D 11-ben és az OpenGL-ben megvalósított PSSM algoritmusban sok a közös. Az algoritmus megvalósításához a következőket kell elkészíteni:
  1. Több árnyéktérkép (a partíciók számától függően). Első pillantásra úgy tűnik, hogy több árnyéktérkép készítéséhez többször meg kell rajzolnia az objektumokat. Valójában ezt nem szükséges kifejezetten megtenni, a hardveres példányosítási mechanizmust fogjuk használni. Ehhez szükségünk van egy úgynevezett textúra tömbre a rendereléshez és egy egyszerű geometriai shaderre.
  2. Tárgyvágó mechanizmus. A játékvilág tárgyai különböző geometriai formájúak lehetnek, és különböző pozíciókkal rendelkezhetnek a térben. A kiterjesztett objektumok több árnyéktérképen, a kis objektumok csak egyben láthatók. Az objektum közvetlenül a szomszédos szegmensek határán lehet, és legalább 2 árnyéktérképpel kell megrajzolni. Ezért szükség van egy mechanizmusra annak meghatározására, hogy az árnyéktérképek melyik részhalmazába esik egy objektum.
  3. A partíciók optimális számának meghatározására szolgáló mechanizmus. Az árnyéktérképek képkockánkénti megjelenítése minden szegmenshez a számítási erőforrások pazarlása lehet. Sok helyzetben a játékos a játékvilágnak csak egy kis részét látja maga előtt (például a lábát nézi, vagy a szeme a falon nyugszik maga előtt). Nyilvánvaló, hogy ez nagyban függ a játék nézetének típusától, de jó lenne egy ilyen optimalizálás.
Ennek eredményeként a következő algoritmust kapjuk az árnyéktérképek megjelenítéséhez szükséges vetületi nézet mátrixok előállításához:
  1. Kiszámoljuk a távolságokat a láthatósági piramis felosztásához a legrosszabb esetre. A legrosszabb eset az, hogy a kamera távoli vágási síkjáig árnyékokat látunk.

    A kód

    void számítaniMaxSplitDistances() ( float nearPlane = m_camera.getInternalCamera().GetNearPlane(); float farPlane = m_camera.getInternalCamera().GetFarPlane(); for (int i = 1; i< m_splitCount; i++) { float f = (float)i / (float)m_splitCount; float l = nearPlane * pow(farPlane / nearPlane, f); float u = nearPlane + (farPlane - nearPlane) * f; m_maxSplitDistances = l * m_splitLambda + u * (1.0f - m_splitLambda); } m_farPlane = farPlane + m_splitShift; }

  2. Határozza meg a távolságot a kamera és az árnyékot vető tárgy legtávolabbi látható pontja között. Itt fontos megjegyezni, hogy a tárgyak árnyékot vethetnek vagy nem. Például egy sík-dombos tájat nem árnyékolóvá lehet tenni, ebben az esetben a világítási algoritmus lehet felelős az árnyékolásért. Csak az árnyékot vető objektumok kerülnek be az árnyéktérképbe.

    A kód

    float számításFurthestPointInCamera(const matrix44& cameraView) ( bbox3 scenebox; scenebox.begin_extend(); for (size_t i = 0; i< m_entitiesData.size(); i++) { if (m_entitiesData[i].isShadowCaster) { bbox3 b = m_entitiesData[i].geometry.lock()->getBoundingBox(); b.transform(m_entitiesData[i].model); scenebox.extend(b); ) ) scenebox.end_extend(); float maxZ = m_camera.getInternalCamera().GetNearPlane(); for (int i = 0; i< 8; i++) { vector3 corner = scenebox.corner_point(i); float z = -cameraView.transform_coord(corner).z; if (z >maxZ) maxZ = z; ) return std::min(maxZ, m_farSík); )

  3. Az 1. és 2. lépésben kapott értékek alapján meghatározzuk a valóban szükséges szegmensek számát és a felosztási távolságot.

    A kód

    voidaan< m_maxSplitDistances.size(); i++) { float d = m_maxSplitDistances[i] - m_splitShift; if (m_furthestPointInCamera >= d) m_currentSplitCount++; ) ) float nearSík = m_camera.getInternalCamera().GetNearPlane(); for (int i = 0; i< m_currentSplitCount; i++) { float f = (float)i / (float)m_currentSplitCount; float l = nearPlane * pow(m_furthestPointInCamera / nearPlane, f); float u = nearPlane + (m_furthestPointInCamera - nearPlane) * f; m_splitDistances[i] = l * m_splitLambda + u * (1.0f - m_splitLambda); } m_splitDistances = nearPlane; m_splitDistances = m_furthestPointInCamera; }

  4. Minden szakaszra (a szakasz határait a közeli és távoli távolság határozza meg) kiszámítjuk a határolókeretet.

    A kód

    bbox3 számít getOrientation().y_direction();float fov = n_deg2rad(m_camera.getInternalCamera().GetAngleOfView());float aspect = m_camera.getInternalCamera().GetAspectRatio();float nearPlaneHeight = n_tan(fov) *0PlaneHeight float nearPlaneWidth = nearPlaneHeight * szempont; float farSíkMagasság = n_tan(fov * 0.5f) * farSík; float farSíkszélesség = farSíkMagasság * szempont; vektor3 nearPlaneCenter = szem + vZ * nearPlane; vektor3 farPlaneCenter = szem + vZbox * távoli mező; begin_extend(); box.extend(vector3(nearPlaneCenter - vX * nearPlaneWidth - vY * nearPlaneHeight)); box.extend(vector3(nearPlaneCenter - vX * nearPlaneWidth + vY * nearPlaneHeight)); box.extend(vector3(vX *PlaneCenter) nearPlaneWidth + vY * nearPlaneHeight)); box.extend (vektor3(NearPlaneCenter + vX * nearPlaneWidth - vY * nearPlaneHeight)); box.extend(vektor3(farSíkKözép - vX * FarSíkSzélesség - vY * TássíkMagasság)); box.extend(vektor3(farSíkKözép - vX * farSíkszélesség + vY * távolsíkmagasság)); box.extend(vektor3(farSíkKözép + vX * farSíkszélesség + vY * távolsíkmagasság)); box.extend(vektor3(farSíkKözép + vX * farSíkszélesség - vY * távolsíkmagasság)); box.end_extend(); visszatérő doboz; )

  5. Minden szegmensre kiszámítjuk a nézet-vetítés árnyékmátrixát.

    A kód

    matrix44 CalculateShadowViewProjection(const bbox3& frustumBox) (const float LIGHT_SOURCE_HEIGHT = 500.0f; vector3 viewDir = m_camera.getOrientation().z_direction(); vector3 size = frustumBox.size(); vector3 view.centerstrumftB - center.y = 0; auto lightSource = m_lightManager.getLightSource(0); vector3 lightDir = lightSource.orientation.z_direction(); matrix44 shadowView; shadowView.pos_component() = center - lightDir * LIGHT_SOURCE_HEIGHT; shadowView.lookatRh(shadowView.pos_component ) + lightDir, lightSource.orientation.y_direction()); shadowView.invert_simple(); matrix44 shadowProj; float d = std::max(size.x, size.z); shadowProj.orthoRh(d, d, 0.1f, 2000.0f); shadowView visszatérése * shadowProj; )

Az objektumok kivágása egy egyszerű teszt segítségével valósítható meg két határolókeret (egy objektum és egy csonka szegmens) metszéspontjára. Itt van egy olyan funkció, amelyet fontos figyelembe venni. Lehet, hogy nem látjuk a tárgyat, de látjuk az árnyékát. Könnyen kitalálható, hogy a fent leírt megközelítéssel minden olyan tárgyat levágunk, amely nem látható a fő kamerában, és nem lesznek árnyékok. Ennek megakadályozására egy meglehetősen gyakori trükköt alkalmaztam - az objektum határolókeretének kiterjesztését a fény terjedésének iránya mentén, ami durva közelítést adott annak a térnek a területén, amelyben az objektum árnyéka van. látható. Ennek eredményeként minden objektumhoz létrejött egy árnyéktérkép-indexek tömbje, amelybe ezt az objektumot be kell rajzolni.

A kód

void updateShadowVisibilityMask(const bbox3& frustumBox, const std::shared_ptr & entitás, EntityData& entityData, int splitIndex) ( bbox3 b = entity->getBoundingBox(); b.transform(entityData.model); // shadow box számítás automatikus lightSource = m_lightManager.getLightSource(0); vector3 lightDir = lightSource.orientation .z_direction(); float shadowBoxL = fabs(lightDir.z)< 1e-5 ? 1000.0f: (b.size().y / -lightDir.z); bbox3 shadowBox; shadowBox.begin_extend(); for (int i = 0; i < 8; i++) { shadowBox.extend(b.corner_point(i)); shadowBox.extend(b.corner_point(i) + lightDir * shadowBoxL); } shadowBox.end_extend(); if (frustumBox.clipstatus(shadowBox) != bbox3::Outside) { int i = entityData.shadowInstancesCount; entityData.shadowIndices[i] = splitIndex; entityData.shadowInstancesCount++; } }


Most pedig vessünk egy pillantást a renderelési folyamatra, valamint a Direct3D 11 és OpenGL 4.3 specifikus részeire.
Implementáció Direct3D-n 11
Az algoritmus Direct3D 11-en való megvalósításához a következőkre van szükségünk:
  1. Textúrák tömbje árnyéktérképek megjelenítéséhez. Az ilyen típusú objektumok létrehozásához a D3D11_TEXTURE2D_DESC struktúra rendelkezik egy ArraySize mezővel. Így a C++ kódban nem lesz olyan, mint az ID3D11Texture2D* tömb[N] . A Direct3D API szempontjából a textúrák tömbje alig különbözik egyetlen textúrától. Egy ilyen tömb shaderben való használatakor fontos jellemző, hogy meghatározhatjuk, hogy a tömb melyik textúrájába rajzoljuk be ezt vagy azt az objektumot (SV_RenderTargetArrayIndex szemantika HLSL-ben). Ez a fő különbség e megközelítés és az MRT (multiple render targets) között, amelyben egy objektum egyszerre rajzolódik be az összes adott textúrába. Azoknál az objektumoknál, amelyeket egyszerre több árnyéktérképbe kell berajzolni, hardveres példányosítást használunk, ami lehetővé teszi az objektumok GPU szintű klónozását. Ebben az esetben az objektumot a tömb egyik textúrájába, klónjait pedig más textúrákba lehet rajzolni. Az árnyéktérképeken csak a mélységértéket tároljuk, ezért a DXGI_FORMAT_R32_FLOAT textúraformátumot fogjuk használni.
  2. Speciális textúra mintavevő. A Direct3D API-ban speciális paramétereket állíthatunk be a textúrák lekéréséhez, amelyek lehetővé teszik a textúrában lévő érték összehasonlítását egy adott számmal. Az eredmény ebben az esetben 0 vagy 1 lesz, és az ezen értékek közötti átmenet lineáris vagy anizotróp szűrővel simítható. Ha a D3D11_SAMPLER_DESC struktúrában szeretne mintavevőt létrehozni, állítsa be a következő paramétereket:

    SamplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS; samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER; samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER; samplerDesc.BorderColor = 1.0f; samplerDesc.BorderColor = 1.0f; samplerDesc.BorderColor = 1.0f; samplerDesc.BorderColor = 1.0f;
    Így lesz bilineáris szűrés, összehasonlítás a „kevesebb, mint” függvénnyel, és mintavételezés a textúrából a tartományon kívüli koordinátákkal. 1-et ad vissza (azaz nincs árnyék).

A renderelés a következő séma szerint történik:

Megvalósítás OpenGL 4.3-ban
Az algoritmus OpenGL 4.3-on való megvalósításához mindenre ugyanarra van szükségünk, mint a Direct3D 11-nél, de vannak finomságok. Az OpenGL-ben csak olyan textúrákhoz tudunk kombinált összehasonlító mintavételt végezni, amelyek mélységi értéket tartalmaznak (például GL_DEPTH_COMPONENT32F formátumban). Ezért csak a mélységi pufferbe fogunk renderelni, és eltávolítjuk a színre írást (pontosabban csak textúrák tömbjét csatoljuk a framebufferhez a mélységi puffer tárolására). Ezzel egyrészt megspórolunk némi videomemóriát, és könnyebbé válik a grafikus csővezeték, másrészt normalizált mélységértékekkel kell dolgoznunk.
Az OpenGL mintavételi paraméterei közvetlenül a textúrához köthetők. Ezek megegyeznek a Direct3D 11-nél korábban tárgyaltakkal.

Const float BORDER_COLOR = ( 1.0f, 1.0f, 1.0f, 1.0f ); glBindTexture(m_shadowMap->getTargetType(), m_shadowMap->getDepthBuffer()); glTexParameter(m_shadowMap->getTargetType(), GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameter(m_shadowMap->getTargetType(), GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameter(m_shadowMap->getTargetType(), GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameter(m_shadowMap->getTargetType(), GL_TEXTURE_COMPARE_FUNC, GL_LESS); glTexParameter(m_shadowMap->getTargetType(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameter(m_shadowMap->getTargetType(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(m_shadowMap->getTargetType(), GL_TEXTURE_BORDER_COLOR, BORDER_COLOR); glBindTexture(m_shadowMap->getTargetType(), 0);
Érdekes folyamat egy textúratömb létrehozása, amelyet az OpenGL-en belül egy háromdimenziós textúra képvisel. Nem készült speciális funkció a létrehozásához, mindkettő a glTexStorage3D segítségével készült. Az SV_RenderTargetArrayIndex GLSL-analógja a gl_Layer beépített változója.
A renderelési séma is változatlan maradt:

Problémák

Az árnyékleképezési algoritmus és annak módosításai számos problémát okoznak. Az algoritmust gyakran gondosan kell hangolni egy adott játékhoz vagy akár egy adott jelenethez. A leggyakoribb problémák listája és azok megoldási módjai megtalálhatók. A PSSM megvalósítása során a következőkkel találkoztam:

Teljesítmény

A teljesítményméréseket a következő konfigurációjú számítógépen végeztük: AMD Phenom II X4 970 3,79 GHz, 16 Gb RAM, AMD Radeon HD 7700 Series, Windows 8.1 operációs rendszerrel.

Átlagos képkockaidő. Direct3D 11 / 1920x1080 / MSAA 8x / teljes képernyő / kis jelenet (~12k sokszög képkockánként, ~20 objektum)

Átlagos képkockaidő. OpenGL 4.3 / 1920x1080 / MSAA 8x / teljes képernyő / kis jelenet (~12k sokszög képkockánként, ~20 objektum)

Átlagos képkockaidő. 4 felosztás / 1920x1080 / MSAA 8x / teljes képernyő / nagy jelenet (~1000 000 sokszög képkockánként, ~1000 objektum, ~500 objektumpéldány)

Az eredmények azt mutatták, hogy nagy és kis jeleneteken az OpenGL 4.3 megvalósítás általában gyorsabb. A grafikus folyamat terhelésének növekedésével (az objektumok és példányaik számának növekedésével, az árnyéktérképek méretének növekedésével) a megvalósítások közötti sebességkülönbség csökken. Az OpenGL implementáció előnyét az árnyéktérkép előállítási módjának tulajdonítom, ami eltér a Direct3D 11-től (csak a mélységi puffert használtuk színre írás nélkül). Semmi sem akadályoz meg bennünket abban, hogy ugyanezt tegyük a Direct3D 11-en, miközben belenyugodunk a normalizált mélységértékek használatába. Ez a megközelítés azonban csak addig működik, amíg a mélységérték helyett nem akarunk további adatokat vagy függvényeket tárolni az árnyéktérkép mélységértékéből. Néhány algoritmus-fejlesztést (például Variance Shadow Mapping) pedig nehéz lesz megvalósítani.

következtetéseket

A PSSM algoritmus az egyik legsikeresebb módja az árnyékok létrehozásának nagy nyílt tereken. Egy egyszerű és világos hasítási elven alapul, amely könnyen skálázható az árnyékok minőségének növelésével vagy csökkentésével. Ez az algoritmus kombinálható más árnyékleképezési algoritmusokkal, hogy szebb lágy árnyékokat vagy fizikailag helyesebb árnyékokat állítson elő. Ugyanakkor az árnyékleképezési osztály algoritmusai gyakran kellemetlen grafikai műtermékek megjelenéséhez vezetnek, amelyeket egy adott játék algoritmusának finomhangolásával kell kiküszöbölni.

Címkék:

  • Árnyékleképezés
  • PSSM
  • Direct3D 11
  • OpenGL 4
Címkék hozzáadása

Negyedik fejlesztői blog: Új grafikai szolgáltatások

Az első grafikus motor frissítési naplóban röviden szót ejtettünk néhány új grafikai fejlesztésről, amelyek hamarosan bekerülnek a játékba. Ezen kívül kijelentettük, hogy ezeknek a fejlesztéseknek a többsége egyenrangú lesz a modern játékmotorokkal, mint például a Unity 5, az Unreal 4 vagy a CryEngine 3. De mit is jelent ez valójában?

Először is szeretnénk megérteni, hogy a frissítési folyamat fokozatos lesz, és nem minden térkép, karakter, fegyvertextúra és tárgy frissül azonnal. Ezek többsége továbbra is a játék forgóeszközeivel fog működni, de idővel ezeket is frissítjük, hogy a Combat Arms valóban frissített megjelenést kapjon.

Érdemes megjegyezni, hogy ezeknek a grafikus funkcióknak a használata egy ilyen régi motoron való futtatáshoz, miközben még mindig visszafelé kompatibilis a régi grafikus móddal és erőforrásokkal, sok érdekes és néha őrült megoldást igényelt, a DirectX 9-re korlátozva. nagyon vicces volt!

Dinamikus világítás és árnyékok

Az eredeti Lithitech Jupiter motor csak korlátozott mértékben támogatta a dinamikus világítást és az árnyékokat, bár a motor által kínált lehetőségek meglehetősen fejlettek ahhoz a korszakhoz, amelyben kifejlesztették. Alapvetően az eredeti Lithtech Jupiter grafikus motorban a világítás és az árnyékolás teljesen statikus volt, ami azt jelenti, hogy előre ki vannak számítva és textúraként tárolva, amelyet a térkép geometriájának renderelésekor használnak. Néhány ponton azonban még a statikus világítás is lehetővé tette számukra, hogy dinamikusan megvilágított jeleneteket hozzanak létre bizonyos tárgyakon, például karaktermodelleken és fegyvereken. Mivel a dinamikus világítás csúcsonként használta az objektumokat, a különféle extra részleteket és dudorokat is előre kellett kiszámítani, és közvetlenül a diffúz textúrákra sütni. És mivel sütve vannak, nem tudnak dinamikusan kölcsönhatásba lépni a különböző fényforrásokkal, és gyakran nem illeszkednek a fényviszonyokhoz. Emiatt a kép nagyon laposnak tűnik, és 2017-re keltezett.

A legnagyobb fejlesztés, amit elértünk, az, hogy a statikus térképgeometriát és az objektumok teljesen dinamikus megvilágítását és árnyékait kombináljuk. A dinamikus világítás valóban lehetővé teszi a jelenetek renderelését pixelenkénti megvilágítással, tükröződésekkel, csúcsfényekkel, dinamikus árnyékokkal és ütési térképpel.

Noha kezdetben nem volt nehéz egyetlen dinamikus fényforrás bevezetése, a nehézség abból adódott, hogy egyszerre több dinamikus fényt kellett hatékonyan támogatni. Számos dinamikus fényforrás támogatása szinte minden modern játékmotor alapvető jellemzőjévé vált. Az egyetlen módja annak, hogy a Lithtech motor több dinamikus fény megjelenítését támogatta, az volt, hogy lényegében többször újrarajzolta a teljes jelenetet, egyszer minden egyes fényhez a térképen. Ez némileg túlzás, mivel a Lithtech képes blokkokba csoportosítani a térkép geometriáját, amelyeket egy határoló fénygömb hajthat végre, és csak ezeket a térképblokkokat kell újrarajzolni. Ez azonban továbbra is nagy CPU-terheléssel jár a jelenet többszöri megjelenítéséhez, és még több korlátozást ír elő a térkép geometriájának összetettségére, valamint arra, hogy egyidejűleg hány objektum jeleníthető meg a képernyőn.

Kezdtük azzal, hogy kezdetben csak a fő irányos napfény volt az egyetlen dinamikus fényforrás. Az összes többi belső körirányú és pontszerű fényforrást statikusan hagytuk. De a Combat Arms játékainak nagy része részben vagy egészben épületekben található, így a beltéri statikus és kültéri dinamikus világítás közötti különbség túlságosan észrevehető volt.

Így a több fényforrást használó dinamikus világításhoz nagy változtatásokat kellett végrehajtani a motor jelenet megjelenítésében és a fény feldolgozásának módjában. Ehhez a Deferred Shading néven ismert renderelési technikát alkalmaztuk. A halasztott világítás és árnyékolás témája meglehetősen tág lehet, és röviden megemlítettük az első fejlesztői blogbejegyzésben. Alapvetően lehetővé teszi, hogy az összes dinamikus megvilágítás átkerüljön az utófeldolgozási renderelési területre, ami teljesen független a jelenet összetettségétől, és a GPU szinte teljesen feldolgozható nagyon kis CPU terhelés mellett.

Mindezen optimalizálások segítségével egy komplex fizikai világítási árnyékolót tudtunk megvalósítani. Ezután alaposan teszteltük ezt a világítási modellt, összehasonlítva azzal, hogy a hasonló jelenetek hogyan jelennének meg más modern játékmotorokban, például a Unity 5-ben és az Unreal 4-ben, valamint a professzionális offline rendereléssel létrehozott, teljesen sugárral renderelt jelenetekkel. Arra szorítkoztunk, hogy a modern grafikus hardverrel, modern világítási árnyékolókkal valós időben megvalósíthassuk. Az eredmények összehasonlíthatók a sugárrendereléssel, a fő különbségek a visszaverődési pontosság és a fénycsillapítás.

Új dinamikus világítási árnyékolók a Combat Armsban:

A jelenet sugárkövető változata:

árnyéktérkép

A dinamikus árnyékok megvalósítása során számos kihívással kellett szembenéznünk a modern, teljesen dinamikus árnyékolás elérése érdekében a Combat Arms-ban. Az eredeti Lithtech motorban a legtöbb árnyék a térképgeometria renderelésekor használt statikus világos textúrákba van beépítve. Ez az oka annak, hogy nem minden objektum vet árnyékot, különösen a dinamikus objektumok, mivel az árnyék rögzített és nem változhat. Bár a Lithtech rendelkezik olyan funkcióval, amely lehetővé teszi dinamikus árnyékok létrehozását bizonyos objektumokon, gyakorlatilag nem használták a Combat Arms-ban. Ezenkívül ennek a funkciónak a hatóköre túlságosan korlátozott, és maguk a dinamikus objektumok nem tudnak árnyékokat fogadni.

Végül úgy döntöttünk, hogy egy teljesen dinamikus kaszkádos árnyéktérképet (CSM) használunk a nap fő irányfényéhez, és egy részlegesen dinamikus megoldást a mindenirányú fényekhez és fényekhez egy előre kiszámított mindenirányú árnyéktérkép segítségével, amely alkalmazható világgeometria és dinamikus objektumok egyaránt. Ez hasonló ahhoz, ahogy a többi modern játékmotor dinamikus árnyékolást biztosít.

Egyáltalán mi az az árnyéktérkép? Ez alapvetően egy nagyon ügyes trükk, amellyel a játékok és a renderelők a GPU-gyorsítású dinamikus árnyékolást szimulálják. https://en.wikipedia.org/wiki/Shadow_mapping.

Az árnyékleképezési algoritmus alapvetően arról szól, hogy a jelenetet a fényforrás szemszögéből egy textúrára kell renderelni, azt a megvilágítási pixelárnyékoló belépési pontjaként használni, majd a textúra alapján kiszámítani, hogy a pixel árnyékban van-e. vagy nem a GPU.

A játékban az árnyéktérkép textúrája így néz ki:

Kérjük, vegye figyelembe, hogy ennek a textúrának nem 1, hanem 4 árnyéktérképe van. Mindegyik árnyéktérképet árnyéktérkép-kaszkádnak nevezzük. A megfigyelt felület távolságának növekedésével nagyobb kaszkádot használnak, de kisebb felbontással. Ez lehetővé teszi, hogy az árnyékok nagyon messzire nyúljanak, de továbbra is illeszkedjenek egy rögzített méretű textúrába. Ebben az esetben a megfigyelő melletti árnyékok nagyobb felbontásúak lesznek. Az árnyéktérkép felbontása közvetlenül függ attól, hogy milyen élesek és pontosak az árnyékok.

Mivel az árnyéktérkép csak egy másik kamera a jelenetben, dinamikusan, valós időben renderelhető. Az árnyékminőség beállításai befolyásolják az árnyéktérkép textúrájának felbontását.

Így néz ki az árnyéktérkép-megoldás szűrve.

Árnyéktérkép szűrés

Csak az árnyéktérkép használata nagyon kemény árnyékokat eredményezhet. És bár néha jól néznek ki egyszerre, ez nem igaz.

A való világban az árnyékok nem mindig kemények vagy lágyak, a fényforrás méretétől és a megvilágított téma távolságától függően változnak. Példákat láthat a képen:

Figyeld meg, hogy ezeken a fényképeken az árnyékok lágyabbá válnak, ahogy távolodsz az őket vető tárgyaktól. A legtöbb modern játék még mindig a legegyszerűbb árnyékolási szűrési módszert használja, amelyet százalékos közeli szűrésnek vagy PCF-nek neveznek, amely rögzített keménységi vagy lágysági értéket alkalmaz minden árnyékra.

Ezek a meglehetősen modern Doom és Overwatch játékok képernyőképei megmutatják, hogy a legtöbb játék hogyan végez egyszerű árnyékszűrést PCF használatával.

A Combat Arms-ban azonban úgy döntöttünk, hogy egy fejlettebb árnyékszűrő technológiát alkalmazunk, amely közelebb áll ahhoz, amit a való életben látunk. A játékban ezt szimuláljuk az NVidia által kifejlesztett Closer Soft Shadows (PCSS) technológiával.

Bár ezt a technológiát még 2005-ben vezették be, a grafikus hardver csak most lett elég erős ahhoz, hogy ezt a módszert használja, és a modern játékok csak az utóbbi években kezdték el erőteljesen használni az árnyéktérkép szűrésére. A blog írásakor ez a technológia még mindig nem érhető el az Unreal 4-ben vagy a Unity 5-ben. Bár technikailag az Unreal 4 egy alternatív megoldást kínál, amelyet távolsági sugárkövetésnek neveznek, ez arra korlátozódik, hogy csak a statikus geometriát engedi árnyékolni.

PCSS letiltva:

PCSS engedélyezve:

Finom PCSS-szűrés kerül alkalmazásra, ha az árnyék minőségi beállításai magasra vannak állítva. Ezenkívül a PCSS-t jelenleg csak alapvető, irányított napfényhez használják minden minőségi szinten. Sajnos a PCSS nem kompatibilis a hardveresen gyorsított árnyékszűréssel. A Shader Model 3 DirectX 9 nem támogatja a Gather4 shader utasításokat, amelyeket általában a DirectX 10+/Shader Model 4+ pixel shaderekben használnak az árnyéktérkép szűrésére. A Shader Model 3 pixel shader-t használó PCSS működési terhelése miatt élsimított szűrést alkalmaznak a GPU terhelésének csökkentésére.

Omnidirekcionális árnyékleképezés

A mindenirányú fényforrásokkal a dolgok kicsit bonyolultabbak. Mivel minden irányba árnyékot vetnek, nem olyan egyszerű nekik árnyéktérképeket készíteni, hiszen a jelenetet valamilyen 360°-os kamerával kell renderelni. Ez általában azt jelenti, hogy a jelenetet a fényforrás helyétől több irányban visszaadják. A jelenetet azonban nehéz átméretezni, ha sok ilyen fény van. Ehhez tehát egy előre kiszámított árnyéktérképet alkalmaztunk, ahol minden képkocka helyett a térkép betöltésekor csak egyszer kerül kiszámításra. Az előre kiszámított árnyéktérkép árnyékot tud vetni a jelenet dinamikus objektumaira, de a jeleneten belüli dinamikus objektumok nem vetnek árnyékot. Ennek a korlátozásnak a megkerülésére a Lithtech saját objektum-árnyékfunkcióját használja, hogy árnyékokat adjon az objektumoknak az előre kiszámított mindenirányú árnyéktérképekből. Ezt kombináljuk a Screen-Space Shadows nyomkövetéssel is, hogy az objektumokhoz részletes sajátárnyékokat és érintkezési árnyékokat adjunk.

Egy érdekes példa arra, hogyan használnak árnyéktérképet egy mindenirányú árnyéktérkép egyetlen textúrára vetítésére:

Teljes 360°-os vetítési módszert használ, amelyet oktaéder gömbparaméterezésként vagy néha "oktaéderleképezésnek" neveznek, ahol a gömb egyetlen textúrára van leképezve az oktaéder felületére való vetülete alapján.

Hagyományosan a mindenirányú árnyéktérképek olyan kockatérképet használnak, amelyhez legalább 6 különböző textúra szükséges a teljes, mindenirányú, 360°-os árnyéktérkép megjelenítéséhez, de ezzel a térképvetítéssel csak 1 textúrát használnak. Ez a módszer kisebb torzítást is biztosít, mint a legtöbb más 2D gömb alakú tervezési módszer, és a kibontott kockatérképtől eltérően tökéletesen illeszkedik egyetlen négyzet alakú textúrába. A játékban lévő térképek közül sok nagyszámú körirányú fényt használ elsődleges fényként, és ez lehetővé teszi, hogy sokuk támogassa a valós idejű dinamikus árnyékolást.

Összegezve

Meggyőződésünk, hogy a világítási és árnyékolási technológiák ezen kombinációja nagyon modern megjelenést kölcsönöz a játéknak 2017-ben, és azt is, hogy megoldásaink meglehetősen versenyképesek a többi játékmotorral szemben. Bár ezek a változtatások önmagukban nem elegendőek a játék „modernizálásához”, még mindig sokat kell dolgoznunk a textúrák és az eszközök javításán, amelyek teljes mértékben kihasználják az új funkciók előnyeit.

Természetesen ez nem minden változás, csupán egy alapos áttekintés volt a dinamikus világítás és árnyékolás megvalósításának technikai részleteiről a Combat Arms közelgő frissítésében. Azt is fontos megjegyezni, hogy a megjelenített képernyőképek egy forgóeszközökkel készült összeállítással készültek a grafikus funkciók bemutatására. Előfordulhat, hogy nem tükrözik pontosan a grafika végső szintjét a frissítés megjelenése után.

Arra is emlékeztetnem kell, hogy a frissített grafikus opciók opcionálisak, és a frissítés megjelenése után válthat a motorverziók között. Ezeket a grafikus fejlesztéseket a mai közép- és csúcskategóriás grafikus hardverek képességei alapján fejlesztjük 2016-tól. Azt akarjuk, hogy a játékmotor teljes mértékben ki tudja használni a modern GPU-k képességeit a lehető legjobb képminőség érdekében. Továbbra is folyamatosan teszteljük és optimalizáljuk az új grafikus funkciókat, de ne feledje, hogy a kissé elavult vagy olcsóbb hardver csak alacsonyabb beállításokkal vagy felbontással tudja futtatni az új grafikus opciókat. Továbbra is támogatjuk a régi grafikus motort, így a régebbi vagy kevésbé erős hardverrel rendelkező játékosok, vagy azok, akik egyszerűen a klasszikus Combat Arms stílust kedvelik, továbbra is ugyanúgy élvezhetik a játékot, mint korábban.

Üdvözlettel: Combat Arms csapata!

Az árnyéktérkép valószínűleg a legnehezebb része egy objektum vizuális megjelenítésének. Arra használjuk őket, hogy fényt és árnyékot kapjunk.
Ezeket egyedileg kell kicsomagolni, hogy a modell minden részének meglegyen a maga helye az UV-térben, hogy a végén a megfelelő fény- és árnyékinformációhoz jusson.
Fontos megjegyezni, hogy az árnyéktérkép felbontása kicsi az UV-tér méretéhez képest.
Azt is fontos megérteni, hogy minél inkább optimalizálni kell egy szintet, annál alacsonyabb szintet kell használnia a tervezőnek a fénytérképeken, néha akár 8x8 vagy 16x16 méretig is kisebb objektumok esetén.
Ez a tendencia megköveteli, hogy sok extra helyet hagyjunk az objektum minden egyes szakasza körül, hogy a sötét területek
nem befolyásolta a csúcsfényeket, és nem rombolta le a játékban lévő árnyékok vizuális helyességének illúzióját.

Három fő módja van egy ilyen sweep létrehozásának:

DOBOZ KICSOMAGOLÁSA

Ez gyakran a legmegbízhatóbb módszer a tárgysöprés létrehozására, mivel a legtöbb környezeti modell alakja közel áll azokhoz a blokkokhoz, amelyeket valamilyen szerkezetté egyesítenek.
A folytonos háló (olyan háló, amelynek nincsenek alaprészei) gyakran nagyon hasznos megoldás sweep építésekor,
ez a megoldás elősegíti a geometriai háló hatékonyabb eloszlását az UV-térben.
Ez még alacsony árnyéktérkép-felbontás mellett is jól működik, mivel ekkor egyetlen színátmenetet képez a sötéttől a világosig.
Ellentétben a töredezett pásztázással, ahol az eredmény kétértelműbbnek tűnik, és szükség lehet az árnyéktérkép felbontásának növelésére az éles átmenetek hatásának kiküszöbölése érdekében.
Ezt mindenhol meg kell próbálnunk elkerülni. Sajnos néha nem lehet alacsonyabb felbontást vagy a geometria egyetlen söprését használni.

SÍK KICSOMAGOLÁS

Ez a módszer különösen hasznos lapos szerkezeteknél, például falaknál több letöréssel vagy kidudorodással. Nagyon hasznos az épületek homlokzatainak nagy részeinél is, például lakóházaknál.
síkbeli sokkal jobban kibontakozik, ha nem folytonos geometriát használ, mert itt csak a kicsomagolt rács „lazításában” lesz a kérdés.
Néha az is jó hüvelykujjszabály, hogy megbizonyosodjon arról, hogy egy ilyen söprésnél több vízszintes, mint függőleges tér van, mivel az árnyékok általában oldalról, kissé megemelt szögben jönnek.
nem egyenesen lefelé. Így a több vízszintes tér nagyobb teret ad az élesebb árnyékoknak, mivel a tervezők hajlamosak szögben választani a világítást,
érdekesebb árnyékok létrehozásához, mint felülről lefelé megvilágítva.

HENGERES KICSOMAGOLÁS

A legtöbb más alakzat a hengeres alak variációjaként fogható fel, kivéve persze, ha közel állnak a paralelepipedonokhoz vagy síkokhoz.
A hengeres kidolgozás sok olyan kialakításhoz jó, amelyeknek van elülső oldala, de hátulja nincs, különben a módszert használnánk DOBOZ KICSOMAGOLÁSA.

Példák

Törésmentes háló volt, így könnyű volt vele telepíteni DOBOZ KICSOMAGOLÁSAés csak fektesse ki vízszintesen, hogy a lehető legtöbb árnyéktérkép-területet kihasználja.
A középső képen esetleg látható alsó felületeket eltávolítottuk, mivel szinte mindig feketék lesznek,
és ha a szkennelés többi részéhez kapcsolódnának, az árnyékok egyszerűen beszivárognának a falakon lévő sötét foltokba, ahol nem kellene. Ugyanez igaz a felső szélekre is.
Kivéve, hogy mindig könnyűek lennének.


Ezzel a kibontási módszerrel szinte tökéletes árnyéktérképet kaphatunk a játékban 32x32-es felbontásban, a geometrián nincs varrat. Ahol árnyéknak kellene lennie, ott vékony fekete vonalakat látunk, ahol pedig nem kellene, ott nincsenek.


Itt látjuk, hogy a lehető legnagyobb helyet kell kihasználni, mivel az árnyéktérkép úgyis lefedi a teljes vizsgálatot.
Ezért az objektum 1:1 és 1:7 képaránya között jelentős különbséget fog látni. Azt is láthatja, hogy itt a sweep egyes részei el vannak választva és el vannak távolítva a fő rácstól.
Ez azért van, mert ezek a részek mindig árnyékban maradnak. Ezek nem érinthetik az árnyéktérkép többi részét.


Még az olyan nagy homlokzatokon is, mint ez, síkbeli jó eredményt mutat. Ez a háló törhetetlen, ami segíti munkánkat,
de ebben az esetben minden ugyanúgy működne, ha a szkennelést több függőleges vagy vízszintes csíkra osztanák, bár ezek között kis behúzásokat kellett készíteni.


Itt látható, hogy a szorosan illeszkedő geometria megkönnyítette az UV-k lerakását. Azt is láthatja, hogy itt behúzások készülnek a sweep részei között, hogy a sötét területek ne érintsék a világosakat.
Minél kisebb a térkép felbontása, annál többet kell behúzni.


Elég agresszív torzítások láthatók az egymást keresztező függőleges darabokon, amelyek összetartják a korlátot.
Látható, hogy a központi tartó három helyett két részre van osztva, mintha a központi rész szélei mentén vágnánk. Ez a varratok számának csökkentése és a nagyobb területen egyenletes megvilágítás biztosítása érdekében történik.


Egyes projektek nem tartják be ezeket az egyszerű szabályokat, mint az alábbi képernyőképen.


Ha ennyi egyedi elem van, akkor nincs más dolgunk, mint a textúrák felbontásának növelése, különben sok helyet pazarolnánk a szkennelés elemei közötti párnázásra, borzasztóan nézne ki a játékban.
Az árnyéktérkép felbontását tehát 128x128-ra emelték, de még mindig nem tűnik tökéletesnek, de még mindig nem elég ahhoz, hogy teljesen tönkretegye a játékban lévő objektum vizuális megjelenését.


Néha könnyű bővíteni egy tárgyat, elég, ha több ésszerű részre bontja. És akkor csak „lazítsd” a söprést. Remek példa erre az alábbi objektum.


Ez a kialakítás lényegében egy lapos aljzatú henger, ezért itt a tárgy kibontásának ezt a két alapvető módszerét alkalmazzuk.
síkbeli letekerteti a geometria egyes részeit a z tengelyen, majd alkalmaz egy "relax" módosítót, és egy kicsit módosítja a csúcspozíciókat, hogy semmi se legyen túl kevés.
Középen az alaphoz hasonló tok található, itt a központi rész van felosztva és felhasználva síkbeli ahelyett Hengeres nagy lefedettségi terület biztosítása érdekében.
Mint mindig, most is többet foglalkozunk a lefedettséggel, mint az 1:1 képaránnyal.Nagy előny, hogy a varratok a tényleges helyükön vannak, így természetesebbek lesznek az árnyékok.
Ha tárgya mély bevágásokkal, rendkívül éles geometriai illesztésekkel rendelkezik, akkor ez egy remek hely a varrat elhelyezésére, kivéve, ha erre szükség van.

Lightmap koordináta index

Alapértelmezés szerint a statikus háló első UV-készletét (0. index) használja a rendszer a statikus világítás árnyéktérképének létrehozásakor.
Ez azt jelenti, hogy ugyanazt a koordinátakészletet, amelyet az anyagok hálóra való felvitelére használnak, a statikus világításhoz is használják.
Ez a módszer gyakran nem ideális. Ennek egyik oka, hogy az árnyéktérkép létrehozásához használt UV-sugárzásnak egyedinek kell lennie,
ami azt jelenti, hogy az UV-térben egyetlen hálófelület sem fedhet át semmilyen más felületet. Ennek oka meglehetősen nyilvánvaló: ha az arcok átfedik egymást az UV-térképen,
az árnyéktérkép ennek a térnek megfelelő része mindkét lapra érvényes lesz. Ez helytelen megvilágításhoz, árnyékok megjelenéséhez vezet, ahol elvileg nem kellene.
A statikus hálók rendelkeznek a tulajdonsággal LightmapCoordinateIndex, amely lehetővé teszi a megadott UV használatát az árnyéktérképhez. Ezt a tulajdonságot úgy állítsa be, hogy a világításhoz megfelelően beállított UV-sugárzásra mutasson.

UV diagramok és párnázás

Az izolált háromszögek összefüggő UV-sugárzással rendelkező csoportjait UV-diagramoknak nevezzük.

A pásztázást diagramokra kell osztani, és külön kell elhelyezni, ha ki szeretné zárni az egyik diagram árnyékainak hatását a másikra. Ezenkívül a behúzáskor emlékezzen egy egyszerű szabályra:
A padding méretének 4x4 texelnél nagyobbnak kell lennie, mivel a DXT tömörítés ilyen méretű blokkokkal működik.

  1. Elpazarolt behúzás
  2. Kötelező behúzás

Ez azt jelenti, hogy egy 32-es felbontású árnyéktérképnél az UV-térkép egyes részei közötti párnázásnak a teljes UV-tér 12,5%-ának kell lennie.
Ne feledje azonban, hogy az UV-fények részei közötti túl sok párnázás azt eredményezi, hogy az árnyéktérképhez lefoglalt memória nagyobb felbontásnál elpazarolódik.
Minél közelebb helyezi el az UV-diagramokat, annál jobb. Ez csökkenti az elvesztegetett memória mennyiségét.


Ez messze nem ideális söprés.

A telepítési problémák egyik példája a túlzott széttagoltság. Látható, hogy az objektum belső részein maradó árnyékok hogyan árnyékolják a külső széleket.
Egy másik lehetséges buktató az automatikus feloldás, mivel ez is ugyanazokhoz a problémákhoz vezethet.


Az árnyéktérkép kibontásának legjobb módja, ha a teljes hálót egyetlen folytonos elemként modellezi, vagy manuálisan kicsomagolja.


Ez egyetlen kihajtást biztosít, amely szinte nem tartalmaz varratokat, és sokkal hatékonyabb.

A végeredmény egy olyan háló, amely megfelelően világít minden műtárgy nélkül.


A módszer további előnye, hogy jellemzően csökkenti az adott modellhez szükséges csúcsok és háromszögek számát is.


KATEGÓRIÁK

NÉPSZERŰ CIKKEK

2022 "kingad.ru" - az emberi szervek ultrahangvizsgálata