Hărți clasice de umbre pe scurt. Blogul dezvoltatorilor Four: Noi caracteristici grafice Combat Arms

Lumina are trei caracteristici principale: luminozitate (Multiplicator), culoare (Color) și umbre proiectate de la obiectele pe care le luminează (Shadows).

Când aranjați sursele de lumină într-o scenă, asigurați-vă că acordați atenție culorii lor. Sursele de lumină naturală au o nuanță albastră, dar pentru a crea o sursă de lumină artificială trebuie să îi dai o culoare gălbuie.

De asemenea, trebuie luat în considerare faptul că culoarea sursei care simulează lumina stradală depinde de ora din zi. Prin urmare, dacă intriga scenei implică seara, iluminarea poate fi în nuanțele roșiatice ale unui apus de vară.

Diverse randeri oferă proprii lor algoritmi de generare a umbrelor. Umbra aruncată dintr-un obiect poate spune multe - cât de sus este deasupra solului, care este structura suprafeței pe care cade umbra, ce sursă a iluminat obiectul etc.

În plus, o umbră poate sublinia contrastul dintre prim-plan și fundal, precum și „emite” un obiect care nu se află în câmpul vizual al lentilei camerei virtuale.

În funcție de forma umbrei proiectate de obiect, scena poate părea realistă (Fig. 6.6) sau nu pe deplin credibilă (Fig. 6.7).

După cum am spus mai sus, un fascicul real de lumină suferă un număr mare de reflexii și refracții, astfel încât umbrele reale au întotdeauna margini neclare. În grafica 3D, un termen special este folosit pentru a descrie astfel de umbre - umbre moi.

Atingerea umbrelor moi este destul de dificilă. Multe dispozitive de randare rezolvă problema umbrelor moi prin adăugarea unei surse de lumină non-punctuală care are o formă dreptunghiulară sau altă formă la interfața 3ds max 7. O astfel de sursă emite lumină nu dintr-un punct, ci din fiecare punct de pe suprafață. Mai mult, cu cât suprafața sursei de lumină este mai mare, cu atât umbrele sunt mai blânde atunci când sunt redate.

Există diferite abordări pentru vizualizarea umbrelor: folosind o hartă a umbrelor (Shadow Map), trasarea (Raytraced) și iluminarea globală (Global Illumination). Să le privim în ordine.

Orez. 6.6. Subiect cu umbre moi

Orez. 6.7. Subiect cu umbre aspre

Orez. 6.8. Lansarea setărilor Shadow Map Params pentru sursa de lumină

Utilizarea unei hărți de umbre vă permite să obțineți umbre neclare

cu margini neclare. Setarea principală Shadow Map este dimensiunea hărții umbră (parametrul Dimensiune) din ruloul de setări Shadow Map Params (Fig. 6.8). Dacă dimensiunea hărții este redusă, va scădea și claritatea umbrelor rezultate.

Metoda de trasare face posibilă obținerea de umbre cu formă ideală, care, totuși, arată nenatural datorită conturului lor ascuțit. Urmărirea se referă la urmărirea căilor razelor de lumină individuale de la o sursă de lumină la obiectivul camerei, ținând cont de reflexia lor de la obiectele din scenă și de refracția în medii transparente. Metoda de urmărire este adesea folosită pentru a reda scene care conțin reflexii speculare.

Începând cu 3ds max 5, metoda Area Shadows este folosită pentru a obține umbre moi, care se bazează pe o metodă de trasare ușor modificată. Area Shadows (Shadow distribution) vă permite să calculați umbrele unui obiect ca și cum nu ar exista o singură sursă de lumină în scenă, ci un grup de surse de lumină punctuale distribuite uniform într-o anumită zonă.

Deși ray tracing reproduce cu acuratețe detaliile fine ale umbrelor generate, nu este o soluție de randare ideală din cauza contururilor ascuțite ale umbrelor rezultate.

Metoda de iluminare globală (Radiosity) vă permite să obțineți umbre fine în imaginea finală. Această metodă este o alternativă la trasarea luminii. Dacă metoda de urmărire vizualizează numai acele zone ale scenei care sunt iluminate de raze de lumină, atunci metoda de iluminare globală calculează împrăștierea luminii în zonele neluminate sau umbrite ale scenei pe baza unei analize a fiecărui pixel din imagine. Acest lucru ia în considerare toate reflexiile razelor de lumină în scenă.

Iluminarea globală vă permite să obțineți o imagine realistă, dar procesul de randare solicită multă sarcină stației de lucru și, de asemenea, necesită mult timp. Prin urmare, în unele cazuri este logic să folosiți un sistem de iluminare care simulează efectul luminii difuze. În acest caz, sursele de lumină trebuie amplasate în așa fel încât poziția lor să coincidă cu locurile de expunere directă la lumină. Astfel de surse nu ar trebui să creeze umbre și ar trebui să aibă luminozitate scăzută. Această metodă cu siguranță nu produce o imagine la fel de realistă pe cât poate fi obținută folosind o adevărată metodă de iluminare globală. Cu toate acestea, în scenele care au geometrie simplă, poate fi destul de util.

Există mai mulți algoritmi pentru calcularea iluminării globale; una dintre metodele de calcul al luminii reflectate este urmărirea fotonilor (Photon Mapping). Această metodă implică calcularea iluminării globale pe baza creării unei așa-numite hărți fotonice. Harta fotonică reprezintă informații despre iluminarea scenei colectate prin urmărire.

Avantajul metodei de urmărire a fotonilor este că, odată salvate ca hartă fotonică, rezultatele urmăririi fotonilor pot fi utilizate ulterior pentru a crea efecte de iluminare globale în scenele de animație 3D. Calitatea iluminării globale calculată folosind trasarea fotonilor depinde de numărul de fotoni, precum și de adâncimea de urmărire. Folosind trasarea fotonilor, puteți calcula și efectul caustic (citiți mai multe despre efectul caustic în secțiunea „Informații generale despre vizualizarea în grafica 3D”, Capitolul 7).

Dintre sursele de lumină standard, trei surse (și anume Spot, Direct și Omni) ne permit să alegem tipul de umbre care trebuie calculate. Dacă folosim standardul Default Scanline Renderer (DSR), atunci următoarele vor fi de interes pentru noi: Umbre avansate cu trasare de raze, Umbre zone, Umbre cu urmărire de raze, Hărți de umbre.

Când selectați un tip de umbră dintre derulările cu parametrii IS, apare un defilare cu parametrii de umbră, al cărui nume începe cu numele tipului.

Harta în umbră

Cel mai simplu și mai puțin solicitant tip de umbre în ceea ce privește resursele de calcul.

  1. Dimensiunea hărții pe baza căreia se calculează umbra. Cu cât harta este mai mare, cu atât calitatea umbrei calculate este mai bună. Este mai bine să folosiți numere de ordinul 2 n
  2. Estomparea marginii umbrei. Mărirea parametrului vă permite să scăpați de marginea zimțată atunci când rezoluția hărții este scăzută
  3. Parametru responsabil pentru controlul valorii Bias. Dezactivat implicit (cel mai bun rezultat în majoritatea cazurilor). În cazul animației, activarea opțiunii
  4. Dacă este dezactivată, lumina trece prin suprafață dacă lovește poligoane cu valorile normale îndreptate spre ea. Activarea acestei opțiuni vă permite să obțineți umbre corecte

În Fig. 1, rândul de sus de imagini arată clar schimbarea calității umbrei pe măsură ce parametrul Dimensiune crește. Chiar și o creștere semnificativă a dimensiunii hărții nu rezolvă problema marginilor zimțate ale umbrei, deși modelul umbrei devine cu siguranță mai detaliat.

În al doilea rând, în toate cele trei cazuri dimensiunea hărții rămâne aceeași, dar parametrul Sample Range se modifică. Mărind-o treptat, am scăpat de crete, estompând marginea umbrei.

Fig.1 Modificarea calității umbrei tip Shadow Map cu diverși parametri

Umbre trasate cu raze

Acest tip de umbră este calculat pe baza unui algoritm de urmărire. Au margini clare și sunt practic imposibil de personalizat.

Umbra trasată cu raze este mai precisă în comparație cu Harta umbră. În plus, este capabil să țină cont de transparența obiectului, dar în același timp este „uscat” și clar, ceea ce nu pare foarte natural în majoritatea cazurilor. Ray-Traced Shadow este mai solicitantă pentru resursele computerului decât Shadow Map.

  1. Distanța obiectului față de umbra proiectată
  2. Adâncimea trasării este un parametru responsabil pentru dezvoltarea umbrei. Creșterea acestei valori poate crește semnificativ timpul de randare

Redarea umbrelor cu trasare de raze cu un IC de tip Omni va dura mai mult decât o combinație de umbre cu trasare de raze + spot (sau direcțional)

Fig.2 Umbre cu trasare cu raze de la obiecte opace și transparente

Umbre avansate cu trasarea razelor

Umbrele de acest tip sunt foarte asemănătoare cu Ray-Traced Shadows, dar, după cum sugerează și numele, au setări mai avansate care permit calcule mai naturale și corecte.

  1. Metoda de generare a umbrei
    Simplu – un singur fascicul iese din IC. Umbra nu acceptă nicio setare de anti-aliasing sau de calitate
    1-Pass Antialias – se simulează emisia unui fascicul de raze. Mai mult, același număr de raze este reflectat de pe fiecare suprafață iluminată (numărul de raze este ajustat de Shadow Quality).
    2-Pass Antialias – Similar, dar sunt emise două fascicule de raze.
  2. Dacă este dezactivat, atunci lumina trece prin suprafață dacă lovește poligoane cu normalurile îndreptate în direcția ei. Activarea acestei opțiuni vă permite să obțineți umbre corecte
  3. Numărul de raze emise de o suprafață iluminată
  4. Numărul de raze secundare emise de suprafața iluminată
  5. Raza (în pixeli) marginii umbrei este estompată. Mărirea parametrului îmbunătățește calitatea neclarității. Dacă micile detalii se pierd la estomparea marginii, corectați acest lucru prin creșterea integrității umbrei
  6. Distanța obiectului față de umbra proiectată
  7. Un parametru care controlează aleatoritatea razelor. Inițial, razele sunt direcționate de-a lungul unei grile stricte, care poate provoca artefacte neplăcute. Introducerea haosului va face umbra să pară mai naturală
    Valorile recomandate sunt 0,5-1,0. Dar umbrele mai neclare vor necesita o cantitate mai mare de Jitter

Umbrele zonei

Acest tip de umbră vă permite să țineți cont de dimensiunile sursei de lumină, astfel încât să puteți obține umbre naturale extinse care „se despart” și se estompează pe măsură ce vă îndepărtați de obiect. 3dsMax produce aceste umbre prin amestecarea unui număr de „eșantioane” de umbre. Cu cât mai multe „eșantioane” și cu cât amestecul este mai bun, cu atât umbra calculată este mai bună.

  1. Forma unei surse de lumină imaginare care vă permite să determinați natura umbrei.
    Simplu – un singur fascicul iese din IC. Umbra nu acceptă nicio setare de anti-aliasing sau de calitate.
    Lumină dreptunghiulară t – se simulează emisia de lumină dintr-o zonă dreptunghiulară.
    Disc Light – CI se comportă ca și cum ar fi căpătat forma unui disc.
    Cutie Lumină – imitarea IC cubici.
    Lumina Sferei t – imitarea unui IC sferic.
  2. Dacă este dezactivată, lumina trece prin suprafață dacă lovește poligoane cu valorile normale îndreptate spre ea. Activarea acestei opțiuni vă permite să obțineți umbre corecte.
  3. Controlează numărul de raze emise (neliniare). Cu cât numărul este mai mare, cu atât mai multe raze, cu atât calitatea umbrei este mai mare.
  4. Un parametru responsabil pentru calitatea umbrei. Pentru calcul rațional, setați întotdeauna numărul mai mare decât Shadow Integrity.
  5. Raza (în pixeli) marginii umbrei este estompată. Mărirea parametrului îmbunătățește calitatea neclarității. Dacă micile detalii se pierd la estomparea marginii, corectați acest lucru prin creșterea integrității umbrei.
  6. Distanța obiectului față de umbra proiectată.
  7. Un parametru care controlează aleatoritatea razelor. Inițial, razele sunt direcționate de-a lungul unei grile stricte, care poate provoca artefacte neplăcute. Introducerea haosului va face umbra să pară mai naturală.
  8. Dimensiunile sursei imaginare. Lungime - lungime, Lățime - lățime, Înălțime (activ numai pentru Box Light și Sphere Light) - înălțime.

Să aruncăm o privire la Fig.3. Pe primul fragment. Mai multe „eșantioane” de umbră sunt suprapuse unele peste altele fără nicio amestecare. În al doilea fragment, acestea sunt deja amestecate (cantitatea de fluctuație a fost schimbată de la 0,0 la 6,0). „Probele” mixte sunt percepute ca o umbră mai naturală, dar calitatea acesteia lasă de dorit. Al treilea fragment arată o umbră cu o calitate excelentă (Shadow Integrity și Shadow Quality au fost modificate de la valori individuale la 8 și, respectiv, 10).

Al doilea rând din Fig. 3. ilustrează modul în care caracterul umbrei se schimbă dacă mărim dimensiunea sursei imaginare. În acest caz, avem o sursă imaginară de tip Rectangle Light (plat dreptunghiular). Pe măsură ce zona sursă crește, neclaritatea umbrei crește.

Fig.3 Modificarea calității umbrei tip Area Shadow cu diferiți parametri

Unele valori ale parametrilor sunt de natură consultativă, dar totul este limitat doar de imaginația ta. Cel mai bun mod de a-ți da seama este prin experimentare. Nu vă fie teamă să experimentați cu lumina. Prinde starea de spirit a imaginii viitoare și cedează setărilor.

În Fig.4. cavaler de șah cu un material bazat pe o textura de lemn procedurală simplă. Trei surse de lumină colorate în culori diferite. Configurare simplă, dar figura arată totuși bine.

Fig.4 Piesa de șah „Cavalerul”. Vizualizarea subiectului

rezumat

Iluminarea este una dintre cele mai importante etape în lucrul la o scenă tridimensională. La prima vedere, poate părea că informațiile uscate ale lecției nu pot fi aplicate muncii creative. Cu toate acestea, cu ingeniozitatea adecvată și munca grea, puteți obține rezultate incredibile. La urma urmei, toate imaginile digitale sunt doar colecții de unu și zero, iar 3dsMax este doar un alt instrument pentru tine, la fel ca un creion sau o pensulă.

Algoritmul original de cartografiere a umbrelor a fost inventat cu destul de mult timp în urmă. Principiul său de funcționare este următorul:
  1. Desenăm scena într-o textură (hartă de umbră) din poziția sursei de lumină. Este important să rețineți că lucrurile se întâmplă puțin diferit pentru diferite tipuri de surse de lumină.
    Sursele de lumină direcționale (într-o anumită aproximare aceasta include lumina soarelui) nu au o poziție în spațiu, dar pentru a forma o hartă de umbră trebuie aleasă această poziție. De obicei, este legat de poziția observatorului, astfel încât harta umbră include obiecte situate direct în câmpul vizual al observatorului. Redarea folosește o proiecție ortografică.
    Sursele de lumina de proiectie (lampi cu abajururi opace, spoturi) au o anumita pozitie in spatiu si limiteaza raspandirea luminii in anumite directii. La redarea hărții de umbră în acest caz, se utilizează o matrice de proiecție în perspectivă convențională.
    Sursele de lumină omnidirecțională (o lampă cu incandescență, de exemplu), deși au o anumită poziție în spațiu, distribuie lumina în toate direcțiile. Pentru a construi corect umbre dintr-o astfel de sursă de lumină, trebuie să utilizați hărți cub, ceea ce înseamnă, de obicei, să desenați scena într-o hartă cu umbră de 6 ori. Nu orice joc își poate permite umbre dinamice din acest tip de surse de lumină și nu orice joc are nevoie de ele. Dacă sunteți interesat de modul în care funcționează această abordare, există un subiect pe acest subiect.
    În plus, există o subclasă de algoritmi de cartografiere a umbrelor (LiSPSM, TSM, PSM etc.), care utilizează matrici de proiecție de vizualizare non-standard pentru a îmbunătăți calitatea umbrelor și pentru a elimina deficiențele abordării originale.
    Indiferent de modul în care este formată harta umbră, aceasta conține invariabil distanța de la sursa de lumină până la cel mai apropiat punct vizibil (din poziția sursei de lumină) sau o funcție a acestei distanțe în versiunile mai complexe ale algoritmului.
  2. Desenăm scena din camera principală. Pentru a înțelege dacă un punct al unui obiect se află în umbră, este suficient să transpuneți coordonatele acestui punct în spațiul hărții de umbră și să faceți o comparație. Spațiul hărții în umbră este determinat de matricea vizualizare-proiecție care a fost utilizată pentru generarea acestei hărți. Prin translatarea coordonatelor punctului obiect în acest spațiu și transformarea coordonatelor din interval [-1;-1] V , obținem coordonatele texturii. Dacă coordonatele primite sunt în afara intervalului , atunci acest punct nu este inclus în harta umbră și poate fi considerat neumbrit. Făcând o selecție din harta umbrelor folosind coordonatele texturii rezultate, vom obține distanța dintre sursa de lumină și cel mai apropiat punct al oricărui obiect de aceasta. Dacă comparăm această distanță cu distanța dintre punctul curent și sursa de lumină, punctul apare în umbră dacă valoarea din harta umbră este mai mică. Acest lucru este destul de simplu din punct de vedere logic, dacă valoarea de pe harta umbră este mai mică, înseamnă că în acest moment există un obiect care este mai aproape de sursa de lumină, iar noi suntem în umbra ei.
Maparea umbrelor este probabil cel mai comun algoritm pentru redarea umbrelor dinamice astăzi. Implementarea uneia sau alteia modificări a algoritmului poate fi găsită în aproape orice motor grafic. Principalul avantaj al acestui algoritm este că asigură formarea rapidă a umbrelor din obiecte complexe din punct de vedere geometric. În același timp, existența unei game largi de variații ale algoritmului se datorează în mare măsură deficiențelor acestuia, care pot duce la artefacte grafice foarte neplăcute. Problemele specifice PPSM și modalitățile de depășire a acestora vor fi discutate mai jos.

Maparea umbrelor divizate în paralel

Luați în considerare următoarea problemă: este necesar să se deseneze umbre dinamice din obiectele situate la o distanță considerabilă de jucător fără a compromite umbrele de la obiectele aflate în apropiere. Să ne limităm la lumina directă a soarelui.
Acest tip de problemă poate fi deosebit de relevantă în jocurile în aer liber, unde în unele situații jucătorul poate vedea peisajul la sute de metri în fața lui. În același timp, cu cât dorim să vedem mai departe umbra, cu atât mai mult spațiu ar trebui să cadă în harta umbrelor. Pentru a menține rezoluția corectă a obiectelor din harta umbră, suntem forțați să creștem rezoluția hărții în sine, ceea ce duce mai întâi la o scădere a performanței, apoi ne întâlnim cu o limitare a dimensiunii maxime a țintei de randare. Ca rezultat, echilibrând între performanță și calitatea umbrei, vom obține umbre cu un efect de aliasing clar vizibil, care este prost mascat chiar și prin estompare. Este clar că o astfel de soluție nu ne poate satisface.
Pentru a rezolva această problemă, putem veni cu o matrice de proiecție astfel încât obiectele situate aproape de jucător să primească o zonă mai mare în harta umbră decât obiectele care sunt situate departe. Aceasta este ideea principală a algoritmului Perspective Shadow Mapping (PSM) și a unui număr de alți algoritmi. Principalul avantaj al acestei abordări este faptul că practic nu am schimbat procesul de redare a scenei, s-a schimbat doar metoda de calcul a matricei vedere-proiecție. Această abordare poate fi integrată cu ușurință într-un joc sau motor existent, fără a fi nevoie de modificări majore la acesta din urmă. Principalul dezavantaj al acestui tip de abordare îl reprezintă condițiile la limită. Să ne imaginăm o situație în care tragem umbre de la Soare la apus. Pe măsură ce Soarele se apropie de orizont, obiectele din harta umbră încep să se suprapună foarte mult. În acest caz, o matrice de proiecție atipică poate agrava situația. Cu alte cuvinte, algoritmii clasei PSM funcționează bine în anumite situații, de exemplu, când jocul atrage umbre de la „Soarele fix” aproape de zenit.
O abordare fundamental diferită este propusă în algoritmul PSSM. Acest algoritm poate fi cunoscut de unii ca Cascaded Shadow Mapping (CSM). Formal, aceștia sunt algoritmi diferiți; aș spune chiar că PSSM este un caz special de CSM. Acest algoritm propune împărțirea piramidei de vizibilitate (frustum) a camerei principale în segmente. În cazul PSSM - cu limite paralele cu planurile de tăiere apropiate și îndepărtate, în cazul CSM - tipul de împărțire nu este strict reglementat. Pentru fiecare segment ( Despicăîn terminologia algoritmului) se construiește propria sa hartă umbră. Un exemplu de împărțire este prezentat în figura de mai jos.


În figură puteți vedea împărțirea piramidei de vizibilitate în 3 segmente. Fiecare dintre segmente este evidențiat cu un dreptunghi de delimitare (în spațiul tridimensional va exista o casetă de delimitare paralelipiped). Pentru fiecare dintre aceste părți limitate ale spațiului, va fi construită propria sa hartă în umbră. Cititorul atent va observa că aici am folosit paralelipipede de delimitare aliniate axial. De asemenea, puteți folosi cele nealiniate; acest lucru va adăuga o complexitate suplimentară algoritmului de tăiere a obiectelor și va schimba oarecum modul în care matricea de vizualizare este generată din poziția sursei de lumină. Deoarece piramida de vizibilitate se extinde, aria segmentelor mai apropiate de cameră poate fi semnificativ mai mică decât aria celor mai îndepărtate. Având în vedere aceeași rezoluție a hărților de umbre, aceasta înseamnă o rezoluție mai mare pentru umbrele de la obiectele din apropiere. Articolul menționat mai sus în GPU Gems 3 propune următoarea schemă pentru calcularea distanțelor de împărțire a piramidei de vizibilitate:



Unde i– indice de partiție, m– numărul de partiții, n– distanța până la cel mai apropiat plan de tăiere, f– distanța până la planul de tăiere îndepărtat, λ – coeficient care determină interpolarea între scările de partiție logaritmică și uniformă.

General în implementare
Algoritmul PSSM implementat în Direct3D 11 și OpenGL are multe în comun. Pentru a implementa algoritmul, trebuie să pregătiți următoarele:
  1. Mai multe hărți de umbră (în funcție de numărul de partiții). La prima vedere, se pare că pentru a obține mai multe hărți de umbră trebuie să desenați obiecte de mai multe ori. De fapt, nu este necesar să facem acest lucru în mod explicit; vom folosi mecanismul de instanțiere hardware. Pentru a face acest lucru, avem nevoie de o așa-numită matrice de textură de randare și de un simplu shader de geometrie.
  2. Mecanism pentru tăierea obiectelor. Obiectele din lumea jocului pot avea diferite forme geometrice și au poziții diferite în spațiu. Obiectele extinse pot fi vizibile în mai multe hărți de umbră, obiecte mici - doar într-una. Un obiect poate apărea direct pe marginea segmentelor adiacente și trebuie desenat cu cel puțin 2 hărți de umbră. Astfel, este necesar un mecanism pentru a determina în ce subset de hărți umbre se încadrează un anumit obiect.
  3. Un mecanism pentru determinarea numărului optim de partiții. Redarea hărților de umbră pentru fiecare segment pe cadru poate fi o risipă de resurse de calcul. În multe situații, jucătorul vede doar o mică parte din lumea jocului în fața sa (de exemplu, se uită la picioarele sale, sau privirea se sprijină pe peretele din fața lui). Este clar că asta depinde foarte mult de tipul de recenzie din joc, dar ar fi bine să existe o astfel de optimizare.
Ca rezultat, obținem următorul algoritm pentru generarea matricelor de vedere-proiectare pentru randarea hărților umbre:
  1. Calculăm distanțele pentru a împărți piramida vizibilității în cel mai rău caz. Cel mai rău caz aici este că vedem umbre până la planul de tăiere a camerei îndepărtate.

    Cod

    void calculateMaxSplitDistances() ( 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. Determinăm distanța dintre cameră și cel mai îndepărtat punct vizibil al obiectului care aruncă umbra. Este important să rețineți că obiectele pot arunca umbre sau nu. De exemplu, un peisaj de deal plat poate fi făcut să nu arunce umbre; în acest caz, un algoritm de iluminare poate fi responsabil pentru umbrire. Numai obiectele care aruncă umbre vor fi desenate în harta umbrelor.

    Cod

    float calculateFurthestPointInCamera(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(); pentru (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_farPlane); )

  3. Pe baza valorilor obținute la pașii 1 și 2, determinăm numărul de segmente de care avem cu adevărat nevoie și distanțele de partiție pentru acestea.

    Cod

    void calculateSplitDistances() ( // calculăm de câte hărți umbre avem cu adevărat nevoie de m_currentSplitCount = 1; if (!m_maxSplitDistances.empty()) ( for (size_t i = 0; i< m_maxSplitDistances.size(); i++) { float d = m_maxSplitDistances[i] - m_splitShift; if (m_furthestPointInCamera >= d) m_currentSplitCount++; ) ) float nearPlane = m_camera.getInternalCamera().GetNearPlane(); pentru (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. Pentru fiecare segment (limitele segmentului sunt determinate de distanțele apropiate și îndepărtate), calculăm paralelipipedul de delimitare.

    Cod

    bbox3 calculateFrustumBox(float nearPlane, float farPlane) ( vector3 eye = m_camera.getPosition(); vector3 vZ = m_camera.getOrientation().z_direction(); vector3 vX = m_camera.getOrientation().x_direction(); vector3 vY = m_camera. getOrientation().y_direction(); float fov = n_deg2rad(m_camera.getInternalCamera().GetAngleOfView()); float aspect = m_camera.getInternalCamera().GetAspectRatio(); float nearPlaneHeight = n_tan(fov * 0.5f) * nearPlane float nearPlaneWidth = nearPlaneHeight * aspect; float farPlaneHeight = n_tan(fov * 0.5f) * farPlane; float farPlaneWidth = farPlaneHeight * aspect; vector3 nearPlaneCenter = ochi + vZ * nearPlane; vector3 = farPlaneC; caseta 3 = farPlaneC; begin_extend(); box.extend(vector3(nearPlaneCenter - vX * nearPlaneWidth - vY * nearPlaneHeight)); box.extend(vector3(nearPlaneCenter - vX * nearPlaneWidth + vY * nearPlaneHeight)); nearPlaneWidth + vY * nearPlaneHeight));box.extend(vector3(nearPlaneCenter + vX * nearPlaneWidth - vY * nearPlaneHeight)); box.extend(vector3(farPlaneCenter - vX * farPlaneWidth - vY * farPlaneHeight)); box.extend(vector3(farPlaneCenter - vX * farPlaneWidth + vY * farPlaneHeight)); box.extend(vector3(farPlaneCenter + vX * farPlaneWidth + vY * farPlaneHeight)); box.extend(vector3(farPlaneCenter + vX * farPlaneWidth - vY * farPlaneHeight)); box.end_extend(); cutie de retur; )

  5. Calculăm matricea umbră a vederii de proiecție pentru fiecare segment.

    Cod

    matrix44 calculateShadowViewProjection(const bbox3& frustumBox) ( const float LIGHT_SOURCE_HEIGHT = 500.0f; vector3 viewDir = m_camera.getOrientation().z_direction(); vector3 size = frustumBox.size(); vector3 center = frustumBox; 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(shadow(View.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); return shadowView * shadowProj; )

Implementăm tăierea obiectelor folosind un test simplu pentru intersecția a două paralelipipede delimitare (un obiect și un segment al piramidei de vizibilitate). Există o caracteristică aici care este important de luat în considerare. Poate că nu vedem obiectul, dar îi putem vedea umbra. Nu este greu de ghicit că, prin abordarea descrisă mai sus, vom tăia toate obiectele care nu sunt vizibile în camera principală și nu vor exista umbre din ele. Pentru a preveni acest lucru, am folosit o tehnică destul de comună - am extins caseta de delimitare a obiectului de-a lungul direcției de propagare a luminii, ceea ce a oferit o aproximare aproximativă a regiunii spațiului în care umbra obiectului este vizibilă. Ca rezultat, pentru fiecare obiect a fost generată o matrice de indici de hartă umbră în care acest obiect trebuie să fie desenat.

Cod

void updateShadowVisibilityMask(const bbox3& frustumBox, const std::shared_ptr & entity, EntityData& entityData, int splitIndex) ( bbox3 b = entity->getBoundingBox(); b.transform(entityData.model); // shadow box calcul auto 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++; } }


Acum să ne uităm la procesul de randare și la părțile specifice Direct3D 11 și OpenGL 4.3.
Implementare pe Direct3D 11
Pentru a implementa algoritmul pe Direct3D 11 vom avea nevoie de:
  1. O serie de texturi pentru randarea hărților de umbre. Pentru a crea acest tip de obiect, există un câmp ArraySize în structura D3D11_TEXTURE2D_DESC. Deci, în codul C++ nu vom avea nimic de genul ID3D11Texture2D* array[N] . Din punctul de vedere al API-ului Direct3D, o serie de texturi diferă puțin de o singură textură. O caracteristică importantă atunci când folosim o astfel de matrice într-un shader este că putem determina în ce textură din matrice vom desena acest sau acel obiect (semantica SV_RenderTargetArrayIndex în HLSL). Aceasta este principala diferență dintre această abordare și MRT (ținte de randare multiple), în care un obiect este desenat în toate texturile specificate simultan. Pentru obiectele care trebuie desenate în mai multe hărți de umbră simultan, vom folosi instanțarea hardware, care ne permite să clonăm obiecte la nivel de GPU. În acest caz, obiectul poate fi desenat într-o textură din matrice, iar clonele sale în altele. Vom stoca doar valoarea adâncimii în hărțile de umbră, așa că vom folosi formatul de textură DXGI_FORMAT_R32_FLOAT.
  2. Prelevator de textură special. În API-ul Direct3D, puteți seta parametri speciali pentru eșantionarea dintr-o textură, ceea ce vă va permite să comparați valoarea texturii cu un anumit număr. Rezultatul în acest caz va fi 0 sau 1, iar tranziția dintre aceste valori poate fi netezită printr-un filtru liniar sau anizotrop. Pentru a crea un sampler în structura D3D11_SAMPLER_DESC, setați următorii parametri:

    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;
    Astfel, vom avea filtrare biliniară, comparație cu funcția „mai puțin decât” și eșantionare din textură la coordonate în afara intervalului va returna 1 (adică fără umbră).

Vom efectua randarea conform următoarei scheme:

Implementare pe OpenGL 4.3
Pentru a implementa algoritmul pe OpenGL 4.3, avem nevoie de totul la fel ca pentru Direct3D 11, dar există subtilități. În OpenGL, putem face preluare comparabilă doar pentru texturi care conțin o valoare de adâncime (de exemplu, în formatul GL_DEPTH_COMPONENT32F). În consecință, vom reda numai la depth buffer și vom elimina înregistrarea la culoare (mai precis, vom lega doar o serie de texturi la framebuffer pentru a stoca depth-buffer-ul). Acest lucru, pe de o parte, ne va economisi puțină memorie video și va ușura conducta grafică, pe de altă parte, ne va forța să lucrăm cu valori de adâncime normalizate.
Parametrii de eșantionare în OpenGL pot fi legați direct de textură. Acestea vor fi identice cu cele discutate mai devreme pentru Direct3D 11.

Const float BORDER_COLOR = ( 1.0f, 1.0f, 1.0f, 1.0f ); glBindTexture(m_shadowMap->getTargetType(), m_shadowMap->getDepthBuffer()); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_COMPARE_FUNC, GL_LESS); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(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);
Procesul de creare a unei serii de texturi, care este reprezentată de o textură tridimensională în interiorul OpenGL, este interesant. Nu a fost creată nicio funcție specială pentru ao crea, ambele sunt create folosind glTexStorage3D . Echivalentul GLSL al SV_RenderTargetArrayIndex este variabila încorporată gl_Layer.
Schema de randare rămâne, de asemenea, aceeași:

Probleme

Algoritmul de cartografiere a umbrelor și modificările acestuia au multe probleme. Adesea, algoritmul trebuie reglat cu atenție pentru un anumit joc sau chiar pentru o anumită scenă. Puteți găsi o listă cu cele mai frecvente probleme și modalități de a le rezolva. În timpul implementării PSSM, am întâlnit următoarele:

Performanţă

Măsurătorile de performanță au fost efectuate pe un computer cu următoarea configurație: AMD Phenom II X4 970 3.79GHz, 16Gb RAM, AMD Radeon HD 7700 Series, care rulează Windows 8.1.

Timp mediu de cadru. Direct3D 11 / 1920x1080 / MSAA 8x / ecran complet / scenă mică (~12k poligoane per cadru, ~20 obiecte)

Timp mediu de cadru. OpenGL 4.3 / 1920x1080 / MSAA 8x / ecran complet / scenă mică (~12k poligoane per cadru, ~20 obiecte)

Timp mediu de cadru. 4 împărțiri / 1920x1080 / MSAA 8x / ecran complet / scenă mare (~1000k poligoane per cadru, ~1000 obiecte, ~500 obiecte)

Rezultatele au arătat că pe scenele mari și mici, implementarea OpenGL 4.3 este în general mai rapidă. Pe măsură ce sarcina pe conducta grafică crește (creșterea numărului de obiecte și a instanțelor acestora, creșterea dimensiunii hărților umbre), diferența de viteză de operare între implementări scade. Asociez avantajul implementării OpenGL cu o metodă diferită de generare a hărților umbre din Direct3D 11 (am folosit doar un buffer de adâncime fără a scrie pe culoare). Nimic nu ne împiedică să facem același lucru pe Direct3D 11, în timp ce ne resemnăm să folosim valori de adâncime normalizate. Cu toate acestea, această abordare va funcționa doar până când dorim să stocăm câteva date suplimentare sau o funcție a valorii adâncimii în harta umbră în loc de valoarea adâncimii. Și unele îmbunătățiri ale algoritmului (de exemplu, Variance Shadow Mapping) ne vor fi dificil de implementat.

concluzii

Algoritmul PSSM este una dintre cele mai de succes metode de creare a umbrelor în spații mari deschise. Se bazează pe un principiu simplu și clar al partiționării, care poate fi ușor scalat prin creșterea sau scăderea calității umbrelor. Acest algoritm poate fi combinat cu alți algoritmi de cartografiere a umbrelor pentru a obține umbre mai frumoase sau mai corecte din punct de vedere fizic. În același timp, algoritmii clasei de cartografiere a umbrelor duc adesea la apariția unor artefacte grafice neplăcute care trebuie eliminate prin reglarea fină a algoritmului pentru un anumit joc.

Etichete:

  • Maparea umbrei
  • PSSM
  • Direct3D 11
  • OpenGL 4
Adaugă etichete

Blogul dezvoltatorilor patru: noi caracteristici grafice

În primul jurnal de actualizare a motorului grafic, am vorbit pe scurt despre unele dintre noile îmbunătățiri grafice care vor fi adăugate în curând jocului. În plus, am afirmat că majoritatea acestor îmbunătățiri vor fi la egalitate cu motoarele de jocuri moderne, cum ar fi Unity 5, Unreal 4 sau CryEngine 3. Dar ce înseamnă asta de fapt?

În primul rând, dorim să înțelegeți că procesul de actualizare va avea loc treptat și nu toate hărțile, personajele, texturile armelor și obiectele vor fi actualizate imediat. Cele mai multe dintre acestea vor continua să funcționeze cu activele actuale ale jocului, dar le vom actualiza în timp pentru a oferi Combat Arms un aspect cu adevărat actualizat.

Merită remarcat faptul că pentru ca multe dintre aceste capacități grafice să funcționeze pe un motor atât de vechi, menținând, în același timp, compatibilitatea cu vechiul mod și resursele grafice, ne-a impus să facem o mulțime de soluții interesante și uneori nebune, limitate la capabilitățile DirectX 9. A fost foarte amuzant!

Iluminare și umbre dinamice

Motorul original Lithitech Jupiter avea suport limitat pentru iluminarea dinamică și umbre, deși ceea ce oferea motorul era destul de avansat pentru epoca în care a fost dezvoltat. Practic, în motorul grafic original Lithtech Jupiter, iluminarea și umbrirea erau complet statice, ceea ce înseamnă că au fost precalculate și stocate ca o textură care a fost folosită la randarea geometriei hărții. Cu toate acestea, chiar și iluminarea statică în anumite puncte le-a permis să creeze scene iluminate dinamic pe anumite obiecte, cum ar fi modele de personaje și arme. Deoarece iluminarea dinamică folosea per-vertex pe obiecte, diferite detalii suplimentare și denivelări au trebuit, de asemenea, să fie precalculate și coapte direct pe texturile difuze. Și pentru că sunt coapte, nu pot interacționa dinamic cu diferite surse de lumină și adesea nu se potrivesc în condiții de iluminare. Acest lucru face ca imaginea să pară foarte plată și depășită pentru 2017.

Cea mai importantă îmbunătățire pe care am putut să o implementăm a fost să combinăm atât geometria statică a hărții, cât și obiectele care primesc lumini și umbre complet dinamice. Iluminarea dinamică vă permite cu adevărat să redați o scenă cu iluminare pixel cu pixel, reflexii, evidențieri, umbre dinamice și hărți cu denivelări.

Deși introducerea unei singure surse de lumină dinamică nu a fost inițial atât de dificilă, provocările au apărut din necesitatea de a susține simultan mai multe surse dinamice de lumină într-un mod eficient. Suportul pentru mai multe surse dinamice de lumină a devenit o caracteristică de bază a aproape fiecare motor de joc modern. Singurul mod în care motorul Lithtech a suportat redarea mai multor lumini dinamice a fost, în esență, să redeseneze întreaga scenă de mai multe ori, o dată pentru fiecare lumină de pe hartă. Aceasta este oarecum o exagerare, deoarece Lithtech este capabilă să grupeze geometria hărții în blocuri care pot fi realizate printr-o sferă de lumină delimitată și numai acele blocuri de hartă vor trebui redesenate. Dar acest lucru necesită încă o încărcare mare a procesorului pentru a reda scena de mai multe ori și impune și mai multe restricții cu privire la cât de complexă este geometria hărții și câte obiecte pot fi afișate simultan pe ecran.

Am început prin a avea doar lumina directă principală a soarelui ca singura sursă de lumină dinamică la început. Toate celelalte surse de lumină interne omnidirecționale și punctiforme au fost lăsate statice. Dar multe dintre locațiile jocului din Combat Arms sunt parțial sau în întregime situate în clădiri, așa că diferența dintre iluminarea statică interioară și cea dinamică exterioară a fost prea vizibilă.

Așadar, iluminarea dinamică care folosește mai multe surse de lumină a necesitat schimbări majore în modul în care motorul redă scena și gestionează lumina în sine. Pentru a face acest lucru, am folosit o tehnică de randare cunoscută sub numele de Deferred Shading. Subiectul iluminării și umbririi amânate poate fi unul destul de larg și l-am menționat pe scurt în prima postare pe blogul dezvoltatorilor. Practic, permite ca toată iluminarea dinamică să fie împinsă în domeniul redării post-proces, care este complet independentă de complexitatea scenei și poate fi gestionată aproape în întregime de GPU cu foarte puțină supraîncărcare a CPU.

Având în vedere toate aceste optimizări, am putut implementa un shader complex de iluminare fizică. Apoi am testat pe larg acest model de iluminare, comparându-l cu modul în care scenele similare ar fi redate în alte motoare de jocuri moderne, cum ar fi Unity 5 și Unreal 4, precum și scenele cu randare integrală cu raze create folosind randarea offline profesională. Ne-am limitat doar la ceea ce am putea implementa în timp real cu hardware-ul grafic modern, folosind shadere de iluminat modern. Rezultatele sunt destul de comparabile cu redarea razelor, principalele diferențe fiind precizia reflexiei și atenuarea iluminării.

Noi shadere dinamice de iluminare în Combat Arms:

Versiunea cu ray-tracing a scenei:

Carte de umbră

La implementarea umbrelor dinamice, ne-am confruntat cu o serie de provocări pentru a obține umbrirea de ultimă generație, complet dinamică în Combat Arms. În motorul original Lithtech, majoritatea umbrelor sunt coapte în texturi de iluminare statică utilizate la randarea geometriei hărții. Acesta este motivul pentru care nu toate obiectele aruncă umbre, în special obiectele dinamice, deoarece umbra este fixă ​​și nu se poate schimba. Deși Lithtech are o caracteristică care vă permite să creați umbre dinamice pe anumite obiecte, nu a fost folosit prea mult în Combat Arms. În plus, această caracteristică este prea limitată în domeniul ei, iar obiectele dinamice în sine nu pot primi umbre.

În cele din urmă, am decis să folosim o hartă a umbrelor în cascadă (CSM) complet dinamică pentru sursa principală de lumină direcțională de la soare și o soluție parțial dinamică pentru lumini și surse de lumină omnidirecționale folosind o hartă de umbră omnidirecțională precalculată care poate fi aplicată. atât geometriei lumii, cât și obiectelor dinamice. Acest lucru este similar cu modul în care alte motoare de joc moderne oferă umbrire dinamică.

În general, ce este o carte umbră? În esență, este un truc foarte inteligent pe care jocurile și programele de randare îl folosesc pentru a simula umbrirea dinamică accelerată de GPU. https://en.wikipedia.org/wiki/Shadow_mapping.

Algoritmul de redare a umbrei se ocupă, practic, de necesitatea de a reda scena în termeni de sursă de lumină pe o textură, folosind-o ca punct de intrare pentru shader-ul de iluminare a pixelilor și apoi folosind textura respectivă pentru a calcula de către GPU dacă pixelul este în umbra sau nu.

În joc, textura hărții umbre arată astfel:

Vă rugăm să rețineți că această textură nu are 1, ci 4 hărți de umbră. Fiecare dintre aceste hărți de umbră este numită cascadă de hărți de umbră. Pe măsură ce distanța până la suprafața observată crește, se folosește o cascadă mai mare, dar cu o rezoluție mai mică. Acest lucru permite umbrelor să se extindă foarte mult, dar încă se potrivesc într-o textura de dimensiune fixă. În acest caz, umbrele din apropierea observatorului vor avea o rezoluție mai mare. Rezoluția hărții de umbre este direct legată de cât de clare și precise pot fi umbrele.

Deoarece harta umbră este doar o altă cameră din scenă, poate fi redată dinamic în timp real. Setările de calitate a umbrei vor afecta rezoluția texturii hărții de umbre.

Așa arată soluția hărții umbre atunci când este filtrată.

Filtrarea hărții în umbră

Folosirea doar a unei hărți de umbre poate duce la umbre foarte dure. Și deși uneori pot arăta bine, aceasta nu este realitatea.

În lumea reală, umbrele nu sunt întotdeauna dure sau moi, ele se schimbă în funcție de dimensiunea sursei de lumină și de distanța de la obiectul iluminat. Puteți vedea exemple în fotografie:

Observați cum în aceste fotografii umbrele devin mai moi pe măsură ce se îndepărtează de obiectele care le aruncă. Majoritatea celorlalte jocuri moderne folosesc încă o metodă simplă de filtrare a umbririi numită Filtrare mai apropiată procentuală sau PCF, care aplică o valoare fixă ​​a durității sau moliciunii tuturor umbrelor.

Aceste capturi de ecran din jocurile foarte moderne Doom și Overwatch arată cum majoritatea jocurilor efectuează filtrarea simplă a umbrelor folosind PCF.

Cu toate acestea, la Combat Arms am decis să implementăm o tehnologie mai avansată de filtrare a umbrelor, care va fi mai aproape de ceea ce vedem în viața reală. În joc, simulăm acest lucru folosind o tehnologie dezvoltată de NVidia numită Closer Soft Shadows (PCSS).

Deși această tehnologie a fost introdusă încă din 2005, abia acum hardware-ul grafic a devenit suficient de puternic pentru a utiliza această metodă, iar jocurile moderne au început să o folosească intens pentru filtrarea hărților umbre în ultimii ani. La momentul scrierii acestui blog, această tehnologie nu este încă disponibilă în Unreal 4 sau Unity 5. Deși din punct de vedere tehnic, Unreal 4 oferă o soluție alternativă numită distance ray tracing, dar se limitează doar la rezolvarea geometriei statice pentru proiectarea umbrelor.

PCSS dezactivat:

PCSS activat:

Filtrarea fină cu PCSS va fi aplicată atunci când setările de calitate a umbrei sunt setate la nivel ridicat. De asemenea, PCSS este utilizat în prezent numai pentru lumina directă a soarelui de bază la toate nivelurile de calitate. Din păcate, PCSS nu este compatibil cu filtrarea umbră accelerată hardware. Shader Model 3 DirectX 9 nu acceptă instrucțiunile Gather4 shader care sunt utilizate în mod obișnuit în shaderele de pixeli DirectX 10+/Shader Model 4+ pentru filtrarea hărții de umbre. Datorită încărcării operaționale a PCSS care utilizează shaderul de pixeli Shader Model 3, filtrarea antialias este utilizată pentru a reduce încărcarea GPU-ului.

Maparea umbrelor omnidirecționale

Cu sursele de lumină omnidirecționale, lucrurile sunt puțin mai complicate. Deoarece aruncă umbre în toate direcțiile, realizarea de hărți de umbre pentru ei nu este atât de ușoară, deoarece scena trebuie redată folosind un fel de cameră de 360°. Aceasta implică de obicei redarea scenei în mai multe direcții de la poziția sursei de lumină. Cu toate acestea, este dificil să scalați o scenă atunci când există multe astfel de surse de lumină. Deci, pentru aceasta, am folosit o hartă umbră precalculată, unde este calculată o singură dată când harta este încărcată în loc de fiecare cadru. O hartă de umbre precalculată poate arunca umbre asupra obiectelor dinamice din scenă, dar obiectele dinamice din scenă nu vor arunca umbre. Pentru a ocoli această limitare, funcția nativă de umbră a obiectelor din motorul Lithtech este utilizată pentru a oferi umbre obiectelor din hărți de umbră omnidirecționale precalculate. De asemenea, combinăm acest lucru cu urmărirea Screen-Space Shadows pentru a oferi obiectelor umbre native detaliate și umbre de contact.

Un exemplu interesant despre modul în care o hartă de umbră este utilizată pentru a proiecta o hartă de umbră omnidirecțională într-o singură textură:

Aceasta folosește o metodă de proiecție completă la 360° cunoscută sub numele de parametrizare octaedrică sferică, sau uneori numită „mapping octaedral”, în care sfera este mapată la o singură textură pe baza proiecției sale pe fața octaedrului.

Hărțile tradiționale de umbră omnidirecționale folosesc o hartă cub, care necesită cel puțin 6 texturi diferite pentru a reprezenta o hartă de umbră omnidirecțională completă de 360°, dar cu această proiecție a hărții este utilizată doar o textură. Această metodă produce, de asemenea, mai puțină distorsiune decât majoritatea celorlalte metode de proiectare 2D sferică și, spre deosebire de o hartă cub neambalată, se potrivește perfect într-o singură textură pătrată. Multe hărți existente în joc folosesc un număr mare de lumini omnidirecționale ca surse de lumină primare, iar acest lucru le permite multora dintre ele să accepte și umbrirea dinamică în timp real.

Să rezumam

Credem că această combinație de tehnologii de iluminare și umbrire va oferi jocului un aspect foarte modern pentru 2017 și că soluțiile noastre sunt destul de competitive cu ceea ce oferă alte motoare de joc astăzi. Deși aceste modificări nu sunt suficiente pentru a „moderniza” jocul, mai avem mult de lucru pentru a îmbunătăți texturile și elementele care vor profita din plin de noile funcții.

Desigur, acestea nu sunt toate schimbările, aceasta a fost doar o privire aprofundată asupra detaliilor tehnice ale implementării iluminării dinamice și umbririi în viitoarea actualizare Combat Arms. În plus, este important de reținut că capturile de ecran afișate au fost făcute folosind o versiune cu activele curente pentru a demonstra caracteristicile grafice. Este posibil ca acestea să nu reflecte cu exactitate nivelul grafic final odată ce actualizarea este lansată.

De asemenea, ar trebui să vă reamintesc că setările grafice actualizate sunt opționale și veți putea comuta între versiunile de motor odată ce actualizarea este lansată. Dezvoltăm aceste îmbunătățiri grafice pe baza capacităților dispozitivelor grafice moderne de gamă medie și înaltă, care sunt relevante pentru 2016. Ne dorim ca motorul de joc să poată profita din plin de GPU-urile moderne pentru a oferi cea mai bună calitate vizuală posibilă. Încă analizăm și optimizăm în mod constant noile funcții grafice, dar rețineți că hardware-ul puțin mai vechi sau mai ieftin poate rula noi opțiuni grafice doar la setări sau rezoluții mai mici. Vom continua să sprijinim motorul grafic moștenit, astfel încât jucătorii cu hardware mai vechi sau mai puțin puternic, sau cei care pur și simplu preferă stilul clasic Combat Arms, să se poată bucura în continuare de joc ca înainte.

Salutări, echipa Combat Arms!

Maparea umbrelor este probabil cea mai dificilă parte a creării unei reprezentări vizuale a unui obiect. Le folosim pentru a obține lumină și umbră copte.
Acestea trebuie să fie despachetate în mod unic, astfel încât fiecare parte a modelului să aibă propriul loc în spațiul UV pentru a ajunge la informațiile corecte despre lumină și umbră.
Este important să ne amintim că rezoluția hărții de umbră este mică în comparație cu dimensiunea spațiului UV.
De asemenea, este important să înțelegem că cu cât un nivel trebuie optimizat mai mult, cu atât designerul de nivel ar trebui să folosească rezoluția mai mică pe hărți luminoase, ajungând uneori până la 8 pe 8 sau 16 pe 16 în cazul obiectelor mai mici.
Această tendință necesită să lăsăm mult spațiu suplimentar în jurul fiecărei secțiuni a măturarii obiectului, astfel încât zonele care sunt întunecate
nu a afectat luminile și nu a distrus iluzia corectitudinii vizuale a umbrelor din joc.

Există 3 moduri principale de a crea o astfel de matură:

DESFALAT CUTIE

Aceasta este adesea cea mai fiabilă metodă pentru crearea unui aspect al obiectului, deoarece majoritatea modelelor de mediu sunt apropiate ca formă de blocuri care sunt combinate într-un fel de structură.
O plasă continuă (o plasă în care nu există părți separate de partea principală) este adesea o soluție foarte utilă atunci când se construiește o plasă,
Această soluție va ajuta la asigurarea unei distribuții mai eficiente a geometriei ochiurilor în spațiul UV.
Acest lucru va funcționa bine chiar și cu o hartă cu umbre cu rezoluție scăzută, deoarece apoi va forma un singur gradient de la întuneric la lumină.
Acest lucru este în contrast cu o scanare fragmentată în care rezultatul va părea mai ambiguu și poate fi necesar să măriți rezoluția hărții umbre pentru a contracara efectul tranzițiilor ascuțite.
Ar trebui să încercăm să evităm asta acolo unde putem. Din păcate, uneori nu este posibil să utilizați o rezoluție mai mică sau o scanare cu o singură geometrie.

DESFĂCUT PLANAR

Această metodă este utilă în special pentru structuri plate, cum ar fi pereții cu mai multe teșituri sau extrudate. De asemenea, este foarte util pentru părți mari ale fațadelor clădirilor, cum ar fi clădirile de apartamente.
Planar se va desfășura mult mai bine dacă folosiți o geometrie continuă, deoarece aici întrebarea va fi doar despre „relaxarea” grilei de scanare.
Uneori, este, de asemenea, o regulă generală să vă asigurați că există mai mult spațiu orizontal pe o scanare ca aceasta decât spațiu vertical, deoarece proiectarea umbrei tinde să fie din lateral la un unghi puțin mai mare.
mai degrabă decât drept în jos. Astfel, spațiul orizontal mai mare oferă oportunități mai mari de a crea umbre mai clare, datorită tendinței designerilor de a alege iluminarea în unghi,
pentru a crea umbre mai interesante decât iluminarea de sus în jos.

DESFALAT CILINDRIC

Majoritatea celorlalte forme pot fi considerate variații ale formei cilindrice, cu excepția cazului în care, bineînțeles, sunt apropiate de paralelipipede sau plane.
Dezvoltarea cilindrica este bine de folosit pentru multe structuri care au fata si laturile, dar fara spate, altfel am folosi metoda DESFALAT CUTIE.

Exemple

Era o plasă continuă, așa că era ușor de extins DESFALAT CUTIEși așezați-l pe orizontală pentru a utiliza cât mai mult spațiu posibil al hărții în umbră.
Suprafețele inferioare care ar fi vizibile în imaginea din mijloc au fost eliminate, deoarece vor fi aproape întotdeauna negre.
și dacă ar fi conectate cu restul scanării, umbrele din ele s-ar pătrunde pur și simplu în pete întunecate pe pereți unde nu ar trebui să fie. Același lucru este valabil și pentru fețele superioare.
Doar că ar fi întotdeauna ușoare.


Această metodă de desfășurare ne permite să avem o hartă a umbrelor aproape perfectă în joc la o rezoluție de 32 x 32. Geometria nu are cusături. Acolo unde ar trebui să existe o umbră, vedem linii negre subțiri, iar acolo unde nu ar trebui să existe, nu există.


Aici vedem că este necesar să folosiți cât mai mult spațiu posibil, deoarece harta umbră va acoperi în orice caz întreaga scanare.
Prin urmare, veți vedea o diferență semnificativă între raportul de aspect al unui obiect 1 la 1 și 1 la 7. De asemenea, puteți vedea că unele părți ale scanării sunt separate aici și îndepărtate de rețeaua principală.
Acest lucru se face deoarece aceste părți vor rămâne întotdeauna în umbră. Ele nu ar trebui să afecteze restul hărții în umbră.


Chiar și pe fațade mari ca aceasta, Planar arată rezultate bune. Această plasă este continuă, ceea ce ne ajută la munca,
dar în acest caz totul ar funcționa la fel chiar dacă scanarea ar fi împărțită în mai multe dungi verticale sau orizontale, deși era necesar să se facă mici indentări între ele.


Puteți vedea aici, geometria strânsă a făcut ușoară așezarea UV-urilor. De asemenea, puteți vedea că există indentări între părțile scanării, astfel încât zonele întunecate să nu le afecteze pe cele luminoase.
Cu cât rezoluția hărții este mai mică, cu atât trebuie să luați mai multă indentare.


Puteți vedea o distorsiune destul de agresivă pe piesele verticale care se intersectează care țin balustrada împreună.
Puteți vedea că suportul central este împărțit în două părți în loc de trei, de parcă l-am tăia de-a lungul marginilor părții centrale. Acest lucru se face pentru a reduce numărul de cusături și pentru a oferi o iluminare lină pe o suprafață mai mare.


Unele proiecte nu respectă aceste reguli simple, ca în captura de ecran de mai jos.


Când există atât de multe elemente individuale, nu avem de ales decât să creștem rezoluția texturilor, altfel am pierde mult spațiu pe căptușeala dintre elementele de scanare, ar arăta groaznic în joc.
Deci rezoluția hărților de umbră a fost ridicată la 128 cu 128, dar încă nu arată perfect, dar încă nu atât de mult încât ar distruge complet imaginea vizuală a obiectului din joc.


Uneori este ușor să extindeți un obiect; este suficient să-l divizați în mai multe părți rezonabile. Și apoi doar „relaxează” măturarea. Un exemplu grozav este obiectul de mai jos.


Acest design este în esență un cilindru cu o bază plată, așa că sunt utilizate aceste două metode de bază de desfacere a unui obiect.
Planar rotește părți ale geometriei în jos pe axa Z, apoi aplică un modificator de „relaxare” și ajustează puțin pozițiile vârfurilor pentru a se asigura că nimic nu primește o acoperire prea mică.
În mijloc este un caz similar cu baza, aici partea centrală este împărțită și folosită Planarîn loc de Cilindric pentru a oferi o zonă de acoperire mai mare.
Ca întotdeauna, suntem mai preocupați de acoperire decât de raportul de aspect 1: 1. Este un mare avantaj să plasezi cusăturile în locațiile lor reale, acest lucru va permite umbrelor să pară mai naturale.
Dacă obiectul tău are tăieturi adânci, îmbinări cu geometrie extrem de ascuțite, atunci acesta este un loc excelent pentru a așeza o cusătură aici, dacă desigur este necesar.

Indexul coordonatelor lightmap

În mod implicit, primul set de UV (indice 0) al rețelei statice va fi utilizat la crearea hărții de umbre pentru iluminarea statică.
Aceasta înseamnă că același set de coordonate care sunt utilizate pentru aplicarea materialelor pe plasă va fi folosit și pentru iluminarea statică.
Această metodă nu este adesea ideală. Un motiv pentru aceasta este că UV-urile folosite pentru a genera harta umbră trebuie să fie unice.
ceea ce înseamnă că fiecare față de plasă nu trebuie să se suprapună cu nicio altă suprafață din spațiul UV. Motivul pentru aceasta este destul de evident: dacă fețele se suprapun pe harta UV,
pe ambele fețe se va aplica porțiunea hărții de umbră corespunzătoare acestui spațiu. Acest lucru va duce la o iluminare incorectă și la apariția de umbre acolo unde acestea nu ar trebui să existe în principiu.
Ochiurile statice au proprietatea LightmapCoordinateIndex, care vă permite să utilizați o anumită scanare UV pentru o hartă în umbră. Setați această proprietate pentru a indica un set de UV-uri care sunt configurate corect pentru iluminare.

Diagrame UV și umplutură

Grupurile de triunghiuri izolate cu UV adiacente se numesc diagrame UV.

Ar trebui să împărțiți scanarea în diagrame și să le plasați separat dacă doriți să excludeți influența umbrelor unei diagrame asupra alteia. De asemenea, atunci când indentați, ar trebui să vă amintiți o regulă simplă:
Dimensiunea indentării trebuie să fie mai mare de 4x4 texeli, deoarece compresia DXT funcționează cu blocuri de exact această dimensiune.

  1. Indentare irosită
  2. Indentare necesară

Aceasta înseamnă că pentru o hartă cu umbră de 32 de rezoluții, umplutura dintre părțile hărții UV ar trebui să fie de 12,5% din spațiul UV total.
Cu toate acestea, rețineți că utilizarea prea multă umplutură între părți ale UV va duce la irosirea memoriei hărții umbre la rezoluții mai mari.
Cu cât vă puteți apropia mai mult de diagramele UV, cu atât mai bine. Acest lucru va reduce cantitatea de memorie irosită.


Aceasta este departe de a fi o implementare perfectă.

Un exemplu de problemă de implementare este fragmentarea excesivă. Vedeți cum umbrele care ar trebui să rămână pe părțile interioare ale obiectului dau umbrire marginilor externe.
Un alt potențial capcan este bazarea pe despachetarea automată, deoarece și aceasta poate duce la aceleași probleme.


Cel mai bun mod de a crea o hartă de rețea pentru o hartă în umbră este de a modela întreaga plasă ca un element continuu sau de a crea rețeaua manual.


Acest lucru va produce o singură măturare care nu are aproape nicio cusătură și este mult mai eficientă.

Rezultatul final este o plasă care se luminează corespunzător, fără artefacte.


Un avantaj suplimentar al acestei metode este că de obicei reduce numărul de vârfuri și triunghiuri necesare pentru un model dat.


CATEGORII

ARTICOLE POPULARE

2023 „kingad.ru” - examinarea cu ultrasunete a organelor umane