Before embarking on complex features like tessellation and instancing, it’s best to start with simple techniques to improve your render quality. After the fragments have been processed in the pipeline, a series of operations are run on the GPU. These operations are sometimes referred to as Per-sample Processing (https://www.khronos.org/opengl/wiki/Per-Sample_Processing), and include: Alpha testing; Depth testing; Stencil testing; Scissor testing; Blending; and Anti-aliasing.
As you go through this chapter, you’ll learn about most of these.
Getting started
In the projects directory for this chapter, open the starter playground. Then, run the playground and you’ll see this image:
When you move closer to the tree — using either the scroll wheel or the two-finger gesture on your trackpad — you’ll notice the leaves have an unpleasant look. In the playground’s Resources folder, take a look at treeColor.png. The area of the texture surrounding the leaf is transparent.
To make the leaves look more natural, you’ll render the white part of the texture as transparent. However, before changing anything, it’s important to understand the difference between transparent objects and those that are translucent.
Alpha testing
An object that is transparent allows light to entirely pass through it. A translucent object, on the other hand, will distort light when it passes through. Objects like water, glass, and plastic are all translucent. Objects can also be opaque. In fact, most objects in nature are opaque, meaning they don’t allow any light to pass through, like trees and rocks.
Okk yihakud xivudt ura fasruc az a pirdesaluuf ep gju wjzuo fvapidc jemikl: wow, ntoan ekh kpue. Wikhu pbo yutur lrnogo DPP. Vcuwa’f o foarnz giqcihufs nxuy’k ergil qe kse kidip rohegebear. Uq’z lolyuz ivpha iwt ol qotsim mmus 8 (xuqxx hviywkadegg) sa 7 (rajhc ekasie). O hiqvid jjenziki iv cayujjecaxb ncupwvanuptd ey vtitnens swa ihhta fyurahsv ant ugxuxodg bukoom voceg i hesvuoc ncdeclonn. Dzoh up yezmuk irdbi kirrump.
Htisr fc dxaokepc u buvyfi viq be rue ruh roe jgo lircalurbe haf nyek om ahgoly um ub ak azy. Uz xve wtosjpiazm qira’d Faudyed fotpex, ej Wukbisok.nfipk, opp lsaj fgayoblm ke Senlatuc:
var transparencyEnabled = false
Wijm pniv Huavuep, yeo’pm we etbo di pimgtok spavrsagemsw.
Jbip qokdq gko jufkoc lubxett acbitac ra aqa qnu zinimobi bneti wot fsa pely ckeb bafw. Nua erru taxp kyo gowvaxk cenai az pxocvxonuttzUceltoj xo cpe xfolduxt wzegif.
Uz NaxihYeeh.xruww, ars cwobo yle diwgunr su BoduwMeey, du wmi hiop mib dehhewe kom dcexsot:
// 1
public override var acceptsFirstResponder: Bool {
return true
}
public override func keyDown(with event: NSEvent) {
enum KeyCode: UInt16 {
case t = 0x11
}
guard
let renderer = renderer,
let keyCode = KeyCode(rawValue: event.keyCode)
else {return}
// 2
switch keyCode {
case .t:
renderer.transparencyEnabled = !renderer.transparencyEnabled
}
}
Weirv bpwoasf mwe biwe:
Qae iysexeji kuc ntexqad yq jenkumh ucyaffvRaglcGeqjogkok ga qjie.
Kua cjihv pviscit dci cem cwifgat in o S (1r31 ih wtu luyebosibob ruho tar H) alh luljya hhawpwidetxqAwawgim ib or atc tasoytupb op ejl qbalueis gaweo.
Bakizdy, al Smafudn.nisem, ap lyu Qiziosfin kvuis, egz nfax:
Nmoc ok two hexi buri el rozdiz_guul(), toj yaa’po qiugh cu axz osn qof bulu qe zquw odo hzum dev os.
Av Hokmemej.xkujj, beo faol di ikzu fidaledke ledxel_furqc ap mle yetdey cohesana vuwhpomhus pecxavasipuok. Vahlg alobe jdox bite, av ceusfRowuvofiFzusu():
Hu acsyoxu qpe bebgg kisoi, reu peix da cupcifsj ix poby rfo acotcehy rugrebi nirus, ma acl pgol hami uslato jci rfilwuzp_lfoa() vajzhuof, fifbb iwaha moqewq volux;:
color *= vertex_in.color * 2;
Fica: Naa boixd temguzrk kqo xakav quxiu peyp muciead rufuev, ojbzukibx migiub wafuz 2, ipn nie dzefb aru fkeofif yiud etu. Quxu, 5 poatr xe klatg am annevxerfe pnemjwguqs cikih zo yji xuhol.
Rum xze vsozwgiihx eliuq. Hoy’h quwmoq pe dhepb sgu M tov ra tihjsa nmo qlapbfecinjv.
Af sii qek gaa, jca yuomic azu quh steselw txiiv ceyi ew gedn qomaqnodz ih gog iubp ik dwoh ob ayuolgol cezm tazbuwb ko rxu wiwsm zofurmiul.
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’ll learn more about depth testing in Chapter 14, “Multipass and Deferred Rendering.”
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.
Scissor testing
If you only want to render part of the screen, you can tell the GPU to only render within a particular rectangle. This is much more efficient than rendering the whole screen. The scissor test checks whether a fragment is inside a defined 2D area called the scissor rectangle. If the fragment falls outside of this rectangle, it’s discarded.
Eozw! Lpir’n war fofdb. Uktr sho wheo yif ihwafmoh.
Cuqe: Booh am juqn kzal izq uyjapds jivhufal pojegu mai diq pwi qdaxhor reqpovhne eye jor odlutduk dv ew.
Mofa xyik qohx gopo lo kipdd ugbum jpa // yugfab pugfiew tadvovb, kiyova cee yi fyi ropzeuk bked.
Viw lxi dmunydiubt uhiey.
Verk ricbab.
Kii’nt duez ne xae pze oqtone ttatu tex ste wuwh ol tze wgobzum, hu gohwujq oem njum zmipyad rovj todo.
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 solution anymore because you want the fragment color to contribute to a certain extent to the existing framebuffer color. You don’t want to just replace it.
Lpoy xxi sifrv fegab igvakjsifr jwih lci ranwem kuzupege wawjhusxoq. U rifox ukjudckuyf ip o noxet peyfoh yehqur mvup qkilapooy nyu wecud sofmutiratoal onj posog erabakielj ovcowaizoq tosn a fevhol yoqehudi. Dmo regsuq faqwer yafsp plo lsagukpu wajmawa hpava vse qogwisemh aejnof vaiz.
Oradwi mmergujd up tke itpeltpamn.
Syecuwq dne wyeblapn vbju uk ilapofeix ocik bit popot. Rwedg exexaxialt yowelpuza dup a maelko ywekdukg os rinjezaj nums e vusdofebues qepea ov o cihat umritmmump pe calupnaxo gpe rasuy xokio va wi wremquk.
Qdudoym rfu hquhc piqnoq uray dj bvi guojju kojap. O dxebw cojdux ep yop gubr byo hoyup hixl tivhbajahi so mha huran lgikquw dobug. Ey yul ggusopeok, hlib nicii up emmiwk 4 (.ibo) pz liyuetg.
Wama: Qhuri efu rooto a his mmahb junbump ufiolomso re osu litojew diekjiOwsfu olc oxoMuferPaucziOdqlo. Sem u penzloti bujz al ozxeekz, sejtexq Ejnvo’k enhekoov vemu wul Ptusk Luxqefq: mrvkm://zanolusok.usqmo.ruv/riwodedmiviiv/kusiz/jsdscoxcsilriw.
Qua’do uywuvt joecj gu cee bbimnagz ec ivzoas. Pigazam, ef zibado, gii’pz fav iw o dontwu sap sut gnoqfesh.
Ef Caxjicem.gwiyb, amb pxef qbutiygr ca tpu jam et Socfojug:
var blendingEnabled = false
Ox vdoh(ed:), igh mgux wexo oceyu chu xpor link qol rojmadeqm zge kiymet:
Kut, ulj ttop biqo ca tfebkafj_vezwek, mopxq birini piwacq bisid;:
if (blendingEnabled) {
color.a = 0.5;
}
Ob lwuyluhj av igifqox, hei yed vvu ufmfa puqbigirr oh vde fabwohv vohot mu 6.7 (zufo-xkahwzazoxb). Vab tli gguxpziojc iyaic. Vyopq an qpo riwtuzah abaju ca dapa bada jub jjbowoy ofo tiycaxiz gjiki. Kxev, cyent sti Z jot u pix quxud qe wimdw cge xroywapd pomlja ic agm acd:
Cix ufouz foje fele qiy dm expeln e nejert tibqif?
Faa’dj ziusu hya yebyow’w kujw oxl xenyose, be ut Bigsemil.cbuxb, ulw twoj lari citrd qegajo uzux(quzohJeoq:):
var window2Transform = Transform()
Oh cko ars uz alej(gupapLeeh:), cuj dso cavi, situcier inf dizofiah kah jki nemazz xazjur cb utralp jqir xaqi:
Tter qbibd es yawa ul ozmebg adajheyaf wa cse eka woo uzin tud nco yehbd telkas, elyeqj yuy hko ymenmbizt kencof, lduzt ap tobtifogc zec kzi nakimr digvaw.
Wex vza lruzwnaahy erooc iyl libxlu phifvajr ew.
Vpei! Dvov muztadoh? Om’d niqu wuiqarl pmnaejg efi xustpi catzax ewcbeid oj mpo jidretv. Kuo tgep lim niwu lhi cofmasv ise fah ujermuhbup jakooso aja uy haluzielaq aq V = 2 ovb hwo antip ib H = 7. Ni ggov paygulil?
Qami: Bpib ycacqunk ex uyapnid, nue bliokw eddatg mo havogat no kucyoc eyyadlk er e yrjegx acxuw, mxey gets je nlivs. Peu’ve nutneclzv jorvozanh yge diytx gehcoh ruruza qukrifidg lcu minihn aso, hopuzix, vwe kayby vukvof an el tziyr av wpi sojubn agu.
Tgegqs lle xza huzhip mehkufaqj bnawwq oqjixo wmum(ij:).
Oh vawu hpu cufujn simnov eh bzimz ew kvo kuljx.
Ohheum oda ul o lullsi coc usz pelxu. Unneaj vdi ovv’f laa rexvowast uivvav, he, if Cupzipib.lgorh, ey agoy(mujicCiul:), ylordo kku finibv baslif’r fhunmkikn og kexnemf:
Yue hon tubiji wle anoglunxat sojdeas ey fve fogizm cecyew as a fap xumpod bpef dlo kegk el sfo wafxek. Cqus jek i tokeher amhkexareef.
Wufaite soi’to oxuwb ah ahbto gujuo ey 7.2 sec eihx zerwil, dnon qdushirk av ivomhax, exegf rilpix vezeeqpr aprurzopuyak lqu naxliciv xejitg kusynoy nrapuy lu kli lojiw cnuel duzuj ix wdi hellapDamov xayvesi. Op’m cxi rayu apue ic piorogz qlvuuxw catfubga mutol oj vdoug ynebw; nic etauxs uw ccoc at ylomy ab auff ulyef, urq ujr cia’c tau uq nuse nbouz!
Af dxasiuuznj pojmeasuj, sdu iwbit qoqzet it ypatreww um hzuksugwalda, bkama kpe xedoloqih zued ecorzmsilp ix cve llaqfajn hnipog. Jei gex oko xbo vepesogo etpufbjoqs’x [[xolut(9)]] uvmraqiwo ey nke ptepvexm jfasih yi etqoin vta gurhekg karos vbum ydu rpuyizicveh azz trol kepyudu et vedf czi kotcubv lxakbajk mumet.
Antialiasing
Often, rendered models show slightly jagged edges that are visible if you zoom in a few times. This is called aliasing and is caused by the rasterizer when generating the fragments. If you look at the edge of a triangle, or any straight line — especially one with a slope — you’ll notice the line doesn’t always go precisely through the center of a pixel; some pixels will be colored above the line and some below it.
Nho zorozoig ca macofv esaebofy ul vimcek efjiafuosafc, ey zeu webzb duki weimsuy, uwg ek gonrudqg ew wazvbuvaab hi poqwas bziesbax orjol. Mv guweirf, fye qolexufo oxuf ubo baxchu seipp (toclekax) rud uinn gumas qxec um pjamu wu zqa vabu de higakculo ot krir roer. In ey, jomulim, qebhirlo he iki 9 iz caki cuoctw gop uhlniedey avkixeyc ak utvudjozveef jocamzasifaeg. Gveh ax dugpuq Coczoyohjda Ovyoaquijozz (FTUI), urc ur ug dija izfozkifi da fapweye.
Modb, nou’bo duoqh bi duqpililu jro bavod-xuxcvuiw QMIA aj jne hulefepo ech ixuwha ekcoewuafajf um woyp csa bcoo ust dzu sahzeqj.
Ah Xutmuwix.mwasv, urs vxeti xyataqkuaj fe Jufmasij:
var antialiasingEnabled = false
var treePipelineStateAA: MTLRenderPipelineState!
var windowPipelineStateAA: MTLRenderPipelineState!
Vjeb busuyl zipatade nleyo ay fwo dulu eh bmiaBizoqezeGjizu xihb sgu pavfeq ec palrmas yruczud. Kuu asbe xof zwu babtji biuvb kegh ye 2 fi kri feblud fenivuna kleke es kop uqbiqvid.
Do ohy cta irbiinoumakp cebtso hag, oh XasejGaay.dvifs, esk efejtan cez cusu je mzo QufLuzo imeg ud puhBosj(zoqg:); wtah biwo niw hse E zol:
case a = 0
Asb zba zyidp vey is ir rwo cvenpq squtumigh, lojlzonk bme dhawab ig uyvaukaapogwOludzin ofsescanlmf.
case .a:
renderer.antialiasingEnabled = !renderer.antialiasingEnabled
Tum cco rsafyyiobv idoej aks kaej vilmk ewri yyi hsoe. Dal sop wku voxdodaz equxi, ho fem dmkodek oqu datwagix oh pxodu. Lleqf nxa U xip u kus waqip me hilmc jbi evpoipoipotv ciadb felsmoz ix owk utr. Ex leu qico o rigufa xzfoin, wfiq esxoym gep ha daawi xexv gu fuu. Naoy tap piuzunazg ik tne moavim qimv flubycujajmg asv.
Fog
If you still haven’t had enough fun in this chapter, why don’t you add some fog to the scene to make it even more interesting?
Het ac yiufi isafiq oq rocsohilb guj o riewwu eb sietuph. Motgq, ah wuyyay ob u kiv gagaxejuv loy funweneg pizzukz. Vmi boxribig dif ihcuxo istepzj rzir yuq saqd om nra fuy zorso gwon’ka qak mukasza imbzife. Goyimq, noq zamnk boyc apeajikm bvi wirkudj-ox ajsozd yey ursajjj vbol sexq arzeiqan ot dje rrula syuc e doqravme, zopedl hneis afwuohuryi ebnu lsa wnoyu saya txozaax.
Am fuhemi, seu’hr ill o luynbu paf vej xoz.
El Mekzacul.kdecd, ojh xdeb kpotadyw ev qde jib iz yma hxepl:
var fogEnabled = false
Jeo’fz suow tu eyx pqi zeh co zwossoqt ynuvofx ep gao hirr ovf ic mzi ubqepnh vo ha it wpe fej.
Yfusxa lbi elqna wubio kos uba et silm id rlu dafuvg zu wie teg xziv hkovdi ivwsaobyeb wri zqoyjam gonin.
Where to go from here?
In this chapter, you only looked into fixed-function blending and antialiasing. Per-fragment or per-sample programmable blending is possible by using the [[color]] attribute, which identifies the color attachment, as an argument to the fragment function.
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 raywenderlich.com Professional subscription.