Stensil bafer

Ovaj članak je dobar. Kliknite ovde za više informacija.
S Vikipedije, slobodne enciklopedije
Primer primene stensil bafera. Gornja polovina slike prikazuje slaganje providne ravni preko trodimenzionog objekta, čime se postiže efekat zatamnjenja. Donja polovina slike prikazuje kako se stensil bafer može upotrebiti za pravljenje rupe u toj ravni — ista se iscrtava svuda osim na mestu kvadrata iz stensil bafera. Drugim rečima, taj kvadrat je oduzet od providne ravni tokom njenog crtanja preko objekta.
Ilustracija primene stensil bafera primerom iz života: dva dela izrezane pločice se mogu koristiti kako da omoguće nanošenje boje unutar izrezane siluete, tako i van nje.

Stensil bafer (engl. Stencil buffer, od Stencil što znači šablon, šara, prošarica) je pojam iz oblasti računarske grafike. Označava bafer pomoću kojeg se svakom pikselu računarski iscrtavane slike može dodeliti oznaka u vidu broja. Ovo označavanje se potom može koristiti za kontrolu načina na koji će pojedinačni pikseli biti iscrtavani. Laički rečeno, stensil bafer je u rukama programera alatka poput šablon-lenjira u rukama tehničkog crtača. Osnovna razlika je u tome što programer ovaj šablon može da oblikuje neograničen broj puta i kako god to pogoduje potrebama iscrtavanja scene. Prvu hardversku implementaciju je predstavio Silikon Grafiks, na manifestaciji SIGGRAPH `88. Hardverska podrška za stensil bafer danas postoji u oba interfejsa zastupljena u industriji računarskih igara: u OpenGL, od prve verzije, i u Direct3D, od verzije 6.0.

Građa i korišćenje[uredi | uredi izvor]

Stensil bafer obično deli isti memorijski prostor sa dubinskim baferom (engl. Depth Buffer, Z-Buffer), a obično je taj odnos 24 bita za dubinski + 8 bita za stensil bafer ili, ranije češće korišćeno, 15 bita za dubinski + 1 bit za stensil bafer. Takođe je prisutna varijanta 24 + 4, gde se od 32 bita 28 koristi, a 4 ignoriše.[1] I stensil i dubinski bafer su deo frejm bafera (engl. Frame Buffer), zajedno za baferom za boju (engl. Color Buffer). Prvi čip dostupan širem tržištu, koji je podržavao jedan bit za stensil bafer, bio je 3Dlabs-ov Permedia II.

Bitovi dodeljeni stensil baferu se mogu koristiti za reprezentaciju brojevnih vrednosti u opsegu [0, 2n-1], ali i kao n bulovih matrica (n je broj dodeljenih bitova), od kojih svaka može da se koristi za kontrolisanje posebnog dela scene. Svaka kombinacija ova dva načina korišćenja raspoložive memorije je takođe moguća.

Stensil test[uredi | uredi izvor]

Stensil test ili stensiling (engl. Stencil test, Stenciling) se među operacijama nad fragmentima (engl. per fragment operations) nalazi nakon alfa testa i pre dubinskog testa. Ovim rasporedom se omogućuje da odgovarajući pikseli, čiji bi prikaz stensil test ionako sprečio, ni ne stignu do dubinskog testa. Time se štedi vreme obrade scene. Na sličan način, alfa test može sprečiti odgovarajuće piksele da stignu do stensil testa.

Sam test se izvodi nad stensil baferom kako bi se neka vrednost u njemu ili izmenila ili upotrebila, a sprovodi se kroz tzv. stensil funkciju i stensil operacije. Stensil funkcija predstavlja funkciju kojom se stensil vrednost određenog piksela poredi sa zadatom referentnom vrednošću. Ukoliko je ovo poređenje logički tačno, stensil test prolazi. U suprotnom ne. Moguće stensil funkcije su:

Značenje OpenGL oznaka[2] Direct3D oznaka[3]
Nikad ne prolazi GL_NEVER D3DCMP_NEVER
Prolazi ako je vrednost piksela manja od referentne GL_LESS D3DCMP_LESS
Prolazi ako je vrednost piksela manja ili jednaka referentnoj GL_LEQUAL D3DCMP_LESSEQUAL
Prolazi ako je vrednost piksela veća od referentne GL_GREATER D3DCMP_GREATER
Prolazi ako je vrednost piksela veća ili jednaka referentnoj GL_GEQUAL D3DCMP_GREATEREQUAL
Prolazi ako je vrednost piksela jednaka referentnoj GL_EQUAL D3DCMP_EQUAL
Prolazi ako je vrednost piksela različita od referentne GL_NOTEQUAL D3DCMP_NOTEQUAL
Prolazi uvek. Ovo je podrazumevana funkcija. GL_ALWAYS D3DCMP_ALWAYS

Pritom, moguća reakcija uslovljena rezultatom poređenja razlikuje tri stanja dubinskog i stensil bafera:

  • Stensil test nije prošao
  • Stensil test je prošao, ali dubinski test nije
  • Oba testa su prošla (ili je stensil test prošao, a dubinski nije omogućen)

Za svaki od ovih slučaja se može podesiti drugačija operacija nad ispitivanim pikselom. Moguće stensil operacije su:

Značenje OpenGL oznaka[4] Direct3D oznaka[5]
Zadržavanje trenutne vrednosti. Ovo je podrazumevana akcija. GL_KEEP D3DSTENCILOP_KEEP
Postavljanje na nulu GL_ZERO D3DSTENCILOP_ZERO
Zamena sa referentnom vrednošću GL_REPLACE D3DSTENCILOP_REPLACE
Uvećanje, ali samo ako je vrednost manja od maksimalne moguće GL_INCR D3DSTENCILOP_INCRSAT
Uvećanje. Ako vrednost premaši maksimalnu moguću, postaje nula. - D3DSTENCILOP_INCR
Umanjenje, ali samo ako je vrednost različita od nule GL_DECR D3DSTENCILOP_DECRSAT
Umanjenje. Ako vrednost treba da postane manja od nule, postaje
maksimalna moguća.
- D3DSTENCILOP_DECR
Invertovanje na nivou bitova GL_INVERT D3DSTENCILOP_INVERT

Sledi šematski prikaz stensil pajplajna[6]:

Sledi opis oznaka koje već nisu pomenute:

  • Maska predstavlja brojevnu vrednost kojom se referentna vrednost i vrednost stensil bafera za aktuelni piksel bitovski konjuguju pre nego što će biti podvrgnuti stensil testu.
  • Maska za stensil operacije predstavlja niz od tri operacije definisane za svaki od navedenih slučajeva (stensil test nije prošao, stensil test je prošao ali dubinski nije, oba testa su prošla). Samo jedna od ove tri operacije će biti izvršena nad stensil vrednošću aktuelnog piksela.

U OpenGL se stensil funkcija, referentna vrednost i maska, tim redom, definišu funkcijom glStencilFunc. U Direct3D se svaka od ovih komponenti podešava pojedinačno, pomoću metode SetRenderState uređaja koji se trenutno kontroliše. Ova metoda očekuje po dva parametra, od kojih je prvi stanje koje se podešava a drugi njegova vrednost. Redom koji je korišćen gore, ova stanja se zovu D3DRS_STENCILFUNC, D3DRS_STENCILREF i D3DRS_STENCILMASK.[7]

Stensil operacije se u OpenGL podešavaju funkcijom glStencilOp koja očekuje tri vrednosti u već navedeonm redu. Kod Direct3D se, opet, svako stanje posebno podešava metodom SetRenderState. Tri stanja kojima se mogu dodeliti operacije se zovu D3DRS_STENCILFAIL, D3DRENDERSTATE_STENCILZFAIL i D3DRENDERSTATE_STENCILPASS.[7]

Primene[uredi | uredi izvor]

Iako je spektar primena stensil bafera prilično širok, može se navesti nekoliko poznatijih primena.

Problem dubinske borbe[uredi | uredi izvor]

Na gornjoj slici se poligon sa slikom nalazi tik iznad bele površi, što nije dovoljno da se spreči efekat dubinske borbe. Nasuprot tome, kod stensilinga (donja slika) ovaj efekat biva potpuno odstranjen, čak i kada su površi koplanarne.

Usled nedovoljne preciznosti dubinskog bafera, koplanarni poligoni koji se nalaze na malim rastojanjima, ili se preklapaju, bivaju prikazivani kao dva objekta sa mnoštvom nepravilnih preseka. Ti preseci mogu da variraju u zavisnosti od položaja kamere i drugih parametara, i da se jako brzo menjaju. Ovo se zove dubinska borba (engl. Z fighting). Rešenja koja mogu da daju određene rezultate su:

  • Približavanje daleke ravni za ograničavanje scene engl. far clip plane, čime se povećava preciznost dubinskog bafera, ali se smanjuje rastojanje na kojem su objekti scene vidljivi.
  • Povećanje broja bitova dodeljenih dubinskom baferu, što je moguće na uštrb memorije za stensil bafer.
  • Odmicanje poligona, što bi moglo da se kosi sa zahtevima obrađivane scene.

Svi ovi pristupi problemu samo smanjuju verovatnoću da će do dubinske borbe doći, i ne garantuju definitivno rešenje u opštem slučaju.

Rešenje koje uključuje stensil bafer se zasniva na znanju koji poligon treba ispred kojeg da stoji. Po ovome se silueta prednjeg poligona ucrtava u stensil bafer. Nakon toga se zadnji poligon crta samo tamo gde silueta nije ucrtana, a ostatak scene može da se crta normalno.

Primer OpenGL implmementacije[uredi | uredi izvor]

Pošto je ovo ujedno i najjednostavniji primer, sledi programski kôd za OpenGL, koji iscrtava sliku sa donjeg dela ilustracije.

// ..

glEnable(GL_STENCIL_TEST);
  glDepthMask(0);
  glColorMask(0, 0, 0, 0);
    glStencilFunc(GL_ALWAYS,
                   1,
                   0xff );
    glStencilOp(GL_REPLACE,
                 GL_REPLACE,
                 GL_REPLACE );


    poligon_sa_slikom();


  glDepthMask(1);
  glColorMask(1, 1, 1, 1);
    glStencilFunc(GL_NOTEQUAL,
                   1,
                   0xff );
    glStencilOp(GL_KEEP,
                 GL_KEEP,
                 GL_KEEP );

    bela_povrs();
glDisable(GL_STENCIL_TEST);

poligon_sa_slikom();
Подесити камеру и остало.

Омогућити стенсил тест
  Закључати дубински бафер
  Закључати бафер за боју
    Подесити стенсил тест тако да увек
    пролази и, референтну вредност на 1.

    Подесити операције стенсил теста
    тако да се у њега пише референтном
    вредношћу где год се неки објекат
    исцртава.

    Исцртати полигон са сликом. Добија
    се његова силуета у стенсил баферу.

  Откључати дубински бафер.
  Откључати бафер за боју.
    Подесити стенсил тест тако да пролази
    кад год је вредност додељена актуел-
    ном пикселу различита од 1.
    Приликом овог пролаза се само чувају
    већ постојеће вредности.


    Исцртати белу површ.
Искључити стенсил тест.

Исцртати полигон са сликом.

Prilikom zaključavanja i otključavanja drugih bafera, korišćene su vrednosti 0 i 1 umesto, redom, konstanti GL_FALSE i GL_TRUE, zarad kraćeg zapisa.

Refleksije[uredi | uredi izvor]

Refleksija neke scene se iscrtava kao njen odraz u odnosu na datu ravan, koju određuje poligon na kome refleksija treba da se oslikava. Deo ovog problema koji se odnosi stensil bafer je ograničavanje prikaza reflektovane scene samo na taj poligon tj. postizanje iluzije da se odraz scene samo na njemu odražava. Stensil bafer to omogućava na sledeći način:

  1. Scena se iscrta bez površi koje predstavljaju ogledala
    • Za svako ogledalo:
      1. Zaključavaju se dubinski bafer i bafer za boju
      2. U stensil bafer se ucrta vidljiv deo ogledala
      3. Dubinski test se podesi tako da za svaki prosleđeni piksel upisuje maksimalnu vrednost i da uvek prolazi
      4. Iscrtava se površina ogledala
      5. Dubinski test se podesi tako da prolazi samo ako je udaljenost nekog piksela manja od trenutne (podrazumevano ponašanje)
      6. Matrica transformacije se izmeni tako da reflektuje scenu u odnosu na ravan ogledala
      7. Otključavaju se dubinski bafer i bafer za boju
      8. Scena se iscrtava, ali tako da se iscrtava samo njen deo koji se nalazi iza ravni ogledala, a vidljiv je na samom ogledalu. Za prvo ograničenje se dodaje jedna ograničavajuća ravan (engl. clip plane), a za drugo ograničenje se koristi sadržaj stensil bafera
      9. Opet se zaključava bafer za boju, dubinski test se podešava tako da uvek prolazi, i pikseli ogledala se brišu iz stensil bafera tako što se ono opet iscrta. Nakon ovoga je stensil bafer opet čist i spreman za sledeće ogledalo.

Umesto poligona, može se raditi i o površi koju čini više nekoplanarnih poligona. U tom slučaju, ova površ se razbija na poligone i svaki od njih se posmatra kao posebno ogledalo. Takođe, ovaj primer pominje samo savršena ogledala, jer to ne utiče na opštost problema. Deo scene koji je označen kao ogledalo se pre, tokom i nakon iscrtavanja refleksije može dorađivati svakim drugim alatom.

Jedan dalji problem je ogledanje jednog ogledala u drugom. Isti ovaj postupak se može ponoviti za odraze svih ovakvih ogledala. Ekonomično rešenje može biti da se odraz ogledala u ogledalu uvek iscrtava kao nereflektivna površina.

Ravanske senke[uredi | uredi izvor]

Prilikom crtanja ravanskih senki, dominantna su dva problema:

  • Prvi se odnosi na problem dubinske borbe u slučaju da se ravan geometrijski ne podeli na deo prekriven senkom i van senke. Videti odeljak koji se na ovo odnosi.
  • Drugi problem se odnosi na prostiranje senke van prostora na kojem ravan postoji.

Još jedan problem, koji može a ne mora da nastupi, u zavisnosti od tehnike, je projektovanje više poligona na jedan deo senke, što rezultuje tamnijim i svetlijim delovima jedne iste senke. Sva tri problema se mogu rešiti geometrijski, no zbog mogućnosti da se hardversko ubrzanje direktno upotrebi, daleko je elegantnija implementacija pomoću stensil bafera:

  1. Omogućiti osvetljenje i sva svetla
  2. Iscrtati scenu bez poligona na koje treba projektovati senke
  3. Iscrtati sve poligone na koje treba projektovati senke, ali bez svetala. Pritom, u stensil baferu, treba pikselima svakog poligona dodeliti vrednost specifičnu za poligon kome pripadaju. Razmak između ovih vrednosti treba da bude najmanje dva, jer će za svaku ravan biti korišćene dve vrednosti za dva moguća stanja: u senci i osvetljeno.
  4. Onemogućiti svako globalno osvetljenje (kako bi se osiguralo da na sledeće korake utiče samo pojedinačno odabrano svetlo)
    • Za svaku ravan:
      • Za svako svetlo:
        1. Izmeniti samo stensil bafer i samo za piksele koji nose vrednost specifičnu za odabranu ravan. Uvećavaju se vrednosti svih piksela na koje se projektuju objekti između date ravni i datog svetla.
        2. Omogućiti samo odabrano svetlo i za njega iscrtati deo ravni na kojem za nju specifična vrednost nije bila menjana.

Prostorne senke[uredi | uredi izvor]

Stensil bafer implementacija crtanja prostornih senki predstavlja svaku senku geometrijskim telom, koje svojom zapreminom obuhvata deo scene koji se nalazi u njoj. Ukoliko neki deo scene pripada ovoj zapremini, nije osvetljen datim svetlom, u suprotnom jeste. Ovaj problem se usložnjava sa porastom broja svetala, ali se ne osvrće na broj površina na koje senke padaju. Postoji više rešenja problema, ali sva slede sledeći algoritam:

  1. Nacrtati scenu bez ikakvog osvetljenja
  2. Zaključati dubinski bafer i bafer za boju, tako da se na njima ne mogu vršiti izmene
    • Za svako svetlo
      1. Koristeći dubinsku informaciju o sceni (dubinski bafer), popuniti stensil bafer samo na delovima scene gde zapremine senki ne postoje ili nisu vidljive od postojećih objekata.
      2. Otključati bafer za boju, i podesiti funkciju dubinskog bafera tako da dozvoli izmene samo tamo gde je dubinska vrednost jednaka već postojećoj
      3. Iscrtati ovu scenu osvetljenu samo ovim svetlom, ali samo za delove scene koji prolaze stensil test

Svaki od ovih prolaza pretpostavlja da mu na raspolaganju stoji čisti stensil bafer.

Kako za senke, ova tehnika se može koristiti i za osvetljavanje delova prostora koji se nalaze pod jakim svetlom. Na primer svetlost reflektora u tamnoj prostoriji sa velikim prisustvom prašine u vazduhu bi vidljivo osvetljavala odgovarajuću zapreminu prostora.

Ostale primene[uredi | uredi izvor]

Jedan dalji primer su takozvane meke senke, kod kojih prelaz između osvetljenog i osenčenog dela scene nije oštar. Naime, jedan način da se ovaj efekat postigne stensil baferom jeste da se zapremina senke umnoži, a da se njene kopije redom skaliraju po geometrijskom nizu sa malim uvećanjem, npr. 1,04. Centar skaliranja može da bude težište poligona koji predstavlja vrh zapremine. Ovo će samo po sebi dati niz kompozitnih senki koje daju željeni efekat.

Još jedna primena obuhvata polje vizuelizacije prilikom modeliranja tehnikom konstruktivne geometrije solida (engl. Constructive Solid Geometry, CSG), gde stensil bafer, zajedno sa dubinskim baferom, može uspešno da rešava probleme Bulovih operacija nad solidima.

Vidi još[uredi | uredi izvor]

Reference[uredi | uredi izvor]

  1. ^ Tom Miller. Managed DirectX 9. str. 61. ISBN 0-672-32596-9. 
  2. ^ Specifikacija glStencilFunc (jezik: engleski)
  3. ^ Specifikacija D3DCMPFUNC (jezik: engleski)
  4. ^ specifikacija glStencilOp (jezik: engleski)
  5. ^ Specifikacija D3DSTENCILOP (jezik: engleski)
  6. ^ Prezentacija o stensil baferu, slajd 4 Arhivirano na sajtu Wayback Machine (7. jun 2008), dokumentacija na sajtu NVIDIA-e (jezik: engleski)
  7. ^ a b Specifikacija ravni stensila, na MSDN (jezik: engleski)

Literatura[uredi | uredi izvor]

  • Poboljšavanje senki i refleksija pomoću stensil bafera, Mark. Dž. Kilgard, NVIDIA Korporacija;

Spoljašnje veze[uredi | uredi izvor]