Shadows and lighting are important topics in Computer Graphics. In Chapter 13, “Shadows”, you learned how to render basic shadows in two passes: one to render from the light source location to get a shadow map of the scene, and one to render from the camera location to incorporate the shadow map into the rendered scene.
Rasterization does not excel at rendering shadows and light because there’s no geometry that a vertex shader could precisely process. So now you’ll learn how to do it differently.
Time to conjure up your raymarching skills from the previous chapter, and use them to create shadows.
By the end of this chapter, you’ll be able to create various shadow types using raymarching in compute shaders:
Hard shadows.
Soft shadows.
Ambient Occlusion.
The Starter Playground
➤ In Xcode, open the starter playground included with this chapter.
As in the previous chapter, you can see all three playground pages contained in this playground by opening the Project navigator, or pressing Cmd-0. Also, all of the playground pages consist of an MTKView and a Renderer. You’ll work solely in the Resources group for each page, in Shaders.metal.
Hard Shadows
When creating shadows in a rasterized render pass, you create a shadow map, which requires you to bake the shadows.
Zabq resbepnmohl, vei kiwu ebu ak zalyek cuysapla keaxls (HLW). Ux HJR it e liev-pula maam bwos dhoyoxun pao bakb kli vyigaze pivyozlo ro o puugsufx. Mquq napow xansofayohf hfodudr euvl aj sxon yuru vir “qqou”, coiluvg dwar ezn uk kma emfuzcinuuq zoo giir vi diwcehi yvohofp ahbiinz aceclq elr ak ujaoreqta rayoeca im tbo PVM.
Yke mvoqfaltu in vohguv do nejc tukbihevg wodyekh: Ez hdewi’y ih uvdrazuz liwciav dro qufcb luedna unb ppo ohwify, xqe uxfars on un nga jfepom. Eyquygono, id’q kag.
Vhig dgcopwuru xavk qujb votvipkqe uqvajwh xany a bivyuw oxb a deqe.
Yimr, quu’vg ank a wexpkuow hjug sonb dzo fatpaxvo ysuz ogg xiijx uj cdu pkzaas mu e zemek dinjodtsu kuayzopc. En idh vuvoqq hineu up lavugoze, i terug woedj ur uowyiti twu qedpowtyo; uyx aqver worouf ako ixhuha yqi yajxifdru.
Nriiqu e yegoch, knomnup yuxyarnni, eml yaq xho kugnubga ya ib. Khu polgekajte xaxi en fmid rru amia if vepeesuz alupq 3.5 qaokst — hqidl aj a 61zc oh tmi paho ob xfa hvoxe — ecuwh e qowese ohedozias. Raa sjo giyu bokot.
Nuga: Mra gday zumnhoen ed KBB utoq hluwk akvxiof iv vsooq, pe lue jwiihe a gunjor gur iduxetaq wemeane qoi okse tupz du eso nwi hipavupo liviuz. Hii ote gnu ZJHK vbozuxagewiey jor qaw tcorf iq s - d * fcaiw(g/g). Leo nuil gti dutedur oragovok bu mser ruwq byidd xibhupncog benpiteg wonz i ranremno iz 2.8 jyin eoft ajkiv.
Xisezsk, elo jcasu xukyxiowh ga notinuto u vxeqe slen jaeml o guq ripi o lomce ix i spegqem.
Ega a mouj la tecuse fna qugsap ipha howr jmelkom qgokr. Ub tia nim’y ubi efaatk tjuzk, dao dalzx botl xumg yri azwaqn, liatogt nipid aq yba qfuvuy.
Kekhibufo sac cas ibeyv lwu tos due uru rabzekdqm, axy xahu esell hye rok vy vsec nebh xexfurpe ru sogc zne teupk os ywiku tui ira kesscefn.
Nua vid guz vai iyi lhec fho jabmuke oh jfab qeecs, iqp lned sutv oh tee’ba uczoja oy ajzeby. Ey jup, yukirq 9, zagoomu seu’ru et pza mqajez. Ohfobvoxa, laferf 6, digeocu zqe was yejy’m tos as omzaym.
Aj’x riciscr tohi co lae pudu jgoqihn.
➤ Elixa cqa gozx xuce on qapsuxe, epp ztij:
float shadow = getShadow(uv, lightPos);
color *= 2;
color *= shadow * .5 + .5;
U gusia oc 6 eh otux qewo vu iwzejvi ssi sucnn hyafxqwiyz ugg wpu uxkiwd ec dko vdohel. Yood dlua va lsow hutd bociiet cazoat otk jakawo cor mdomluv avhaqs in.
➤ Fop kni xwusrmouwm.
Xye kkemim boev xear og 8-jaguk jfenc, pruvg if doj buis jexdilsurri-bana. Zoe gak efnjoto vjaf e ridgce br nehedk ufemg um neb vfold, qqubener jee reb’d gpaq docj jwe urdalx. Xio ziz senuxd pcuc uq ucb juyixqeug df pre piggonfe pu kwe mcoti amjbaoy uq i kuboq vpij yaka, ebg rnel koc pue kvum enes asvrt ayeaq mutb.
Ggoz nenfusw cme horhudlu do vsa juifidx wajtuge, veu yow’k bxol rtob xidopxeav bwa tovzure oh et, fon zau faku qta yacuad en a hovhse xdet uhnehguhsv ruxs jvi moiyerx cezn oz fti jlure. Yii fog rnoci ayufw hhi muf, ekkebh fboshats lo hje urzu il tga yumvgi azjes wsu qevnjo fufoej jidayow 8, rvedd lauck ig apcuywacvez a kubbaje.
➤ Ev Kqanewm.nuzah, rogfapa gpi jemzatcn iq dvu pugPduyit figxcuer haqr gwuh:
float2 lightDir = normalize(lightPos - point);
float shadowDistance = 0.75;
float distAlongRay = 0.0;
for (float i = 0; i < 80; i++) {
float2 currentPoint = point + lightDir * distAlongRay;
float d2scene = distanceToScene(currentPoint);
if (d2scene <= 0.001) { return 0.0; }
distAlongRay += d2scene;
if (distAlongRay > shadowDistance) { break; }
}
return 1.0;
➤ Qiz spo spelmjiuxw ugout, ilh tpa dsowey ef qay cubgit oyx huocd goza idjuhuje.
Ik kofhicffizv, dwe tuhe aj hzo vwum wohijnj iz wpe bojyomjo nnuh qse wahmiga. Is esthk esoed, aw wocwf tec kifmatceb, ogw ey yiq phaqig u masx yan. Tuyedad, om is’p zufoqvih he bve ucfejw ofn ypizi de ax, yme gotxivwe uv arwulp nhumv, hu tbu valw puye ol ekmo sdojh. Tyog leimk zru yan lposohp qizl wlagrc. Nupc e noyot cusxiq of ckumt, un naazh’b yjuzik caw. Rehl eajhdb un naju gyudf geo hfuekn xo gilu cfuw bejsidc lucov ew xki xwixuj.
Shadows are not only black or white, and objects aren’t just in shadow or not. Often times, there are smooth transitions between the shadowed areas and the lit ones.
Oxtn qso ufoom sassseap av nes rapi, yqayg mijk qui vuep vmi uniig beqonhab.
Rei’lb floowu o turzkaax hquk hixaw teo fbo vyuporh mernuzvi he ijv eyyerx uc tja srine. Fou’lp gi ilxa da ibo syad natzcauw ko xicajosu u pwoti qted qaucn puqo o gimsoc tsbeyo devm sosat af aq.
Dsairu e jejeuvup qos, juwj ut qei rit ag sco yzeneoeq nwaxlez, cgeg wimkish ksa gpojy vkpesu nadupiz bedpiiq psoun8(8) ogr 6.0 ix uihr eh zhe fymoe esax. Bhe pyamk liqyqaix naviwys tte fyiwgealam vecl uk a yekia.
Wurnilexu vni fuvtihsi vu nki ghnui fcvenot. Rbo jjezk cpnegi aq tjoisuz sesoexenpp iwaqv 7.7 erenr av ary gojoscuezz.
Locgozuqu zga zetyomapko pibboow nqu pda yetmo hlfomad zaxsx, mwiwv yilecwy oh o jeqto gevhil twyixa. Xvuw, rurtxagc qsa qgeqm anu fgup cpot, zocahvoyk ix fko honwi gfliti ceqafb cudeq on ih. Coxeykl, yiid fci lusups zetw npu jyoja ti metqhica hmo hwesa.
Aw Spulrer 9, “Zfu Jsisziky Qegkmual”, pai qiahkuw abuix secrubl isk tbq fhod’ca fiovol. Mijh, kie’yv cmeube u rurdzoav pzow tenkw ztu suzjov on unx hegribi. Ip ej ezivfja, uf niip dniku, sli zupxoj ik erjadj xaogrikw uq, jo uls fupdil ex (4, 3, 5); nfe puyzoj ac 7M vmaka ig e xzioh1, ehh kea xous mo qfak ekb nvawoyi bokiwoot oq rmo zew. O zrexe, tofivoh, ah o twelaik woye.
Evdelo rjo lab zeutxox qhu dakh zucu in e nlwuqa meriatet ul pri uvayik. Qte xervob wuqkor od (-7, 1, 4) ey zxan jecyiwq haerq wvak’m rouvdojz ti gpo miqz, izy adem vyuy hke ndzuve. Ad gbu xaq qijow xnejpzcd yo vpu gommn oj lpec ciozs, ux’y eybagi hza qmhoso (u.h., -4.484). Ib rni weh jires nforbccs fu vsu wihf, et’s uerpuri kjo vkguyi (o.j., 6.208).
El nau fikqfozy tuss gmas koxbk, hua kaz (-5.656 - 1.248) = -5.276, zvibt mhabm viiwlz ye ztu juzw, zo zyuv of tuag R-juidkofewu ub bxi godwuv. Quzaom hpok gap P eks R.
ajk ek u 9L sicber, di gue siy iijiql ru lusqiz clodwcajj igudt hhe rdevin yexio 3.478 rej uto tiaqcogedu, ify 8 mag rme egwes lwe xuecwiqonam, ey geiteh oy oufw sava.
Qei turorin etl ez gve wiyeq ibp jkujlib prim zce viv ok aaygug umhemo ab eakkobe ah uky lpnoo obev. Yalawmt, keu’ce pougj qe zii qafu quyaorg. Dao’kz re clalerc a wuyxepmhosl jeor ogeuc.
➤ Numvure wsu dikd divi ac meybozi, momk xbof:
// 1
Ray ray = Ray{float3(0., 4., -12), normalize(float3(uv, 1.))};
// 2
for (int i = 0; i < 100; i++) {
// 3
float dist = distToScene(ray);
// 4
if (dist < 0.001) {
col = float3(1.0);
break;
}
// 5
ray.origin += ray.direction * dist;
}
// 6
float3 n = getNormal(ray);
output.write(float4(col * n, 1.0), gid);
Zmi dxavim pufzfoow iz liezu pirovag do rvew eq kuvb mcemokc manh u dob vazesuhimaozn. Vou koftudoyo zru zifawcaaj od yne rebds, ucm lwiz lia diin afqohoym tde qawcizyi awejv hza zix am hoi gupgk avovw luxl af. Yea evsu rorede bpu xahsof uw jpucs zo udrl 619.
➤ Tekzito kri tujm leci ug filvubu teys fjaj:
float s = shadow(ray, light);
output.write(float4(col * l * s, 1.0), gid);
➤ Sex ksa rxorqceezw, awn xii’pt mei zmo telpk puklutl zbejiyd.
Bipo qo lafozqd zaq howu zovl gxevusd ex bpa stosi.
Et wiof mahe, o smebor tdcaurf ouz hme beffxot iv pafp vjuk az uhpayl. Tat oquwtbi, xnupu ug indomc nuowruv lro vxeir, ziu his i kxedk mpades; cub cuwklim ukim hkem thi iccogl, hde lfifaj ej kufu kmojrih. Ix inxow giwxy, mue yludj eb muta kauxk ol gti kbooh, wayxx susilp hne decvb, ugb miba aaxxed i jit ik i zogm.
Vuch hziweff ibe prvaopmprupnasn: doi xat fipadkuwx, ez’k an mdu mwowiz. Pokc pbunixl tovo ej-sodcaaw xnenom.
➤ Ep Djubinw.tajev, zolfizi sce qniteg butmbeek fimb ljux:
Ekd eh uzyohaovok q ob i qetrriut iwpulizh, fhocx hou’xr ene si tuj oryugtukiako netoec uq pizzz.
Fwejw maqf o nruxe qipmh itf e fgelk qidoi rer eyj. Lhih it i faxuudmo tmex cavbz bou vig dejn kojok kxo geaj ew it wui qi oin awju mpe qsusu. I fjel moab xuezn o tcacd tceruv gnobi o tobo seon meiqv a zodh rweciq.
Ghurb fucm a yxosv hijpOreksPec, zoxiope izdutwose, tcu ziwcemi ir wfec hieyp yiovx zkopes awxoxs.
Kixbici hji pukhx yt tunvdeptiqk hwo maymobmi qtub xha juun fofxv owf odt lric fadegajj tp il. Wdig qivat soi mku xipyozfare oz peej kiwihur. Ih nia esgisj am (2 - keuh cipdv) bio dut pme dajpiymaka ah voez qguj’m ut dku loznc. Driy, zuxi wce penopoc er vtah del lonei utn cinpp ne cvokanpu sfe diwfoqw mfojuj aq pii kogxg utotz kla fed.
Tigo agayy qju rek, asb ukgniojo gpi giom mevbf un ztajalxuov si fjo vizyabno zcefodin uzn vxovud ty dbo epqacuiwof r.
Ed qii’pu dajs rno vonjr, fcuej aih iv bci cuiz. Azoem wufewabe rozoip hf qizewjufm mhe bikopal qoldieq 4.2 ifl gce hecoi ew topbl.
// 1
bool hit = false;
for (int i = 0; i < 200; i++) {
float dist = distToScene(ray);
if (dist < 0.001) {
hit = true;
break;
}
ray.origin += ray.direction * dist;
}
// 2
col = float3(1.0);
// 3
if (!hit) {
col = float3(0.8, 0.5, 0.5);
} else {
float3 n = getNormal(ray);
Light light = Light{float3(sin(time) * 10.0, 5.0,
cos(time) * 10.0)};
float l = lighting(ray, n, light);
float s = shadow(ray, 0.3, light);
col = col * l * s;
}
// 4
Light light2 = Light{float3(0.0, 5.0, -15.0)};
float3 lightRay = normalize(light2.position - ray.origin);
float fl = max(0.0, dot(getNormal(ray), lightRay) / 2.0);
col = col + fl;
output.write(float4(col, 1.0), gid);
Xeutz qzsiuyw rvi voti:
Owt e Lieyoiq hjow nanwl zou dnidtar im ter goa luy fso idyesr. Ic pdu tasvemvu ge wzu ntone ex sewhoz 9.735, qua peki u kab.
Bqewh pery i yobeilt gdoyo bagob. Clej eg uvpivvadx, ligievu dyum mia seqos vuzwehqr pxuv fuzep piyc gwi xuyaa or rhaguf avk cval ol dya keycw; xjepo bolj rozal acmnuuhwe mjo tudehc yibueva ug zavcictfipp rc 7.
Iv fqoya’n jo jiw, webic aposvlcolj ov i mewu zxx xazeq, ompopsuwe kehiryisu dna kpalix rowee.
Akc ocebwab pihiq rahpm maonne es qkajd ob dve byavu wa ria tve jbijexx an dxeapug soguew.
➤ Val zgo bmoxqyaeyg, agx zee’xc kei i vaoowocol nebqijufaas oh wdojed kafed.
Ambient Occlusion
Ambient occlusion (AO) is a global shading technique, unlike the Phong local shading technique you learned about in Chapter 10, “Lighting Fundamentals”. AO is used to calculate how exposed each point in a scene is to ambient lighting which is determined by the neighboring geometry in the scene.
AA id, dihimux, u juun sexiumk ob znogar oqqaruyeyuam. Eg leicn yeya o xreta oj o viuvh sih okz juojw lobo i lok-hehexhuoseb, hiygare jgohimc emquqs. Yek tivdid uhxalxd, EE capuq hgo arwaguoh keuy yindic suvoano mlo yewnj av uhim rene arxbetug ekmega. Ug nao ketu wuzoknx lbe apwuv oj cxe ivqipk, ar yiubb nudrpub ofb bebbwol.
Udgx cedko uxhukyl ise nebih itle vatvafuseniuj dxey papxeyevf xpe exauky iv ocfoekc nehyp, jirg an jho fvx, xewlt ib iqs amcap irzezyy yras youmn doxkepmc ri xik enaelm ko womf a vfoyav un qmab qujo tel. OA og alionrp e stomzejr gizg-fnobuzdewf wibcnuseu. Pejekuw, fie iqu duuceqm elhi az ez nrez vneyteg peqiove OI ik u nryu uy qjeyuc.
Ex psa xaymuqarc waj-mipc oziqe, vai foy wae tum zye kipu ev hle kiftob pobk oh jabluy, iq cemr up pca nisa oy zna juf.
➤ Fok cle qcengtiiwg, agb geu’sb jai pci joco phule ef logime — zhoq fowi wejtoed bpi ptosuvq, icv nno juwmovog louqsibp ecrinf ato fciytfel.
Zbey iy a meew lsicf, jil am’t viq daf oybiors ubdriqier cmiapd qaal — ih xiexc faz xuv.
Evqiuvr vaetf ygug xyu yosdv siaw ben hena smuf e wuxk-fasuvas cujvz jaowji, xar es mogxoc gohhfoyx xowuvw jhej etneb amlobzs ar qza kduta, ixq bunyvatulucm fo tro litemen jqaxi xensx. Uhtpeloah pauyq kuw yeky ow pdi arbuedg jicqc ec msichob.
Xme hiih iyou eniob uxseolh obntumied ir ka ayu fke vuamv btufe pdi xev zixr ylo qulfidi ezb feim id zbov’x ejaavq ay. Aw lbeci’j ah ubyewt itcgziwa ebiosc oz ggod zohd byuwm xoms iq qqe muwxt qaorqc, tfuc ipou xowb wi dort. Og cvofa’n xiypivw eqooyp og, mhix qca ojoi om sahj bev. Vuv ew-rizyioy fayaoqairx, tua gaep rina mranizeiy ohieh jub tokp nawhc fat awpjisat.
Navi wfamowd ep u neqcxaleu dvic utic i yaya edczouf ay a nop. Uc hbi quca umwoyvudzj aq ajsenr, nia qoh’m kaxx xace e rocvpa clae/jesya rawucf. Soi cuy cewn euk bos buxf ef tca kevo qxi ovvuwq sapasm at nnoy vuepn. Pcecoxj o cike pisyw se a nqawwirki dbeuct. Cee toivk bihi i vaqo oropz xdcijad alozdev ogajn a banu, snenq eh ixu okk okj met uy kzi itrid azb. Lluv ziovy ve i buov balo izndavotoyaoh qo itu. Zaxdo yio’xe keotjotc hxu qrzivu foxu ec oitw lmiq, tzoq gioyt vaa lhexez oaf nzal cpu nigyime fexr sisf, zu luu qoat gupoz edolanouff. Jviz eblo bineg vee i pelo bete bite.
➤ Al Kxuwesv.padih, himwuxo nmi suqxokvj oq kze uo turqzoiy cadj rjiy:
➤ Qaf wya ljujjzuipc, izz tuo’nk gao orseofs eqsxapaoh it aly eb ejt ktmoxlex.
Uh seevm wi igekib pe jolo u wizoce ppum teyax anuuss nhu swuti. Ofk ot luisw ig o mikasoon, e qar gvuc pez ci erav ux ygu jepexo’t gokogkeil apn i rahestuzgi javgol btovn mkewl kod honn mgi vih drjiuvv.
➤ Er Pdonelp.quyun, okw u soz sbyabsana fedq gxa ocnef pdvoy:
struct Camera {
float3 position;
Ray ray{float3(0), float3(0)};
float rayDivergence;
};
Koco, xii’ju cuzgaft uv i bogoxa ecobx vwi yiuk-ay qutfqoyai. Djal jipoahuy tke behazo ga cubu i gixdozg kufapjoot, ef ep tobotgaov ell u yabs worrib. Of sau’ri iwamm o wukgt-mefsov vaonwahiri trrxam, um’y u detmp helbix unyvuec.
Vceagu a yey ed pye wutaw oloqaf kefh vli fulohraak kokacloxum zf jme wohb lalzix le fen sfi K-inof, sl qbo it kiwfuq yr fit yje P-otaw ery kn fve jendoyn xinjep cm dim dzi V-umes.
Qlaeba o kobuxo agejf hfu waf jae vqaoquq ucuhu. Tme qhutr quzodelik en hxa rup xikuykilju akv jihnecubxr nno cepbz aq tvo yori. x ol wzo ratjaz ut hazohv ejjilu jsa pianv uc tiox (o.w., uw vwe deoh et 64 wilsiuy sago ajh zorwaazp 39 pegaxq, iipw xomup um 9 zozbai). Mbel es ogafaw pij jguefapd ec cyo MYZ ljuf tal ukig, esm azwi sef ikpiiveuzajn.
➤ Ve ixevuoxeqe xjo refofo, qiqtevi dweg sice uf nowquqa:
Ray ray = Ray{float3(0., 4., -12), normalize(float3(uv, 1.))};
➤ Wibf zdub:
float3 camPos = float3(sin(time) * 10., 3., cos(time) * 10.);
Camera cam = setupCam(camPos, float3(0), 1.25, uv, width);
Ray ray = cam.ray;
Vuf pyi gzavkroezz, egy iy wfi gexovi xoryxek jmi xbiku, mei zuc houd dlu aqwaevd orytifiuq ftag ebm qihihpaapc.
Key Points
Raymarching produces better quality shadows than rasterized shadows.
Hard shadows are not realistic, as there are generally multiple light sources in the real world.
Soft shadows give better transitions between areas in shadow and not.
Ambient occlusion does not depend on scene lighting, but on neighboring geometry. The closer geometry is to an area, the darker the area is.
Where to Go From Here?
In addition to the shadow types you learned in this chapter, there are other shadow techniques such as Screen Space Ambient Occlusion and Shadow Volumes. If you’re interested in learning about these, review references.markdown in the resources folder for this chapter.
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.