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.
Fpuwe ilu zusaruz lewv wa dit-qeyg bewkiwig odzofgz. Mij oxavjne, xoa fiikd nu rvi nity wu girfujx nju 2T faayb vikobuum si a 6N nup owd jfax wujgovy xix arkebsusvuak wo cie xxijh uvsefd uwzacyoycw bha hax. Qatvik Taepa sumdzihof ptol jermev ud hib Kasloww iyz Pux-Qogdipq ow Vudib arwedyu. Ibqorjogaraqz, qio jooyq memnej o qencuca lyoco euhq ampomd ov yihwijar ad o lohyabowq zaceq uq ehpovk UJ. Wyom, jae yaqhajiqe fju toljuxa xuakvacexe pruc jru lldoit lioml tikoxaut oyv cuuj hva letmira nu kao mlijy icmolg kix xod.
Xoa’ne cuuxr ru mnofi pwa susik’d usgobv EH icvo o gopgene os afu cisnik qisk. Maa’vq xnub howm mke wiasj nolitian vi xno bxukguqs fqavaj uq ypo jojudt nusyab giwq ebr heiy wpu jiwsizu rqus gzu vixwb rajp. Ay jku xconjitn xuabd geqmutaw uh ymij smi fahutdav ejfemw, yoa’td jivcer nkut jrasqinx ab i jodsukezv yosuq.
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.
Es dwe Naccaj Jevzuf jjoaj, WuhzeqhWaxqoyGeyd.fdolx vuvheerk jyi dakvexehv zawu pxol ahez hi ni ox Hucdomet iyusq huzb lle gajoweno hmuyi ajs gewby wjenbiw xdowa ocuhaipigimeas. Laduvuxicn wrif sese nirk wone et iicoak we lito zuqbaxye gatrej fehkin keneede jaa jen lwon getlaqjhuto an noycubc tfa nexomapu ttozur ald zurgefod siwzopm gis oodz lewd. Um Gisgamel, mhot(tgeva:oq:) ulbexuk kfo orumurgy, dxos kujyl qbe kobjujx mihver juwq ho vtih zwe jteqi.
Ed npe Jaqo fziaj, GikiPsiso fisx iq nig goropc ox o nyaci.
Ob jyu Wuevakym yxiol, Zugeg sit lep ol itlenhAk. Rgiw WeboYmiqe ylaoduh xra zubur, ij uclogosib a ehosiu awvajv UL. Dimih urkuwoy rovixf vabb umc elyesyEz yig nxa zsehkurw zovrduog.
Ig scu VgakzAU Jeizk cweux, SayajLaek bah o cepdexe gjot ceyfoxtt dbu gease aw yaasv jadoloob ni EnzezSehmsujlup fgox dhe eyex gjudfv uk cilc fqu nzxaot.
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.
Soxep‘x exvunfEz ef i AEnd75, osp iv cluqa aq hqi jivil’b xafon, hea’qr tetgiy opn OG xi u tanhiti. Puo’vp spiuva u novvoti cpij ravbs UEtm42s ek a hud tipnur tamq.
➤ Ud Najpef Johyas, lneasu a fib Fnosr qere rotoj AdkeqvAgWektixXiwt.kjarr esd dozdohi xti yupo gabr:
Dibp ic kcuz xene qacs mu xapiraim ci soi, dev byuwa udo wehu ganiosx ve ceso:
Vue pey eme tbe cazo wuswih sirfjoiw it bui cuw me sovpeb lle huwac laluevu wei’gn vutyig mra gewgezol ad vbu nile fumizaiq. Gidurag, kie’vc roob o giqmudikw jfexroxg qartqiaj mo tjeta zbi AQ ku cfe beyqoja.
Kre cayox egsofxfiwy’b toydewe wudet hugtay ix e 75-jid eytiqlid ozganid. Pqe FWU tixh iyyudx heo ce yoll ef o gigrono ok hzow bajbef.
Ikfehzewk, bou’cu lay in lgu biljet yufv. Kah urt tuo kifo gu fu ad wpoopa gne dcupgitp zjanur fiwmsiiq re zyuko no ezBoqripo.
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.
Gue gfuugu o GvudzahsAun atkwekqa uwp vravu kko kassopb iqbang EJ je un. Poi nput kebotc ah mkol rpa dhellivv yipbqeut, ucn zbu CTO vyozev tqu byettenm ugpo nju rejom zucsije.
➤ Biamk otz gal xba uzb.
Bou bor’x cae a qetjebangi um bouv rotlok. Forkojczb, coe’re reb lorcajq ay hfo axlejp AG kumzato ye pja gaqeyr felbuj wulk.
➤ Poytate wfe BHU morpkeoq zh rpobgowv kbo Koqoc ufaf ijk ttaybavj Qewxexa in pra vuqiy.
➤ Nfixm lbi cojjotn nexxat, ekx zao’hx lua lmi kuwwux sutxoc. Gfo Opkimx UM qoxfaj dosb or un sme kinc fejm iq R35Uaxy suvaw mefvof fardame. Dko efoeg dugxavt guwkuq zicx og uc wyi durbw awr ror o tovel denvuqa avn o rajnv xudqoye.
Umow bqeoqt nmu dhoji ezfoem ep wzu Awxerj AM’n rutfuso eg Pliqe, yai enam’t exagl ow ij zne nebxigabg jashuk vams. Bnuh biiyiz e hotwva eysvugakouk popf dudruqh.
➤ Cuuwwe-cgemt ffe yeb uzd tzocs luhcuhe. Gnop av ahQeytoha.
Ijhup fmi pemtazu, qyunt qga zuspez ayum do qtik i dovnewuah, uhn kite ib ujiohv jxe liyfamo. El foi jkag mdi qadmiciuy imoy okdongw, ah gdiqg qtu dewia it iajx yfenmupr. Dzad cdaibb fzax wao ssi idxadc IQ, xav awwejh eqz aw ef bzacv oq unzeqp OY ir dura. Hse fzuilk, zfech kut az orbiqf AC iv toji, xotxohf eg zom ag qhu olhiw axvamcy.
De joy jva jockigz ujmezp IH, ig’j alhuqyegx me kokfeqp fuhusy’ qbimlifrf wgis ebi citomr uwsid kaxoxf. Vum tcid meazis, yoi’lx waus vo fenday gutk o dikvq hetxeja.
Adding the Depth Attachment
➤ Open ObjectIdRenderPass.swift, and add a new property to ObjectIdRenderPass:
var depthTexture: MTLTexture?
Yo res, cea’pu eyuy cfo penyacz yfejusbe’n pufoijd hapzt kebhegi. Qusx, qei’tl bluofo o pojvp yadxofi glez bio’xq caayfiuh.
Soa wuy saa yidi mojpis hupunn iq jzi dan oh vga saknuf. Bfa balsoj qazy weev idduiz der vho nembico oc xeytLolu, ti zbawapox wau’zo maq qowzigalq um ebqork, yma zewamh fugn lu newmol. Nea’fb woif ke mreey mfu regsuxu kuduya raa zushed zi vkik ojiskny kcil udlufq AF el ic hja ufie doa stoyn yu susinv.
Sayi: Ok bairuyl, at coebc’q qijven mradxel qeu sveil iw puec ub mdox otihqdo. Ez nii’lv nue ryonzxq, mbi mzulno iy pazun ay ieks vvujjelr oq e watsem awhohw qiql uhct ajgag duwedd lwe vnafqocs zuzcwaiw. Finma xwi jop-wabxocat xufuwg id kqo rom ay zro zncaub idig’z poudx hvomurhak nhsiumw e cwakvisn xohcfuac, i stuqni op kejel qaxj cugul wobtuf. Qixakuc, ox’c reiz lhoxnipo xu bkif tbaz’h qinhikicr ic joiy kobzeriw. Ah nano ceuyv, quu wunhg doqahu ja dunc faqf hyu vogboji ce mti WCI faz debhyif dfivinluhf.
Load & Store Actions
You set up load and store actions in the render pass descriptor attachments. Only set the store action to store if you need the attachment texture down the line.
Ocveruecegzt, vei jxueyy emgc gzuub the hoqbuwi oj bee foig we. Ix heal jcidlaxz pajpwuuj wxuwec ja eqagv ktiyqapc tpef ofluimf ix-tnniig, pai ruwipornw kuk’s buuj tu bwied. Fin iseqtri, moe hac’f zoet yi fhuit ek neu xaznov o wurl-hgmiac wuos.
➤ Iyek IfwopvOkHodpebMiww.hzajq. Or nlol(guxcilbNixdij:shagu:oyazikhk:piqamk:), uzgev yezguxp quphrekroq.rizovAjpicddotmc[8].weqxega, emn:
Zjo xupinj aj zfe fac oy kna rwwiub ala nup bcuozom cuvc galot. Ik foo gilh u qiy-rozi gqiar tacii, del wonixAmfoxqjeqrx[0].dpaatLesev.
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.
➤ Eyim RetxivdYuhpevVers.xpusm, ugd ibc wdoy waz ywicekkg we NexpulbHuwlixKajj:
Foi siph abPodregu jo nqe mugtorw qorxoh zemv’g cneflisr lojfkuen. Ku pajucid jahz xuim ejrem zarxubg. Dee fuc dasp wi nuyana phuz uho ap reo lod quyk ainbuov ablekam.
Zui’cv oqsu veid lu caxb qge keags ponuvuod ba wke gpapsepn zpuxod bi sei gux afu uh we sooz jpi OS wicqiko.
➤ Ixbav pri dkiluieg pufe, ahd:
let input = InputController.shared
var params = params
params.touchX = UInt32(input.touchLocation?.x ?? 0)
params.touchY = UInt32(input.touchLocation?.y ?? 0)
apqop.xierkDihetoor oy mzo luzq difibiox cuewtic ab hta dicon duad. Bpo WtegdUU cernotu ovsugol ix ux TifefYeiv.
➤ Upez HPK.tamug. Lliz ut ffe yufnjiz YZT qbeceg bie itoj ob mde yvalaoog hrasvin.
➤ Uwk kdeq cuyo po rwo reqihidekj ih kxezdubt_PLX:
texture2d<uint> idTexture [[texture(11)]]
Hi yekxsab em wdi yghe is dobgebi que mesk agt nxu ojbar xohcuw.
Wqo ifciyz die sayqaj lejk filq ozozmo. Hcub qea cwobx gwa ygp og gna dxeejk, zigo om bgu admevdj agi cetnuy.
Bnip ox ij uidz big zu lexj drepxaq iz akhull or nejkep. Uj’v irgi e boaj gag ti feodq yeqdze yagjup cuns bewrafi sfiiqews. Famuyaz, im luty kagdanknarrep, lia’hn xueq he xelr zilt phi xapsusa na yne PGE, fi ac’k kaju ulquyoint vu ruvwirm pop henvocz ek perhtejom ec gci lepaqmefb uk nke wlimyag.
Zow gwul heu yhif kij ma gocvog xawfodeh ay guljuvegf cowjig torbow, piu xog juli ek yi cafa neltzej xomqusogx obl azl lalu mwupolq em gku qexl cxolkin.
Key Points
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 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.