WebGL varjutajate kasutamine WebAssembly'is

WebAssembly on kiire numbrite krigistamise, mängumootorite ja paljude muude asjade jaoks, kuid miski ei saa võrrelda GPU-l töötavate varjurite äärmist paralleelsust.

See kehtib eriti siis, kui soovite pilditöötlust teha. Tavaliselt tehakse seda veebis WebGL-i kaudu, kuid kuidas pääsete WebAssemble'i kasutamisel juurde selle API-dele?

Seadistan

Tutvume lühidalt näidisprojekti seadistamisega, seejärel vaatame, kuidas pilti tekstuurina laadida. Seejärel rakendame eraldi kontekstis pildile servatuvastuse GLSL-shaderit.

Kui eelistate sellele otse hüpata, on kogu kood siin repos. Pange tähele, et WebAssembly toimimiseks peate oma faile serveri kaudu teenindama.

Eeltingimusena eeldan, et olete juba oma WebAssembly projekti üles seadnud. Kui ei, siis vaadake siin olevat artiklit selle kohta, kuidas seda teha, või lihtsalt kahvlige ülaltoodud linki.

Allpool oleva koodi demodeerimiseks kasutan ma tavalist html-faili, mis on mõeldud ainult pildi laadimiseks, selle imageData hankimiseks ja funktsiooni ccallArrays abil WebAssembly-koodile edastamiseks.

Eelvaate sisendpildiga HTML-fail

Mis puudutab C ++ -koodi, siis on olemas fail emscripten.cpp, mis haldab ja suunab meetodikõned Context.cpp-failis loodud kontekstinäidetele. Context.cpp fail on üles ehitatud järgmiselt:

Kompileerimine

WebGL põhineb OpenGL ES (Embedded Systems) spetsifikatsioonil ja järgib seda, mis on OpenGL alamhulk. Kompileerimise ajal kaardistab emscripten meie koodi WebGL API-le.

Sihtida saame paar erinevat versiooni. OpenGL ES 2 kaardistab WebGL 1, OpenGL ES 3 aga WebGL 2. Vaikimisi peaksite sihtima WebGL 2, kuna see sisaldab mõningaid tasuta optimeerimisi ja täiustusi.

Selleks peame lisama kogumile lipu USE_WEBGL2 = 1.

Kui plaanite kasutada mõnda OpenGL ES-i funktsiooni, mida WebGL-i kirjelduses pole, võite kasutada lippe FULL_ES2 = 1 ja / või FULL_ES3 = 1.

Suurte tekstuuride / piltide käsitlemiseks võime lisada ka lipu ALLLOW_MEMORY_GROWTH = 1. See eemaldab WebAssembly programmi mälupiirangu mõne optimeerimise hinnaga.

Kui teate juba ette, kui palju mälu vajate, võite selle asemel kasutada lippu TOTAL_MEMORY = X, kus X on mälu suurus.

Nii et me lõpetame midagi sellist:

emcc -o ./dist/appWASM.js ./dev/cpp/emscripten.cpp -O3 -s ALLOW_MEMORY_GROWTH = 1 -s USE_WEBGL2 = 1 -s FULL_ES3 = 1 -s WASM = 1 -s NO_EXIT_RUNTIME = 1-std = c ++ 1z

Lõpuks vajame oma koodis järgmist importi:

# lisage 
# kaasata 
# hõlmake 
# lisage 
välimine "C" {
   #include "html5.h" // moodul emscripten
}

Rakendamine

Kui teil on WebGL-i või OpenGL-iga varasemaid kogemusi, võib see bit tunduda tuttav.

OpenGL-i kirjutamisel ei tööta API enne, kui olete loonud konteksti. Tavaliselt tehakse seda platvormipõhiste API-de abil. Kuid veeb ei ole platvormiga seotud ja selle asemel võime kasutada OpenGL ES-i integreeritud API-d.

Suuremat osa jalavarjust saab aga hõlpsamini rakendada html5.h-failis olevate emscripteni API-de abil. Funktsioonid, mis meid huvitavad, on järgmised:

  • emscripten_webgl_create_context - see kiirendab antud lõuendi ja atribuutide konteksti
  • emscripten_webgl_destroy_context - seda on vaja mälu puhastamiseks kontekstikogumite hävitamisel
  • emscripten_webgl_make_context_current - see määrab ja vahetab, millisesse konteksti WebGL kuvatakse

Loo kontekst

Rakendamise alustamiseks peate kõigepealt lõuendi elemendid looma oma JavaScripti koodis. Seejärel edastate funktsiooni emscripten_webgl_create_context kasutamisel esimese parameetrina lõuendi ID, teise konfiguratsiooniga konfiguratsioone. Funktsiooni emscripten_webgl_make_context_current kasutatakse uue konteksti seadmiseks selliseks, nagu praegu kasutatakse.

Järgmisena koostatakse nii tippvari (koordinaatide täpsustamiseks) kui ka fragmentide varjutaja (iga piksli värvi arvutamiseks) ja programm on üles ehitatud.

Lõpuks kinnitatakse varjurid programmi külge, mis seejärel lingitakse ja valideeritakse.

Ehkki see kõlab palju, on selle kood järgmine:

Shaderi kompileerimine toimub CompileShaderi abistaja funktsioonis, mis teostab kompileerimise ja prindib välja kõik vead:

Loo varju

Selle näite varjutatav kood on minimaalne ja see kaardistab iga piksli enda jaoks, et kuvada pilt tekstuurina:

Lõuendi kontekstile pääsete lisaks C ++ -koodi kontekstile juurde ka JavaScriptis, kuid see peab olema sama tüüpi, „webgl2”. Mitme kontekstitüübi määratlemisel pole JavaScripti kasutamisel midagi, kui teete seda enne webgl2 konteksti loomist WebAssembly'is, viskab see koodi käivitamisel viga.

Tekstuuri laadimine

Shaderi rakendamisel tuleb esimene asi helistada emscripten_webgl_make_context_currentfunction, et veenduda, et kasutame ikka õiget konteksti, ja glUseProgramto veenduda, et kasutame õiget programmi.

Järgmisena saame funktsioonideglGetAttribLocation ja glGetUniformLocation kaudu GLSL-i muutujate indeksid (sarnaselt osutiga), et saaksime neile asukohtadele oma väärtused määrata. Funktsioon, mida selleks kasutatakse, sõltub väärtuse tüübist.

Näiteks vajab täisarv, näiteks tekstuuri asukoht glUniform1i, samas kui ujuk vajab glUniform1f. See on hea ressurss, et näha, millist funktsiooni peate kasutama.

Järgmisena saame tekstuuriobjekti glGenTextures kaudu, määrame selle aktiivseks tekstuuriks ja laadime imageData puhvri. Seejärel seotakse tipu- ja indekspuhvrid tekstuuri piiride seadmiseks lõuendi täitmiseks.

Lõpuks puhastame olemasoleva sisu, määratleme andmetega allesjäänud muutujad ja juhime lõuendile.

Tekstuur laaditakse

Avastage servad varjutaja abil

Uue konteksti lisamiseks, kui serva tuvastamine toimub, laadime teistsuguse fragmentide shaderi (mis rakendab Sobeli filtrit) ning seome koodiga lisamuutujatena laiuse ja kõrguse.

Erinevate kontekstide jaoks fragmentide varjutajate vahel valimiseks lisame konstruktorisse lihtsalt if-else lause, näiteks nii:

Laiuse ja kõrguse muutujate laadimiseks lisame käitamisfunktsioonile järgmise:

Kui ilmneb tõrge, mis sarnaneb viitegaERROR: GL_INVALID_OPERATION: glUniform1i: tüübi vale ühtlane funktsioon, siis on antud muutuja jaoks sobimatu määramisfunktsioon.

Üks asi, mida imageData saatmisel tasub tähele panna, on kasutada õiget hunnikut, allkirjastamata täisarvu (Uint8Array trükitud massiiv). Nende kohta saate lisateavet siit, kuid kui kasutate funktsiooni ccallArray, määrake heapIn-i konfiguratsioon väärtuseks „HEAPU8”, nagu ülalpool näidatud.

Kui tüüp pole õige, laaditakse tekstuur ikkagi, kuid näete kummalisi renderdusi, näiteks järgmisi:

Järeldus

Oleme läbinud mini-teemalise tereprojekti "Tere maailm!", Et näidata, kuidas WebAssemble'is tekstuure laadida ja neile GLSL-varjureid rakendada. Täielik kood hostitakse siin GitHubis, et neid täiendavalt vaadata.

Tõelise projekti jaoks võiksite lisada mõne täiendava tõrkekäsitluse. Jätsin selle selguse huvides siin ära.

Samuti võib olla tõhusam (ülaltoodud näites) selliste andmete nagu imageData tekstuuri jagamine kontekstide vahel. Selle ja enama kohta saate lugeda siit.

Mõne edasise lugemise jaoks saate sellel lingil vaadata levinumaid vigu või otsida mõnda demoprojekti emscripteni glbooki kaustas GitHubis.

Et näha WebGL-i kasutamist WebAssembly-projektis, saate vaadata veebipõhise süvaõpperaamistiku jsNet dev-haru, kus järgmise paari nädala jooksul töötan raskemate arvutuste varjunditesse viimisel (WebGL-i arvutuse tugi) Shaderid OpenGL ES 3.1 kaudu ei saa tulla nii kiiresti ).

Uuenda

Et näha, kuidas GPU arvutus varjutajaid kasutades WebAssemble'is välja näeks, saate vaadata GPGPU - väikese raamatukogu, milles ma töötan - repo nii JavaScripti kui ka WebAssemble versiooniga.