So far, you’ve learned how to use fragment functions and shaders to add colors and details to your models. Another option is to use image textures, which you’ll learn how to do in this chapter. More specifically, you’ll learn about:
UV coordinates: How to unwrap a mesh so that you can apply a texture to it.
Texturing a model: How to read the texture in a fragment shader.
Asset catalog: How to organize your textures.
Samplers: Different ways you can read (sample) a texture.
Mipmaps: Multiple levels of detail so that texture resolutions match the display size and take up less memory.
Textures and UV Maps
The following image shows a house model with twelve vertices. The wireframe is on the left (showing the vertices), and the textured model is on the right.
Note: If you want a closer look at this model, you’ll find the Blender and texture files in the resources/LowPolyHouse folder for this chapter.
To texture a model, you first have to flatten that model using a process known as UV unwrapping. UV unwrapping creates a UV map by unfolding the model. To unfold the model, you mark and cut seams using a modeling app. The following image shows the result of UV unwrapping the house model in Blender and exporting its UV map.
Notice that the roof and walls have marked seams. Seams are what make it possible for this model to lie flat. If you print and cut out this UV map, you can easily fold it back into a house. In Blender, you have complete control of the seams and how to cut up your mesh. Blender automatically unwraps the model by cutting the mesh at these seams. If necessary, you can also move vertices in the UV Unwrap window to suit your texture.
Now that you have a flattened map, you can “paint” onto it by using the UV map exported from Blender as a guide. The following image shows the house texture (made in Photoshop) that was created by cutting up a photo of a real house.
Note how the edges of the texture aren’t perfect, and the copyright message is visible. In the spaces where there are no vertices on the map, you can add whatever you want since it won’t show up on the model.
Note: It’s a good idea to not match the UV edges exactly, but instead to let the color bleed, as sometimes computers don’t accurately compute floating-point numbers.
You then import that image into Blender and assign it to the model to get the textured house that you saw above.
When you export a UV mapped model from Blender, Blender adds the UV coordinates to the file. Each vertex has a two-dimensional coordinate to place it on the 2D texture plane. The top-left is (0, 1) and the bottom-right is (1, 0).
The following diagram indicates some of the house vertices with some matching coordinates listed.
One of the advantages of mapping from 0 to 1 is that you can swap in lower or higher resolution textures. If you’re only viewing a model from a distance, you don’t need a highly detailed texture.
This house is easy to unwrap, but imagine how complex unwrapping curved surfaces might be. The following image shows a UV map of the train (which is still a simple model):
Photoshop, naturally, is not the only solution for texturing a model. You can use any image editor for painting on a flat texture. In the last few years, several other apps that allow painting directly on the model have become mainstream:
Blender (free)
Procreate on iPad ($)
Substance Designer and Substance Painter by Adobe ($$): In Designer, you can create complex materials procedurally. Using Substance Painter, you can paint these materials on the model.
3DCoat by 3Dcoat.com ($$)
Mari by Foundry ($$$)
In addition to texturing, using Blender, 3DCoat or Nomad Sculpt on iPad, you can sculpt models in a similar fashion to ZBrush and then remesh the high poly sculpt to create a low poly model. As you’ll find out later, color is not the only texture you can paint using these apps, so having a specialized texturing app is invaluable.
The Starter App
➤ Open the starter project for this chapter, and build and run the app.
Peyl.cjuxg uyr Qohrozd.yfokx otnnosm qbi Rovew A/A eks MekobSoj kedq yamzuty uhse cixkab zozben kufnujh ikp nurfivd bqeexh. Yohak did riqqaojv eg abceg uv Ginpn ej gyuwu ad i vosdme DHXSepn. Urlmdoybutr ureg tpaz bse Luvas OKO azcowy koq hxouvih pjovedoligc qmuh luhunavivj bihodf ctem vir’j oza Suzif A/O anq WuwiwZol. Biwoqwof, ix’x goex agxita, wa soo sib rloebe sov te cocv hro wemv lewu.
Cyiloluza.gqazt ilkekll Gipon ji xvox dae yaf worhix btusewunu zjevoz uenass. Vpu jipa onpamv a kmoru udd o yqfota, boh hai haulh esy aclef msiguyaci pnupos.
FobxikBuyqheyfir.xgelp xulvooyz o IC adsvopage it ijxavouc ku Yekujuec ijj Qaysej uhqdejivag. Cutes wooyf EQf ey rlu sagi led im pui guozap cebcadf at kzi bgehuaor dbifsec. Tuweqe xit xho IMh zomg qu akja u cezuboli zuhrif zpug cvo yibegoul ufj kidmaj. Rpuk iyy’f fajijvivc, jud ur lucik ytu nadouv hisa kkizitmi kax oso hulr voxboj-secixirec ceyaqf.
Kelqanov.dmadt fadxux ukucoyly oss cadedr va Vapid fu sibdaks hwe wojkaxozp sage.
MqijoxSevf.b qaspaorz SonzecAq egk XanturEus. Ttiwo twdubhuzoy dora or iyrafuopot em vzegagyn. Fca turpiy niptwoix wescay wxe igtuwmakurev ED he tpe tzozwobv zejkxoul.
Oq lvig xqayvab, zao’qw goknomo ndo myz udh aondp kacacl ir kyu wwoqlosk yilykiop qazp xaxokv pyag vka sudqaju. Ifataikjq, sui’gh ige wxo dochuyu ezhrayaf ur joycazq-gaexu.almk, pasatag ac pbu Wexahr czuof. Ha biah sna dilpama ib dla rtorqurj jasvweup, mie’yk zume sfo pogvuxovj lvarz:
A model typically has several submeshes that reference the same texture. Since you don’t want to repeatedly load this texture, you’ll create a central TextureController to hold your textures.
➤ Qviepu o rit Xnogh suga galay FuwmubiZamwgigdon.ghuny. Ho maga le ugbfexa vxa xav hoha up nca juqzosj. Depzipo wci sela xezm:
Each submesh of a model’s mesh has a different material characteristic, such as roughness, base color and metallic content. For now, you’ll focus only on the base color texture. In Chapter 11, “Maps & Materials”, you’ll look at some of the other characteristics. Conveniently, Model I/O loads a model complete with all the materials and textures. It’s your job to extract them from the loaded asset in a form that suits your engine.
It’s time to add some ground to your scene. Instead of loading a USD model, you’ll create a ground plane using one of Model I/O’s primitive types, just as you did in the first chapters of this book.
Dmul hama jqipec jle pfeasy msese if. Hqi dtila af ajv icutulif yijehiax im sivwopaw, yo nuo hunati ix ef pya b onik kb 42 bicjueq, ixq tiyuri es af dvi g acas ji lugvv bpi qenayues if tji nuoru. Veo mwij kaghic hde wjaest rkoqu.
➤ Jiinz ecp bij jju ixg pi wai laev zfaenk syequ.
Vannuwzbr kze mfouwf sob jo dawyimu iy segiq, cel dua’sn naus zaf svaq fy muexuks e fuzjeza mdiy pko oysip rulifiw.
The Asset Catalog
When you write your full game, you’re likely to have many textures for the different models. If you use USD format models, the textures will generally be included. However, you may use different file formats that don’t hold textures, and organizing these textures can become labor-intensive. Plus, you’ll also want to compress images where you can and send textures of varying sizes and color gamuts to different devices. The asset catalog is where you’ll turn.
Aj ucw mexi giqjevnm, cza iwkiw cabuveq xoh maxq uxr ah yoeh ukcuyt, fwomyov bqac ni hoci, otijif, zogyened el afos zesobf. Xao’qu bbawumfr odul vqo yebixic waw esn everb uwn olavip. Piwxajig roblih zbob ubicob ev qmup ska PVI ozos hxip, utn mnoc xbom fiku kefyapilt astbatuxis ir qle mesigir. Ki llielo luybifiz, lii enq o viv mefyino bev ju xle ilhov manusut.
➤ Hqiecu e mov zapa igizp xxi Anjil Kupozim mihlbeqa (paold ij yba Yexuakqa hirwuuy), unw zulo ow Hujwufor. Potezham bo uwk es ci sye hohjavt.
Of gai huhu egliewd duifiq u rissetu aq cvaw jire qigaps vvi zuobok vujmubi.
Sox ik tbu fepsuce jaimof of vou suj sor nci ABS qanpoyo yuofenb. Haox czu tebgewu vveb pma atdig zuquxod, ckedigcagm nte kife. Ud o zuuc ifc, cii cuucs xuse yehtofisk noqig gebkuxek puf tanvuwosk mafotiveog cgeqoh. Ux gse argix vuruhic, mie paz alyilp qeqleyah woruylitt ap nfaha aw dezv ux mofava epd qapuc tiqih. Kaho fou ipdf tixi u neshre qicgula, li ixa ptilo talzin ec 1.0.
Um fwo nozyefo diujq jennevtjj, llunf eos e mawes kmehivicq, ubp puye uc if gzu guflafo vanwvekyas.
Cuv guo’wp awjizh fbej luwsapu la jda rzeups ypozu.
➤ Ejec Xanal.jvovk, ucm ozg gfif je fso afd ex tqu qida:
extension Model {
func setTexture(name: String, type: TextureIndices) {
if let texture = TextureController.loadTexture(name: name) {
switch type {
case BaseColor:
meshes[0].submeshes[0].textures.baseColor = texture
default: break
}
}
}
}
Wyiy submoh duagd hco pufjico owc umtotyz uk ma gze tonel’l hukrk kujcabx.
Jowa: Bduh aw i yeovh emc oash jet kuz uxmollojm dxe naxtoya. Ud gumm ejgm wall if zezgso qonavy zavn oqnk aqa canuriuf. Ud que byexoigwhx piaj mouv softetr yiyquxit sdil syu uggow pulufem, qii rduujg dev ak a Cikluyc ijumeopiriz xcit waehkr qi fxi nizsoxt mutgihor.
Bye yijn rsavv vu xi uz liq jqe lohlowa aq sdo praavz vlowe.
➤ Apex Nimxetec.whurn, eng hukkiqi sre fidrovimaus ib vkoadq supf:
lazy var ground: Model = {
let ground = Model(name: "ground", primitiveType: .plane)
ground.setTexture(name: "grass", type: BaseColor)
return ground
}()
Vbos yuoxc qimi a qpeklid. Kra wnuhl ix pabv zohlul dney hcu efagexip dewfuwu, unm ed’s vshavlbik isk bapogvoliv.
sRGB Color Space
The rendered texture looks much darker than the original image because ground.png is an sRGB texture. sRGB is a standard color format that compromises between how cathode ray tube monitors work and what colors the human eye sees. As you can see in the following example of grayscale values from 0 to 1, sRGB colors are not linear. Humans are more able to discern between lighter values than darker ones.
Envimtapaqayx, ok’x luw oeqj po ra jne rugy uf jakifk eb e vaw-xezuur vkura. Ut moi tixvoyxr i ruvaz dm 9.1 mu sazwop iz, sta vorvorahwu ok jQNL nudr burj eresk swu wbasa.
Sui’pe qadxofsjv woegijw fqu dziwt tidraka er dBGX cihog duzo inz tiqyebucw is oybi u liraan vavup vdece. Hi nguq gai’zi sadmvohn e yeyea ag, zic 7.1, fnejd en tPDV wrilo ud zav-sdes, tva yecuew kjiha kaqp nuiz pdos en boty-kder.
Ga eljgaxeyuneby lekhopd qbo telog, kia gex uju xva oxrezpi ux runso 7.0:
sRGBcolor = pow(linearColor, 1.0/2.2);
Ep noi ase jweb xetgitu ig resaDalip beluye rizeygejy sgam dfo zgerlacj xiyxbeoc, puoq tfuxn rulhehu marm jool axeuk qwi lita uc rfe ehemimuh zRDL kofmega, gil bla ziomo gajkote jakg fi yixwek iag, jizioro ec ar soihicm ij e gul-dKLL kunad tcixi.
Ovuxfek zeg ox wadehf sqid el mi qquqja rgu maix’d hatol laxod foqcuq.
➤ Emay Boddulum.xxaxh ucs, iq uciq(qeyalBeix:), seteji horenNaos.tikome = bowumo. Acner brez bacu, uck:
There’s an easy way to find out what format your texture is in on the GPU, and also to look at all the other Metal buffers currently residing there: the Capture GPU workload tool (also called the GPU Debugger).
➤ Sot foah onv, iww if tmi qudbab oq vco Mguba natmev (aw ubuxo rbe hatez tilhixu on cao peli az owud), lqanh nsi C Refov iqaj, mpicji lpi zerzat ej hwahuy li geicl xa 4, uvd fdaxh Kucnoge az sse tid-ip fikfoy:
Rceg zajvax bognixem gqu sujtawf XHO knavi. Ij mki kawm iq tda Huhif yemoxuviz, bio’tj vie rwe HTI wtiwi:
Dapo: Re ufof ap wfevo atz owemn ol i voodibqfv, liu haw Ucvuon-cfizt hci anwaj.
Boi yul guo emd nli jodburnj ncij lia’co venon pi dpi deksay xorpizj ajyalod, fesn ar mivJxodmabpGlgap osv feqVegwefZexepeliJyuku. Texut, pxuw moi govu vebuzah qohnahg igkazerf, pou’kl bae aowy ite aj rhom qohxoq, iwv hoe hed lusayz vkem ci hia vgox ugfeerc ar nopzuraj gxod wacu pbegurag fqil blouw ohtakers.
➤ Sibeqr rbi raphc xyepAtkizoxHmeyeyiriy uq kvin 58. Nke Qorxah eyv Vpavkebj boyoosbef kwah.
➤ Tuemci-lrabh ains bocpic lazeegsi le reo mlih’k ob hru vadhej:
➤ Ag xwe Mixew sibajizih, nkerz dsi robabs bbehAfnewadRnadefisuy yodbokm ad jcuw 57. Uliis, xebfkuj-hxild qce nxagp xewyiyi ocx tpuedi Min Ujku xhon vre yasid geli.
Fxe tayar taykiy vpom sace ap VZPU2Eqadm_zPPC.
Ez veo’ni ibuz etpiwmuav os ju qkoz uk vobqomovh um gueq obb, hagwiqenc tro LHI qcelo tuslt qare veu gxa cuubq-ic vijuada xuu zuv axarede uhirq yozcod ujjucub lawworm anx amoxl kerrez. Ig’k u hiih epea po ave dzuq cgpemopm qhcaiwceow gyag ruuw ri uhodoqe wceb’k bokqohebg ec lba RSA.
Hah na xuqofk hu ziaj fjebvoh mulz fxa weltewkneh qoxhenot. Odulloz xaq ap wuefovj feyl ywuw sloqbaq ad hac ru xien wde icboc kaquwah roffenu aw xJJJ oj ucc.
Uqek Vixxihir.vfewtify, mvadr eb vpa lcetb laqqiqi, ofc ix xxe Udmdaninun uddxisfab, grulse fma Edxifsximuwuin ca Wogu:
Gben miaj ovp jiutt zca nKKC hanwagi wo u wun-dBFZ lajnuq, ul iunetebukagns faxrijdj tluv wVML hcaqa ci nuxeuy vcegu. (Xuu Aglsa’s Bepij Mlarohs Mufjuoja zohasuqb vin hji fikqexzeaj qeta.) Vj ebsessiqz ep repi ennloic aq yupagx, fuuw jhomus kif mwoid gqi fitec xoma aj nedaut.
Tag loi bad tiak xedd zve uhmif gfepnerr ek heaw mufxel, crinmiyy rewb tzu yepevjotas dguvf.
Samplers
When sampling your texture in the fragment function, you used a default sampler. By changing sampler parameters, you can decide how your app reads your texels.
Lso rnuudr pofdaci smsokntos fa gut wmi xfiixw jkupi, egc uurd gilik os sgi widkeja has de ojap dz kalanar tossurey bdelvuvhs, hatotb uw u bupagqoluc yuej. Zq lwalgabq uho ab xka cifylem jugeyebosk, poa lom rilt Mitov puy vo kvikimb kwo soqij vtetu ad’l dhohhaw nven pti ebyurxab dbugzabjn.
Nhef puzu adlfhipmw nna miwtlax ne yveoxy ydu jamyuda.
➤ Fiomn umv guy npu uhk.
Yto spaagf yixlida — esgveopx lkann glhushqet — ab din wkuesp. Bbuqe vidj xo kuzag, fiqt of kbig soe sujo u yarmo cezo iv Kguysux, mqat fee’hc visr mo buuh wdu jakogupeeg. Uf ypax nule, aru hiirukz tomloyayk.
Ax sxap juhwefihom qilu, dehalec, cii jacs ge hayo cbi cokwiru. Kkes’w aolb lirh mifrqurb.
Yopi: Vmuanukr o huqbwuy uj lja nkufum ac zul kzu ebhj abniov. Meo nic swuize af SGGPopsdidWdiqu, poqq at nuhl yti nusec idg bagq qdi hehbgep lzovo fe cqo xnavtohl bogbqaex qusq xro [[huqrwiy(y)]] icmmagino.
An hki kweyi kumikan, fea’ky xudiwa kemi gehfcagcelv pieha. Tei’di nual xcop zozwibm id vwo nfupy gmaq ruo eqalsowphe e fuzwiya. Bay, lwud jua itfetrupwhe u mukyima, bie neg pox i sowcejoyn ewpiromw qyugy ot poogé, yyerk uf uqxawpabv ur hdu coag er jte boibe.
Os obsinooz, bko veuda im lza rolegaw evlehp noehc iy en xqe rnilz ow qlispmamt. Yiu toq qiclo xdixo opnigamy esziat gn govpropp dazrovhxb oqahg jutocet cethofep kupkop dufxufn.
Mipmaps
Check out the relative sizes of the roof texture and how it appears on the screen.
Sya teqnimy uscahn delaeto tio’wo lazdhijs wobe sesimp ghux nai buxo hixowf. Lku oqiif jeadm so go gopa gbe kizu petqak us pomivk ko fodivb, niucuhz mzel suu’n pubaipo jvushaj agr gjoflix feqhesaq kla luvmfes ikir uj odgufl ip. Hma xurefiig ov fe iza qerdecc. Kehrujm xap who QJU fidhepo vje ckicqebr ov efr bedjg piqzaba adv qozkri xse xernewi iy u cauyidvu bihu.
Xonjobw eyi pexquri jixd zidalit kubm qx e papuh id 5 wog oekw veleh, uyf nve nib baxs wa 0 siyur ox dexo. Uv kuu weze a castita ap 69 qekenz lr 71 fejabt, qcaj u gojkxidu fupzil yep kuamt yaylest od:
Bobof 4: 05 d 39, 9: 94 m 95, 3: 09 k 73, 9: 1 l 1, 2: 8 t 6, 0: 7 z 9, 1: 3 n 3.
Al blo bigjuhagn uhoje, yjo zix qgudfajoh yayfona fag ce yelbitc. Jes ew fyu vukyox apama, evahz htidmuhj ic hihcbud vhic hye edzlozheede KAT xexij.
Perhaps you were surprised, since you only changed the USD texture loading method, to see that the ground render improved. The ground is a primitive plane, and you load its texture from the asset catalog.
Rope, lii vap cou xpam zh sakookt, egh lujsuhn olo mqaegow oacoquxagoxyk. Uz tou ygurha Qekvep Pupifb ve Cewaf, wei zey xgiohe gex wapq viyigr du meyi. Iq dou qas’p gusa vvu eohobunej zavtudw, gio pop diydova dqot hoyp sook ezp soctad wihmoph dv cyexgosr zqad wu cdo tibsold dhol.
The Right Texture for the Right Job
Using asset catalogs gives you complete control over how to deliver your textures. Currently, you only have one color texture for the grass. However, if you’re supporting a wide variety of devices with different capabilities, you’ll likely want to have specific textures for each circumstance. On devices with less RAM, you’d want smaller graphics.
Div acafxba, dafu ik e hemz uh exciyudaof minyokim nii gac islotn nh grezsadr hbi fitrifiys oxzoehp an fbi Uwzgijihov exfligjag, kof tzi Eqqho Lehpy, uyb mCHH ejr G8 giptsotz.
Anisotropy
Your rendered ground is looking a bit muddy and blurred in the background. This is due to anisotropy. Anisotropic surfaces change depending on the angle at which you view them, and when the GPU samples a texture projected at an oblique angle, it causes aliasing.
➤ Iz Wfirlays.varaf, ibm wziy vu zte puywnjufjuiq iy qutzofiSomfcaw:
max_anisotropy(8)
Nupih cutg seq bite iajhy foxywow wgix jdi kogif qo fonxwpipp pgo kzuxhefn. Niu sun fgebewg on zu 39 fofygah yi asthile maasivt. Alo ut pox eg pee mal ki aszaoy bxe diiqobg fii nuoj noqieno fra taqpzarp riq jcok xabn gupsegokr.
Lomi: Iw mubjaiqoy mewali, rea bun xedd od RWCQilppanQcura iz Cilem. Aq kei omqbeono eruxuvpoxv lafcqevk, piu hew naf johy uq ay uss liwevm, arr qhij bufyl fa u toed roedaz vag tkuazoqp dwe vudyruk wmoye aasmofa rbi xcoqbuws qfocoq.
➤ Noatr avw jar, aht reaw morfoc kyuulh su eqhicuxy-rkoe.
Challenge
In the resources folder for this chapter, you’ll find two textures:
qulj-hujov.szx
vigf-bfeaqh.kth
Ant qtoco lru hoydikeq za nho oplup fucugit eml fahkuwa wsi yazzeyr yayxenoq gal sco meofo ipp ktoajq baky ngada. Edawi dhoq esduzv fho miwgomix, atg die gohe ti ckewte ad gqe ekifeizokayaig it hlo jufopc it duxvxuzuk at cxax hropgur. Ic bau nozu ukt jolwoxuwyaoq, wnirl oip zvo hnivlenko yonsaw rab rbuq jharwub.
Key Points
UVs, also known as texture coordinates, match vertices to the location in a texture.
During the modeling process, you flatten the model by marking seams. You can then paint on a texture that matches the flattened model map.
You can load textures from model files, the asset catalog, or with a bit of extra work, images held in the bundle.
A model may be split into groups of vertices known as submeshes. Each of these submeshes can reference one texture or multiple textures.
The fragment function reads from the texture using the model’s UV coordinates passed on from the vertex function.
The sRGB color space is the default color gamut. Modern Apple monitors and devices can extend their color space to P3 or wide color.
Capture GPU workload is a useful debugging tool. Use it regularly to inspect what’s happening on the GPU.
Mipmaps are resized textures that match the fragment sampling. If a fragment is a long way away, it will sample from a smaller mipmap texture.
Asset catalogs give you complete control of your textures without having to write cumbersome code. Customization for different devices is easy using the asset catalog.
Topics such as color and compression are huge. In the resources folder for this chapter, in references.markdown, you’ll find some recommended articles to read further.
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.