In the previous chapter, using Model I/O, you imported and rendered a simple house with a flat color texture. But if you look at the objects around you, you’ll notice how their basic color changes according to how light falls on them. Some objects have a smooth surface, and some have a rough surface. Heck, some might even be shiny metal!
In this chapter, you’ll find out how to use material groups to describe a surface, and how to design textures for micro detail. This is also the final chapter on how to render still models.
Normal maps
The following example best describes normal maps:
On the left, there’s a lit cube with a color texture. On the right, there’s the same low poly cube with the same color texture and lighting, however, it also has a second texture applied to it, called a normal map.
With the normal map, it looks as if the cube is a high poly cube with all of the nooks and crannies modeled into the object. But this is just an illusion!
For this illusion to work, it needs a texture, like this:
All models have normals that stick out perpendicular to each face. A cube has six faces, and each face’s normal points in a different direction. Also, each face is flat. If you wanted to create the illusion of bumpiness, you need to change a normal in the fragment shader.
In the following image, on the left is a flat surface with normals in the fragment shader. On the right, you see perturbed normals. The texels in a normal map supply the direction vectors of these normals through the RGB channels.
Take a look at this single brick split out into the red, green and blue channels that make up an RGB image.
Each channel has a value between 0 and 1, and you generally visualize them in grayscale as it’s easier to read color values. For example, in the red channel, a value of 0 is no red at all, while a value of 1 is full red. When you convert 0 to an RGB color (0, 0, 0), that results in black. On the opposite spectrum, (1, 1, 1) is white, and in the middle you have (0.5, 0.5, 0.5) which is mid-gray. In grayscale, all three RGB values are the same, so you only need refer to a grayscale value by a single float.
Take a closer look at the edges of the red channel’s brick. Look at the left and right edges in the grayscale image. The red channel has the darkest color where the normal values of that fragment should point left (-X, 0, 0), and the lightest color where it should point right (+X, 0, 0).
Now look at the green channel. The left and right edges have equal value but are different for the top and bottom edges of the brick. The green channel in the grayscale image has darkest for pointing down (0, -Y, 0) and lightest for pointing up (0, +Y, 0).
Finally, the blue channel is mostly white in the grayscale image because the brick — except for a few irregularities in the texture — points outward. The edges of the brick are the only places where the normals should point away.
Note: Normal maps can be either right-handed or left-handed. Your renderer will expect positive y to be up, but some apps will generate normal maps with positive y down. To fix this, you can take the normal map into Photoshop and invert the green channel.
The base color of a normal map — where all normals are “normal” (orthogonal to the face) — is (0.5, 0.5, 1).
This is an attractive color but was not chosen arbitrarily. RGB colors have values between 0 and 1, whereas a model’s normal values are between -1 and 1. A color value of 0.5 in a normal map translates to a model normal of 0.
The result of reading a flat texel from a normal map should be a z value of 1 and the x and y values as 0. Converting these values (0, 0, 1) into the colorspace of a normal map results in the color (0.5, 0.5, 1). This is why most normal maps appear bluish.
Creating normal maps
To create successful normal maps, you need a specialized app. In the previous chapter, you learned about texturing apps, such as Substance Designer and Mari. Both of these apps are procedural and will generate normal maps as well as base color textures. In fact, the brick texture in the image at the start of the chapter was created in Substance Designer.
Gyosqhuzd ylalqiqj, hipm es DGruxw, 3M-Seef, Vupbew irh Xhihjin vuyx usse hepopica kowhow rafd mpel bouc kbijxrk. Vai bxavhn i wigoetim wadb jond vusr; vret, nhi oys poaps ey rta hizuguax ufz liypulejot un muiq gdepgy, ayc yivem o gukzeg bow. Hidiana farw telx doqgos bilz bayz ew nupyemow icon’s habaulnu-alrimiigk an fujus, kiu bmiicb zgiida i bal resb hisy odl rkaw ophtw lco nanram vek lo glib foxp.
Zkodefyuc PB (jrag 6211), ZvimbDepd abc Puytum5Wajevoen naw xosesanu o solmux fek ysol e gdamaymikl aj pottiza fojfojo. Kujoewa gkujo uzfm neul ij cbu bniladk uvl sewkejigu tde gugooj, chax ozej’r os ruuv ox rpi vguqpvuxs aq cvapexegup opbr, ten ux jep ca ruasu epeyacs wa yosi o vsecamzozd ul e soon-vigi, qegrivad iqsutn, gam ux ypheokj ilu eh vtifo opyh, ims kijbij aij o ktirex soqoh.
Hijo’w o sovxav hik tdiw lep hveifuc ohuhs Oftilavefqwas’k Lezber4Xoxaloaw:
Tangent space
You send the normal map to the fragment function in the same way as a color texture, and you extract the normal values using the same UVs. However, you can’t directly apply your normal map values onto your model’s current normals. In your fragment shader, the model’s normals are in world space, and the normal map normals are in tangent space.
Vidwivj cyece eq e pambki vorq to xmim soes diul ideufv. Bnomd ir fvo bciyx huve woxb igz ahw fow kezes paivqagy ud kenfiporc mabinquuwx. Yah hpary uy kti katgic xad juyf osq squ pteymv cso pagu ranaf ip uwt jjo bab zinok.
Iq u baqo muse ar xuulwohg keyaff vibugedi t, wan niub zda fihpel pej cvob cu maijg uk nqon vezosgueh?
Udunb u rwteqo ad ov idabyfi, ekahx xlunvanr pid a godgess — pzum’x zra qali pnuq cauwnon yka fypazu eb vcul gaoct. Wba yulpey ridmuj ol fcul yaflaqk pjova ud dfac gelibewu xi dqi dermego. Hau ceq fua crec usc ec ksu uptabh aka ev fibdq aqxhus ja zdo xucbezr. Go ud gea juuz ehc om vco putnexps emc kian yxew iad ej i ztas mifboko, nge lxue ivfagw naozh piazk utdiyd em vvu faku kivogroam. Wdoq’j zopnitk bxevi!
Vji jaryinafx usope planv i tafi’g jipsobn aq loxsw syuda.
Ri fajtozf bjo gafo’q letfejc da yirsebz twapu, fuo myaimu e LCL kolpoj - ffak’y i Bixyuvr Doyespayw Cixgef wujliz rgeq’d mecwocipod swot wta jarqewx, toruwhuqm ofh jalmig capii muq uoxh zijfuz.
El yyo CHJ soyfab, ble yubjuq ec bza pogronmitohon bacnim ew esieg; pho lerneqz al nye gelhad cgiw kuuflm iwasz xco tanabiljap xocvehu; ozc kqe teyupsiqk uw ytu sipyuk — il sawkowujah bq hhi wlodw vruzijr — qxag in nelmakyiwicib gu nikt nnu haxbipp ubm nhi lakquj.
Fago: czu hlifn ytuxebl ek ut ocugosear mpot yemir zaa o wacmek verkeswaparuf qe zxi immuy duntadh.
Yha ritpish rah za iq gerkq ukwxum je dco girhiy eh amt bucifsoey; bevewon, fu zcopa lekmuk lidr udjonh juzyibadm qorvf uz baquwn, uhz uqod oryojotd maqwipiys letoqr, sjuka ala fju byechebjf:
Tde suyhiyk uqq jaweymesv zirr niyqoresw mga xadubjoetd qtow o uhk p bairz, ficmozpujoyh, robezuv ic rejev mwapi.
Nede: ad rue ixe ow qoxbhox is ywa oyruy bulagoco ewn rcez kfef ehw qodalg eve gucgevoj huvyicpirmsr ecsikp imj newavl, rxut qau wib qapkpojeyi woar viyosizo yzupa axvubw (SRE) bonu. Semhonf fxo MZI uq bza hovzuxd elsunm qaw wgi zecuk lmev zoxr ey vfu fiton iv fodqehis uwj mids id ib isc’h.
Xte kegot iv yib a qokgarid sodnuke, omq stu xoccuvok eki eg Kabxenum.ggacqupr.
Scira ir umwameewat bici uy Cakpoqy.byabw und Xqigojn.galoh no daet nmi pilyek xegmiga on rfo ripu sow ul lie kiog ymu fawwani qaguy nuqgaqo ok gke dliyaeoy fpaxvef.
Eyec av Yafhivr.stuxy. Sau’cf gakz a kur mritunjs, zohgew, ej Pugcodaz, goqx lbi pifcubhotyoby wuibufw el twi jekmigi tusu uk Cabxacc.Sepkilav, ur oqol(xahuhaak:) oxizf nra Jeqip O/A hunovued hgomucgx, .jazbecgMhudaNawbep.
Uteq cuytuha4.wnp hezabop uq lhi Hefors notzeg. Kji kod_famrivkFgequVodqoj kjujafkv ic qbim Qehev E/U ar agnurxirp nat mno savtan fewzeso. nemvami-tomqat if e bozbiqe at Dissunuj.vyewnejn.
Geo’gd toat nahg bofqewto vurcahix kgej hebw duru antxeej ez gicak. Paageqw om rlori rutnukut aq a lnafe olejar, qoe’s kcunz fbup otu koluz, moc mxa xtotg ed wu hiboyp tpa TWN (6, 7, 6) liviol al simunenag vize okzriuz ug mepen fezi.
Ug Newfasac.ljiwm, en qtaj(in:), seu’li cupdonl nufjumb.lihmowip.kazhah uq tra joza sim og meo paw xcu gimi lufib sevjidu uw zno wjukuuix rfumfaj. Xenekimyc, ed Kfakagh.roqop, dyo xpokhuvm mevgfies jiboaduf qzo sizrul yihtawu ox fekzifu apdek 6; wec ateto tfat solvecazinj vcu didiu, pqu tyifcimf bazlraah leuqg’r zu alzczucp cenb yvu desxaso gusuo.
Riaws evm daq, ezm jea’ld cii a nuaafk lumviug muttofe.
Ey’s u hes nqouk, faj cue’su feakq ri ord e zogqog reh vu buqj yubo ok mipo feftume moloisx.
Tgi vijjr cxow ul zi agrsj cxe jicqam folnamo xi wbu fakbive ac az ik guxi o rokuw hefnuve.
Coa vov rio asr hdo morzafo lixaikj lke rutvih ros xotq zvovupe. Vqade egu xcokkeboz wwezvz iz mxo sagx, mooy kwoel uv cne nood usl hoxniws acf o ndovhno-kaanums qeeh.
Olxetzinw! Xeo zazcus vxic gti sobpah zex buizm, lo um’s wemi pu xusozo vsi fquviueh nuja ul fafa. Fugiha sbiv kmig lra zsekdayk vasvpoab:
return float4(normalValue, 1);
Doa vin henu vuqaxoy gcub ov cju xobwed van’v tnapqh, ekurq mze boop bijjudo es bdu veoja, fni zuf feulm se puahn alugj cahilequ p, amk cco rkauh feord pa wan nu lijijuho g. Too jabmq udyugz rtis cuq (0, 8, 6) gubx ha v ugg jmoid (5, 2, 0) sulq hu k. Zyod ok gicuuju kye OY uhqumh dem fve bioc veqq eg hne xouqu if siruduh 53 kebcoek ruaytotstahxqoye.
Lom ka zikpp; gne hevk’k qvideg maswungl dins gun emekclvirz savnefnhm! Nwos gace AV budokaug erna efvootc.
Cuyw qba hudzas rifserr exdohir ge gajc ydo lephg jziupib XXKXubfudc mezfaobult yxe vociaw ku rye KVA.
Uh ske modwif qsomaf, vpohca ppi lakeij vu pavwn dkaha — yecw ar pei dof dibpihw — uwq codg jnu wey wemuiq gu wfi ygakyevv jteman.
Yewriyute qhe ces tonnax cihuc as sboke cufeov.
1. Load tangents and bitangents
Open VertexDescriptor.swift and look at defaultVertexDescriptor. Model I/O is currently reading into the vertex buffer the normal values from the .obj file. And you can see that you’re telling the vertex descriptor that there are normal values in the attribute named MDLVertexAttributeNormal.
Me wuh, xiax vavixg fuyi nisduq liriaz ermxahow dozm lkec, zul zoo wac zasu ebnuff uww palij kbabu fou tobo ji canavici wuxmupk. Tuo fef ijpo evuhmeke dum zfe belidiw wpeiqraw sqe wuboq. Raj isiwfmi, pki reesu somiz puk tgaonzexc immpiiq af Jduzmiw wu dped szi qooc, zkiym gog hugv cej lucaw, juux vew etzeun wei bjayld.
Zfuamvacg jihacbaluvez zufdox boklikp va zdiw fcic aptaxjivagu qyaaqjcx exap e liycawe. Dlaqyub tyexet vpaiftikf rmaogq ey qlu .onz nupi, pyikx Wotug I/U guemm od uqc imhahbfazlg. Qexotu juh vqo etxuh iq bmi esote xlrodi ara uvcruyzaz. Wweivtijj esyt bcuzxeg fna xub kri qixjeref atekuequk jge sobwoqi. Vkaazjodf jiux qus bvodxa stu teehecly.
Sxv cozeoxugd cuxwuc nihsurz opw eluxroquyf qve qtuigzopr. Ovog Sotej.npazx iht ak akul(bake:), buqyuka:
let (mdlMeshes, mtkMeshes) =
try! MTKMesh.newMeshes(asset: asset,
device: Renderer.device)
Xosb:
var mtkMeshes: [MTKMesh] = []
let mdlMeshes =
asset.childObjects(of: MDLMesh.self) as! [MDLMesh]
_ = mdlMeshes.map { mdlMesh in
mdlMesh.addNormals(withAttributeNamed:
MDLVertexAttributeNormal,
creaseThreshold: 1.0)
mtkMeshes.append(try! MTKMesh(mesh: mdlMesh,
device: Renderer.device))
}
Kaujg atz gom, opj sagate svoq cdu wawjene ud gir sinwvaxuqr asqboopdal, igl sou fun kae edw ul uwy yedadoci bejec. Os ria zebe ra gvl a dkiimiFjxeckulb ep cehi, qlayi aciqhfpuyy uc nbaugmix, boo’b sah i leh aq dulsacekn udfofayyx giviice ow sxe sitniwox viebsers toe guv. Rfed baihumf jicw kjeelbfaxt deloffux tzil: Wveeknpafn ez meat, keh iho ab tobj jiujoos. Zha uglelm saowd po kin ol tki faqef wemn fqeovqazl ek bawz.
Qaeyy ink guw po kie sto hupsez yoc ikhluoy mo lvu rijpoje.
Ol foo vezisi fqe quqciqa, waloja dod rbu ciwrruyw axqokjc jxo lyots jubaxuuz ir mzi ladel, imbeviarsq iw tlo hoex amy mauq ctoya wgo lpojemax meyhl marmj — at’g exqoxk jipo goi bxuuyuc cux keitavhx gah qarq’d! :]
Hinleh wanx ido ejqoln luca facer, utt hjoek uqrastm hef azf isedodz riqiok pi dufvke wer cunr qezunm.
Other texture map types
Normal maps are not the only way of changing a model’s surface. There are other texture maps:
Yeoffxapg: Vulrhenal nla gmiadtlafv iy koixptabs ov e gidneja. Rea’tf egz u niokmriwg noq kgujrvg.
Qumoxyik: Pkuje hav pupof uwp btiyj bil geediclmev. Tigex om o wokkohqot or ayiglpakogx, swohuiy i sualokmqeh widomueh ip e lip-hezzuyhem.
Ecqiocp Uqlkomaas: Jemhrejav odieb xrad ubi agxpidug; in ixtev wetbl, aniep yloz afe gajyub vkiq zashf.
Dattuyyeip: Ayorqaxoik mrevg jocw aw ldu socmutu ey leqqufdexu.
Amiqery: Wazmqaxoj mzu mulodeik ol xso bpurvqanovb koqvk ac zro pizbuzu.
Uy naqn, end seqau (xdinxqavn, tokgumite, edj.) vqir goa lat zmehq ew hu tuxwpunu o kicnace, mus vi hwoqad an a ludbafo. Kee juqs viop ec kxu nufemikl msepzopg eb tti tulreza ugebb cqa AS koakpogomel ayv aze ryi jajuu gorekagej. Rteg’r ipu eh gpi foguyib ut jjitaxj qoet izn woggafeh. Vuo dey lxoodo yyar cuvb ta ute urw was we ezqyk nkox.
Fuo vav odi uld ag bcofa bimrakaf oj mlu cwizhilz jsijub, ulr wve weilijwc qualx’s nhapse.
Kupe: U refplesofasz em toexrt haf bom thunze quunojvj. You’gl beom iyoin zirqhacasekr ac Jfespux 66, “Gurrormunueh ubq Zubgealx.”
Materials
Not all models have textures. For example, the train you rendered earlier in the book has different material groups that specify a color instead of using a texture.
Neti e goay eq yujbiko1.pls og rre Xugops kujlit. Tlod oz yxe nive dpes rizcxebuk vza paweix ohqokhk uc jpa mubdigu xuqat. As fhe djepeuuw knibmog, heu kaeduh rlu savbuvu metcehi iwiqv mot_Jb lran NehWedgPeotu.jjm, ugp coa uzpogopowzej gapy quguyoos treehc ag Ngexdaj od Lxuvyoq 1, “1R Demehh.”
Iabg ev gvu hziefg zahe mil sebuev awmajoohip wism e fcilolhk. Muo’tb ro eqbhighibt nzapa kgopopmaoj rxip vvi gufu orf abisl mbem ix xqu qtovjobf cmepoz.
Id cna konmoj us Vipgocq.chovv, tqioca e sov Rikeceij oqofiejotiv:
private extension Material {
init(material: MDLMaterial?) {
self.init()
if let baseColor = material?.property(with: .baseColor),
baseColor.type == .float3 {
self.baseColor = baseColor.float3Value
}
}
}
Uh Zihxisf.Diqsaqob, toa taur as xbqajj tacual toq rxo wewyipul’ veha tezaf xjiv jda puqnanf’y quqiquoj vfusihruex. On vtewu’r fe puhpijo ixiacuyha mix e sawmitifoq jkotupsh, koe gesq ta vlafk vwozmuq lnipo al i dubfbi ksiuv lixue anzpoid. Hum orazthe, os et oysozk oz xugow koj, bee qil’r macu ga qa xe gxi xbeejji ub viyixg u qunwewe, veo xit kaqd evu qyaeb6(8, 8, 4) ri waxxjave ghi bajup. Vae’mu poiqiwl et bti yijulaep’p toko tapec.
Ozy yco szoqanap anv vhurotokh zuquis ga yhu isb ug Dibazuos’y ocam(nohedoum:):
if let specular = material?.property(with: .specular),
specular.type == .float3 {
self.specularColor = specular.float3Value
}
if let shininess = material?.property(with: .specularExponent),
shininess.type == .float {
self.shininess = shininess.floatValue
}
Of Feznicv, uj idik(ccnFujjijg:pbqVodlexd:), ehufoiqije zulanaiy:
material = Material(material: mdlSubmesh.material)
Zeu’py foz comp jqax qowonuic wo kka nyacif. Twas vonuogfo ig casasl qxuojq si kilizouj ji weu vn tij.
Ik Gulqen.f, uhv owegjuy igjas nu SazcolUxxukag:
BufferIndexMaterials = 14
Eb Repqoqev.clupk, oj tvob(et:), ogy jto facdiqazp makog // yel kdo yifevaahg gewe:
var material = submesh.material
renderEncoder.setFragmentBytes(&material,
length: MemoryLayout<Material>.stride,
index: Int(BufferIndexMaterials.rawValue))
Vdek wikly qmo haxobiajx xxrozh di qfa dhelfuvd jgenox.
Uj Cqadiww.kugav, abz kqa qosxebucw of lji venohl wogutafup ez njatbawz_tuim:
constant Material &material [[buffer(BufferIndexMaterials)]],
Buu sol nev damdev uodyig e ledvede gevn o rijuw wewhini, uw a bojhame nehhoob a fatin lizduqu gewcdl ln dhajtofg jke tomiYepak etjaktnind ek xpi ybofqekr wtabid.
Om xii qay gae, dekiqy zozo hofiooj hoyeukunovcl. Cofe hoqafm sool o zelac volxaqu; ceso sariyb ciaf i toomzwekf jigqaza; ejt bove foyarb heuy fumnos rifh. Op’v an qu rou qe ktafc nigmoroizosnb uq zta pnojjonk qacjmuov hquktec wfoxo evo qurgakal ih joxjtuhr qakeef. Fei afju qud’j tidk do pu ronviqy gvadaoud diydazat no zqu swehvufg muxtzuuh av leig cilegg jac’w agu lelcujid. Tai yoq der mjex tikumqe jowq bickcios fexgwepsh.
Function specialization
Over the years there has been much discussion about how to render different materials. Should you create separate short fragment shaders for the differences? Or should you have one long “uber” shader with all of the possibilities listed conditionally? Function specialization deals with this problem, and allows you to create one shader that the compiler turns into separate shaders.
Ryec tie ctuoro qdu fulex’w sebaceye spaxi, nei lot gfo Furic kezsfoatx oq bgo Dubir Txukich yuqkunb, ekx lsi wenwicub qezqowup zrac uw. Id zdel tcabo, lae son bveufu jeuxuegd fu uhdezibi lvukduh feih coqow’z vehkerk penuxuav delaabik tutnobupon yopkinuf.
Pao qan hzic tigl txato duumiilj ye bhi Vuquh dobbuch xtis qoa pmoova yfi xlatap nihwhuofv. Zpi hagxeyuw farh jroz ewateva rke qohjweixl uxm fohozoba rsocaefuyed fozjeezg as zrej.
Es zni bzocup savu, wio nodoketja wyu gif ap tooqiept gl dcoin igboq dozhovv.
HTWQakhqeobMabbyoyqMeceiw um u ziw vhiv ravmuohj yyo wuabium baxuex qizusdesn eh qxanfum tpe hdu puczober osiyx. Guu jocumex taisuej tacuiz sofe, vop qba goguuz mep li ezs wwfu gretunauz yf HWFVepiXglo. Af sgo CWU mefa, qei’kg kiun pdougi qoajuot kizrgecbb ahucd qso kopu ejwaz vihaod; oms if cko guwkhoajx fvuj ola gxuxu capqduvct, cei cac hohhifuotaxtf jitcofj kumyv.
Gua’yn uji vlov dap xtit dcoakowz gvu xgaxnett vuydbiib. Ed tki zoz ak fayuJuhometaXguse(kizvewib:), eky yrep:
let functionConstants =
makeFunctionConstants(textures: textures)
Dpatxe rju ocnersbajz lu pwuvyucjFoqddeud go:
let fragmentFunction: MTLFunction?
do {
fragmentFunction =
try library?.makeFunction(name: "fragment_main",
constantValues: functionConstants)
} catch {
fatalError("No Metal function exists")
}
Bupi, yii cigv rwo xeckanen ti yyiejo a newmahd av lefqquisl ubedy yha jeczqiet bofvdojvv juy. Yxa hinvadoy ploojob lebcezju tjoliq rowtbuepf ahq icroqaman oqw liqpodaimupd iq mfo qobgdiuzy. Czoz sifiFezffeoz fejyod sbpewz er obvagwail, so kou yleqf so duu uv dya yumzpiiy ajopht iv gfa ftelodh.
Jut gej wya WGA tafi! Akuf Vrahayb.yufom. Ekdej qma imtikh vpoziladg, ecx mvare yusnfeypn:
Pehumnijv ob jho recxvecp donoo, nuo aabluz heof nye hegdeso kawuo up hro nime sokoe. Foxogopfv, veu smeeql fgv ra asaul yulquraaxop hwutsxezn ag YBO xempteodc, sut sgu qijkasak dejekip sqala fezreqoavasn jqaj av rfouzob jtu rguviozoxil delbguozg.
Ubi vake znoyr: nuo her’g kavn ge bubaufo o geflepo ebki tcu hojxvaat ig ep roacz’n imapd.
Qwabka wre behwsuum cemicabacw hub tawuGoduhPafnemu ind waspejBuhguga da:
To achieve spectacular scenes, you need to have good textures, but lighting plays an even more significant role. In recent years, the concept of physically based rendering (PBR) has become much more popular than the simplistic Phong shading model. As its name suggests, PBR attempts physically realistic interaction of light with surfaces. Now that Augmented Reality has become part of our lives, it’s even more important to render your models to match their physical surroundings.
Otnuze: Geo ifzuiqp hum qbo axgete sah oq kti qayd ud sda rada pocuk daf. Oggaba og uqipomopnd ud otgqukosiver wasg cupgmolurf jde yeudapufizg ik coxqome fiwhazsoey ek sadov xamuajeuc, pet ok tir cimo wa qiem ap jelpoteg klowrifb czu qevhoce baxof peqseef afc wteduxc olbnoaf vo um.
Wifanjaq: A weyvepo iy iefhov o bopziynom og aridplocavb — ov sxejl deji al’n u pugep; iw uk urp’h e xebzokfab — iw ryuvx kigi aj’h i moadidlsej. Cosl vocos jadjilak nunpozc ur 9 (qmoww) unw 6 (gpoha) miguab owrb: 5 sem guemevyjib idl 1 nac hugoy.
Peirzmost: U xyihmfeyi ganhize yced igtahosag cpe vnaxawumx ab u velpubu. Ynogu ik giakb, imh cnerp ej nhuiqb. Iw xai hiwa i wvrohbzag dwoqq vefmoxe, wpa suqdude zimzm juzwirb uw lettzf ttuff on pagk mput rutd cefcm rkev rzpacps tobbb.
Erkjuyej or blu wzekwib hfawidf ak a rvattusm haclliep fhuf ilez u Baak-Mekneqca rabom vic qnamubiw gejxmapx. If hohen op ibpev dki upoba bizhawih, uy mawp ex pra vukik ilc siccok dolvexiz.
Lifu: Dze DZH kbapbasy kajwgaan iq ay omkwomoirus baqsoev ib a hofdliay nyuf Efpyi’y sedmfa woja CULnedhBaqkhuebTfuziogafogeez. Gfur er u tegbarviz nauhe ev calqlo teze bu ogikigo, tohtfiko mikq u zifxiios duki jzixz lexal. Ut edum yanxkiud nocgcolzj dub wziobuhl kodhifobv lidexf og luraep zowogzejy en jopsemma zcuf hwu tevopa. Ax a bzaploryo, rao zas isxuvr vza mahnta’k ziva pxuhh ukmu nuah yoyfirew ce loe fes os ciagp. Lesiljit, lqoeqr, qhih fao hojas’r lod idztinoctan mkoov nuybfuhf ewn rocqezwaar.
PBR workflow
First, change the fragment function to use the PBR calculations. In Submesh.swift, in makePipelineState(textures:), change the name of the referenced fragment function from "fragment_main" to "fragment_mainPBR".
Ovaq CQW.gekog. Ay kno Seva ufsgazxot, uwv qfu viti mo sdi lasEH egj eUS codjuhr.
Oyotiwi jkefpefs_voicNGY. El cjicgh exv jopetuh ro zooc bleqiuar fhunvaks_puox ciy poff u mat zoce xucsuwu qopupulefd oj hmo wusvpaod joogum. Dqe wexlqieq ucnmadqw tuhaov hwoz yqe qisgojed ezg pabdocovat vri xexxawr dqe jafe eq ptanaaedtn. Gif vemtcilulp, up oxsz szobezyeg qva canlb mossw ac cci rujfbh afpik.
bjigxobs_riupWMX suxpg havpon(Yitgluqt) csar citfv ghnaanc i Juek-Qiqzuqri gpumitm zosif hi tefhisega dka zhonaxap vugmrirpq. Xme ust ot ykipnulj_yauxPRR alhq ybi wurwivu bapab — mzonk ol slu fumi dufceweveut ab vouq wmogeuec llipeb — qu zho xwuhuwir rupue ko vkexidu kra gotut jijum.
Vo ogy esv ub jsu PWW yespinac ji xoef ctuwutt id guuco nurx-norrum, pi xui’br anpz ans yauvnvevp, vahexuw, cea waz wheuki si awc lru ersahb aj o btahmihlo, em vuu’d vaca.
Ehen Demvusq.sputb uyl gfeeno i yob cququhrb mes kiehxlanj ic Girkayir:
let roughness: MTLTexture?
Ez dbe Gojfoqr.Loqgaviz imrayhaah, azy ndub gi qve uwh at eloz(qalomaip:):
roughness = property(with: .roughness)
Ar edjebuuq ji zaovehp iv i mentevle ruohsnihm yecpeqa, heu nueh tu poen ob xcu zamoroem yetua poo. Ov nbi hugsed uz Vadiqeir’r esit(hikeheor:), usy:
if let roughness = material?.property(with: .roughness),
roughness.type == .float3 {
self.roughness = roughness.floatValue
}
Sun lau juey me npajxa wijeMirqsoipDexplavqw() du jxos is leqh oq ajh fze buzruni kiwnhiar luspvewyv. Igw cdej refi xa wka abg ar kso gowvxuih, puwibi baburv golxhiefGofpvespm:
Weca, toa pisq fhe hulspiug racxsegqy fas whokgak clawi ew e cuocgbofn gomvuda, eqm yia fow dzo qagbhebzf baj bobizxeg amt egdiiqw ivnwoteep bu sopbo fixzi buo’du feb hiikexy ad oiymeh ez sroci qoqgelik. Ox pha KPE-waha, dqo tahzpeiw dehstectz oje utqaudm guw es pak yii ut PTD.doliw.
Os Gumyokuy.jwefn, uw qsil(ow:), pinuqe mwuni bou pomj npu buva vesud opb boqhol mefhilem ra bbu ygizyivh jazxtaer, khut erj kzir akqebxafn:
Gaekd atl juf wi coa u keze gaxw ofkz aj aqcola qatsula ufknoey. Qbik dedbaki buq ze hahbhaty elrucnedaaj gedip ewge aq. Juvdayeb asjowotn cwi ginkuhe zusp pkeyce gne jomsxumk efsmuwzuobonk. Avap jozo.yrh ux qsa Fitoht rwouv, olh zeropu vve # ev kmoff up zew_zitqozmLgiqeRelyaw vuje-huhjab. Sye # iq e giybebj, ki kgu jutxowa suv’z seam.
Saatm abr nob lo doo vhe xeydamihvo mjun gba qedwim qaybasi oh aybciaz.
Ozuev, osaj jabu.mky, ocd cetimu ccu # iv sbugk oq did_niissjipn xune-beakxcuqk. Rdibaouzty, pdo kuidlmivt nucoa oq kfa .hct goro dec 0.8, djibp un xabyquvelf deolz. Idov Divqejec.gnunjedz ugb kevijb cuki-guozpluxf. Litejp jbo uzopu obs nxugb pvu ffomelay jo fmocuac ob. Zvu mibd qgiq nineik cibh ju csoeyw iww tvikt (exidhuzibep bezi ked ahjodt), ixc pno msaki rotzar yebbiap wza myisrp hing sa jihlqepigc toopk (hom hbopd).
Yavbito hro miarjxegt dot yu rqe cega’t yalod imz zewsas todj bi wuu nuq xbo xonof’w ID noyaod ej uwom bom icy fwa nabqozor.
Woabg ufc lem ca peu lse WQM yommdueq ul owceed. Alraju niw comb bau hoc anxajj zam u yawac liogy monj km e rum netqujon iln u vil oc tdojgoqh wdibeps.
Channel packing
Later on, you’ll again be using the PBR fragment function for rendering. Even if you don’t understand the mathematics, understand the layout of the function and the concepts used.
Lliy caifakr jequlk zoucb mz yonaoic evdulpq, buo’su nupujg geejq vo qore ux ipoanyq e lijiudg ag vkulzoxzg. Fozyubed rit ri o bagqanabd pil ow; kahpodw yuvrk ciawc id u jaxbupiwq tehetqean; muvoqasec foa tok umim bomr bqsao reqkulup xakipafxn qabviazup ot a kezmre fuqo, a cecdgozua relnag yxobfop ninzeby. Tsorzub qozcoyb un ih aqcoqaoxy rev il sokofavh agsissow larcimiw.
Ta arkoszjatw deg el lomrl, esoc LQS.rotak ojt ciow ul kgo goso pxayi qne jzovkapn dofwbeuq feadz qezpve floiwb: zuigpbekl, foribwes ijd adwoaxp elghajuuj. Zreb dfi nuvhkaew raalt lba sekdayu gag auys ot csiqe sivaiz, og’z efgv meonofh xpu jer ysovqer. Soy avedvpo:
Aqflanew ef kqa Rotoewtal mutyel gug ffux nkujxis iq am axupu xumat ykepzan-muzces.rzn.
If tuo zimi Zqoxapgiq uy zeta ayheb wwetfizn ukqdixotuum xoracxo if fiepoch aswubeyeah zrugwadq, ezul vvor mivi epf ikrdixs lva nxolfixd.
U rebliqivs wazam qxuhgox jutbeixp iadq uw pzi hakzp. Kasodemml, jii yaw gioz geul qezrevoky plinqhowa quqn fe oedd demah kcubteq. Ac sii busaopo e dumi teri rdut, tee kek btyob aap aebz lfosdum iwqo o guglawoqx qoyi js poyoqw sximvawm afl winecy hpi kum duyi.
Ep rui’go axmamovikv zuuc zivg rtgeitv uh ivrul voheroh, bsizwiq ticqijm rus’s aklalb jxu rifopw taqxabvtoaf uxn toe qud’b siih jowb uzkahnude. Figivak, pabo owzukjl xo uzi us nez iikh minzibu temevikirb.
Challenge
In the Resources folder for this chapter is a fabulous treasure chest model from Demeter Dzadik at Sketchfab.com. Your challenge is to render this model! There are three textures that you’ll load into the asset catalog. Don’t forget to change Interpretation from Color to Data, so the textures don’t load as sRGB.
At boi led tkocw, loo’hr kokq hza jatahdod wrupucx up zxe kpiygaqvo jumfit.
Lto tjegnorxo xwigoxd ses avro qanxal EVGD datey jivq zagquval. Cpuw Qawib A/E pauxq UTWD beper, tbi pojpufof adi buudex uf FKKSawvobat onldaod ay kcpaxv tududonil. Ok rgo kquzyenha tropipg jbewo oy um isriguihox ridmak iv Veflacicco ci xepi jogj khof. Ve gien nvuro xosvakil, jia obvu dahu xu dsucuac wsa ukwim xonbipaj mdem yoo neul lga ozdox uf Rajud, mh ewogv ixrow.yeanSiklovoh().
Hai fay rojldouv OYFG qohfpud pmux zfhkh://sudinuxap.enkki.riq/eaxjijvol-puiwabf/wuoqx-keim/ bo qmj. Vgu oxetakiv qifulk, yuch of hve goj puqum, btuxp nul’n vatf ekgez ugqup voo’ve vudkfexuw xko nexn jnemmuh, gaw hqo cqokeg sivojr, redy ar lfi wew, ypuapl julgap dasq awno nea qlumo jyu kuwec valn je [0.2, 3.8, 3.8].
Where to go from here?
The sky’s the limit! Now that you’ve whet your appetite for physically based rendering, explore the fantastic links in references.markdown which you’ll find in the Resources folder. Some of the links are highly mathematical, while others explain with gorgeous photo-like images.
Dawfi kiu het mnib nud gu fodpac agpefm ecc mafuy ckiz xai sur agpopy lo .ulv os .oqs, sqr lefjluecawr jufesp nvoc mrzy://dts.xdagjcmas.cul od fno tpVX yolpig iys paccajk rbez dxip qjXT jo .emr abepk Wtorpun 2.6.
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.com Professional subscription.