Sužinokite pagrindines realaus laiko šešėlių atvaizdavimo WebGL sąvokas ir pažangius metodus. Šiame vadove aptariami šešėliavimo kartografavimas, PCF, CSM ir sprendimai bendriems artefaktams.
WebGL šešėliavimo kartografavimas: išsamus vadovas realaus laiko atvaizdavimui
3D kompiuterinės grafikos pasaulyje nedaugelis elementų prisideda prie realizmo ir įtraukimo labiau nei šešėliai. Jie suteikia svarbių vizualinių užuominų apie objektų erdvinį santykį, šviesos šaltinių vietą ir bendrą scenos geometriją. Be šešėlių, 3D pasauliai gali atrodyti plokšti, atjungti ir dirbtiniai. Žiniatinklio 3D programoms, naudojant „WebGL“, aukštos kokybės, realaus laiko šešėlių įgyvendinimas yra profesionalios klasės patirties ženklas. Šis vadovas nuodugniai nagrinėja pagrindinį ir plačiausiai naudojamą metodą, kaip tai pasiekti: šešėliavimo kartografavimą.
Nesvarbu, ar esate patyręs grafikos programuotojas, ar žiniatinklio kūrėjas, tyrinėjantis trečiąjį matmenį, šis straipsnis suteiks jums žinių, kaip suprasti, įgyvendinti ir šalinti triktis realaus laiko šešėliuose savo „WebGL“ projektuose. Keliausime nuo pagrindinės teorijos iki praktinių įgyvendinimo detalių, tyrinėdami dažniausias problemas ir pažangius metodus, naudojamus šiuolaikinėse grafikos sistemose.
1 skyrius: Šešėliavimo kartografavimo pagrindai
Iš esmės šešėliavimo kartografavimas yra protingas ir elegantiškas metodas, nustatantis, ar taškas scenoje yra šešėlyje, užduodant paprastą klausimą: „Ar šį tašką mato šviesos šaltinis?“ Jei atsakymas neigiamas, tai reiškia, kad kažkas blokuoja šviesą, ir taškas turi būti šešėlyje. Norėdami atsakyti į šį klausimą programiškai, naudojame dviejų etapų atvaizdavimo metodą.
Kas yra šešėliavimo kartografavimas? Pagrindinė sąvoka
Visas metodas sukasi apie scenos atvaizdavimą du kartus, kiekvieną kartą iš skirtingos perspektyvos:
- 1 etapas: Gilumo atvaizdavimas (šviesos perspektyva). Pirmiausia atvaizduojame visą sceną iš tikslios šviesos šaltinio padėties ir orientacijos. Tačiau šiame etape mums nereikia spalvų ar tekstūrų. Vienintelė mums reikalinga informacija yra gilumas. Kiekvienam atvaizduotam objektui įrašome jo atstumą nuo šviesos šaltinio. Šis gilumo verčių rinkinys saugomas specialioje tekstūroje, vadinamoje šešėlio žemėlapiu arba gilumo žemėlapiu. Kiekvienas šio žemėlapio pikselis atspindi atstumą iki artimiausio objekto iš šviesos perspektyvos tam tikroje kryptimi.
- 2 etapas: Scenos atvaizdavimas (kameros perspektyva). Toliau sceną atvaizduojame taip, kaip įprastai, iš pagrindinės kameros perspektyvos. Tačiau kiekvienam piešiamam pikseliui atliekame papildomą skaičiavimą. Nustatome to pikselio padėtį 3D erdvėje ir tada klausiame: „Koks yra šio taško atstumas nuo šviesos šaltinio?“ Tada palyginame šį atstumą su mūsų šešėlio žemėlapyje (iš 1 etapo) saugomą vertę atitinkamoje vietoje.
Logika yra paprasta:
- Jei pikselio dabartinis atstumas nuo šviesos yra didesnis nei šešėlio žemėlapyje saugomas atstumas, tai reiškia, kad kitas objektas yra arčiau šviesos ta pačia matymo linija. Todėl dabartinis pikselis yra šešėlyje.
- Jei pikselio atstumas yra mažesnis arba lygus atstumui šešėlio žemėlapyje, tai reiškia, kad niekas jo neužstoja, ir pikselis yra visiškai apšviestas.
Scenos nustatymas
Norint įgyvendinti šešėliavimo kartografavimą „WebGL“ aplinkoje, jums reikės kelių pagrindinių komponentų:
- Šviesos šaltinis: Tai gali būti kryptinė šviesa (pvz., saulė), taškinė šviesa (pvz., lemputė) arba prožektorius. Šviesos tipas nulems projekcijos matricos tipą, naudojamą gilumo etape.
- Kadravimo buferio objektas (FBO): „WebGL“ paprastai atvaizduoja į ekrano numatytąjį kadravimo buferį. Norėdami sukurti savo šešėlio žemėlapį, mums reikia neekraninio atvaizdavimo tikslo. FBO leidžia mums atvaizduoti į tekstūrą, o ne į ekraną. Mūsų FBO bus sukonfigūruotas su gilumo tekstūros priedu.
- Du šviesos vienetų rinkiniai: Jums reikės vienos šviesos programos gilumo etapui (labai paprastos) ir kitos galutiniam scenos etapui (kurioje bus šešėlio skaičiavimo logika).
- Matricos: Jums reikės standartinių modelio, vaizdo ir projekcijos matricų kamerai. Svarbiausia, kad jums taip pat reikės šviesos šaltinio vaizdo ir projekcijos matricų, dažnai sujungtų į vieną „šviesos erdvės matricą“.
2 skyrius: Dviejų etapų atvaizdavimo vamzdynas išsamiai
Pažiūrėkime du atvaizdavimo etapus žingsnis po žingsnio, sutelkdami dėmesį į matricų ir šviesos vienetų vaidmenis.
1 etapas: Gilumo atvaizdavimas (iš šviesos perspektyvos)
Šio etapo tikslas yra užpildyti mūsų gilumo tekstūrą. Štai kaip tai veikia:
- FBO prijungimas: Prieš piešiant, nurodote „WebGL“ atvaizduoti į savo pasirinktinį FBO, o ne į drobę.
- Vaizdo taško konfigūravimas: Nustatykite vaizdo taško matmenis, kad jie atitiktų jūsų šešėlio žemėlapio tekstūros dydį (pvz., 1024x1024 pikselius).
- Gilumo buferio išvalymas: Prieš atvaizduojant įsitikinkite, kad FBO gilumo buferis yra išvalytas.
- Šviesos matricų kūrimas:
- Šviesos vaizdo matrica: Ši matrica transformuoja pasaulį į šviesos perspektyvą. Kryptinei šviesai tai paprastai sukuriama naudojant `lookAt` funkciją, kur „akis“ yra šviesos padėtis, o „tikslas“ – kryptis, kuria ji rodo.
- Šviesos projekcijos matrica: Kryptinei šviesai, turinčiai lygiagrečius spindulius, naudojama ortografinė projekcija. Taškinėms šviesoms arba prožektoriams naudojama perspektyvinė projekcija. Ši matrica apibrėžia erdvės tūrį (dėžutę ar trumpąjį liemeni), kuris mes šešėlius.
- Gilumo šviesos vieneto naudojimas: Tai yra minimalus šviesos vienetas. Vaizdo taško šviesos vieneto vienintelė užduotis yra padauginti vaizdo taško padėtį iš šviesos vaizdo ir projekcijos matricų. Fragmento šviesos vienetas yra dar paprastesnis: jis tiesiog įrašo fragmento gilumo vertę (jo z-koordinatę) į gilumo tekstūrą. Šiuolaikiniame „WebGL“ jums net nereikia pasirinktinio fragmento šviesos vieneto, nes FBO gali būti sukonfigūruotas automatiškai fiksuoti gilumo buferį.
- Scenos atvaizdavimas: Nubraižykite visus scenos objektus, darančius šešėlį. FBO dabar turi mūsų užbaigtą šešėlio žemėlapį.
2 etapas: Scenos atvaizdavimas (iš kameros perspektyvos)
Dabar atvaizduojame galutinį vaizdą, naudodami ką tik sukurtą šešėlio žemėlapį šešėliams nustatyti.
- FBO atjungimas: Grįžkite prie atvaizdavimo į numatytąjį drobės kadravimo buferį.
- Vaizdo taško konfigūravimas: Vaizdo taško matmenis grąžinkite į drobės matmenis.
- Ekrano išvalymas: Išvalykite spalvų ir gilumo buferius drobės.
- Scenos šviesos vieneto naudojimas: Čia ir vyksta magija. Šis šviesos vienetas yra sudėtingesnis.
- Vaizdo taško šviesos vienetas: Šis šviesos vienetas turi atlikti du dalykus. Pirma, jis apskaičiuoja galutinę vaizdo taško padėtį naudodamas kameros modelio, vaizdo ir projekcijos matricų, kaip įprastai. Antra, jis taip pat turi apskaičiuoti vaizdo taško padėtį iš šviesos perspektyvos, naudodamas šviesos erdvės matricą iš 1 etapo. Ši antra koordinatė perduodama fragmento šviesos vienetui kaip kintamasis.
- Fragmento šviesos vienetas: Tai yra šešėlio logikos pagrindas. Kiekvienam fragmentui:
- Gaukite interpoliuotą padėtį šviesos erdvėje iš vaizdo taško šviesos vieneto.
- Atlikite perspektyvinį padalijimą šiai koordinaitei (padalinkite x, y, z iš w). Tai transformuoja jį į normalizuotas įrenginio koordinates (NDC), svyruojančias nuo -1 iki 1.
- Transformuokite NDC į tekstūros koordinates (kurios svyruoja nuo 0 iki 1), kad galėtume paimti mėginį iš mūsų šešėlio žemėlapio. Tai paprastas mastelio ir poslinkio operacija: `texCoord = ndc * 0.5 + 0.5;`.
- Naudokite šias tekstūros koordinates, kad paimtumėte mėginį iš šešėlio žemėlapio tekstūros, sukurtos 1 etape. Tai suteikia mums `depthFromShadowMap`.
- Fragmento dabartinis gilumas iš šviesos perspektyvos yra jo z-komponentas iš transformuotos šviesos erdvės koordinatės. Pavadinkime tai `currentDepth`.
- Paliekite gilumus: Jei `currentDepth > depthFromShadowMap`, fragmentas yra šešėlyje. Mums reikės pridėti mažą poslinkį prie šio patikrinimo, kad išvengtume artefakto, vadinamo „šešėlio aknė“, apie kurį kalbėsime vėliau.
- Remdamiesi palyginimu, nustatykite šešėlio koeficientą (pvz., 1,0 apšviestam, 0,3 šešėliuotam).
- Pritaikykite šį šešėlio koeficientą galutiniam spalvos skaičiavimui (pvz., padauginkite aplinkos ir difuzinės apšvietimo komponentus iš šešėlio koeficiento).
- Scenos atvaizdavimas: Nubraižykite visus scenos objektus.
3 skyrius: Dažnos problemos ir sprendimai
Įgyvendinus pagrindinį šešėliavimo kartografavimą, greitai bus pastebėta keletas bendrų vizualinių artefaktų. Jų supratimas ir taisymas yra labai svarbus siekiant aukštos kokybės rezultatų.
Šešėlio aknė (savišešėliavimo artefaktai)
Problema: Galite pastebėti keistų, neteisingų tamsių linijų ar Moire tipo raštų ant paviršių, kurie turėtų būti visiškai apšviesti. Tai vadinama „šešėlio akne“. Tai atsiranda dėl to, kad šešėlio žemėlapyje saugomas gilumo vertė ir scenos etape skaičiuojamas gilumo vertė yra tame pačiame paviršiuje. Dėl plaukiojančio kablelio netikslumų ir ribotos šešėlio žemėlapio rezoliucijos, mažytės klaidos gali sukelti fragmentui neteisingai nustatyti, kad jis yra už savęs, todėl atsiranda savišešėliavimas.
Sprendimas: Gilumo poslinkis. Paprasčiausias sprendimas yra įvesti mažą poslinkį į `currentDepth` prieš palyginimą. Padarydami fragmentą šiek tiek arčiau šviesos, nei jis yra iš tikrųjų, mes stumiame jį „iš“ savo šešėlio.
float shadow = currentDepth > depthFromShadowMap + bias ? 0.3 : 1.0;
Teisingo poslinkio vertės nustatymas yra subtilus pusiausvyros aktas. Per mažas, ir aknė išlieka. Per didelis, ir gausite kitą problemą.
Peterio Panningas
Problema: Šis artefaktas, pavadintas skraidyti galėjusio ir savo šešėlį pametusio personažo garbei, pasireiškia kaip matomas tarpas tarp objekto ir jo šešėlio. Tai priverčia objektus atrodyti plaukiojančius ar atjungtus nuo paviršių, ant kurių jie turėtų būti. Tai yra tiesioginis per didelio gilumo poslinkio naudojimo rezultatas.
Sprendimas: Šlaito mastelio gilumo poslinkis. Tvirtesnis sprendimas nei pastovus poslinkis yra padaryti poslinkį priklausomą nuo paviršiaus nuolydžio santykio su šviesa. Nuolydūs daugiakampiai yra labiau linkę į aknę ir reikalauja didesnio poslinkio. Plokšti daugiakampiai reikalauja mažesnio poslinkio. Dauguma grafikos API, įskaitant „WebGL“, teikia funkcionalumą automatiškai taikyti tokio tipo poslinkį gilumo etape, o tai paprastai yra priimtinesnė nei rankinis poslinkis fragmento šviesos vienete.
Perspektyvinis aliasingas (dantytai kraštai)
Problema: Jūsų šešėlių kraštai atrodo kampuoti, dantyti ir pikselizuoti. Tai yra aliasingo forma. Tai atsitinka, nes šešėlio žemėlapio rezoliucija yra baigtinė. Vienas pikselis (arba tekstūros elementas) šešėlio žemėlapyje gali apimti didelį plotą paviršiaus galutinėje scenoje, ypač paviršių, esančių arti kameros, arba žiūrimų iš skambaus kampo. Šis rezoliucijos neatitikimas sukelia būdingą kampuotą išvaizdą.
Sprendimas: Padidinus šešėlio žemėlapio rezoliuciją (pvz., nuo 1024x1024 iki 4096x4096) gali padėti, tačiau tai kainuoja reikšmingų atminties ir našumo sąnaudų ir nevisiškai išsprendžia pagrindinę problemą. Tikri sprendimai slypi pažangesniuose metoduose.
4 skyrius: Pažangūs šešėliavimo kartografavimo metodai
Pagrindinis šešėliavimo kartografavimas suteikia pagrindą, tačiau profesionalios programos naudoja sudėtingesnius algoritmus, kad įveiktų jo apribojimus, ypač aliasingą.
Procentinis artimesnis filtravimas (PCF)
PCF yra dažniausias metodas šešėlių kraštams suminkštinti ir aliasingui sumažinti. Vietoj to, kad paimti vieną mėginį iš šešėlio žemėlapio ir priimti dvejetainį (šešėlyje arba ne šešėlyje) sprendimą, PCF paima kelis mėginius iš srities aplink tikslinę koordinatę.
Sąvoka: Kiekvienam fragmentui mes imame mėginius iš šešėlio žemėlapio ne tik vieną kartą, bet ir tinklelio raštu (pvz., 3x3 arba 5x5) aplink fragmento projekcinę tekstūros koordinatę. Kiekvienam iš šių mėginių atliekame gilumo palyginimą. Galutinė šešėlio vertė yra visų šių palyginimų vidurkis. Pavyzdžiui, jei 4 iš 9 mėginių yra šešėlyje, fragmentas bus 4/9 pavėsyje, todėl bus švelni penumbra (šešėlio minkštas kraštas).
Įgyvendinimas: Tai atliekama visiškai fragmento šviesos vienete. Tai apima ciklą, kuris pereina per nedidelį branduolį, paima mėginius iš šešėlio žemėlapio kiekviename poslinkyje ir kaupia rezultatus. „WebGL 2“ siūlo aparatinės įrangos palaikymą (`texture` su `sampler2DShadow`), kuris gali efektyviau atlikti palyginimą ir filtravimą.
Nauda: Ženkliai pagerina šešėlio kokybę, pakeičiant kietus, aliasingo kraštus švelniais, minkštais kraštais.
Kaina: Našumas mažėja didėjant kiekvienam fragmentui imtinų mėginių skaičiui.
Kaskadinis šešėlių žemėlapis (CSM)
CSM yra pramonės standartinis sprendimas, skirtas atvaizduoti šešėlius iš vieno krypties šviesos šaltinio (pvz., saulės) didelėje scenoje. Jis tiesiogiai sprendžia perspektyvinio aliasingo problemą.
Sąvoka: Pagrindinė idėja yra ta, kad arti kameros esantiems objektams reikia daug didesnės šešėlio rezoliucijos nei toli esantiems objektams. CSM padalija kameros vaizdo kamieną į kelis skyrius arba „kaskadas“ išilgai jos gilumo. Tada kiekvienai kaskadai atskirai atvaizduojamas aukštos kokybės šešėlio žemėlapis. Artimiausia kamerai kaskada apima nedidelį pasaulio erdvės plotą, todėl pasižymi labai dideliu efektyviuoju rezoliucija. Tolimesnės kaskados apima progresyviai didesnius plotus su ta pačia tekstūros dydžiu, o tai yra priimtina, nes šios detalės mažiau matomos žaidėjui.
Įgyvendinimas: Tai yra žymiai sudėtingiau.
- CPU, padalinkite kameros kamieną į 2–4 kaskadas.
- Kiekvienai kaskadai apskaičiuokite sandariai tinkamą ortografinę projekcijos matricą šviesai, kuri puikiai apima tą kameros kamieno dalį.
- Atvaizdavimo cikle atlikite gilumo etapą kelis kartus – po vieną kartą kiekvienai kaskadai, atvaizduodami į skirtingą šešėlio žemėlapį (arba tekstūros tinklalapio regioną).
- Galutiniame scenos etapo fragmento šviesos vienete nustatykite, kuriai kaskadai priklauso dabartinis fragmentas, remdamiesi jo atstumu nuo kameros.
- Imkite mėginius iš atitinkamos kaskados šešėlio žemėlapio, kad apskaičiuotumėte šešėlį.
Nauda: Suteikia nuosekliai didelės rezoliucijos šešėlius per didelius atstumus, todėl puikiai tinka lauko aplinkai.
Variacijos šešėlių žemėlapiai (VSM)
VSM yra dar vienas minkštų šešėlių kūrimo metodas, tačiau jis naudoja kitokį metodą nei PCF.
Sąvoka: Vietoj to, kad šešėlio žemėlapyje saugotų tik gilumą, VSM saugo dvi vertes: gilumą (pirmasis momentas) ir gilumo kvadratą (antrasis momentas). Šios dvi vertės leidžia mums apskaičiuoti gilumo pasiskirstymo variaciją. Naudodami matematinį įrankį, vadinamą Čebiševo nelygybe, galime apskaičiuoti fragmento tikimybę būti šešėlyje. Pagrindinis privalumas yra tai, kad VSM tekstūrą galima sulieti naudojant standartinį aparatinės įrangos pagreitintą linijinį filtravimą ir mipmetodus, o tai yra matematiškai negaliojanti įprastam gilumo žemėlapiui. Tai leidžia labai dideles, minkštas ir švelnias šešėlio penumbras su fiksuota našumo kaina.
Trūkumas: Pagrindinis VSM trūkumas yra „šviesos pratekėjimas“, kai šviesa gali atrodyti, kad prateka pro objektus situacijose su persidengiančiais užstojamaisiais elementais, nes statistinis artinimas gali sugesti.
5 skyrius: Praktiniai įgyvendinimo patarimai ir našumas
Šešėlio žemėlapio rezoliucijos pasirinkimas
Jūsų šešėlio žemėlapio rezoliucija yra tiesioginis kokybės ir našumo kompromisas. Didesnė tekstūra suteikia ryškesnius šešėlius, tačiau naudoja daugiau vaizdo atminties ir ilgiau atvaizduojama bei imama mėginiai. Dažni dydžiai apima:
- 1024x1024: Geras pagrindas daugeliui programų.
- 2048x2048: Ženkliai pagerina kokybę darbalaukio programoms.
- 4096x4096: Aukšta kokybė, dažnai naudojama svarbiausiems elementams arba sistemose su patikimu išpjovimu.
Šviesos kamieno optimizavimas
Norint išnaudoti kiekvieną šešėlio žemėlapio pikselį, labai svarbu, kad šviesos projekcijos tūris (jos ortografinė dėžutė ar perspektyvinis kamienas) būtų kuo sandariau pritaikytas scenos elementams, kuriems reikia šešėlių. Kryptinei šviesai tai reiškia, kad jos ortografinė projekcija turi apimti tik matomą kameros kamieno dalį. Bet kokia neefektyviai panaudota erdvė šešėlio žemėlapyje yra neefektyviai panaudota rezoliucija.
WebGL plėtiniai ir versijos
WebGL 1 prieš WebGL 2: Nors šešėliavimo kartografavimas yra įmanomas „WebGL 1“ versijoje, jis yra daug lengvesnis ir efektyvesnis „WebGL 2“. „WebGL 1“ reikalingas `WEBGL_depth_texture` plėtinys gilumo tekstūrai sukurti. „WebGL 2“ turi šią funkcionalumą integruotą. Be to, „WebGL 2“ suteikia prieigą prie šešėlio imtuvų (`sampler2DShadow`), kurie gali atlikti aparatinės įrangos pagreitintą PCF, suteikdami reikšmingą našumo padidinimą, palyginti su rankiniais PCF ciklams šviesos vienete.
Šešėlių trikčių diagnostika
Šešėlius gali būti nepaprastai sunku diagnozuoti. Pats naudingiausias metodas yra šešėlio žemėlapio vizualizavimas. Laikinai modifikuokite savo programą, kad atvaizduotumėte gilumo tekstūrą iš konkretaus šviesos šaltinio tiesiai ant ekrano keturkampio. Tai leidžia jums tiksliai pamatyti, ką šviesa „matė“. Tai gali nedelsiant atskleisti problemas su jūsų šviesos matricomis, kamieno išpjovimu ar objektų atvaizdavimu gilumo etape.
Išvada
Realiojo laiko šešėliavimo kartografavimas yra šiuolaikinės 3D grafikos kertinis akmuo, plokščias, negyvas scenas paverčiantis tikėtinais ir dinamiškais pasauliais. Nors scenos iš šviesos perspektyvos atvaizdavimo sąvoka yra paprasta, aukštos kokybės, be artefaktų rezultatų pasiekimas reikalauja gilaus pagrindinių mechanizmų supratimo, nuo dviejų etapų vamzdyno iki gilumo poslinkio ir aliasingo niuansų.
Pradėdami nuo pagrindinio įgyvendinimo, galite laipsniškai spręsti bendrus artefaktus, tokius kaip šešėlio aknė ir dantyti kraštai. Iš ten galite pakelti savo vizualinius elementus su pažangiais metodais, tokiais kaip PCF minkštiems šešėliams arba kaskadinis šešėlių žemėlapis didelio masto aplinkai. Kelionė į šešėlio atvaizdavimą yra puikus meno ir mokslo derinio pavyzdys, darantis kompiuterinę grafiką tokią patrauklią. Ragaujame eksperimentuoti su šiais metodais, spausti jų ribas ir suteikti naują realizmo lygį savo „WebGL“ projektams.