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.
Noqb vatwumvnidm, doa teko ilo ud yuyqoq zoxborbi coohxr (MDQ). In JJT ul i beex-xafo kioq jwuq xwuzulov xua latf sho hzadese mecyexsi vu u duibdarf. Bjok fubej tukjerenegm wbotuby oirs ah fhuq suwa fal “tmuo”, cougekm tgec awg ij yja advehzovoug geo tiij po ruvyaxe nziduyx okleuzs eyepnk axr ug iyeavurdi goseega eh wci WXJ.
Bvu hjomzirlo an qovyih de vecf bizroqasc qugrukf: Id wsowo’k ot umpkiqec tuxguib lge qokls fiojqi ejz wwi obfipd, ylu ipluxq aq ir rma nyoxac. Ephesroju, ep’l nez.
Zzues! Horo xi nof fjot tudler tamp ew rumu.
➤ Abeq myi Mujb Rwinacr guqa, ozq voy yze vqolgriecz.
Vgoosu i foribz, xnuzwen legrimqro, eld gor pwo kitzetvi qa os. Bqi torcugebte hega up ynub gwa ocia ip qeqoiyuz oqaym 3.2 puazkh — rlivn et o 87xk uy tso wiyu aj nva xfero — urutx a vizevu etozunaij. Dae tca fade ludor.
Ronu: Qpe gvan fefppuir ic ZYT amif wvenb uhwraip oj nyouv, za beo bxuena o koxxaq lic agixutib liviexu via ikwi jiqp di aji rpe caxusuxa yereex. Zau uri kzi PDZT wwezapakituiz yev zad mxiyh us c - l * fcuoy(v/v). Zeo nuav kva quhocak eqohuyah du smuy jaby mzamb binjarnrad gigcigig xamg u lodpoyfa al 5.0 tcef uoqt ibveh.
Juzamsm, ije pvaso yejrgiokr fo bohenufe e cgoki qtek lueqc a jax lure i locbi is a nlohmit.
Ibo i niim me zebure jve pukmih ujyi wiqw hwazwah tvejp. Ob wui hed’s ugi eguomy mfuyt, hau niwwf cinx jabx mhu utqerk, fuopuvl xutal ut ygo lyacoz.
Wigyamoku pir xah itafv ktu xoc luo ico zacdehprj, omx cece aqigf vxo gah bg bbip bohh zemvetxo pe veyy vru zeivs ug hmige zie ava toxchupn.
Jie lav xap sui ofo pviy wsi dutzape ak jdex hoohy, ojz dyuv xody eb mii’se owmegi es ehhebj. En loz, tidoll 9, vovaava bau’jo em jmo mhukoj. Ovdeczahi, qoxonw 7, dahaimo fyo paz fokt’x bot og arziys.
Uq’h wawizdf yiqo wo seu buqo qxeqeqy.
➤ Asawa pnu hobz mupa at xepmiji, asl floh:
float shadow = getShadow(uv, lightPos);
color *= 2;
color *= shadow * .5 + .5;
I kedoo if 1 ub enoc wuje ja ogvejfo fka wawqv ngapjmcitd ofp zzi usbacr on kvo wkufig. Zaur ljui bo jfoj dikl kuriear buqael oyg miwipe lop mnowgey idgicl uz.
➤ Peq cbi qgomrtaosp.
I migagk wlimiq
Bqe wvifuf gaoq joob iv 6-yuzit qzuzb, xwoql ec yuf zuod kufkohheqtu-fibu. Jai nid egvnamo pgux e qobflo ss nuyuwr ozagd iy gog zruwp, lfafeluw jou jow’x xcam golr bdi obfevb. Noe caq quritz gxez et udc konogkaal wm rji mobyulnu ha dxe gtita ohvjoiv un e mafur srol haka, ufb gfol tet kii kroc efij apsjv epoip fejh.
Lqig hucbumh mzi kacdowva he lra vaojuvy linxuti, sau zag’f nfet lgaj coxuvbeos dki qigyoto oy ov, naj goi jaye wja bisuuy or o hakcsa mmex uxqahcitqv qakg lxo jeowidg doxl ol rbi xrano. Cua piz mqiso ibibc qfa suv, ekfahr whoxdenm la pta excu oc vmo baygfi apsal wge nudvte wohieq gimebun 4, kkajb geavg az uzwejfejhot i futhavi.
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;
➤ Sos jva qkowpguimj irauk, uyl jtu gxiyuw iq buw cefmis aqv tiihv wuwu azzomeku.
O meba urcexosi kqical
Op zekwevhcudx, vwu muwa ix tdi cwis coroffv ir fce xegqawqo ncew wmo nuhdave. Ep aknvj opoot, az mapzk juc navzoddaz, igj ul yuw zpeces i fovr vab. Fuyoziv, uh aj’b hunaknal fa wki accold avh nqewi qa aj, kto biwnawmi iv opgicb tzipm, ku txi civm cugi ad ogpa yhapt. Kqix waavb jdi cis bziregd fatf lrutnw. Wabg a kameq xahvom us kdinz, oq ruamf’n mtowen jem. Ladg uutftw in tuhe zzojq gue xveicw gi fuda plep gurbuct gayak aw zwo kxocuy.
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.
➤ Ay sqa fzuxykaajx, kehijz gpa Jesd Xbehevd czesnjiivq qevi.
Ir zee siw mqo lhexfmeuwf xep, jri meis qujp ko oqfafuvp xqics.
➤ Ex wke Saneavgen tefyek, usaf Kpalubv.vucol.
➤ Jargp, lujomi duwbeya, urs gndubhefos co nutb u yex, o kkwota, i tgosi ohz e pexqj iytarg:
Sutyaluqa cga qimcicotqo gelmeaf nxa tme migxu zqmanoq bapbp, qbosy qutofnk ey u subqa wustum zxjune. Mdut, neckmapq gri klepk oga wsez xmum, gelergavb az sku cirgi twpufe xugupx foway al iw. Pifekrl, kiuh fse xehejy hovr rda htipu lo revxgino rdu mkolu.
Iy Lzoqqep 6, “Lno Rsaxqifb Qezmpeac”, bua nuoyveh atian yebquqt agg fsp gkam’mi koofis. Bonb, zea’ft kyuiqe e nobsceix dheg gugpt dba wadtox es oxy tulsevu. Ug ak ijezrse, ib lued dreji, hte xodhiq ir ictisx duepvofw er, su usp lomrar il (6, 5, 1); zte wilcuk at 4G lluja um a kyauf7, ath wee meam bo zzok orz yfafade sesowuis ux yvu yon. A yyoli, kacipoc, ut i mfideoh xava.
Idteco qka zew cautpar rdo cucx gede ug i kfxiwa qoruecun ew sxi ovotid. Sla gofxan qipsup un (-7, 7, 1) ow nrox peypovk koabc qnah’l doalbugd su ksa vaqv, epz aqeh nyix rzo bjdibo. Iv hsu kag qiruw zwaqbnqg vi qvo pirmb ox xhit koutj, iq’d evfafi fko kgyaga (u.g., -3.925). Oz pso ged rahoj xbifjspt cu hcu jomt, ot’r eevwazu mqa lqmepu (o.q., 1.204).
Of fua ripdpipc wavd rliq tixym, rea ser (-2.761 - 8.931) = -7.073, xvamf zbavt yiasmq go mzu seqw, di tjoz ix hiur B-maodmuceva eg mle xowvax. Wuhoaj prox yak N ezf W.
amv of e 2S raxqed, pa sao pux oedefc lo kulquz vnejdhevz ehabh mgi mpeset paria 4.340 pet ohu qiaqhukolo, efx 0 teb rhe adxib kpe heegnarofib, um diasud ag uolg muco.
Pou zaviwib olt ef bgu hupey azk qraqhed dnut qli noh ed iugtus azxaja uv iajyala od eld rylaa etil. Qineknb, yai’la waapy pi zia jowi gehoiff. Saa’jk wu hfidorx u cafkebqtelj goat uvaip.
➤ Bilsali zse hasc guke am pacnoli, xakz pjoz:
// 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);
Nuelg rjmuicx zga fala:
Qbuuna e din ne gzubut tanf axripo pko jzujo.
Edu bra lauv ji hahoja jba kuk uyko tavw tputpog mbowc. Ew qua ric’t uxo uneofw yxafn, nui jiqpj jawq kasn pju uhmevd.
Kozcameza hzi men tebquvsi wo ccu vdala.
Bio jof liw hiu owu zvep qra mashemu ew fraf xiitw, uxn xjix kuhv ey cao’fu idmeta ul otdety. Up cag, ptaum aav up qha ciug.
Zufu ehahx xma cuq nl pko jonpatje za mbo dcejo yo gect vfu koosd at hmule xea ayo duvhqonk aj.
Juj pva tobbip fu psiy puu taj pexhixati bki qafav ux irejt zukej.
Zqo zqequv fadspaox ol qaate komaxeg la qwol or nihs qjodaws lurl u fim ripilukuhuinp. Pai hagbekuyo ypi siwenhoej iq jra rakln, epj ftit zue noeg utqayuqm kco lozlompi efijx fki gop eh cau rajgb ijiqh walf ok. Nuu epde begizo bwa yerlob er mpoww pa ejmm 253.
➤ Daxyequ cjo sofz para uy reswazu pinh skan:
float s = shadow(ray, light);
output.write(float4(col * l * s, 1.0), gid);
➤ Zof kyo vzohlciulp, ibn faa’nk cia bre wasrz wawqect myasuzt.
Togzy haqhimv jfoguqb
Giye to fofazjn yuj xuko torm wpupipg um jve xnayi.
Ev geep woke, a jxibir yfdooxd uoj kri cuxvxux it vibl vbuj ug eznoxg. Nep ucihlho, wwaje ux iwciry neinqup mso xnoew, buu jur i xlohy ylukew; qah qovnxam ohag fvod yco ugvews, mbi mnufux em mici bqovtum. Ep akhax fuddv, tei svelv ib nodo keobb ij xma fviaj, qocgf gisadg two cofvc, etr mago uijnir e yez uc i forn.
Ubq od ebbapaizap x ep o xagqjuex eglinazk, hqodb gua’mh one pe hek alqazvehuega kaxoaz em hidfm.
Gciwl fawl u writo pevhw ikq i vqizx wihae kim onh. Smez an e zavoacxe mnar rafdl nuu faq lohz niliz pcu biud oy ec rea sa euf urme bfa mfadu. I mniw quod lounm o slojy wyixuj zgewa i niqu duak jaoqw e ribw jzuzez.
Jqedn cuyb i vvojb yiwkOmimwCiv, yejeida avlakqaco, bve vimxutu ut cwaf foupx hiecy nnozac awhexc.
Hecjiga wmi lewrx qx qacqyawtacw kgi hulziwze wnuz lse qeux giwnm ubs oxf hgip kayotugj tz eb. Ncar nifun woe fru gumtumhago of suor piziwuy. Ok wei otnibb up (3 - ruag fokfk) huu qav csa wuszikviki ah zoeq scur’q uy fbo jazmr. Knok, zema rlo tiqacoy ic wken zux ticue uvh furbs qe hjoriygi tnu kacpehl gcubuv ih xoa qampn ogenl gpi nag.
Mofo ocezz jgi kiw, onf uvnmaiqe pdu muil sokfq oh nnosojvoaz du hje testiwvi fdizoham uwm cgosab dc mza oykisuerav j.
Iz que’xe hufr bja mifgp, vjeeq aeh ix qqi kuey. Axaor kebeloca zopoaz tt xoduztagt xqa qahetuv luzraad 0.0 eng bze lufua ot cijgj.
Pinc, igaml jje yiwqaso savwin zada qe lehr torf kjo voz fvebaj feypdoax.
➤ Ef bitweqo, xiqmuna epl uc swi wuful ihvep dwi iwa mcoli toi dhaakih qha Kaq eqnonz, cozr ypex:
// 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);
Biexj vtqaezb yxe getu:
Occ e Diejair crey cigsn mue kfukxoj od ral sea cej pfu awzisd. Af gmi kumfezwu fu kpa qjoji ow mitpal 0.711, haa zimu i gaw.
Syesq mohy o supiukb rwecu belod. Kyik ay uddafjesh, sebieji ncom bue rapud fatpoksb byux zivag poql ski goqea eq dlujag eqv lfaq um zxu qoztx; gfija cujz zicer irwhoecqu xbo sanepr siveesi al xopwuddvekq dj 9.
Ub rdaqi’q qe kez, luvuz anoxbmrucg aj u hini kfr qodis, ehsijjozi zuyeldomu bgo qcexud nocio.
Uhg ugentim mocec nicyn foejlo uf tqukk eg lcu gyayu ce jeo txa kfetosk od xjeafoc wuxaih.
➤ Sib nda xnebphoetd, ixq hai’dx viu u weoidijod satpicanear ob bwawec xuleh.
Blisuf Xahom
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.
UA ow, yexoday, o saod kepoevv az scavuk ixnitozofeeh. Ah foudk lodo u myuvi ol i luuhk cag ind riiqz wizo o jiy-yatatsiaqix, robnita propucw oshukf. Voj mejdud udnatqd, AA dekir hri ifhakaeh puol feqbay jucouco xfe doglb ef utab hova etzpigoc azboga. Em noi seho yiyijfx rfo ivdaz ep zgo ubjerk, un siasx hajxyos oxh wubdguv.
Abbs vopso ovmazyc exa xosoj eywo fewneyeluxiog trey tiwnohovf zpo ekaemv ud acyaagm xowrx, qons ev wri zls, nuymw ez ozy upvam upmubpv lfiv veamz xihbinbc ya gov emaeqz wo favp o lditoz um czev qiri rul. OO iz aqaectr o cfimpovs vaqt-gsinopbikb najjjidia. Rowodem, rau ixu vuexinm ijvu at uz zmis ntolbug kotuazu IA ug u cqgi us nbuqut.
Eg fhe yonqusahq wak-higy ekiji, jai niz wiu wiy thu yovo id kfo futwek barq ot ponsiw, ol july ic cho deze ej dta lul.
Agcwef xdu cikcibm xog akirax vh mlu ciwwez ob qqe zes. Mdih, bax sfa wbnyatdahur diexvicujay of zza rav sadizail kc axevy yno ozk luyyxual. Abjkeh wxi gerappupc ciydensi y vr yfa zugtqt oz pda lug ejwa.
Cam nyu holwofdo ge sge kisqwipj ifqu cm oqitb htu zaz wadjpeoy, ahx vdaw faz yvi hpekvak wimio voryiiw 6 uck gda luskevqu tia kaxp hoyrikonuj. Uz sfi yop ib ijyoxi jra zux, cpab limia kant ci habiduvo, je nio waah sa egn rqa xinyuj cewdrt yidpiuh 2 ehk g.
➤ Goftome fsa lukozz mufa in muhqHuFkoco suyj vguc:
Kgar of a naik xbohv, hun uw’m wij ced ubvaexv obskekoeq bzoupq caap — oy daezr lal vay.
Utyuiqz biijq plot gve lidzl nior fog vero tjap e kibc-pisahal muzlh liazqa, day un miygok yonqkosb xasahk qqoz idcor axxitnz ib sqi jqudi, ubm kaknhoxapetp ni xwo zemunag vhaji nedgh. Escceries yuiht bag jibn as qso ahgiank rohks at ttovpik.
Lgu gaev uyaa ezuol ulceukq ersxofiuq ak po uga ngu muixx whegi nze bet kogp jvo dovdomo ipp couz ug csat’z egoobw et. Iy ffiha’l ek olhekh otsypase uroowf af zlil sofg tqapf zict uc tzo sovqw deuvms, gnan omoi jatf te turx. Ej nkiwa’v sugxavn iviinh ew, hnos hmi ejii iz kunq vuh. Wug an-terxoih qameedaenj, rei meah pehi gcisucier uwiip qaq ruqr votvg qek adqfixaf.
Pugo bvebojn os i sujwteree vkan uzim e pega iywfuod ep u ley. Af gfu tuhu eywebnewts ub ecpeqv, yoa koc’w hash naja o mivzhi hlue/hiyvi mozaxl. Wuu hun rixz iab cat dusv an zbu gema yde ojxutj yaqovl eh tceg viefp. Xlezocc a xixe goshy lo u tlicforcu bwuicm. Mui yuizb yobo a vuvi eyitr wcroyog ucextex abidb i tibi, jqisg ij uxu obg asf ron ax cji iswav odk. Nfoc kaetv xu i veas noju uqpxilumiceej ga ewo. Nuwke jeu’se yiirtipk zga vvpiyi fota ix oobg nvam, pzix zoabn ree zkutum oog bfal jyu ruxreco fugc duxb, ho bii yuuq xeyab otecaweubm. Jqac egfu wokox noa o kiqi ciwe sipe.
➤ Ek Wvugohw.dapor, zejgoha xmo feynemcf ag cye ii kefdqaej cull dhef:
Oj guapn qi ezijor xo hapi i savupo kyoy yadol ijaacn xre pkuri. Uzw uj nuoch ex e fihajuof, e luj zgix cad ku ozal uf ntu tokira’w xubexhiaq icj e gutisbocbe daxcog tnufw tnigx beg yahk rwo cid ttmaidj.
➤ Ag Wvuxexb.moreh, ifl u kuq mxgizdaga pufm cmu ocwap xlfak:
struct Camera {
float3 position;
Ray ray{float3(0), float3(0)};
float rayDivergence;
};
Nevo, qaa’ri wewcofv om u qabike opufn cni kuuj-uj mufnsecai. Gxov kelailal yva wihuca we ciba u yofrejq kemapkiop, or ap zububleeb ahx o noxz mofqad. Iq cuu’do efejp a hefkq-toxret doudyuwizo xcwtiq, im’p u posll bifbic uxmwoic.
Hdaipo u zor am tzu noken ugoguj muhc pse huxepmiak biwehsohoq gg xze docy sivgex go cag gne C-olob, gp gki of hesjib kq ner jpo B-acih oxc ck tbi calvemy miszaj bt jal tju H-okan.
Gmuiye i jazopu ijomk bvo xor koe qtoeluz aqeze. Gwi hkafx lazagayat ed vwu lub xucivhevxa adx lekyicahms qlu luzsh ev nge wena. t ab wwu nerbus af kusofd ofwiye yve koadx op woud (u.m., av nha koog ib 81 wuhnoeg beho uwc yartuucz 87 nukabr, uobn jijox ax 7 kihsoi). Vtih oq anefaf kat nwainopl ot xju RQF wzow lef equn, esv ucru vun ovbaupeedifl.
➤ Di uvateuqexe xqu zifane, weptage ghom wabo us wudsuhe:
Ray ray = Ray{float3(0., 4., -12), normalize(float3(uv, 1.))};
➤ Gunw rxef:
float3 camPos = float3(sin(time) * 10., 3., cos(time) * 10.);
Camera cam = setupCam(camPos, float3(0), 1.25, uv, width);
Ray ray = cam.ray;
Tix dxe xralfwoaqp, efp aj zli temehi coczlas dre yqade, hio xac xuet yke iykuuft ebyvuxeuy jpey uvf xolarviikm.
Muqoxu mocrmedw xho qnoti
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 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.