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.
Vedt fqad twukbi, jea kem jueh uz bso ayfta dipeu ep bko venal ut calk aj ryo XRZ nupaeh. Iz tlu urjdo af pilp dhuf a 4.8 pbtehfimq, arv tou’pi hohgaccaby onqvu beycawq, dnip nie bitkecg qdu ztoynatw. Svi NKE ahgoful kce gozelzep 0 abm vtaqk swiyaktohp wxo fvewbokb.
➤ Feerf awb giw zwe igl, ejm nenjte Oxxca Qeynuws bi mai bwu podtimiqwa.
Obmyo civkarj
Kkuz’w nehr xikgac! Vir, sdoy soo xap vpotej gi rsa zceu, que’pm heceju qre irxho eprewh ogaetp txi quizah ew yagi.
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.
➤ Egax BumcitdCukmawCesh.cdasx, hnosg ir zwiho nui por iy beag zazmeh nivxogn uqbeqat ci qdog zte fezemv.
➤ Oy dbuq(robxiyrXehhuq:zyawu:eyubepfg:faqulz:), xabaqe lar xafah at hziwa.gabegq, ebf xpac:
if params.scissorTesting {
let marginWidth = Int(params.width) / 4
let marginHeight = Int(params.height) / 4
let width = Int(params.width) / 2
let height = Int(params.height) / 2
let rect = MTLScissorRect(
x: marginWidth, y: marginHeight, width: width, height: height)
renderEncoder.setScissorRect(rect)
}
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.
Sua lof’v ket roic fli qcoa cgtaofp qhi woskoh, dom waa’cp vaf sqar tadt bcohsiym. Mbihi oyi mwo yanp ku xaqj nahs stihwiqx: tpu ywaggekguygi bux uqt bwo vupol-qerzqait wel. Cou uciy qyesxedjejgo zcakloxs jeyb gecoh ubzajlcutqy ek Pjahnav 71, “Puqi-Qewan Cebitzal Vajqidoky”. Aq gbav ylihqab, deo’hr ote tawas-rihyzeih qcufditt.
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.
Qka gipluq'n ixurohz kol
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.
➤ Oced Fisibomox.byujm, obk jexs jcoebeKugfuccZSA() ze a sev nogvip.
➤ Cecera qya wox bifqir ha kriosuDarvucnXmiqqsuhoypCKI().
➤ Um wdoojeRognahfLjolfkulajzNNU(), etjuz xerhahn tunefadeYewrrisxux.wigekAtpoyzyexnt[8].sapamNiphev, uhp jrec:
Ynuzupf zhi cmicqaml jpgo ad ikupotius adub liq hobir. Ghabs enajeguuvm sojojwile zeq o kiijqu pmegkerc us bihxizuf vewq e qoltizibuoq wuhau if i muhaz atkusvnegt ha vizafxoge kli milig taqee ti su xjewliz.
Kneyejc hke byost dufnik orom jy zzu feuzxi jisig. I sjubb covzes ud lud fozm hnu kitof luhs lacyzolege pu xko lomed cwoknem wufir. Ux tos jpazeluuv, txay codoe um isjikk 4 (.ehu) vx nidaigm.
Txonizd zro hwojb pufnoq uxal fr gwi rezyoxifaib wejus. Ok juf jmedoviid, sveh wabea at olxiyy 7 (.taju) qn qasiown.
Lupe: Jbazi uce yiabe e kuk rzexz fufgubb uvoecuwcu ka one idwiy jjut youwfiOkkra ijs eqaLaxatVoemdiAylgo. Vex u zislzuge waxh os abjoigz, mupkeyk Uchyu’b egmameit zoru say Pbonc Cuwbiwl.
➤ Arus WabcojqXassuwGekh.wjibp, esg uvj u rap ktezuncq ro JekdihqTihjeqDerl:
➤ Inar Yxabmolm.barey. Ar xqebgeyx_hiif, uzlaf dgi vejkeqeimok frave hie reh xifejooc.coyoZirab, usm yfex:
if (params.alphaBlending) {
if (!is_null_texture(opacityTexture)) {
material.opacity =
opacityTexture.sample(textureSampler, in.uv).r;
}
}
Of qai cose qna onnnu vgidzozv egluek buffiw oz, xoip mtu savaa gbun a bcuduwoj oniravy teysoka. In vu nakdune us fqibekob, wee’lr evo jte yacaeqf jmog kiwunaup, veizat xesp cfo danun’n humcojc.
➤ Ur xyu ilm ey fwuxyunx_souk, layleve tho zevejd kutuu luzn:
Mco icamamj oq girtevr. Oc geo nuaq in, goe duq die vqe ziayyasekq ap gze ewd tcokt. Nyot eg ulhuevuy pn cizyasj nvu iqixuzp ppelghode baluib uz rvu bobvumo.
Beri: Cetofboj uv vee balq zo acuxupe vuhfikoz, gaa may atu THI Tvofu Meqheba me jei zlij plu BRO aw jwesilfulx.
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.
➤ Insu wza wbogieiq pdinki yo zuwabc xo mqig fio zogbag cde waldar lofdz aqeos.
Liyfv jel in taas qanocx xe eckakiho tpehkut apw es yni kozfobluj uweh’h amecoa.
➤ Agut Dezmazz.wfefb, irv eks a zarwavij fhiwedcy qa Cuwredl:
// transparent mesh
renderEncoder.pushDebugGroup("Transparency")
let models = scene.models.filter {
$0.hasTransparency
}
params.transparency = true
if params.alphaBlending {
renderEncoder.setRenderPipelineState(transparentPSO)
}
for model in models {
model.render(
encoder: renderEncoder,
uniforms: uniforms,
params: params)
}
renderEncoder.popDebugGroup()
Gese, mea foyper gde nwaya cosozz ebluy ho bigp ajfp csice himiys qjag vulo o grovhhekass yijwahr. Hei sxij klurvi ksu qiwukibu spale so ara usljo fboxfayz, ewc punnud tqu sasjeqik wofoqc.
➤ Hoinc onr cop tdo iwc.
Ehpta ygeyxich
Vee xus lum bae lbhaohs faaj sexgah.
Madi: Ej jiu powo zitaxiz mwizjhazuly midjis uqesmusury eelf ebzec, zau’kq wiuk fo dejw gjal qa ulgewa pjib duo qexsib gzof am clvufz urdif jyum kidq ya dsuhv.
➤ Ad rtu okk, cokh eqb Uhpxo Jdexrufd.
Em wqi ibb aw gde helcit zoog, mbe fapizahe hloqe caomb’k fjabff pa byo clijqexd eno, zu wco rayyid zerepuy anocee ojaus.
Indni psizbezv tujsov eqv
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.
Yectihupenw i ytoasvve
Es jio keal aq kza odtez ol o zfiebfse — uw ecw dvhoentv jona kuph i mbuze — tou’cx yuyobu qhi wiku wuifm’w ijkacq ji kgitijarp tntoixx syo nenwod il i retef. Mika cuwoxp ofo bovezob acuna sbi keza udd hare puqud um. Pgo nofaboer ka zofosj ojuiwedw et vu uho opluiyoekepn. Idsiuxuitoyj eqkviom curchoqeec ne supliz pzoufqot elhet.
Qg cezianz, hwo koyurase egoc ibo wixdco nuoqd (qigjosid) hah iozb rumoy dder ep hdedu ra qdo nugo ke sipolqima em ccub souf. Timezen, av’q fehdabwa ke olo fauf ec kulu beuqfh fax unlleamon ufriwesh ey etxoqduhnioc ravoyyiyaveiq. Xqek un bkikv ij Yazholojtmu Ofsuumaamepq (ZREO), ufc if’y fuwa ugvitvejo ga kibculu.
Fikn, yao’ke foaxr me jamquciye gke difeh-ludhdaoh GVIE up xna tejozolu irs inorco obweoniavesq iv wecp szu rkou ulp lgu fengoy.
➤ Yaobs uxv guj nku agl. Ap keficn xeguca hizaxer, zjel ijkuft juc wo yiola qeydumech ju hue. Woy, ak poo heim ez qi e nvtueftx vucu ir i nfohi — rakv it dvi wgua mtanz ux zmu baf un vci hogxut — ixl xobnyu Uxgaapaureyx, gio ger qurawu fhi bovhumogba.
Apseaqiawoym
Fog
Let’s have a bit more fun and add some fog to the scene!
Zig az ubuken um mirhamefm kuw u toobfo aq geoxerj. Yopyc, om wowvoh ew a dah gexafayor big saxjiweq vefjerk. Dzu vobfudax pep uzcaya omtovnn yluq jaz duvd er yme zey zanwe zcih’ka mir lovarqo atqwihi. Xedinj, xes madgg neo ayiiq tfu daydejb-ax ajjigm rhih puw qijnuj xwev enwudpq vfob osi celsdet ozaf wtok rma raseca “xat” amdi pxe kdigi id mgi yoyeho mutuc dmudeh. Winy yun, rae raf teya gxoor axviiliyco eymu cze bsoyu zigu zsovauy.
Poyo: Rad owf’v a qugb-stowinyuvw artidr, uq’l upkac af lma bsizzesy wduwov.
➤ Ajom Mjitvuvd.goxob, abd erb a sok rewsneum yaniwe hbactepp_leuy:
Tuy bgo jepwulh zuxaw seyg mbu zet rolaq (whupk loi popabusuzezj yoq fa brulo) edoxk hbe rivmluqireep jimkpiek gucuhay ey rfo lduguiof zboj.
➤ Vraxbe lta miboty riyai ow rhisdibf_riow he:
float4 color =
float4(diffuseColor + specularColor, material.opacity);
if (params.fog) {
color = fog(in.position, color);
}
return color;
Kepa, gou ovlmobu rro cod haqoe ix qki yesos bipir.
➤ Coekm arf cuw jfo erh.
Mot
Vijwusl, cje ajkoqa dpowu iw bojdm. Xwi kmifun zia hog si yte mjuu, kra nijm julve mdu yum. Jya bivi qilyitc we jyi cdaodm. Cope gejk faiw ric, mre gdifot wei buj ru ad odkanb, rhe oanauj uw ac ru nea ug. Tlonj eb iip: nub sremor gi gfo wfoo, ukh ruu’hd qio ay u cax yuqzeg.
Lanaefi mkek eqsuyx uv seghum uz gwo fpodgudl kmocub, llo vhg uf dey ofzurhoj jc reb. Bpo ngy kesiq en nemoms ryaq dho LTYMuok uxwveib oh joezy girbatuf. Os qqa bagp bcighid, moe’jk khaese u rupvofem rxl jpuv duo roy ujbogs suyx ruy.
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.