Hărți clasice de umbre pe scurt. Dev Blog 4: Noi caracteristici grafice Combat Arms

Lumina are trei caracteristici principale: luminozitate (Multiplicator), culoare (Color) și umbre proiectate de la obiectele iluminate de aceasta (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ă subiectul scenei implică seara, iluminarea poate fi în nuanțe roșiatice ale unui apus de vară.

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

În plus, umbra 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 tocmai credibilă (Fig. 6.7).

După cum am spus mai sus, o rază de lumină reală suferă un număr mare de reflexii și refracții, astfel încât umbrele reale au întotdeauna margini neclare. În grafica tridimensională, un termen special este folosit pentru a desemna 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ță. În acest caz, cu cât aria sursei de lumină este mai mare, cu atât umbrele sunt mai blânde atunci când sunt redate.

Există diferite abordări pentru randarea umbrelor: folosind o hartă de umbre ( Shadow Map ), trasare ( Raytraced ) și iluminare globală ( Global Illumination ). Să le considerăm în ordine.

Orez. 6.6. Obiect cu umbre moi

Orez. 6.7. Obiect cu umbre dure

Orez. 6.8. Defilare de setări Shadow Map Params (Parametrii hărții de umbră) ale sursei de lumină

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

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

Metoda de urmărire vă permite să obțineți umbre perfect modelate, care, totuși, arată nenatural datorită conturului lor ascuțit. Urmărirea este urmărirea căilor razelor de lumină individuale de la sursa 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 au 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 (Distribuția umbrelor) vă permite să calculați umbrele din 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 trasarea razelor reproduce cu acuratețe detaliile fine ale umbrelor generate, nu este ideală pentru randare, deoarece umbrele rezultate sunt tăiate.

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 redă doar acele părți ale scenei care sunt lovite de razele de lumină, atunci metoda de iluminare globală calculează împrăștierea luminii în părțile neluminate sau umbrite ale scenei pe baza analizei fiecărui pixel al imaginii. Acest lucru ia în considerare toate reflexiile razelor de lumină din scenă.

Iluminarea globală vă permite să obțineți o imagine realistă, dar procesul de randare este încărcat puternic pe stația de lucru și, în plus, durează mult. Prin urmare, în unele cazuri este logic să folosiți un sistem de iluminare care simulează efectul luminii împrăștiate. Î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ă o 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 foarte 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ă calculul iluminării globale pe baza creării unei așa-numite hărți fotonice. Harta fotonică este informații despre iluminarea scenei, colectate folosind trasarea.

Avantajul metodei de urmărire a fotonilor este că, odată salvate ca hartă fotonică, rezultatele urmăririi fotonului pot fi utilizate ulterior pentru a crea un efect de iluminare globală î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 trasării. Cu ajutorul urmăririi fotonilor, puteți calcula și efectul caustic (pentru mai multe informații despre efectul caustic, consultați secțiunea „Informații generale despre vizualizarea în grafica 3D” din Capitolul 7).

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

Când este selectat un tip de umbră, apare o rulare a parametrilor de umbră printre derulările parametrilor IS, al căror nume începe cu numele tipului.

hartă în umbră

Cel mai simplu și nesolicitant tip de umbre pentru resursele calculate.

  1. Dimensiunea hărții pe care se bazează umbra. Cu cât harta este mai mare, cu atât umbra calculată 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ă a marginii la rezoluție scăzută a hărții
  3. Parametru responsabil pentru controlul valorii Bias. Dezactivat implicit (cel mai bun rezultat în majoritatea cazurilor). În cazul animației, activarea opțiunii poate ajuta.
  4. Dacă este dezactivată, lumina va trece prin suprafață dacă lovește poligoane îndreptate spre ea cu valorile normale. Activarea opțiunii vă permite să obțineți umbrele corecte

În Fig.1, rândul de sus de imagini arată clar schimbarea calității umbrei cu o creștere a parametrului Dimensiune. Chiar și o creștere semnificativă a dimensiunii hărții nu rezolvă problema marginilor zimțate ale umbrei, deși desenul umbrei devine cu siguranță mai elaborat.

Î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 Schimbarea calității unei umbre de tip Shadow Map cu diferiți parametri

Ray Traced Shadows

Umbrele de acest tip sunt calculate pe baza unui algoritm de urmărire. Au margini ascuțite și sunt aproape imposibil de ajustat.

Umbra trasată cu raze este mai precisă decât Harta umbră. În plus, sunt capabili să țină cont de transparența obiectului, dar în același timp „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 de urmărire este un parametru responsabil pentru dezvoltarea umbrei. Creșterea acestei valori poate crește semnificativ timpul de randare.

Umbrele cu trasare de raze cu circuite integrate de tip Omni vor dura mai mult pentru randare decât Umbrele cu trasare de raze + spot (sau direcțional)

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

Umbre avansate în urma cu raze

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 vă permit să obțineți calcule mai naturale și corecte.

  1. Metoda de generare a umbrei
    Simplu - un singur fascicul iese din IS. Shadow nu acceptă nicio setare de anti-aliasing și de calitate
    1-Pass Antialias - se imită 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 reglat de Shadow Quality).
    2-Pass Antialias - În mod similar, dar sunt emise două fascicule de raze.
  2. Dacă este dezactivată, lumina va trece prin suprafață dacă lovește poligoane îndreptate spre ea cu valorile normale. Activarea opțiunii vă permite să obțineți umbrele corecte
  3. Numărul de raze emise de suprafața iluminată
  4. Numărul de raze secundare emise de suprafața iluminată
  5. Raza (în pixeli) pentru a estompa marginea umbrei. Mărirea parametrului îmbunătățește calitatea neclarității. Dacă micile detalii se pierd la estomparea marginilor, corectați acest incident 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. Adăugarea haosului va face umbra să pară mai naturală.
    Valorile recomandate sunt 0,5-1,0. Dar umbrele mai blânde 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 se îndepărtează de obiect. 3dsMax obține astfel de umbre amestecând un număr de „eșantioane” (mostre) de umbre. Cu cât mai multe „eșantioane” și o amestecare 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 IS. Umbra nu acceptă nicio setare de anti-aliasing și de calitate.
    Lumină dreptunghiulară t - simulează emisia de lumină dintr-o zonă dreptunghiulară.
    lumina discului - CI se comportă ca și cum ar fi luat forma unui disc.
    cutie de lumină – imitarea unui IC cubic.
    Lumina Sferei t este o imitație a unui IC sferic.
  2. Dacă este dezactivată, lumina va trece prin suprafață dacă lovește poligoane îndreptate spre ea cu valorile normale. Activarea opțiunii vă permite să obțineți umbrele 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. Parametrul responsabil pentru calitatea umbrei. Pentru calcul rațional, setați întotdeauna un număr mai mare decât Shadow Integrity.
  5. Raza (în pixeli) pentru a estompa marginea umbrei. Mărirea parametrului îmbunătățește calitatea neclarității. Dacă micile detalii se pierd la estomparea marginilor, corectați acest incident 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 imaginea umbrei 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 una peste alta, fără nicio amestecare. Pe 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 natura umbrei se schimbă dacă mărim dimensiunile sursei imaginare. În acest caz, avem o sursă imaginară de tip Rectangle Light (plată dreptunghiulară). Pe măsură ce zona sursă crește, estomparea umbrei crește.

Fig.3 Modificarea calității umbrei tipului 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 afla este să experimentezi. Nu vă fie teamă să experimentați cu lumina. Prindeți starea de spirit a imaginii viitoare și predați-vă setărilor.

Pe Fig.4. un cal de șah cu un material bazat pe o textură procedurală simplă Wood. Trei surse de lumină colorate în culori diferite. O simplă punere în scenă, totuși, figura arată bine.

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

rezumat

Iluminarea este unul dintre cei mai importanți pași în lucrul la o scenă 3D. La prima vedere, poate părea că informațiile uscate ale lecției nu pot fi aplicate muncii creative. Cu toate acestea, cu ingeniozitatea și diligența cuvenite, se pot obține rezultate incredibile. La urma urmei, toate imaginile digitale sunt doar seturi de zerouri și unu, iar 3dsMax este doar următorul tău instrument, la fel ca un creion sau o perie.

Algoritmul original de cartografiere a umbrelor a fost inventat cu 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 de reținut aici că, pentru diferite tipuri de surse de lumină, totul se întâmplă puțin diferit.
    Sursele de lumină direcționale (într-o anumită aproximare, lumina soarelui poate fi denumită ca atare) nu au o poziție în spațiu, totuși, pentru a forma o hartă de umbră, această poziție trebuie aleasă. De obicei, este legat de poziția observatorului, astfel încât obiectele care se află direct în câmpul de vedere al observatorului cad în harta umbră. La randare, se folosește o proiecție ortografică.
    Sursele de lumina de proiectie (lampi cu nuanta opaca, 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ă matricea obișnuită de proiecție în perspectivă.
    Sursele de lumină omnidirecționale (o lampă cu incandescență, de exemplu), deși au o anumită poziție în spațiu, răspândesc lumina în toate direcțiile. Pentru a construi corect umbre dintr-o astfel de sursă de lumină, trebuie să utilizați texturi cub (hărți cub), care, de regulă, înseamnă să desenați scena într-o hartă de umbră de 6 ori. Nu orice joc își poate permite umbre dinamice de la acest tip de lumină și nu orice joc are nevoie de ele. Dacă sunteți interesat de modul în care funcționează această abordare, există un thread pe acest subiect.
    În plus, există o subclasă de algoritmi de cartografiere a umbrelor (LiSPSM , TSM , PSM , etc.), care utilizează matrici de vizualizare de proiecție 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ă punctul oricărui 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 vedere-proiectare, care a fost folosită la formarea acestei hărți. Prin translatarea coordonatelor punctului obiect în acest spațiu și conversia coordonatelor din interval [-1;-1] în , 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. După ce am făcut o selecție din harta umbrelor în funcție de coordonatele texturii obținute, vom obține distanța dintre sursa de lumină și punctul unui obiect cel mai apropiat de aceasta. Dacă comparăm această distanță cu distanța dintre punctul curent și sursa de lumină, atunci punctul este î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ă, atunci în acest moment există un obiect care este mai aproape de sursa de lumină, iar noi suntem în umbra ei.
Maparea umbrelor este de departe cel mai comun algoritm pentru redarea umbrelor dinamice. 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 geometrice arbitrar complexe. Î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.

Mapare paralelă a umbrelor divizate

Luați în considerare următoarea problemă: este necesar să desenați umbre dinamice din obiectele care se află la o distanță considerabilă de jucător, fără a afecta umbrele de la obiectele din apropiere. Ne limităm la lumina direcțională a soarelui.
Acest tip de sarcină 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 păstra rezoluția corespunzătoare a obiectelor din harta umbră, suntem nevoiț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 limită 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 bine marcat, 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 care sunt aproape de jucător să primească mai multă zonă în harta umbră decât obiectele aflate la distanță. 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 un motor existent, fără a fi nevoie de modificări majore la acesta din urmă. Principalul dezavantaj al unor astfel de abordări este condițiile de 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 în umbră încep să se suprapună 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. Pentru unii, acest algoritm poate fi cunoscut sub numele de Cascaded Shadow Mapping (CSM). Formal, aceștia sunt algoritmi diferiți, chiar aș spune că PSSM este un caz special de CSM. În acest algoritm, se 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 separare nu este strict reglementat. Pentru fiecare segment ( Despicăîn terminologia algoritmului) își construiește propria hartă umbră. Un exemplu de separare 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 marcat cu o casetă de delimitare (în spațiul 3D va exista o casetă, o casetă de delimitare). 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 casete de delimitare aliniate pe axe. Puteți folosi, de asemenea, cele nealiniate, acest lucru va adăuga o complexitate suplimentară algoritmului de tăiere a obiectelor și va schimba oarecum modul în care se formează matricea de vizualizare din poziția sursei de lumină. Deoarece piramida vizibilității se extinde, aria segmentelor mai apropiate de cameră poate fi semnificativ mai mică decât aria celor mai îndepărtate. Cu aceeași rezoluție a hărții de umbre, aceasta înseamnă o rezoluție mai mare pentru umbrele de la obiectele din apropiere. În articolul menționat mai sus în GPU Gems 3, se propune următoarea schemă pentru calcularea distanțelor de împărțire a piramidei vizibilității:



Unde i– indice de partiție, m- numărul de partiții, n este distanța până la planul de tăiere apropiat, f este distanța până la planul de tăiere îndepărtat, λ este coeficientul care determină interpolarea între scara 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, este necesar 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ă pentru randare și de un simplu shader de geometrie.
  2. Mecanism de tăiere a obiectelor. Obiectele din lumea jocului pot avea diferite forme geometrice și au poziții diferite în spațiu. Obiectele extinse pot fi văzute în mai multe hărți de umbră, obiectele mici într-una singură. Obiectul poate fi chiar la marginea segmentelor învecinate ș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 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 lui (de exemplu, se uită la picioarele sale sau ochii se sprijină pe peretele din fața lui). Este clar că asta depinde foarte mult de tipul de vizualizare din joc, dar ar fi bine să existe o astfel de optimizare.
Ca rezultat, obținem următorul algoritm pentru generarea matricelor de vizualizare de proiecție pentru randarea hărților umbre:
  1. Calculăm distanțele pentru împărțirea piramidei vizibilității în cel mai rău caz. Cel mai rău caz aici este că vedem umbre până în planul îndepărtat de tăiere al camerei.

    Codul

    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. Determinați distanța dintre cameră și cel mai îndepărtat punct vizibil al obiectului care aruncă umbra. Lucrul important de remarcat aici este că obiectele pot arunca umbre sau nu. De exemplu, un peisaj plat-deluros poate fi realizat fără a arunca umbre, în acest caz algoritmul de iluminare poate fi responsabil pentru umbrire. Numai obiectele care aruncă umbre vor fi desenate în harta umbrelor.

    Codul

    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ța de împărțire a acestora.

    Codul

    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 caseta de delimitare.

    Codul

    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 proiecției vizuale pentru fiecare segment.

    Codul

    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; )

Tăierea obiectelor este implementată folosind un test simplu pentru intersecția a două casete de delimitare (un obiect și un segment tronc). Există o caracteristică aici care este important de luat în considerare. Poate că nu vedem obiectul, dar putem vedea umbra lui. Este ușor 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 un truc destul de comun - extinderea casetei de delimitare a obiectului de-a lungul direcției de propagare a luminii, ceea ce a dat o aproximare aproximativă a zonei spațiului în care se află umbra obiectului. vizibil. Ca urmare, pentru fiecare obiect s-a format o matrice de indici de hartă umbră, în care acest obiect trebuie trasat.

Codul

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ă aruncăm o privire asupra procesului de randare și a părților specifice Direct3D 11 și OpenGL 4.3.
Implementare pe Direct3D 11
Pentru a implementa algoritmul pe Direct3D 11, avem nevoie de:
  1. O serie de texturi pentru randarea hărților de umbre. Pentru a crea acest tip de obiect, structura D3D11_TEXTURE2D_DESC are un câmp ArraySize. Astfel, în codul C++, nu vom avea nimic de genul ID3D11Texture2D* array[N] . Din punctul de vedere al API-ului Direct3D, o serie de texturi este puțin diferită 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 simultan în toate texturile date. 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. În hărțile de umbră, vom stoca doar valoarea adâncimii, așa că vom folosi formatul de textură DXGI_FORMAT_R32_FLOAT .
  2. Prelevator de textură special. În Direct3D API, puteți seta parametri speciali pentru preluarea texturii, care vă vor 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ă cu 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ă prin coordonate în afara intervalului va returna 1 (adică fără umbră).

Redarea se va realiza conform următoarei scheme:

Implementare în 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 doar eșantionare de comparație combinată pentru texturi care conțin o valoare de adâncime (de exemplu, în formatul GL_DEPTH_COMPONENT32F). Prin urmare, vom reda numai în buffer-ul de adâncime și vom elimina scrierea la culoare (mai precis, vom atașa doar o serie de texturi la framebuffer pentru a stoca tamponul de adâncime). Pe de o parte, acest lucru ne va economisi ceva 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 din 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);
Un proces interesant este crearea unei serii de texturi, care în interiorul OpenGL este reprezentată de o textură tridimensională. Nu a fost creată nicio funcție specială pentru ao crea, ambele sunt create folosind glTexStorage3D . Analogul GLSL al SV_RenderTargetArrayIndex este variabila încorporată gl_Layer.
Schema de randare a rămas, 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ă. Odată cu o creștere a încărcăturii pe conducta grafică (o creștere a numărului de obiecte și a instanțelor acestora, o creștere a dimensiunii hărților umbre), diferența de viteză între implementări este redusă. Atribuim avantajul implementării OpenGL modului de generare a hărții umbre, care este diferită de Direct3D 11 (am folosit doar tamponul 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 atâta timp cât nu dorim să stocăm niște date sau funcții suplimentare din valoarea adâncimii din 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 modalități de a crea umbre în spații mari deschise. Se bazează pe un principiu simplu și clar de divizare, 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 produce 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 jocului în curând. În plus, am afirmat că cele mai multe dintre aceste îmbunătățiri vor fi la egalitate cu motoarele de joc moderne precum Unity 5, Unreal 4 sau CryEngine 3. Dar ce înseamnă asta cu adevărat?

În primul rând, dorim să înțelegeți că procesul de actualizare va fi 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 în timp le vom actualiza și pe acestea pentru a oferi Combat Arms un aspect cu adevărat actualizat.

Este demn de remarcat faptul că utilizarea multor dintre aceste caracteristici grafice pentru a rula pe un motor atât de vechi, deși încă era compatibil cu vechiul mod grafic și resursele vechi, ne-a impus să facem o mulțime de soluții interesante și uneori nebunești, limitate la DirectX 9 . a fost foarte amuzant!

Iluminare și umbre dinamice

Motorul original Lithitech Jupiter avea suport limitat pentru iluminarea dinamică și umbrele, 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 au fost complet statice, ceea ce înseamnă că sunt pre-calculate și stocate ca o textură care este 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 unele obiecte, cum ar fi modelele de personaje și armele. Deoarece iluminarea dinamică a folosit per-vertex pe obiecte, diferite detalii suplimentare și umflături 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 datată pentru 2017.

Cea mai mare îmbunătățire pe care am reușit să o facem este să combinăm atât geometria statică a hărții, cât și obținerea obiectelor pentru a avea iluminare și umbre complet dinamice. Iluminarea dinamică vă permite într-adevăr să redați o scenă cu iluminare per pixel, reflexii, lumini, umbre dinamice și o hartă cu denivelări.

Deși introducerea unei singure surse de lumină dinamică nu a fost atât de dificilă inițial, dificultatea a apărut din necesitatea de a susține mai multe lumini dinamice în același timp într-o manieră eficientă. Suportul pentru multe surse de lumină dinamică a devenit o caracteristică de bază pentru aproape fiecare motor de joc modern. Singurul mod în care motorul Lithtech a susținut 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 executate de o sferă de lumină delimitată și numai aceste blocuri de hartă vor trebui redesenate. Dar acest lucru implică încă o încărcare mare a procesorului pentru a reda scena de mai multe ori și impune și mai multe restricții asupra cât de complexă este geometria hărții și câte obiecte pot fi afișate pe ecran în același timp.

Am început prin a spune că la început doar lumina directă principală a soarelui era singura sursă de lumină dinamică. 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 găzduite în clădiri, așa că diferența dintre iluminarea statică interioară și cea dinamică exterioară a fost prea vizibilă.

Astfel, pentru iluminarea dinamică folosind mai multe surse de lumină, a fost necesar să se facă schimbări majore în modul în care motorul redă scena și procesează 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 destul de larg și l-am menționat pe scurt în prima postare de blog pentru dezvoltatori. Practic, permite ca toată iluminarea dinamică să fie transferată în zona de redare post-proces, care este complet independentă de complexitatea scenei și poate fi aproape complet procesată de GPU cu o încărcare foarte mică a CPU.

Cu toate aceste optimizări, am putut implementa un shader fizic complex de iluminare. 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 joc moderne, cum ar fi Unity 5 și Unreal 4, precum și scenele redate complet cu raze create folosind randarea offline profesională. Ne-am limitat 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 luminii.

Noi shadere dinamice de iluminare în Combat Arms:

Versiunea cu ray-tracing a scenei:

hartă în umbră

La implementarea umbrelor dinamice, ne-am confruntat cu o serie de provocări pentru a obține umbrirea modernă complet dinamică în Combat Arms. În motorul original Lithtech, majoritatea umbrelor sunt coapte în texturile luminoase statice 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, practic nu a fost folosit în Combat Arms. În plus, această funcție 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 lumina direcțională principală a soarelui și o soluție parțial dinamică pentru luminile și luminile omnidirecționale folosind o hartă a umbrelor omnidirecționale precalculată care poate fi aplicată la atât geometria lumii cât și obiectele dinamice. Acest lucru este similar cu modul în care alte motoare de joc moderne oferă umbrire dinamică.

Oricum, ce este o hartă în umbră? Practic, este un truc foarte inteligent pe care jocurile și randerii îl folosesc pentru a simula umbrirea dinamică accelerată de GPU. https://en.wikipedia.org/wiki/Shadow_mapping.

Algoritmul de redare a umbrei se referă, în principiu, la a reda scena din punctul de vedere al sursei de lumină pe o textură, folosind-o ca punct de intrare pentru shader-ul de pixeli de iluminare și apoi folosind textura respectivă pentru a calcula dacă pixelul este în umbră. sau nu de GPU.

Î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 de lângă observator vor avea o rezoluție mai mare. Rezoluția hărții umbrelor 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 umbrelor vor afecta rezoluția texturii hărții de umbre.

Iată cum arată soluția hărții umbre când este filtrată.

Filtrarea hărții în umbră

Utilizarea numai a hărții de umbre poate duce la umbre foarte dure. Și deși uneori pot arăta bine în același timp, acest lucru nu este adevărat.

Î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 față de subiectul iluminat. Puteți vedea exemple în fotografie:

Observați cum în aceste fotografii umbrele devin mai moi pe măsură ce vă îndepărtați de obiectele care le aruncă. Majoritatea celorlalte jocuri moderne folosesc încă cea mai simplă metodă de filtrare a umbririi numită Filtrare mai aproape de procente sau PCF, care aplică o valoare fixă ​​de duritate sau catifelare tuturor umbrelor.

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

Cu toate acestea, în 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 folosi această metodă, iar jocurile moderne au început să o folosească abia în ultimii ani pentru a filtra harta umbră. La momentul scrierii acestui blog, această tehnologie nu este încă disponibilă în Unreal 4 sau Unity 5. În timp ce din punct de vedere tehnic, Unreal 4 oferă o soluție alternativă numită urmărirea razelor la distanță, se limitează la a permite doar geometriei statice să arunce umbre.

PCSS dezactivat:

PCSS activat:

Filtrarea subtilă 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țiuni Gather4 shader care sunt utilizate în mod obișnuit în shader-urile 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 anti-alias este utilizată pentru a reduce sarcina pe GPU.

Maparea umbrelor omnidirecționale

Cu sursele de lumină omnidirecționale, lucrurile sunt puțin mai complicate. Deoarece aruncă umbre în toate direcțiile, realizarea hărților 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, scena este greu de scalat atunci când există multe astfel de lumini. Deci, pentru aceasta am aplicat o hartă umbră precalculată, unde este calculată o singură dată când harta este încărcată în loc de fiecare cadru. Harta 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 de umbră a obiectelor Lithtech este folosită pentru a da umbre obiectelor din hărțile de umbră omnidirecționale precalculate. De asemenea, combinăm acest lucru cu urmărirea Screen-Space Shadows pentru a oferi obiectelor umbre proprii 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ă pe o singură textură:

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

În mod tradițional, hărțile 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ă la 360°, dar cu această proiecție a hărții este utilizată doar o textură. Această metodă oferă, de asemenea, mai puțină distorsiune decât majoritatea altor metode de proiectare sferică 2D și, spre deosebire de harta cubului desfășurat, se potrivește perfect într-o singură textură pătrată. Multe dintre hărțile existente în joc folosesc un număr mare de lumini omnidirecționale ca lumini principale, iar acest lucru le permite multor dintre ele să accepte și umbrirea dinamică în timp real.

Rezumând

Credem că această combinație de tehnologii de iluminare și umbrire va oferi jocului un aspect foarte modern pentru 2017 și, de asemenea, că soluțiile noastre sunt destul de competitive cu ceea ce oferă alte motoare de joc astăzi. Deși aceste modificări în sine nu sunt suficiente pentru a „moderniza” jocul, avem încă 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, a fost doar o privire aprofundată asupra detaliilor tehnice despre implementarea iluminării dinamice și a umbririi în viitoarea actualizare Combat Arms. De asemenea, este important să rețineți că capturile de ecran afișate au fost făcute folosind o versiune cu active curente pentru a demonstra caracteristicile grafice. Este posibil ca acestea să nu reflecte cu exactitate nivelul final de grafică după lansarea actualizării.

De asemenea, ar trebui să vă reamintesc că opțiunile grafice actualizate sunt opționale și veți putea comuta între versiunile de motor după lansarea actualizării. Dezvoltăm aceste îmbunătățiri grafice pe baza capacităților hardware-ului grafic de gamă medie și high-end de astăzi, începând cu 2016. Ne dorim ca motorul de joc să poată profita din plin de capacitățile GPU-urilor moderne pentru a oferi cea mai bună calitate posibilă a imaginii. Încă analizăm și optimizăm în mod constant noile funcții grafice, dar rețineți că hardware-ul ușor învechit sau mai ieftin va putea rula noile opțiuni grafice doar la setări sau rezoluții mai mici. Vom continua să susținem vechiul motor grafic, 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, vor putea continua să se bucure de joc ca înainte.

Cu stimă, echipa Combat Arms!

Harta umbră este probabil cea mai dificilă parte în crearea unei reprezentări vizuale a unui obiect. Le folosim pentru a obține lumină și umbră copte.
Acestea trebuie desfășurate în mod unic, astfel încât fiecare parte a modelului să aibă propriul loc în spațiul UV pentru a obține informațiile corecte despre lumină și umbră în final.
Este important să ne amintim că rezoluția hărții umbrelor este mică în comparație cu dimensiunea spațiului UV.
De asemenea, este important să înțelegeți că, cu cât un nivel trebuie optimizat, cu atât designerul de nivel ar trebui să folosească mai mult pe hărți luminoase, uneori ajungând până la 8x8 sau 16x16 pentru obiecte mai mici.
Această tendință necesită să lăsăm mult spațiu suplimentar în jurul fiecărei secțiuni a desfășurării obiectului, astfel încât zonele care sunt întunecate să fie
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ă de a crea o matură a obiectelor, deoarece majoritatea modelelor de mediu sunt apropiate ca formă de blocuri care sunt combinate într-un fel de structură.
O plasă continuă (o plasă care nu are părți în afara bazei) este adesea o soluție foarte utilă atunci când se construiește o măturare,
această soluție va ajuta la asigurarea unei distribuții mai eficiente a rețelei de geometrie în spațiul UV.
Acest lucru va funcționa bine chiar și la o rezoluție scăzută a hărții de umbră, deoarece apoi formează un singur gradient de la întuneric la lumină.
Spre deosebire de o măturare fragmentată, în care rezultatul va părea mai ambiguu și poate fi necesar să creșteți rezoluția hărții umbre pentru a opri efectul tranzițiilor ascuțite.
Ar trebui să încercăm să evităm asta oriunde putem. Din păcate, uneori nu este posibil să utilizați o rezoluție mai mică sau o singură trecere a geometriei.

DESFĂCUT PLANAR

Această metodă este utilă în special pentru structuri plate, cum ar fi pereții cu mai multe teșituri sau umflături. De asemenea, este foarte util pentru părți mari ale fațadelor clădirilor, cum ar fi clădirile de apartamente.
plană se va desfășura mult mai bine dacă folosiți geometrie nediscontinuă, deoarece aici întrebarea va fi doar în „relaxarea” grilei desfășurate.
Uneori, este, de asemenea, o regulă generală bună să vă asigurați că există mai mult spațiu orizontal decât vertical pe o astfel de măturare, deoarece proiectarea umbrei tinde să vină din lateral la un unghi ușor ridicat,
nu drept în jos. Astfel, mai mult spațiu orizontal oferă mai mult spațiu pentru umbre mai clare, datorită tendinței designerilor de a alege iluminarea în unghi,
pentru a crea umbre mai interesante decât atunci când sunt luminate 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 cilindrică este bună pentru multe modele care au față și părți laterale, dar fără spate, altfel am folosi metoda DESFALAT CUTIE.

Exemple

Era o plasă care nu se rupe, așa că a fost ușor de implementat DESFALAT CUTIEși așezați-l pe orizontală pentru a utiliza cât mai mult spațiu pe hartă umbră.
Suprafețele care ar putea fi vizibile în imaginea din mijloc au fost eliminate, deoarece vor fi aproape întotdeauna negre,
iar dacă ar fi conectate la restul scanării, umbrele de la ele s-ar pătrunde pur și simplu în pete întunecate de pe pereți, unde nu ar trebui să fie. Același lucru este valabil și pentru marginile superioare.
Cu excepția faptului că ar fi întotdeauna ușoare.


Această metodă de desfășurare ne permite să avem o hartă a umbrelor aproape perfectă în joc la 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ă folosim spațiul maxim posibil, deoarece harta umbră va acoperi oricum întreaga scanare.
Prin urmare, între raportul de aspect al obiectului 1 la 1 și 1 la 7, veți vedea o diferență semnificativă. De asemenea, puteți vedea că aici unele părți ale maturii sunt separate și îndepărtate de grila principală.
Acest lucru se datorează faptului că 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, plană arată un rezultat bun. Această plasă este indestructibil, 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 că aici, geometria strânsă a făcut ușoară așezarea UV-urilor. De asemenea, puteți vedea că aici sunt făcute indentări între părțile de măturare, 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 mai mult este necesar să se ia o indentă.


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 sunt 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 padding-ul dintre elementele scanării, ar arăta groaznic în joc.
Deci rezoluția hărții de umbre a fost ridicată la 128x128, dar încă nu arată perfect, dar încă nu este suficient pentru a distruge complet aspectul vizual al obiectului din joc.


Uneori este ușor să extindeți un obiect, este suficient să-l despărțiț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ă aceste două metode de bază de desfășurare a unui obiect sunt folosite aici.
plană derulează 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 o carcasă asemănătoare bazei, aici partea centrală este împărțită și folosită planăîn loc de Cilindric pentru a oferi o zonă mare de acoperire.
Ca întotdeauna, suntem mai preocupați de acoperire decât de un raport de aspect 1: 1. Este un mare avantaj să avem cusăturile în locațiile lor reale, acest lucru va face umbrele să pară mai naturale.
Dacă obiectul dvs. are tăieturi adânci, îmbinări extrem de ascuțite ale geometriei, atunci acesta este un loc grozav pentru a așeza o cusătură aici, cu excepția cazului în care, desigur, este necesar.

Index de coordonate 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 este folosit pentru aplicarea materialelor pe plasă va fi folosit și pentru iluminarea statică.
Această metodă nu este adesea ideală. Unul dintre motivele 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 partea hărții de umbră corespunzătoare acestui spațiu. Acest lucru va duce la o iluminare incorectă, la apariția de umbre unde, în principiu, nu ar trebui să fie.
Ochiurile statice au proprietatea LightmapCoordinateIndex, care vă permite să utilizați UV specificat pentru harta 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 învecinate se numesc diagrame UV.

Ar trebui să împărțiți matura î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 căptușelii trebuie să fie mai mare de 4x4 texeli, deoarece compresia DXT funcționează cu blocuri de această dimensiune.

  1. liniuță irosită
  2. Indentație obligatorie

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


Aceasta este departe de a fi o matură ideală.

Un exemplu de problemă de implementare este fragmentarea excesivă. Puteți vedea cum umbrele care ar trebui să rămână pe părțile interioare ale obiectului dau umbrire marginilor exterioare.
Un alt potențial capcan este să se bazeze pe auto-unwrap, deoarece și asta poate duce la aceleași probleme.


Cel mai bun mod de a despacheta o hartă în umbră este de a modela întreaga plasă ca un element continuu sau de a despacheta manual.


Acest lucru va da un singur desfășurare care nu are aproape cusături ș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ă reduce, de obicei, numărul de vârfuri și triunghiuri necesare pentru un model dat.


CATEGORII

ARTICOLE POPULARE

2022 "kingad.ru" - examinarea cu ultrasunete a organelor umane