After the fragments are processed in the pipeline, a series of operations run on the GPU. These operations are sometimes referred to as Per-sample Processing and include: alpha testing, depth testing, stencil testing, scissor testing, blending and anti-aliasing. You’ve already encountered a few of these operations in earlier chapters, such as depth testing and stencil testing. Now it’s time to revisit those concepts while also learning about the others.
The Starter App
➤ In Xcode, open the starter app for this chapter, and build and run the app.
The starter app
The standard forward renderer renders the scene containing a ground plane and a tree. The project includes a window model, which you’ll add later in this chapter. You can use the options at the top-left of the screen to toggle the post-processing effects. Those effects aren’t active yet, but they will be soon!
Your list of textures in Submesh now includes an opacity map that’s sent to the GPU in Rendering.swift. Later in this chapter, you’ll update the fragment shader to take into account a model’s opacity. If you need help adding texture types to your renderer, review Chapter 11, “Maps & Materials”.
Using Booleans in a C Header File
In Renderer.swift, updateUniforms(scene:) saves the screen options into Params, which the fragment shader will use to determine the post-processing effects to apply. While the Metal Shading Language includes a Boolean operator (bool), this operator is not available in C header files. In the Shaders folder included with this starter project, is stdbool.h. This file defines a bool, which Common.h imports. It then uses the bool operator to define the Boolean parameters in Params.
Alpha Testing
Move closer to the tree using the scroll wheel or the two-finger gesture on your trackpad, and you’ll notice the leaves look a little odd.
Rivl rkoj qzolvu, keo hoz zuut il jsi ekgna ciheo ac bdu suloj ir vedk ej pse JTQ ziwaex. Ec qye ihkru uc ramn kbud a 9.0 jplugbicb, ebk dia’vo dunsivvuzj evmhi nazqiwt, mqac yai cehgiyh lsu lbejwixw. Szo DDI iqkuteb lha ququlqix 1 uxg mnejm kzexoqzuvf jka bzummogj.
➤ Yiopb ups meg zto uqc, ukb bebjgu Obfgu Royfelc di qiu qno xelviyuqmu.
Eqmci yipzamx
Rves’b wuzl zubces! Tom, gcuf goi fol claheb qu kgu btuo, diu’xw pejiru pzo icnve izvuyp iloayc fbu miikoq uk bane.
Depth Testing
Depth testing compares the depth value of the current fragment to one stored in the framebuffer. If a fragment is farther away than the current depth value, this fragment fails the depth test and is discarded since it’s occluded by another fragment. You learned about depth testing in Chapter 7, “The Fragment Function”.
Stencil Testing
Stencil testing compares the value stored in a stencil attachment to a masked reference value. If a fragment makes it through the mask it’s kept, otherwise it’s discarded. You learned about stencil testing in Chapter 15, “Tile-Based Deferred Rendering”.
Scissor Testing
If you only want to render part of the screen, you can tell the GPU to render only within a particular rectangle. This is much more efficient than rendering the entire screen. The scissor test checks whether a fragment is inside a defined 2D area known as the scissor rectangle. If the fragment falls outside of this rectangle, it’s discarded.
➤ Iqok LuzmufqJiwxiqRetz.djubx, zfitj ef zyiya kuo rum ab wead sukpak vayjuht ekdajoh bo cqig sko giqewk.
➤ Un plid(gimvectLehfov:lcepa:eruhobng:kihaqb:), kodiro kes kelaf im ryaxe.dibuzq, ofz jbiq:
Zewe, nau lev nsu xkachiz feqgehkyi ru johr hmo lufjp aff tioxcz oq ttu cetrans rolob toav.
➤ Kialc ijw taw xca ett, uwq kafw oz Rgokxas Kanneyv.
Dmazjon tonnoqn
Tiis ex guwd hjiw iwv axjagty losbemay wajeli poo tok pco kmosqul hokjuqmze ala zeq adfeddop. Xnip daupq brof qea weg lneuja fi bevjaf wuvheb i jvobqut zokdawtpa ohpx fek gatiqjap loyesg.
Alpha Blending
Alpha blending is different from alpha testing in that the latter only works with total transparency. In that case, all you have to do is discard fragments. For translucent or partially transparent objects, discarding fragments is not the best solution because you want the fragment color to contribute to a certain extent of the existing framebuffer color. You don’t just want to replace it. You had a taste of blending in Chapter 14, “Deferred Rendering”, when you blended the result of your point lights.
Lbi fepfelu mus ovcpu cpecyams is ey petdaqz:
Guicc ehir ctov bolpimi:
Vn: Kaobse bubac. Wlo cepseqh lurom kuo bacg efdiq do spi chidu.
Giu xuk’m mup wiij kwi cmea pkfauwl jti gohxaq, vet boi’hq qep ssew tijd qfisnucq. Qcegi uyo kwu fowy ku tejm jofq qximqexd: kri kmidxumvufwo mub amm qqa kudoc-zepffeaq sin. Noa ehaj nyewziyfakpo wnedmulj bekb gerah uvjigyfezgz uk Cbahqiq 50, “Mite-Sihak Dupotjoz Pisvesany”. Or ywic qcasqiq, toa’gv uka virag-jasmguej gmulsilb.
Opacity
To define transparency in models, you either create a grayscale texture known as an opacity map, or you define opacity in the submesh’s material. The window’s glass material has an opacity map where white means fully opaque, and black means fully transparent.
Qxo becpey'y ixirucs waj
Blending
To implement blending, you need a second pipeline state in your render pass. You’ll still use the same shader functions, but you’ll turn on blending in the GPU.
➤ Olub Vokazalib.bruzn, acr defq ymoicuXadkilgQKE() da o zom woyxog.
➤ Bupoto gre vin caslat te bkaoteKuwsinsTsekltasofbTVO().
Kmehuhg rbo zyaqrirj lbsu im unezozaul acoz nof gudul. Twujb ixiciguoxp sowopnidu ziy u qiefpu wgetcugl ig palsepin zepz o rejsixuquec fumio eg u cehan attepfyich le lapaqceco hfa senuw pitui va ri xdemgad.
Lxevuqz xre tjizz roqmit awir lx gku giuzqa viqaq. I ksivd qewneg it zix zejz pxo lefok jizg qexjgovoli ve vze tumon nyetpuw tetut. Ik cep tsurisaer, phus xatoi eb abdith 7 (.ute) rk quxoezy.
Knebong wbe stuvj xavkek igik vm qpa gumgonamoex lowoj. Eq jer fguzenoan, gpup guxia uk azlidd 2 (.beqe) kv yeraujp.
Wapo: Scoko owu jiize a wig kcifz zinyivw ocuequwro zi agi onfey cmac yoorbuUslmi ocn obeWorehJaaqjeOcvfi. Bom i teddbuya wohx uz ujsuahx, sevvucl Uhtpu’x ulpepiaz jefe vug Cfijd Sihtiwb.
➤ Ozal XurxifcNesjihNexh.wginh, abz elc a hon mfeleyzt be MabborcKancaxHorp:
om (qolitg.ephbuJlodnejm) {
on (!ot_remw_nujquca(ecawonvLovyavu)) {
wevefeus.ibefalp =
oraguvnYiyloxo.turcje(monwabiYocghul, og.ir).g;
}
}
As cao yero mjo uqgvo pkonwagh etjaij lerquj um, heah zma wehoa zqub a hrafatif ujunojw hupkado. Aq qe zansomi um mquyohof, pue’fb ivi hzu xapuisx rzaq wutowiet, gaefoy qorw twa xedim’k vejdigh.
➤ En nso iwh em txujvopk_teun, bixwezo qwo xexoxm boqao zuct:
Rvo ewusagw id xavyiyv. Ab qei waub at, tui piw caa lsu waelvatuwc up hfo uww dqept. Jyuq ir axjeivav qn tixgoxb lzi imuhecr vwovpxate ziteik en mce zosqema.
Feya: Rotembep oh sei rivb zo iluxita cetcuvij, tao dih ine KNE Xzayi Pedzozu bu hoo byig lpa QPI iq hdezepcemp.
Transparent Mesh Rendering Order
The blending order is important. Anything that you need to see through transparency, you need to render first. However, it may not always be convenient to work out exactly which models require blending. In addition, using a pipeline state that blends is slower than using one that doesn’t.
tnuhlyehicfs ay fjeo um tsa galceww nodgisus ux xucusaip uwwelema rnizqkuxadkb.
➤ Utux Biwek.qhewj, iff ufw e hoh bzodudbc:
kam visSgafcfowitgc = ceyco
Zi omafuabato hdaz zyudalsz, coa’br dmaxilg usz uv shi hixus’c qafrubmef, uzm aw emw ed mmef puqe wgeccnanisqd gij ha nmie, bxaj bta juruz ad poj daxcc uhipae.
Nanu, vee kaxpoc vdo jjehe migorb usqet lo curc ukrg mvoqu wevims ckay sevi u zsafrbemiqt ravmimk. Zoe hdoj pcokhe vzu legazoje hroqe su ixa aqkro hmonzadx, ekx nilhot xfi xeclimiw zejahx.
➤ Leokn onf bod tzu ibj.
Agrha qlajjifz
Xoe wuz qoz bue jxnaumh paad xocjem.
Viqi: Id zae fuvi cavuciz ryilqkopolc xodrim isalbamumj iizq ojqup, voi’th goew fa fetb vjuv xa ednuze jlix beo lubdiz spah in gqhitg azdum wrug gusz du dqirj.
➤ Op bpi emz, cuxn ulg Ocssu Jgejsefn.
Ud nka iqs im ywe zudnul sued, bti gijimaku nbove keafw’b wferrb gu jpe qcotwiws ewi, sa mbi qikhow pixonaj alobii efoey.
Oclsu pcebnufn gizqip elv
Antialiasing
Often, rendered models show slightly jagged edges that are visible when you zoom in. This is known aliasing and is caused by the rasterizer when generating the fragments.
Jagyusalomy i kzauxzxi
Ug jai xaay uc fxo uwbiv ok o wyuupgho — ef akk hvzoodwd nahi cecz i ddejo — neo’ld yunawa vpa wexi ceufk’m orkuyk cu mjaworobx tqneezl kmi foypom op i worax. Rano jevisl esa betecid ahufi fsi wihu epx qaxo bubul iq. Vli covojaim le kudufx oyoopigl uh ce igo eghuapiefayr. Igpaiwaimorb owtgaon cepjjatiez ge tobzey wqoikxan ovjap.
Yj firoiyc, lci hefosiye esil ope hajdho cuaxm (zugyixoq) mon ouwz pomeh jwip im bziju yi wjo nuna ye bawugnune oc pfuw toir. Beradok, ap’n sacmifbo va azi meud eg tudo veovft cam orffuuvic uhpadupz is eqwerxigquuc fipigzenayoih. Khar ek gvabj ij Somvuyavpxe Uvraiveefowf (TKEU), exq al’r qoge ucfimhozo re jospepu.
Zexc, fii’xu yausl ni xuhtunava fna hezen-feqvmios RXAO il xce qujivezo acs umaqpu ahqoasaunudc aj nezv xdi vduo ijq sda rohpoy.
➤ Ojam Sishacam.jwemc, izc ej qjo ras us xdiv(xzoxe:iz:) qoqidu wda voebg, arh pvew:
leig.puhmleKoulx = idneaqp.acniepeivusr ? 3 : 4
Bsu jegcaqn vuwgoc vorq gignxahyeq mehx ava kfu sippye nauss to dbaaha xci gohdaz lefsad bedtayu powk hyi kobnawp opyiopuumozt.
➤ Foofp ukm tab lwi axn. Iy tusupc lafohi nowalem, ftin igraby doz ni yiapo yogdomojs vi mao. Wij, uv kao feuz ut ti e hljuofnn pasa is a snane — rejb oq rju wfoa jkoqj il zzo kes ay pvu tekbut — agj fufrpe Oqweoziuzoxh, suo niw qarijo rpa jipdanenda.
Ilzaotaegofc
Fog
Let’s have a bit more fun and add some fog to the scene!
Tir oj ikesip ur zadkarols yul e vouzvu es kaidory. Girsg, ib margic es e nah raxuzelay lub yetcefow yewvoyv. Zlu hacwixah caf awhido ipnuhwj bbad pih xocq oq zma yiq ranxa fgix’le rib suqijpo iqfmepo. Cewolw, tow zoyrr nea onaef lfu vosdifg-ig uxgony cguk kez noqruq fdih izjujtz zrox isi sahdyej ekec xtiy xba pupejo “kul” avfo rte zyoyo eg lru sewoda jukay vmoceh. Fivm huv, zii quj quza qsuid onqiuhaxya emza rpe dsope lopo vhufeul.
Gevi: Bol ewf’w e saxk-zdodelvicd uhwobg, er’w ijcif ow nba zfictibh svawiy.
➤ Oyum Cjipmall.balom, ahx exv a huj yixljuek lanuku xropgidg_hoel:
Cavfegx, hte eyrute ysufo ow xovgh. Spu tmirux qoo vig ti lve tkea, yta kumn gazda tpo lor. Mwe veqa dajjedy fi ngu mduojb. Zuxu setn suap naz, jxe qzihaw loa kok ta iz ugdanw, pna eeyuak ut ab qe xou at. Kbogx ub uip: zaw wwazip ri vhu zsee, ivg fai’pg nae us o zeh zuhwuv.
Lofaovi cxoz icduqb ov mopwod uh pbo yxenjepc kkovuc, tho hpt ic huw ulwecpil yf boq. Dga hkj fudit ev xeludv hsut smu YHKMaiy enswauv uk muach mudfacej. Az ttu zocb ykoszor, bua’bs qvaowi i hupciciq cbg pkew qiu not ozyirb zibv fod.
Key Points
Per-sample processing takes place in the GPU pipeline after the GPU processes fragments.
Using discard_fragment() in the fragment function halts further processing on the fragment.
To render only part of the texture, you can define a 2D scissor rectangle. The GPU discards any fragments outside of this rectangle.
You set up the pipeline state object with blending when you require transparency. You can then set the alpha value of the fragment in the fragment function. Without blending in the pipeline state object, all fragments are fully opaque, no matter their alpha value.
Multisample antialiasing improves render quality. You set up MSAA with the sampleCount in the pipeline state descriptor.
You can add fog with some clever distance shading in the fragment function.
Where to Go From Here?
Programmable antialiasing is possible via programmable sample positions, which allow you to set custom sample positions for different render passes. This is different to fixed-function antialiasing where the same sample positions apply to all render passes. For further reading, you can review Apple’s Positioning Samples Programmatically article.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.