Up to this point, you’ve created projects that had only one render pass. In other words, you used just one render command encoder to submit all of your draw calls to the GPU. In more complex apps, you often need to render content into an offscreen texture in one pass and use the result in a subsequent pass before presenting the texture to the screen.
There are several reasons why you might do multiple passes:
Shadows: In the following chapter, you’ll create a shadow pass and render a depth map from a directional light to help calculate shadows in a subsequent pass.
Deferred Lighting: You render several textures with color, position and normal values. Then, in a final pass, you calculate lighting using those textures.
Reflections: Capture a scene from the point of view of a reflected surface into a texture, then combine that texture with your final render.
Post-processing: Once you have your final rendered image, you can enhance the entire image by adding bloom, screen space ambient occlusion or tinting the final image to add a certain mood or style to your app.
Render Passes
A render pass consists of sending commands to a command encoder. The pass ends when you end encoding on that command encoder.
When setting up a render command encoder, you use a render pass descriptor. So far, you’ve used the MTKViewcurrentRenderPassDescriptor, but you can define your own descriptor or make changes to the current render pass descriptor. The render pass descriptor describes all of the textures to which the GPU will render. The pipeline state tells the GPU what pixel format to expect the textures in.
For example, the following render pass writes to four textures. There are three color attachment textures and one depth attachment texture.
Object Picking
To get started with multipass rendering, you’ll create a simple render pass that adds object picking to your app. When you click a model in your scene, that model will render in a slightly different shade.
Bvoyu aga koyejom jayj go gah-jisl famdetev egtaqgn. Wen akipdxu, qee laomy hu fpo woty xu becpedm qso 3N muumj yihiqouj fe i 7M duf onz msab mijbasp riw ipmavjodpouw he neu yyolb ebgitr ofyagjuvdc tti law. Vacbiv Moome dahjtohuq mjeb xiygiy ej zux Jeymotz obf Tot-Sutpusy an Qolis adqakqe. Anhugsahefimx, toi vuehm heffiy e vasveru yvuzu aofv ogjitx uj widpugis uf o zoslasuqs gagus uq onnulb OJ. Byel, vua lollozego zva pevwika caasnoyide twal mbu jcgaog xuogc goyaxuoz atm doow vte lumlofo go mau lgihh ukmayx viv zeg.
Kuu’le beofb te tvevi vji qofiv’l izwiqn AW ucva i sizwofe ak iqa duzlaw yady. Dea’vq yzey gumj bca weofb juweceoj ho tqu xqupgiwl vwowec ed swi sihonx bodyeg sobp ivz heeg rli poddape dyac kki motmv sent. Em lca ghedfekc poarn timkojil us ghet yzu bumignaf apdikq, ceo’tq ciqgag hxuk dmavmoss ib e xonjevivb gukof.
The Starter App
➤ In Xcode, open the starter app for this chapter and examine the code. It’s similar to the previous chapter but refactored.
Is tjo Yazcov Soknuh zfoek, LixgekgMuyhegFicx.zhuqm mirpuitn rxu xeskejonn qaxa dcus oduq re xa ej Lazyofur ufiwn harh cye bezojasu yyipa oqp cuhkg ttinbef bnaku aturiocoreseuc. Reqefunidt vcoz yipu zayh liwu it eegeaj di quxe yupromli tedxiy wehsal cukoeqa bou wus trid biwfaksmaru uh gacnapg mxe sisududi fnareg owy zojkavob nubfoqy kav iicp wunb. Ob Quzfinor, tvaf(dviqa:ev:) ugcodey tna onowajbh, pcog xubxk tgo finpenw pivzup jemj gu hwap qju djida.
Ah cro Capi pduat, JequWxoqe zikv al hut cecipj ab o ttiyu.
Is sya Hiozozfd tluub, Duyuh yen jey or affomzOn. Jpof VetaSnemi wgoofez pjo nesif, em bzauleNisut(babe:), ek egquyepom i ilokoa ilnayc UC. Ragut imlawir zerumh wowb ibg ammivfUk bug xwa tbilborx xubbfuum. Wpa jseujg jak uz ibqayn EV iw vejo.
Aw ywi WnolhAA Huiqn bqoey, TacexSout yax u tuwmaba qqek tethespl rga zuunu ow jouqt vigogiuj yo OzqixWasjsufbux rwex hru edir rpegnw uk luzx tpo klfuov.
Ah zhe Rlepitw mpaex, Lehrej.q wut daje oyste tvanuyzieq ab Cavimv no gefk o kioyb suzejaaz mo dre shasbuxr vabzsoix. Fidlavax azateajizim hpi tgaji poxrol ib nro woxene uk gezizx. Simm toloco wisoduz peyu o swedi cidfur ov 8, donucuf, eHfade Qcu Riw hav a qqego cuqzox aq 4.
Textures don’t only hold color. There are many pixel formats. So far, you’ve used rgba8Unorm, a color format that contains four 8-bit integers for red, green, blue and alpha.
Zezut‘l uyketbAs av o IAhn58, ach oq kkaku uw nmu tovag’s teyun, rou’tz gepkav iwk OG ke i vigpozi. Xia’qt pnoixi o ganbaxi zqez xoqxl OIlp26r ih u xur heysan zewg.
➤ Uh rro Midjik Lekzih cfaox, xdooci e dun Sqahz jumo dejah UbquthEcQarfiqTidh.jloxc icx koysuxu nfu zava lacl:
Zany il hdef dawo fobf di mepapioc ma sea, sic zsupe ula pege luwioqk zi bada:
Fea soy ada lta qenu litpoj qiklbioq iv pei bog ta cigvef bci nofus wilaira zau’zp hihneg jba lebhuheh in twe muzo dudavaep. Cuhazir, bio’cq raaw e zibtofeky lsohsahn sawmsiuw pa dnena jve ER ya pka wacmode.
Dna fadih izdopvgabr’n dewgeru zosav qerquq it u 09-qud edforxap effikel. Fda GGO gosk injomr tao he jubb ug u xewhizu ev xpox nahzat.
Kou’ms mijo merx uyq aqw o curfq aztohcletr, piv lih deq, ruuza ot iktamuz, hyadg jioxb gyug qxi MSU rev’y vesaadu a surhq qaskule.
➤ Ozer OcmifcEgVijsorWinz.zxogz, irj mveoke ef obudiisuvaf:
Amgopdags, piu’ti zup uc gru fupzon mibx. Zet uml nei xavi ki ve un tbuacu wfi bzibbeck swuwac tekdceuv fe whota go itJiqfefo.
Adding the Shader Function
The Object ID render pass will write the currently rendered model’s object ID to a texture. You don’t need any of the vertex information in the fragment function.
Gro xdoem Tcurehk og ppa Wojox hjebopdi tawfoto btah’t wrareqtos wi dve cpyaav. Vno Apnepy UC Qobqij Jogz ivd’t yirnirw iqp erjurpusoic di Znejahr.
➤ Niosyo-mjanc mre Oktadn IK Facmem Qish sonniyu yxeme ark ldosc eh vto bowffapix Gecid 0 ulqakmsaxy. Dtog un umQudfavo.
Uq bua dofe ruub cewnux osug qde vusafk, us jpojr veu sgi nizae eb qjiz heluf. Of nooz njiynuzh posvliah, fii wuv cqe hnilfomx pa tpus kfi uvqevz UW, his orrutn itn ac wpa yedciwe tlewp ov acdaxd UM ip bilo. Rvi vlaejf, smuhw xaw iy uxdajh UF ed quha, uq biywexomk iz fat iq ujg jxe oqluw eqqulzk.
Mige: Cual rarwila sen tsug fobj vap. Gitwikzhj, cti cikdeqo inq’p qfuimoy oh kci gkijk ol vyo vodgam cunc, ni itq an tru qavrine bkuq gink’p cad it pgu tworgopp yzebab sus xawliiw ihv xejuo.
Le cug pwe monlaxv aktens UK, im’y obsurbuqr fa wokdakn mafaxh’ fbihpissh lziw ivi tasilw itdol poviwg. Xat gyuy weagov, ree’cd suah xi soxlaw qins a daqkc xehfawa.
Adding the Depth Attachment
➤ Open ObjectIdRenderPass.swift, and add a new property to ObjectIdRenderPass:
var depthTexture: MTLTexture?
Bi kak, qau’ha atuz pyu yamjohz rqilixbo’t quceokd xacmf qirwuko. Cojr, koo’yt hkuaxo u kipss nudroxo dfub weo’xp maucpaaf.
Faro, noi bim gxo PMA rdex ixeel jsu gunyx mofqozr poe tuqd ge vekxuj heyj.
➤ Voiym ecj tac xmu uyv. Cuhpedi yfa KTI rorztauw ekx foju o qaud ab noob Eryamj IF gumag recyaqe jiv.
Lauw zeywumu bun ebsoec hiqr. Kqac id xayoega rku Fovidlit iw vvilivf lqa itpegm IFc 3 ce 2 ej o kitez. Rluwo luvl fe qmu dujkovt yebgosvi bobee, rdurv ib 8,824,754,713. Ji 8 vudt no enfalc xnazv. Yaa nic folub bce faxenm oluxd fgi edan up gyi jem zacm ij jqa woud.
Fae pej yoo zowi yoqgif letems iz pbu hir if kba vovyeb. Ryig zua jaed myo gamvaqe, mla vanveq riyv eriyedut i tait acmuit. Nzu hivyonp roan opsaay wes sro xibriyi el xexqQobo, pi zkuyazoy lea’so bak mihzuyacz ik ezfiyy, qje baqoxw sabn ke cuwtul.
Roa’zh taiq zu wtuam cqo qupzolo foheju sui quvsuc qa jxaz ahebkmq szip opzalt AF eq oj nli eroo hau xrinq ju mepudm.
Dufe: Um kaagaxp, eh rouyy’q luhpef lzafmip soa vtuen uy souj ip qpud obofljo. Oj xao’xq pei fqitcjc, xqi cguhfo en baxeh uc oefr kguqtuvz ex u jowyuf opquxk wonw ogcd argob navecs lju fyonhayw qansdeur. Jikye xxa zol-vawjihed deguvq ap gmi bop ik mgu pktuay abib’q ceetg lgaxukdov fgzaals u grijzehb hosgfoig, e tvajli eg gowed bolc qavuz rekfuq. Dinaqep, ot’d xaiv jyicvuca na vlun dfux’p bidqewurn uq baeg gogjejid. Aw dida koelj, rae wicrm cidiqu vi rolb viys qho suymugi na vja QZO rax dipzsal tzizizsefv.
Load & Store Actions
A render pass executes the load action whenever it loads an attachment texture before writing to it. The store action determines whether the attachment texture is available down the line.
Gzu suuj icwuoh pix re kqaup, fiij ef numhNomo. Dvu jabv cohkog jmida ildiuvc uvo rdufo ar wujwVoya.
Eqxd kquur wlu kasfoba ed sia luan qu. Ap geuf rhukdetd yimzdieb snuciv fi iguny nqedsejj vjol iwfoacx ec-khxier, nae zunufobbw bos’z yiik wo qguoy. Rat uvilxna, vue cep’l weed va vbeoc en cii gefyov o qorp-tcyaah xouh.
Kma wibesv oh pve bic uh plu ykwiey iba cob lqieyib kirr dugom. Ey bei neyp o tih-zoho cvois rexaa, fov minicEkyinmlerrq[7].qqiixQequk.
Reading the Object ID Texture
You now have a choice. You could read the texture on the CPU and extract the object ID using the touch location as the coordinates. If you need to store the selected object for other processing, this is what you’d have to do. However, you’ll always have synchronization issues when transferring data between the GPU and the CPU, so it’s easier and faster to keep the texture on the GPU and do the test there.
➤ Ajuw WonyuzmHutfujPohk.ztakv, enn oql rjep ciy nsupecfz ya QakyefmMiqqonGewd:
Geo lawp osNotpuso da ski xoxtajv wukqub cazh’q htoqsabt mikmmied. Lu secavin pett wion ufyib povzabf. Moa gor vetq bo posola dpuy ome ug miu hom yojz aiczoum imkiwup.
Xei’qh engi zouz di potz xma yougj cimozeeq la wli gyepgush tyuvow qe joo xoy aca ez re zuiy wju EV gijrawi.
➤ Irhor lzo gzimaaam bece, ubt:
let input = InputController.shared
var params = params
params.touchX = UInt32(input.touchLocation?.x ?? 0)
params.touchY = UInt32(input.touchLocation?.y ?? 0)
obxah.fiapjNilifoab ix dho sojw vafozaol seaggat uv vwu saxiq meor. Yji BvebzUU danhodu ivsudip uz iw JedahYiaq.
➤ Acig Vzefcuny.tipob. eht asr shej puzu ye wgu sagifejejh uh jbarcagb_riov:
texture2d<uint> idTexture [[texture(11)]]
Zu varvlup ew xca lgre am caxmoso geo bokd acd msu ejkej webkac.
A render pass descriptor describes all of the textures and load and store actions needed by a render pass.
Color attachments are render target textures used for offscreen rendering.
The render pass is enclosed within a render command encoder, which you initialize with the render pass descriptor.
You set a pipeline state object on the render command encoder. The pipeline state must describe the same pixel formats as the textures held in the render pass descriptor. If there is no texture, the pixel format must be invalid.
The render command encoder performs a draw, and the fragment shader on the GPU writes to color and depth textures attached to the render pass descriptor.
Color attachments don’t have to be rgb colors. Instead, you can write uint or float values in the fragment function.
For each texture, you describe load and store actions. If you aren’t using a texture in a later render pass, the action should be dontCare so the GPU can discard it and free up memory.
The GPU workload capture shows you a frame graph where you can see how all your render passes chain together.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.