Стенсил бафер
Стенсил бафер (енгл. Stencil buffer, од Stencil што значи шаблон, шара, прошарица) је појам из области рачунарске графике. Означава бафер помоћу којег се сваком пикселу рачунарски исцртаване слике може доделити ознака у виду броја. Ово означавање се потом може користити за контролу начина на који ће појединачни пиксели бити исцртавани. Лаички речено, стенсил бафер је у рукама програмера алатка попут шаблон-лењира у рукама техничког цртача. Основна разлика је у томе што програмер овај шаблон може да обликује неограничен број пута и како год то погодује потребама исцртавања сцене. Прву хардверску имплементацију је представио Силикон Графикс, на манифестацији SIGGRAPH `88. Хардверска подршка за стенсил бафер данас постоји у оба интерфејса заступљена у индустрији рачунарских игара: у OpenGL, од прве верзије, и у Direct3D, од верзије 6.0.
Грађа и коришћење
уредиСтенсил бафер обично дели исти меморијски простор са дубинским бафером (енгл. Depth Buffer, Z-Buffer), а обично је тај однос 24 бита за дубински + 8 бита за стенсил бафер или, раније чешће коришћено, 15 бита за дубински + 1 бит за стенсил бафер. Такође је присутна варијанта 24 + 4, где се од 32 бита 28 користи, а 4 игнорише.[1] И стенсил и дубински бафер су део фрејм бафера (енгл. Frame Buffer), заједно за бафером за боју (енгл. Color Buffer). Први чип доступан ширем тржишту, који је подржавао један бит за стенсил бафер, био је 3Dlabs-ов Permedia II.
Битови додељени стенсил баферу се могу користити за репрезентацију бројевних вредности у опсегу [0, 2n-1], али и као n булових матрица (n је број додељених битова), од којих свака може да се користи за контролисање посебног дела сцене. Свака комбинација ова два начина коришћења расположиве меморије је такође могућа.
Стенсил тест
уредиСтенсил тест или стенсилинг (енгл. Stencil test, Stenciling) се међу операцијама над фрагментима (енгл. per fragment operations) налази након алфа теста и пре дубинског теста. Овим распоредом се омогућује да одговарајући пиксели, чији би приказ стенсил тест ионако спречио, ни не стигну до дубинског теста. Тиме се штеди време обраде сцене. На сличан начин, алфа тест може спречити одговарајуће пикселе да стигну до стенсил теста.
Сам тест се изводи над стенсил бафером како би се нека вредност у њему или изменила или употребила, а спроводи се кроз тзв. стенсил функцију и стенсил операције. Стенсил функција представља функцију којом се стенсил вредност одређеног пиксела пореди са задатом референтном вредношћу. Уколико је ово поређење логички тачно, стенсил тест пролази. У супротном не. Могуће стенсил функције су:
Значење | OpenGL ознака[2] | Direct3D ознака[3] |
---|---|---|
Никад не пролази | GL_NEVER | D3DCMP_NEVER |
Пролази ако је вредност пиксела мања од референтне | GL_LESS | D3DCMP_LESS |
Пролази ако је вредност пиксела мања или једнака референтној | GL_LEQUAL | D3DCMP_LESSEQUAL |
Пролази ако је вредност пиксела већа од референтне | GL_GREATER | D3DCMP_GREATER |
Пролази ако је вредност пиксела већа или једнака референтној | GL_GEQUAL | D3DCMP_GREATEREQUAL |
Пролази ако је вредност пиксела једнака референтној | GL_EQUAL | D3DCMP_EQUAL |
Пролази ако је вредност пиксела различита од референтне | GL_NOTEQUAL | D3DCMP_NOTEQUAL |
Пролази увек. Ово је подразумевана функција. | GL_ALWAYS | D3DCMP_ALWAYS |
Притом, могућа реакција условљена резултатом поређења разликује три стања дубинског и стенсил бафера:
- Стенсил тест није прошао
- Стенсил тест је прошао, али дубински тест није
- Оба теста су прошла (или је стенсил тест прошао, а дубински није омогућен)
За сваки од ових случаја се може подесити другачија операција над испитиваним пикселом. Могуће стенсил операције су:
Значење | OpenGL ознака[4] | Direct3D ознака[5] |
---|---|---|
Задржавање тренутне вредности. Ово је подразумевана акција. | GL_KEEP | D3DSTENCILOP_KEEP |
Постављање на нулу | GL_ZERO | D3DSTENCILOP_ZERO |
Замена са референтном вредношћу | GL_REPLACE | D3DSTENCILOP_REPLACE |
Увећање, али само ако је вредност мања од максималне могуће | GL_INCR | D3DSTENCILOP_INCRSAT |
Увећање. Ако вредност премаши максималну могућу, постаје нула. | - | D3DSTENCILOP_INCR |
Умањење, али само ако је вредност различита од нуле | GL_DECR | D3DSTENCILOP_DECRSAT |
Умањење. Ако вредност треба да постане мања од нуле, постаје максимална могућа. |
- | D3DSTENCILOP_DECR |
Инвертовање на нивоу битова | GL_INVERT | D3DSTENCILOP_INVERT |
Следи шематски приказ стенсил пајплајна[6]:
Следи опис ознака које већ нису поменуте:
- Маска представља бројевну вредност којом се референтна вредност и вредност стенсил бафера за актуелни пиксел битовски конјугују пре него што ће бити подвргнути стенсил тесту.
- Маска за стенсил операције представља низ од три операције дефинисане за сваки од наведених случајева (стенсил тест није прошао, стенсил тест је прошао али дубински није, оба теста су прошла). Само једна од ове три операције ће бити извршена над стенсил вредношћу актуелног пиксела.
У OpenGL се стенсил функција, референтна вредност и маска, тим редом, дефинишу функцијом glStencilFunc. У Direct3D се свака од ових компоненти подешава појединачно, помоћу методе SetRenderState уређаја који се тренутно контролише. Ова метода очекује по два параметра, од којих је први стање које се подешава а други његова вредност. Редом који је коришћен горе, ова стања се зову D3DRS_STENCILFUNC, D3DRS_STENCILREF и D3DRS_STENCILMASK.[7]
Стенсил операције се у OpenGL подешавају функцијом glStencilOp која очекује три вредности у већ наведеном реду. Код Direct3D се, опет, свако стање посебно подешава методом SetRenderState. Три стања којима се могу доделити операције се зову D3DRS_STENCILFAIL, D3DRENDERSTATE_STENCILZFAIL и D3DRENDERSTATE_STENCILPASS.[7]
Примене
уредиИако је спектар примена стенсил бафера прилично широк, може се навести неколико познатијих примена.
Проблем дубинске борбе
уредиУслед недовољне прецизности дубинског бафера, копланарни полигони који се налазе на малим растојањима, или се преклапају, бивају приказивани као два објекта са мноштвом неправилних пресека. Ти пресеци могу да варирају у зависности од положаја камере и других параметара, и да се јако брзо мењају. Ово се зове дубинска борба (енгл. Z fighting). Решења која могу да дају одређене резултате су:
- Приближавање далеке равни за ограничавање сцене енгл. far clip plane, чиме се повећава прецизност дубинског бафера, али се смањује растојање на којем су објекти сцене видљиви.
- Повећање броја битова додељених дубинском баферу, што је могуће на уштрб меморије за стенсил бафер.
- Одмицање полигона, што би могло да се коси са захтевима обрађиване сцене.
Сви ови приступи проблему само смањују вероватноћу да ће до дубинске борбе доћи, и не гарантују дефинитивно решење у општем случају.
Решење које укључује стенсил бафер се заснива на знању који полигон треба испред којег да стоји. По овоме се силуета предњег полигона уцртава у стенсил бафер. Након тога се задњи полигон црта само тамо где силуета није уцртана, а остатак сцене може да се црта нормално.
Пример OpenGL имплементације
уредиПошто је ово уједно и најједноставнији пример, следи програмски кôд за OpenGL, који исцртава слику са доњег дела илустрације.
// ..
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.
Приликом овог пролаза се само чувају
већ постојеће вредности.
Исцртати белу површ.
Искључити стенсил тест.
Исцртати полигон са сликом.
|
Приликом закључавања и откључавања других бафера, коришћене су вредности 0 и 1 уместо, редом, константи GL_FALSE и GL_TRUE, зарад краћег записа.
Рефлексије
уредиРефлексија неке сцене се исцртава као њен одраз у односу на дату раван, коју одређује полигон на коме рефлексија треба да се осликава. Део овог проблема који се односи стенсил бафер је ограничавање приказа рефлектоване сцене само на тај полигон тј. постизање илузије да се одраз сцене само на њему одражава. Стенсил бафер то омогућава на следећи начин:
- Сцена се исцрта без површи које представљају огледала
- За свако огледало:
- Закључавају се дубински бафер и бафер за боју
- У стенсил бафер се уцрта видљив део огледала
- Дубински тест се подеси тако да за сваки прослеђени пиксел уписује максималну вредност и да увек пролази
- Исцртава се површина огледала
- Дубински тест се подеси тако да пролази само ако је удаљеност неког пиксела мања од тренутне (подразумевано понашање)
- Матрица трансформације се измени тако да рефлектује сцену у односу на раван огледала
- Откључавају се дубински бафер и бафер за боју
- Сцена се исцртава, али тако да се исцртава само њен део који се налази иза равни огледала, а видљив је на самом огледалу. За прво ограничење се додаје једна ограничавајућа раван (енгл. clip plane), а за друго ограничење се користи садржај стенсил бафера
- Опет се закључава бафер за боју, дубински тест се подешава тако да увек пролази, и пиксели огледала се бришу из стенсил бафера тако што се оно опет исцрта. Након овога је стенсил бафер опет чист и спреман за следеће огледало.
- За свако огледало:
Уместо полигона, може се радити и о површи коју чини више некопланарних полигона. У том случају, ова површ се разбија на полигоне и сваки од њих се посматра као посебно огледало. Такође, овај пример помиње само савршена огледала, јер то не утиче на општост проблема. Део сцене који је означен као огледало се пре, током и након исцртавања рефлексије може дорађивати сваким другим алатом.
Један даљи проблем је огледање једног огледала у другом. Исти овај поступак се може поновити за одразе свих оваквих огледала. Економично решење може бити да се одраз огледала у огледалу увек исцртава као нерефлективна површина.
Раванске сенке
уредиПриликом цртања раванских сенки, доминантна су два проблема:
- Први се односи на проблем дубинске борбе у случају да се раван геометријски не подели на део прекривен сенком и ван сенке. Видети одељак који се на ово односи.
- Други проблем се односи на простирање сенке ван простора на којем раван постоји.
Још један проблем, који може а не мора да наступи, у зависности од технике, је пројектовање више полигона на један део сенке, што резултује тамнијим и светлијим деловима једне исте сенке. Сва три проблема се могу решити геометријски, но због могућности да се хардверско убрзање директно употреби, далеко је елегантнија имплементација помоћу стенсил бафера:
- Омогућити осветљење и сва светла
- Исцртати сцену без полигона на које треба пројектовати сенке
- Исцртати све полигоне на које треба пројектовати сенке, али без светала. Притом, у стенсил баферу, треба пикселима сваког полигона доделити вредност специфичну за полигон коме припадају. Размак између ових вредности треба да буде најмање два, јер ће за сваку раван бити коришћене две вредности за два могућа стања: у сенци и осветљено.
- Онемогућити свако глобално осветљење (како би се осигурало да на следеће кораке утиче само појединачно одабрано светло)
- За сваку раван:
- За свако светло:
- Изменити само стенсил бафер и само за пикселе који носе вредност специфичну за одабрану раван. Увећавају се вредности свих пиксела на које се пројектују објекти између дате равни и датог светла.
- Омогућити само одабрано светло и за њега исцртати део равни на којем за њу специфична вредност није била мењана.
- За свако светло:
- За сваку раван:
Просторне сенке
уредиСтенсил бафер имплементација цртања просторних сенки представља сваку сенку геометријским телом, које својом запремином обухвата део сцене који се налази у њој. Уколико неки део сцене припада овој запремини, није осветљен датим светлом, у супротном јесте. Овај проблем се усложњава са порастом броја светала, али се не осврће на број површина на које сенке падају. Постоји више решења проблема, али сва следе следећи алгоритам:
- Нацртати сцену без икаквог осветљења
- Закључати дубински бафер и бафер за боју, тако да се на њима не могу вршити измене
- За свако светло
- Користећи дубинску информацију о сцени (дубински бафер), попунити стенсил бафер само на деловима сцене где запремине сенки не постоје или нису видљиве од постојећих објеката.
- Откључати бафер за боју, и подесити функцију дубинског бафера тако да дозволи измене само тамо где је дубинска вредност једнака већ постојећој
- Исцртати ову сцену осветљену само овим светлом, али само за делове сцене који пролазе стенсил тест
- За свако светло
Сваки од ових пролаза претпоставља да му на располагању стоји чисти стенсил бафер.
Како за сенке, ова техника се може користити и за осветљавање делова простора који се налазе под јаким светлом. На пример светлост рефлектора у тамној просторији са великим присуством прашине у ваздуху би видљиво осветљавала одговарајућу запремину простора.
Остале примене
уредиЈедан даљи пример су такозване меке сенке, код којих прелаз између осветљеног и осенченог дела сцене није оштар. Наиме, један начин да се овај ефекат постигне стенсил бафером јесте да се запремина сенке умножи, а да се њене копије редом скалирају по геометријском низу са малим увећањем, нпр. 1,04. Центар скалирања може да буде тежиште полигона који представља врх запремине. Ово ће само по себи дати низ композитних сенки које дају жељени ефекат.
Још једна примена обухвата поље визуелизације приликом моделирања техником конструктивне геометрије солида (енгл. Constructive Solid Geometry, CSG), где стенсил бафер, заједно са дубинским бафером, може успешно да решава проблеме Булових операција над солидима.
Види још
уредиРеференце
уреди- ^ Tom Miller. Managed DirectX 9. стр. 61. ISBN 0-672-32596-9.
- ^ Спецификација glStencilFunc Архивирано на сајту Wayback Machine (3. новембар 2008) (језик: енглески)
- ^ Спецификација D3DCMPFUNC (језик: енглески)
- ^ спецификација glStencilOp Архивирано на сајту Wayback Machine (2. новембар 2008) (језик: енглески)
- ^ Спецификација D3DSTENCILOP (језик: енглески)
- ^ Презентација о стенсил баферу, слајд 4 Архивирано на сајту Wayback Machine (7. јун 2008), документација на сајту NVIDIA-е (језик: енглески)
- ^ а б Спецификација равни стенсила, на MSDN (језик: енглески)
Литература
уреди- Побољшавање сенки и рефлексија помоћу стенсил бафера, Марк. Џ. Килгард, NVIDIA Корпорација;
Спољашње везе
уреди- Побољшавање сенки и рефлексија помоћу стенсил бафера, Марк. Џ. Килгард (језик: енглески)