Õpi WebGL-is reaalajas varjurenderdamise põhimõisteid ja täiustatud tehnikaid. See juhend hõlmab varjukaardistamist, PCF-i, CSM-i ja lahendusi tavalistele artefaktidele.
WebGL Varjukaardistamine: Põhjalik Juhend Reaalajas Renderdamiseks
3D arvutigraafika maailmas aitavad vähesed elemendid realismile ja kaasahaaravusele rohkem kaasa kui varjud. Need annavad olulisi visuaalseid vihjeid objektide ruumiliste suhete, valgusallikate asukoha ja stseeni üldise geomeetria kohta. Ilma varjudeta võivad 3D-maailmad tunduda lamedad, lahtiühendatud ja tehislikud. WebGL-i toega veebipõhiste 3D-rakenduste jaoks on kvaliteetsete reaalajas varjude rakendamine professionaalse kvaliteediga kogemuste tunnus. See juhend pakub põhjaliku ülevaate kõige põhilisemast ja laialdasemalt kasutatavast tehnikast selle saavutamiseks: Varjukaardistamine.
Olenemata sellest, kas olete kogenud graafikaprogrammeerija või veebiarendaja, kes sukeldub kolmandasse dimensiooni, annab see artikkel teile teadmised, et mõista, rakendada ja tõrkeotsida reaalajas varjusid oma WebGL-i projektides. Me rändame põhilistest teooriatest praktiliste rakendusdetailideni, uurides levinud lõkse ja täiustatud tehnikaid, mida kasutatakse kaasaegsetes graafikamootorites.
1. peatükk: Varjukaardistamise põhitõed
Oma olemuselt on varjukaardistamine nutikas ja elegantne tehnika, mis määrab, kas stseeni punkt on varjus, esitades lihtsa küsimuse: "Kas valgusallikas näeb seda punkti?" Kui vastus on ei, tähendab see, et miski blokeerib valgust ja punkt peab olema varjus. Sellele küsimusele programmiliseks vastamiseks kasutame kaheastmelist renderdamise lähenemist.
Mis on varjukaardistamine? Põhimõiste
Kogu tehnika keerleb stseeni kaks korda renderdamise ĂĽmber, iga kord erinevast vaatenurgast:
- 1. etapp: Sügavuse etapp (valguse perspektiiv). Esiteks renderdame kogu stseeni valgusallika täpsest asukohast ja orientatsioonist. Kuid me ei hooli värvidest ega tekstuuridest selles etapis. Ainus vajalik teave on sügavus. Iga renderdatud objekti puhul salvestame selle kauguse valgusallikast. See sügavusväärtuste kogum salvestatakse spetsiaalsesse tekstuuri, mida nimetatakse varjukaardiks või sügavuskaardiks. Iga piksel sellel kaardil tähistab kaugust lähima objektini valguse vaatenurgast konkreetses suunas.
- 2. etapp: Stseeni etapp (kaamera perspektiiv). Järgmisena renderdame stseeni nii, nagu me tavaliselt teeksime, põhikaamera perspektiivist. Kuid iga joonistatava piksli puhul teeme täiendava arvutuse. Me määrame selle piksli asukoha 3D-ruumis ja küsime seejärel: "Kui kaugel on see punkt valgusallikast?" Seejärel võrdleme seda kaugust meie varjukaardil (1. etapist) salvestatud väärtusega vastavas asukohas.
Loogika on lihtne:
- Kui piksli praegune kaugus valgusest on suurem kui varjukaardile salvestatud kaugus, tähendab see, et samal nägemisjoonel on valgusallikale lähemal mõni teine objekt. Seetõttu on praegune piksel varjus.
- Kui piksli kaugus on väiksem või võrdne varjukaardil oleva kaugusega, tähendab see, et miski seda ei blokeeri ja piksel on täielikult valgustatud.
Stseeni seadistamine
Varjukaardistamise rakendamiseks WebGL-is vajate mitmeid peamisi komponente:
- Valgusallikas: See võib olla suunav valgus (nagu päike), punktvalgus (nagu lambipirn) või prožektor. Valguse tüüp määrab sügavuse etapis kasutatava projektsioonimaatriksi tüübi.
- Framebuffer Object (FBO): WebGL renderdab tavaliselt ekraani vaike-framebufferisse. Meie varjukaardi loomiseks vajame ekraanivälist renderdamise sihtmärki. FBO võimaldab meil renderdada tekstuuri, mitte ekraanile. Meie FBO konfigureeritakse sügavustekstuuri lisandiga.
- Kaks varjutajate komplekti: Vajate ühte varjutajaprogrammi sügavuse etapi jaoks (väga lihtne) ja teist lõpliku stseeni etapi jaoks (mis sisaldab varju arvutamise loogikat).
- Maatriksid: Vajate kaamera jaoks standardseid mudeli-, vaate- ja projektsioonimaatrikseid. Eelkõige vajate ka valgusallika vaate- ja projektsioonimaatriksit, mis on sageli kombineeritud üheks "valgusruumi maatriksiks".
2. peatĂĽkk: Kaheetapiline renderdamise torujuhe detailselt
Jaotame kaks renderdamise etappi samm-sammult, keskendudes maatriksite ja varjutajate rollidele.
1. etapp: SĂĽgavuse etapp (valguse perspektiivist)
Selle etapi eesmärk on täita meie sügavustekstuur. Siin on, kuidas see töötab:
- FBO sidumine: Enne joonistamist käsite WebGL-il renderdada oma kohandatud FBO-sse lõuendi asemel.
- Vaateava konfigureerimine: Määrake vaateava mõõtmed vastavaks teie varjukaardi tekstuuri suurusele (nt 1024x1024 pikslit).
- SĂĽgavuspuhvri tĂĽhjendamine: Veenduge, et FBO sĂĽgavuspuhver on enne renderdamist tĂĽhjendatud.
- Valguse maatriksite loomine:
- Valguse vaatemaatriks: See maatriks teisendab maailma valguse vaatenurka. Suunava valguse korral luuakse see tavaliselt funktsiooniga `lookAt`, kus "silm" on valguse asukoht ja "sihtmärk" on suund, kuhu see osutab.
- Valguse projektsioonimaatriks: Suunava valguse korral, millel on paralleelsed kiired, kasutatakse ortograafilist projektsiooni. Punktvalgustite või prožektorite puhul kasutatakse perspektiivset projektsiooni. See maatriks määratleb ruumala ruumis (kast või püramiid), mis heidab varje.
- Sügavusvarjutajaprogrammi kasutamine: See on minimaalne varjutaja. Tipuvarjutaja ainus ülesanne on korrutada tipu asukoht valguse vaate- ja projektsioonimaatriksitega. Fragmentvarjutaja on veelgi lihtsam: see kirjutab lihtsalt fragmendi sügavuse väärtuse (selle z-koordinaadi) sügavustekstuuri. Kaasaegses WebGL-is ei vaja te sageli isegi kohandatud fragmentvarjutajat, kuna FBO saab konfigureerida sügavuspuhvri automaatseks jäädvustamiseks.
- Stseeni renderdamine: Joonistage kõik stseenis varju heitvad objektid. FBO sisaldab nüüd meie valmis varjukaarti.
2. etapp: Stseeni etapp (kaamera perspektiivist)
Nüüd renderdame lõpliku pildi, kasutades äsja loodud varjukaarti varjude määramiseks.
- FBO lahtisidumine: Lülituge tagasi vaikimisi lõuendi framebufferisse renderdamisele.
- Vaateava konfigureerimine: Määrake vaateava tagasi lõuendi mõõtmetele.
- Ekraani tühjendamine: Tühjendage lõuendi värvi- ja sügavuspuhvrid.
- Stseeni varjutajaprogrammi kasutamine: Siin juhtub maagia. See varjutaja on keerulisem.
- Tipuvarjutaja: See varjutaja peab tegema kahte asja. Esiteks arvutab see lõpliku tipu asukoha, kasutades tavaliselt kaamera mudeli-, vaate- ja projektsioonimaatrikseid. Teiseks peab see ka arvutama tipu asukoha valguse perspektiivist, kasutades 1. etapi valgusruumi maatriksit. See teine koordinaat edastatakse fragmentvarjutajale varieeruvana.
- Fragmentvarjutaja: See on varjuloogika tuum. Iga fragmendi puhul:
- Võtke tipuvarjutajalt vastu interpoleeritud asukoht valgusruumis.
- Tehke sellel koordinaadil perspektiivi jagamine (jagage x, y, z w-ga). See teisendab selle normaliseeritud seadmekoordinaatideks (NDC), ulatudes -1 kuni 1.
- Teisendage NDC tekstuurikoordinaatideks (mis ulatuvad 0 kuni 1), et saaksime proovida meie varjukaarti. See on lihtne skaleerimis- ja niheoperatsioon: `texCoord = ndc * 0.5 + 0.5;`.
- Kasutage neid tekstuurikoordinaate, et proovida 1. etapis loodud varjukaardi tekstuuri. See annab meile `depthFromShadowMap`.
- Fragmendi praegune sĂĽgavus valguse perspektiivist on selle z-komponent teisendatud valgusruumi koordinaadist. Nimetame seda `currentDepth`.
- Võrrelge sügavusi: Kui `currentDepth > depthFromShadowMap`, on fragment varjus. Me peame lisama sellele kontrollile väikese nihke, et vältida artefakti, mida nimetatakse "varju akneks", mida me järgmisena arutame.
- Võrdluse põhjal määrake varjutegur (nt 1,0 valgustatud, 0,3 varjutatud).
- Rakendage seda varjutegurit lõpliku värvi arvutamisel (nt korrutage ümbritseva ja hajuva valgustuse komponendid varjuteguriga).
- Stseeni renderdamine: Joonistage kõik stseenis olevad objektid.
3. peatĂĽkk: Levinud probleemid ja lahendused
Põhilise varjukaardistamise rakendamine paljastab kiiresti mitmeid levinud visuaalseid artefakte. Nende mõistmine ja parandamine on kvaliteetsete tulemuste saavutamiseks ülioluline.Varju akne (isevarjutavad artefaktid)
Probleem: Võite näha kummalisi, valesid tumedate joonte mustreid või Moiré-sarnaseid mustreid pindadel, mis peaksid olema täielikult valgustatud. Seda nimetatakse "varju akneks". See juhtub seetõttu, et varjukaardil salvestatud sügavuse väärtus ja stseeni etapis arvutatud sügavuse väärtus on sama pinna jaoks. Ujuvkoma ebatäpsuste ja varjukaardi piiratud eraldusvõime tõttu võivad väikesed vead põhjustada fragmendil valesti kindlaks määrata, et see on enda taga, mille tulemuseks on isevarjutamine.
Lahendus: Sügavuse nihe. Lihtsaim lahendus on lisada `currentDepth` -le enne võrdlust väike nihe. Muutes fragmendi veidi valgusallikale lähemal olevaks, kui see tegelikult on, lükkame selle oma varjust "välja".
float shadow = currentDepth > depthFromShadowMap + bias ? 0.3 : 1.0;
Õige nihke väärtuse leidmine on õrn tasakaalustamine. Liiga väike ja akne jääb alles. Liiga suur ja saate järgmise probleemi.
Peter Panning
Probleem: See artefakt, mis on nime saanud tegelase järgi, kes oskas lennata ja kaotas oma varju, avaldub nähtava lüngana objekti ja selle varju vahel. See paneb objektid näima hõljuvat või lahtiühendatuna pindadest, millel nad peaksid puhkama. See on liiga suure sügavuse nihke otsene tulemus.
Lahendus: Kaldest sõltuv sügavuse nihe. Püsiva nihke asemel on jõulisem lahendus muuta nihe sõltuvaks pinna järsusest valguse suhtes. Järsemad polügoonid on aknele kalduvamad ja vajavad suuremat nihet. Lamedamad polügoonid vajavad väiksemat nihet. Enamik graafika API-sid, sealhulgas WebGL, pakuvad funktsionaalsust seda tüüpi nihke automaatseks rakendamiseks sügavuse etapis, mis on üldiselt eelistatavam kui käsitsi nihe fragmentvarjutajas.
Perspektiivi aliase (sakilised servad)
Probleem: Teie varjude servad näevad välja tükilised, sakilised ja pikseldatud. See on aliase vorm. See juhtub seetõttu, et varjukaardi eraldusvõime on piiratud. Üks piksel (või tekstsel) varjukaardil võib katta suure ala lõpliku stseeni pinnal, eriti kaamera lähedal asuvate pindade või libiseva nurga all vaadatavate pindade puhul. See eraldusvõime mittevastavus põhjustab iseloomuliku tükilise välimuse.
Lahendus: Varjukaardi eraldusvõime suurendamine (nt 1024x1024-lt 4096x4096-le) võib aidata, kuid sellel on märkimisväärne mälu- ja jõudluskulu ning see ei lahenda täielikult põhiprobleemi. Tõelised lahendused peituvad täiustatud tehnikates.
4. peatükk: Täiustatud varjukaardistamise tehnikad
Põhiline varjukaardistamine pakub aluse, kuid professionaalsed rakendused kasutavad selle piirangute, eriti aliase ületamiseks keerukamaid algoritme.Protsendi-lähedasem filtreerimine (PCF)
PCF on kõige levinum tehnika varjuservade pehmendamiseks ja aliase vähendamiseks. Selle asemel, et võtta varjukaardilt üks proov ja teha binaarne (varjus või mitte-varjus) otsus, võtab PCF mitu proovi sihtkoordinaadi ümbrusest.
Kontseptsioon: Iga fragmendi puhul proovime varjukaarti mitte ainult üks kord, vaid ruudustikumustris (nt 3x3 või 5x5) fragmendi projekteeritud tekstuurikoordinaadi ümber. Iga nende proovide puhul teeme sügavuse võrdluse. Lõplik varjuväärtus on kõigi nende võrdluste keskmine. Näiteks kui 9 proovist 4 on varjus, on fragment 4/9-ndiku võrra varjutatud, mille tulemuseks on sile penumbra (varju pehme serv).
Rakendamine: Seda tehakse täielikult fragmentvarjutajas. See hõlmab silmust, mis itereerib üle väikese kerneli, proovides varjukaarti igas nihkes ja akumuleerides tulemusi. WebGL 2 pakub riistvaratuge (`texture` koos `sampler2DShadow`-ga), mis suudab võrdlust ja filtreerimist tõhusamalt teostada.
Eelis: Parandab drastiliselt varju kvaliteeti, asendades kõvad, aliaste servad siledate, pehmetega.
Kulu: Jõudlus väheneb koos iga fragmendi kohta võetud proovide arvuga.
Kaskaaditud varjukaardid (CSM)
CSM on tööstusstandardne lahendus varjude renderdamiseks ühest suunavast valgusallikast (nagu päike) väga suurel stseenil. See lahendab otseselt perspektiivi aliase probleemi.
Kontseptsioon: Põhiidee on see, et kaamerale lähedal asuvad objektid vajavad palju suuremat varju eraldusvõimet kui kaugel asuvad objektid. CSM jagab kaamera vaatepüramiidi mitmeks osaks ehk "kaskaadiks" piki selle sügavust. Seejärel renderdatakse iga kaskaadi jaoks eraldi kvaliteetne varjukaart. Kaamerale lähim kaskaad katab väikese maailmaruumi ala ja seega on sellel väga kõrge efektiivne eraldusvõime. Kaugemal asuvad kaskaadid katavad sama tekstuurisuurusega üha suuremaid alasid, mis on vastuvõetav, kuna need detailid on mängijale vähem nähtavad.
Rakendamine: See on oluliselt keerulisem.
- CPU-s jagage kaamera pĂĽramiid 2-4 kaskaadiks.
- Arvutage iga kaskaadi jaoks valguse jaoks tihedalt sobiv ortograafiline projektsioonimaatriks, mis ümbritseb täielikult selle püramiidi osa.
- Renderdamistsüklis tehke sügavuse etapp mitu korda – üks kord iga kaskaadi jaoks, renderdades erinevale varjukaardile (või tekstuuriatlase piirkonnale).
- Lõpliku stseeni etapi fragmentvarjutajas määrake, millisesse kaskaadi praegune fragment kuulub, lähtudes selle kaugusest kaamerast.
- Proovige varju arvutamiseks sobiva kaskaadi varjukaarti.
Eelis: Pakub järjepidevalt kõrge eraldusvõimega varjusid suurtel vahemaadel, muutes selle ideaalseks väliskeskkondade jaoks.
Variatsiooni varjukaardid (VSM)
VSM on veel üks tehnika pehmete varjude loomiseks, kuid see kasutab PCF-ist erinevat lähenemist.
Kontseptsioon: Selle asemel, et salvestada varjukaardile ainult sügavust, salvestab VSM kaks väärtust: sügavus (esimene moment) ja sügavus ruudus (teine moment). Need kaks väärtust võimaldavad meil arvutada sügavuse jaotuse dispersiooni. Kasutades matemaatilist tööriista, mida nimetatakse Tšebõševi võrratuseks, saame seejärel hinnata tõenäosust, et fragment on varjus. Peamine eelis on see, et VSM-tekstuuri saab hägustada tavalise riistvarakiirendusega lineaarse filtreerimise ja mipmappinguga, mis on tavalise sügavuskaardi jaoks matemaatiliselt kehtetu. See võimaldab väga suuri, pehmeid ja siledaid varju penumbra fikseeritud jõudluskuluga.
Puudus: VSM-i peamine nõrkus on "valguse lekkimine", kus valgus võib ilmuda läbi objektide olukordades, kus on kattuvad okludeerijad, kuna statistiline lähendus võib laguneda.
5. peatükk: Praktilised rakendamisnõuanded ja jõudlus
Varjukaardi eraldusvõime valimine
Teie varjukaardi eraldusvõime on otsene kompromiss kvaliteedi ja jõudluse vahel. Suurem tekstuur pakub teravamaid varjusid, kuid tarbib rohkem videomälu ja võtab kauem aega renderdamiseks ja proovimiseks. Levinud suurused on:
- 1024x1024: Hea lähtepunkt paljude rakenduste jaoks.
- 2048x2048: Pakub lauaarvutirakenduste jaoks märgatavat kvaliteediparandust.
- 4096x4096: Kõrge kvaliteet, mida sageli kasutatakse kangelasvarade jaoks või mootorites, millel on jõuline kärpimine.
Valguse pĂĽramiidi optimeerimine
Varjukaardi iga piksli maksimaalseks kasutamiseks on ülioluline, et valguse projektsioonimaht (selle ortograafiline kast või perspektiivipüramiid) oleks võimalikult tihedalt sobitatud stseeni elementidega, mis vajavad varje. Suunava valguse korral tähendab see selle ortograafilise projektsiooni sobitamist, et ümbritseda ainult kaamera püramiidi nähtavat osa. Varjukaardil raisatud ruum on raisatud eraldusvõime.
WebGL-i laiendused ja versioonid
WebGL 1 vs. WebGL 2: Kuigi varjukaardistamine on võimalik WebGL 1-s, on see WebGL 2-s palju lihtsam ja tõhusam. WebGL 1 vajab sügavustekstuuri loomiseks laiendust `WEBGL_depth_texture`. WebGL 2-l on see funktsionaalsus sisse ehitatud. Lisaks pakub WebGL 2 juurdepääsu varjuproovidele (`sampler2DShadow`), mis suudavad teostada riistvarakiirendusega PCF-i, pakkudes varjutajas käsitsi PCF-i silmustega võrreldes märkimisväärset jõudluse tõusu.
Varjude silumine
Varjud võivad olla kurikuulsalt raskesti silutavad. Kõige kasulikum tehnika on varjukaardi visualiseerimine. Muutke oma rakendust ajutiselt, et renderdada sügavustekstuur konkreetsest valgusallikast otse ekraanil olevale nelinurgale. See võimaldab teil näha täpselt, mida valgus "näeb". See võib kohe paljastada probleeme teie valguse maatriksite, püramiidi kärpimise või objektide renderdamisega sügavuse etapis.
Järeldus
Reaalajas varjukaardistamine on kaasaegse 3D-graafika nurgakivi, muutes lamedad, elutud stseenid usutavateks ja dünaamilisteks maailmadeks. Kuigi valgusallika perspektiivist renderdamise kontseptsioon on lihtne, nõuab kvaliteetsete, artefaktidevabade tulemuste saavutamine põhjalikku arusaamist aluseks olevast mehaanikast, alates kaheetapilisest torujuhtmest kuni sügavuse nihke ja aliase nüanssideni.
Alustades põhilise rakendusega, saate järk-järgult lahendada levinud artefakte, nagu varju akne ja sakilised servad. Sealt edasi saate oma visuaale täiustada täiustatud tehnikatega, nagu PCF pehmete varjude jaoks või kaskaaditud varjukaardid suuremahuliste keskkondade jaoks. Teekond varjurenderdamisse on suurepärane näide kunsti ja teaduse segunemisest, mis muudab arvutigraafika nii köitvaks. Soovitame teil katsetada nende tehnikatega, nihutada nende piire ja tuua oma WebGL-i projektidesse uus realismitase.