350п|мини|Пример примене стенсил бафера. Горња половина слике приказује слагање провидне равни преко тродимензионог објекта, чиме се постиже ефекат затамњења. Доња половина слике приказује како се стенсил бафер може употребити за прављење рупе у тој равни — иста се исцртава свуда осим на месту квадрата из стенсил бафера. Другим речима, тај квадрат је одузет од провидне равни током њеног цртања преко објекта. мини|250п|Илустрација примене стенсил бафера примером из живота: два дела изрезане плочице се могу користити како да омогуће наношење боје унутар изрезане силуете, тако и ван ње. Стенсил бафер (, од -{Stencil}- што значи шаблон, шара, прошарица) је појам из области рачунарске графике. Означава бафер помоћу којег се сваком пикселу рачунарски исцртаване слике може доделити ознака у виду броја. Ово означавање се потом може користити за контролу начина на који ће појединачни пиксели бити исцртавани. Лаички речено, стенсил бафер је у рукама програмера алатка попут шаблон-лењира у рукама техничког цртача. Основна разлика је у томе што програмер овај шаблон може да обликује неограничен број пута и како год то погодује потребама исцртавања сцене. Прву хардверску имплементацију је представио Силикон Графикс, на манифестацији -{SIGGRAPH `88}-. Хардверска подршка за стенсил бафер данас постоји у оба интерфејса заступљена у индустрији рачунарских игара: у -{OpenGL}-, од прве верзије, и у -{Direct3D}-, од верзије 6.0.
Грађа и коришћење Стенсил бафер обично дели исти меморијски простор са дубинским бафером (), а обично је тај однос 24 бита за дубински + 8 бита за стенсил бафер или, раније чешће коришћено, 15 бита за дубински + 1 бит за стенсил бафер. Такође је присутна варијанта 24 + 4, где се од 32 бита 28 користи, а 4 игнорише. И стенсил и дубински бафер су део фрејм бафера (), заједно за бафером за боју (). Први чип доступан ширем тржишту, који је подржавао један бит за стенсил бафер, био је -{3Dlabs}--ов -{Permedia II}-.
Битови додељени стенсил баферу се могу користити за репрезентацију бројевних вредности у опсегу [0, 2-{n}--1], али и као -{n}- булових матрица (-{n}- је број додељених битова), од којих свака може да се користи за контролисање посебног дела сцене. Свака комбинација ова два начина коришћења расположиве меморије је такође могућа.
Стенсил тест Стенсил тест или стенсилинг () се међу операцијама над фрагментима () налази након алфа теста и пре дубинског теста. Овим распоредом се омогућује да одговарајући пиксели, чији би приказ стенсил тест ионако спречио, ни не стигну до дубинског теста. Тиме се штеди време обраде сцене. На сличан начин, алфа тест може спречити одговарајуће пикселе да стигну до стенсил теста.
Сам тест се изводи над стенсил бафером како би се нека вредност у њему или изменила или употребила, а спроводи се кроз тзв. стенсил функцију и стенсил операције. Стенсил функција представља функцију којом се стенсил вредност одређеног пиксела пореди са задатом референтном вредношћу. Уколико је ово поређење логички тачно, стенсил тест пролази. У супротном не. Могуће стенсил функције су:
Значење -{OpenGL}- ознакаСпецификација -{glStencilFunc}- -{Direct3D}- ознакаСпецификација -{D3DCMPFUNC}- Никад не пролази -{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}- ознакаспецификација -{glStencilOp}- -{Direct3D}- ознакаСпецификација -{D3DSTENCILOP}- Задржавање тренутне вредности. Ово је подразумевана акција. -{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}-
Следи шематски приказ стенсил пајплајнаПрезентација о стенсил баферу, слајд 4 , документација на сајту -{NVIDIA}--е :
центар|500п
Следи опис ознака које већ нису поменуте: Маска представља бројевну вредност којом се референтна вредност и вредност стенсил бафера за актуелни пиксел битовски конјугују пре него што ће бити подвргнути стенсил тесту. Маска за стенсил операције представља низ од три операције дефинисане за сваки од наведених случајева (стенсил тест није прошао, стенсил тест је прошао али дубински није, оба теста су прошла). Само једна од ове три операције ће бити извршена над стенсил вредношћу актуелног пиксела.
У -{OpenGL}- се стенсил функција, референтна вредност и маска, тим редом, дефинишу функцијом -{glStencilFunc}-. У -{Direct3D}- се свака од ових компоненти подешава појединачно, помоћу методе -{SetRenderState}- уређаја који се тренутно контролише. Ова метода очекује по два параметра, од којих је први стање које се подешава а други његова вредност. Редом који је коришћен горе, ова стања се зову -{D3DRS_STENCILFUNC}-, -{D3DRS_STENCILREF}- и -{D3DRS_STENCILMASK}-.Спецификација равни стенсила, на -{MSDN}-
Стенсил операције се у -{OpenGL}- подешавају функцијом -{glStencilOp}- која очекује три вредности у већ наведеном реду. Код -{Direct3D}- се, опет, свако стање посебно подешава методом -{SetRenderState}-. Три стања којима се могу доделити операције се зову -{D3DRS_STENCILFAIL}-, -{D3DRENDERSTATE_STENCILZFAIL}- и -{D3DRENDERSTATE_STENCILPASS}-.
Примене Иако је спектар примена стенсил бафера прилично широк, може се навести неколико познатијих примена.
Проблем дубинске борбе мини|200п|На горњој слици се полигон са сликом налази тик изнад беле површи, што није довољно да се спречи ефекат дубинске борбе. Насупрот томе, код стенсилинга (доња слика) овај ефекат бива потпуно одстрањен, чак и када су површи копланарне.
Услед недовољне прецизности дубинског бафера, копланарни полигони који се налазе на малим растојањима, или се преклапају, бивају приказивани као два објекта са мноштвом неправилних пресека. Ти пресеци могу да варирају у зависности од положаја камере и других параметара, и да се јако брзо мењају. Ово се зове дубинска борба (). Решења која могу да дају одређене резултате су: Приближавање далеке равни за ограничавање сцене , чиме се повећава прецизност дубинског бафера, али се смањује растојање на којем су објекти сцене видљиви. Повећање броја битова додељених дубинском баферу, што је могуће на уштрб меморије за стенсил бафер. Одмицање полигона, што би могло да се коси са захтевима обрађиване сцене. Сви ови приступи проблему само смањују вероватноћу да ће до дубинске борбе доћи, и не гарантују дефинитивно решење у општем случају.
Решење које укључује стенсил бафер се заснива на знању који полигон треба испред којег да стоји. По овоме се силуета предњег полигона уцртава у стенсил бафер. Након тога се задњи полигон црта само тамо где силуета није уцртана, а остатак сцене може да се црта нормално.
Пример -{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}-, зарад краћег записа.
Рефлексије
Рефлексија неке сцене се исцртава као њен одраз у односу на дату раван, коју одређује полигон на коме рефлексија треба да се осликава. Део овог проблема који се односи стенсил бафер је ограничавање приказа рефлектоване сцене само на тај полигон тј. постизање илузије да се одраз сцене само на њему одражава. Стенсил бафер то омогућава на следећи начин: Сцена се исцрта без површи које представљају огледала За свако огледало: Закључавају се дубински бафер и бафер за боју У стенсил бафер се уцрта видљив део огледала Дубински тест се подеси тако да за сваки прослеђени пиксел уписује максималну вредност и да увек пролази Исцртава се површина огледала Дубински тест се подеси тако да пролази само ако је удаљеност неког пиксела мања од тренутне (подразумевано понашање) Матрица трансформације се измени тако да рефлектује сцену у односу на раван огледала Откључавају се дубински бафер и бафер за боју Сцена се исцртава, али тако да се исцртава само њен део који се налази иза равни огледала, а видљив је на самом огледалу. За прво ограничење се додаје једна ограничавајућа раван (), а за друго ограничење се користи садржај стенсил бафера Опет се закључава бафер за боју, дубински тест се подешава тако да увек пролази, и пиксели огледала се бришу из стенсил бафера тако што се оно опет исцрта. Након овога је стенсил бафер опет чист и спреман за следеће огледало.
Уместо полигона, може се радити и о површи коју чини више некопланарних полигона. У том случају, ова површ се разбија на полигоне и сваки од њих се посматра као посебно огледало. Такође, овај пример помиње само савршена огледала, јер то не утиче на општост проблема. Део сцене који је означен као огледало се пре, током и након исцртавања рефлексије може дорађивати сваким другим алатом.
Један даљи проблем је огледање једног огледала у другом. Исти овај поступак се може поновити за одразе свих оваквих огледала. Економично решење може бити да се одраз огледала у огледалу увек исцртава као нерефлективна површина.
Раванске сенке
Приликом цртања раванских сенки, доминантна су два проблема: Први се односи на проблем дубинске борбе у случају да се раван геометријски не подели на део прекривен сенком и ван сенке. Видети одељак који се на ово односи. Други проблем се односи на простирање сенке ван простора на којем раван постоји. Још један проблем, који може а не мора да наступи, у зависности од технике, је пројектовање више полигона на један део сенке, што резултује тамнијим и светлијим деловима једне исте сенке. Сва три проблема се могу решити геометријски, но због могућности да се хардверско убрзање директно употреби, далеко је елегантнија имплементација помоћу стенсил бафера: