Shaderi u processing-u

Što su shaderi?

Nova značajka u processing 2 je uključivanje GLSL shader-a. U stvari, sve što processing crta na zaslonu s P2D i P3D renderers je posljedica odgovarajućeg "default Shader-a" pokrenutog u pozadini. Processing obrađuje ove zadane shader-e transparentno, tako da korisnik ne mora brinuti o njima, a ona ili on može nastaviti koristiti poznate funkcije za crtanje i očekivati iste vizualne rezultate kao sa prethodnim verzijama processing-a. Međutim, processing 2 uključuje novi set funkcija i varijabli koje omogućuje naprednim korisnicima zamijeniti zadane shader-e sa vlastitim. To otvara brojne uzbudljive mogućnosti: renderiranje 3D scene pomoću sofisticirane rasvjete i teksturnim algoritmima, primjenjujući sliku nakon obrade efekta u realnom vremenu, stvarajući složene proceduralne predmete koje bi bilo vrlo teško ili nemoguće generirati s drugim tehnikama, te dijeljenje shader učinke između desktop, mobile i web platforma sa minimalnim promjenama koda.

Da bi se razumjelo kako shader-i rade i kako ih se može koristiti za proširenje mogućnosti crtanja u processing-u, potrebno je imati pregled ključnih pojmova Shader programiranja, najprije općenito, a onda iz "perspektive" u Processing skica.

Odgovarajući na pitanje aludira i naslov ovog odjeljka, shader je u osnovi program koji radi na Processing Unit (GPU) grafike na računalu, a stvara vizualni izlaz koji vidimo na ekranu primjenjujuči dobivene informacije koje definiraju 2D ili 3D scenu: vrhovi, boje, teksture, svjetla, itd. Pojam "Shader" sam po sebi može biti mala zabluda, budući da preveden sa engleskog znači "sjenčanje" a riječ sjenčanje u kontekstu crteža podrazumijeva proces koji predstavljaju različite razine tame na površini objekta zbog okolnog svjetla, kako bi stvorili iluziju dubine. Prvi računalni shader-i uglavnom su se bavili sintetskim obračunavanjem tih razina sjenčanje no danas, shaderi ne koriste samo za izračunavanje sjenčane ili rasvjetne razine u virtualnom sceni, nego su odgovorni za sve faze izrade, počevši od transformacije kamere sve do ocjenjivanja konačne boje svakog piksela vidljivog na zaslonu.

Postoje više jezika koji se mogu koristiti za pisanje shader-a: Cg, HLSL i GLSL. GLSL je akronim za OpenGL shader language. Processing koristi OpenGL kao osnova za njegovu P2D i P3D renderiranje. GLSL je jezik koji se mora koristiti u processingu za pisanje prilagođenih shadera koji se žele uključiti u obradu crteža.

Pisanje shader zahtijeva razumijevanje pojedinih faza uključenih u renderiranje scene preko GPU-a, i kako možemo koristiti GLSL da ih isprogramiramo. Mi ovdje nećemo ulaziti u dubinu, već ćemo samo pokazati jednostavni primjer za početak te pokazati nekoliko vrsta shader-a u processing-u.

Počnimo sa jednostavnom 3D skicom kao model za razumijevanje odnosa između Processing funkcija i varijabli. Ova skica crta kvadrat sa svjetlima i nekim geometrijskim transformacijama primijenjenim na njega:

Ovaj primjer kao i svi ostali mogu se skinuti u tabu Primjeri te pokrenuti u processing-u

an image

Na slici vidimo opis kako pojedina linija i funkcija utječe na izlaznu skicu, odnosno upotrebu jednostavnih shader-a.

PShader klasa

U prethodnom poglavlju vidjeli smo da su dvije programabilne faze u GPU cjevovodima vertex i fragment shader . Obje su potrebne kako bi se definirao cjeloviti, radni cjevovod. U Processing-u moramo napisati GLSL kod za fragment i vertex shader u zasebne datoteke, koje zajedno sa glavnim programom čine jedan "Shader program" koji se može izvršiti u GPU. Riječ "program" se često izostavlja, sa implicitnom pretpostavkom da kad velimo shader mislimo na potpuni shader programa koji uključuje fragment i vertex shader-e.

Shader (Program) enkapsuliran je u PShader klasi. PShader objekt je stvoren sa loadShader() funkcijom koja prima datoteke vertex i fragment kao argumente. Ako je navedena samo jedna datoteke, Processing će pretpostaviti da naziv datoteke odgovara fragment shader-u, te će koristiti default-ni vertex shader. Slika ispod prikazuje primjer koji koristi PShader klasu koja renderira razine sjene u sferi pomoću toon effect shader-a.

Kod za ovaj primjer kao i za sve ostale nalazi se u tabu Primjeri dok detaljan opis svake varijable, funkcije itd. možete pronaći na Processing.org

an image

Vrste shader-a u Processing-u

Ovisno o tome da li scena ima linije ili točke, ili koristi teksture i / ili svjetla, shader koji se koriste u takvim okolnostima mora predstavljati određeni skup uniformnih i atributnih varijabli koje će omogućiti Processing-u interakciju sa Shader-om te slanje odgovarajućih podataka.

Na temelju ovih uniformnih i atributnih zahtjeva, shader-i u processing-u moraju pripadati jednoj od 6 različitih vrsta. Ove 6 vrste možemo svrstati u 3 klase:

  • POINT shader-i: koriste za renderiranje točaka.
  • LINE shader-i: koriste za renderiranje linija.
  • TRIANGLE shader-i: koriste se za renderiranje svega ostalog, što znači da će oni riješavati (lit /unlit, teksturom / bez tekstura) oblike. Naziv su dobili budući da su svi oblici u Processing-u u konačnici izrađeni od trokuta

Prilikom postavljanja shader-a sa shader() funkcijiom, ako nije naveden argument tipa onda se pretpostavlja da se radi o trokut shader-u.

Nadalje, triangle ili trokut shader se još dijeli na 4 tipa što zajedno sa prijašnje spomenutim POINT i LINE shader-ima čini ukupno 6 vrsta.

  • COLOR: renderiranje geometrije bez svjetla i teksture
  • LIGHT: renderiranje geometrije sa svjetlom ali bez teksture
  • TEXTURE: renderiranje geometrije sa teksturom ali bez svjetla
  • TEXLIGHT: renderiranje geometrije sa teksturom i svjetlom

Svakog od ovih tipova shader-a ćemo pomalo objasniti te prikazati primjere koji se mogu preuzeti i pokrenuti u već spomenutom tab-u Primjeri

Color shader-i

Ovisno o vrsti shader-a kojeg želimo koristiti, u GLSL datoteci možemo definirati vrstu koju želimo te ju zatim kao što je objašnjeno prije pozvati preko PShader klase.

  • #define PROCESSING_POINT_SHADER for POINT shaders
  • #define PROCESSING_LINE_SHADER for LINE shaders
  • #define PROCESSING_COLOR_SHADER for COLOR shaders
  • #define PROCESSING_LIGHT_SHADER for LIGHT shaders
  • #define PROCESSING_TEXTURE_SHADER for TEXTURE shaders
  • #define PROCESSING_TEXLIGHT_SHADER for TEXLIGHT shaders

U ovom primjeru koristit ćemo dakako #define PROCESSING_COLOR_SHADER, dok ćemo za ovaj i sve ostale primjere koristiti isti glavni kod za crtanje a to je rotirajući cilindar koji se mjenja ovisno o vrsti shader-a.

an image

Iz koda vidimo tu našu funkciju createCan() za crtanje cilindra, dok ono što se mjenjamo su naše glsl datoteke a samim time i vrsta shader-a.

Kao rezultat dobivamo rotirajući cilindar u boji kao na slici

an image

Ispod vidimo i kod .glsl datoteka koje sadrže kod za color shader.

colorfrag.glsl

an image

colorvert.glsl

an image

Texture shader-i

Za razliku od prijašnjeg primjera ovdje ćemo koristiti novi parametar kojeg koristi naša funkcija za crtanje kao i shader, a to je slika odnosno tekstura. Naravno osim toga glsl datoteke koje koristimo su različite odnosno kod u njima napisan je za texture shader-e.

an image

Iz glavnog koda za crtanje vidimo dakle tu razliku, dok se razlika u glsl datotekama može vidjeti ako se skinu. Kao rezultat dobivamo rotirajući cilindar koji na sebi ima teksturu koju smo mu dali.

an image

Light shader-i

Osvjetljavanje 3D scene uključuje stavljanje jednog ili više izvora svjetlosti u prostor, te utvrđivanje njihovih parametara, kao što su tip (točka izvorišta, jačina) i boja (difuzna, ambijentalna, reflektirajuća). Nećemo ići u detalje rasvjete u OpenGL-u, ali važno je napomenuti da su svi matematički modeli, koje koristimo za proizvodnju svjetla s GLSL shader-ima, vrlo jednostavne aproksimacije rasvjete u stvarnom svijetu.

Model koji ćemo koristiti u sljedećem primjeru je vjerojatno jedan od najjednostavnijih, a procjenjuje se intenzitet svjetlosti na svaki vrh objekta, a zatim se koristi ugrađena interpolacija grafičkog cjevovoda da bi se postepeno došlo do boja preko cijelog objekta. Intenzitet svjetla na svaki vrh se izračunava kao skalarni produkt između vrha normale i smjer vektora između tjemena i izvora svjetlosti pozicijama. Ovaj model predstavlja točkasti izvor svjetla koji emitira svjetlost jednako u svim smjerovima (nije usmijerena svijetlost). Dosad izrečeno je vizualno prikazano slijedećom skicom.

an image

Slijedi dio koda koji smo koristili za slijedeće primjere. Posebno treba obratiti pozornost na loadShader funkciju, te pointLight funkciju.

an image

Ovo je klasični primjer light shader-a, dok vidimo da je točka izvorišta svijetlosti ispred samog objekta, pa nam ga osvijetljava tako da zatamnjuje lijevo i desno od točke gledanja.

an image

U slijedećem primjeru smo pojačali svijetlost.

an image

U slijedećem primjeru smo promijenili točku izvorišta svijetlosti.

an image

Kao i u svim primjerima, opet imamo dvije .glsl datoteke(fragment i vertex), koje sadrže kod za light shader.

lightfrag.glsl

an image

lightvert.glsl

an image

Texture-light shader-i

Navedeni oblik shader-a je, kao i što možemo zaključiti po imenu, spoj light i texture shader-a. Primjere koje smo prije naveli za light i texture shadere sada ćemo ukomponirati u jedan, te ka prikazati slijedećim dijelom koda.

an image

U slijedećem primjeru smo primjenili texturu iz primjera texture shader-a, te osvijetljene iz primjera klasičnog light shader-a. Kombinacijom tih svojstava dobivamo slijedeći primjer.

an image

U slijedećem primjeru smo promijenili točku izvorišta svijetlosti.

an image

Image post-processing efekt

Fragment shader se može koristiti za pokretanje post-processing efekata vrlo učinkovito, iskorištavanjem paralelne prirode rada GPU-a. Na primjer, zamislimo da želimo renderirati teksturu korištenjem samo crno-bijele boje: crna ako je svjetlina u određenom piksela u slici ispod određenog praga, i bijela ako je iznad. To može biti jednostavno implementirano u fragment shader-u.

Primjer kako se taj shader implementira može se skinuti u tabu Primjeri kao i ostale dvije .glsl datoteke koje implementiraju shader-e Edge-detection i emboss a rezultat njihove primjene je sljedeći:

an image Black and white

an image Emboss

an image Edge

Point and line shader-i

Point and line shader-i koriste se samo od strane P3D renderera kako bi se crtala stroke geometrija. Razlog je u tome što stroke geometrija uvijek suočava ekran okrenuta "licem" u 3D-u, tako da treba drugačiji izračun projekcije u vertex-u. U P2D, sva geometrija se nalazi u istoj ravnini, tako da nema potrebe za posebnim rukovanjem za stroke linijama i točaka Tehnika renderiranje poligona okrenutog prema zaslonu zove se "billboarding", te se naširoko koristi u igrama za svaranje iluzije 3D objekata pomoću 2D slike koje se uvijek suočavaju sa kamerom.

Mi se ovdje nećemo baviti tim shader-ima ali njihova primjena i kako ih koristiti može se lako naći na službenoj stranici Processing.org

Sve zajedno

U svim primjerima koje smo do sada vidjeli, samo jedan shader se koristi tijekom izvršenja cijelog crteža. Međutim, možemo učitati i koristiti onoliko shadera koliko nam je potrebno. U svakom danom trenutku, jedan shader će biti izabran i pokrenut, ali možemo promijeniti odabrani shader pomoću shader() funkcije, i vratiti zadani shader sa resetShader() funkcijom.Sljedeći primjer kombinira sve shader-e iz prethodnih odjeljaka, tako da oni mogu biti omogućeno / onemogućeno korištenje tipkovnice(1-9). Primjer se može preuzeti te isprobati.

an image

an image

an image

an image

Iz koda iznad vidimo da za svaki tip shader-a imamo jedan objekt koji zatim koristimo ovisno o pritisnutoj tipki, odnosno koji shader želimo da se primjenjuje na naš crtež. Jedan od rezultata je slika ispod:

an image

Prikaz shader-a u pregledniku

Trenutno(siječanj,2015) nije moguće prikazati shader programe napisane u processing-u preko processing.js ili nekog drugog js-a u pregledniku. Budući da to nije moguće nismo mogli prikazati i koristiti naše primjere direktno kao npr. ovaj ispod koji ne koristi dodatne shader-e.