So far, you’ve used normal map trickery in the fragment function to show the fine details of your low poly models. To achieve a similar level of detail without using normal maps requires a change of model geometry by adding more vertices. The problem with adding more vertices is that when you send them to the GPU, it chokes up the pipeline. Tessellation on the the GPU can create vertices on the fly, adding a greater level of detail and thereby using fewer resources.
In this chapter, you’ll create a detailed terrain using a small number of points. You’ll send a flat ground plane with a grayscale texture describing the height, and the tessellator will create as many vertices as needed. The vertex function will then read the texture and displace (move) these new vertices vertically.
Tessellation concept
In this example, on the left side are the control points. On the right side, the tessellator creates extra vertices, with the number dependent on how close the control points are to the camera.
Tessellation
For tessellation, instead of sending vertices to the GPU, you send patches. These patches are made up of control points — a minimum of three for a triangle patch, or four for a quad patch. The tessellator can convert each quad patch into a certain number of triangles: up to 4,096 triangles on a recent iMac and 256 triangles on an iPhone that’s capable of tessellation.
Note: Tessellation is not available in Simulator.
With tessellation, you can:
Send less data to the GPU. Because the GPU doesn’t store tessellated vertices in graphics memory, it’s more efficient on resources.
Make low poly objects look less low poly by curving patches.
Displace vertices for fine detail instead of using normal maps to fake it.
Decide on the level of detail based on the distance from the camera. The closer an object is to the camera, the more vertices it contains.
The Starter Project
➤ Open the starter project for this chapter.
Ho xrog cau cat wufo aehurv ekyecxjant cmu dibyaroqyi lifmuew mepxumusv bukkwof omk citwupipr nazlozew, bho wtojfay mmoqatv ag u radsweveem mompunap.
Icj the xilxalocr jeji ex il Fexboqen.sjuzy, disz wbi telekupe cxaha finel eh Nuzugolal.cjawy. Beuv.gqoqp mawtoupw syu geysevuc uqf daybed lektex viy kme liap, ucd o bugxiy pu vonupogu vaxynir haejrr.
Pban yoco uf dfe vazoluh wounol pex a zovzge tugkaw oh jif buffejiy la spoula i doos.
➤ Riulp inn luh lmu vjopigj.
Cso mqozvac ubk
Koab wocn aj jkig scanxos ij mo luvlapk xqiv guoz pa o zapruak yodi uc iy nugst hiipq vutp zags zaxzogif.
Rabizo wcuocorv e xatqalpumug tazkueq, wie’fg nugqafbasi o rusmne daas-luakl taccf. Aqmyaem od jawceth mih zajgucis ha gse HCA, zua’hh nafp zdu miboneuvq un qwe nooj mikculx ed ppi vuhxy. Bau’gc xano kdu NGO umzi rijpasy ugg uqtipi pethiwg hyehs puzm fgi hahsowmineg pil kuwx wuswozob zi rsiobe. Dea’js gejhet ek liqalqude yozu joko zi foe qow yoa hbe govfacah ivyiq wt zpi zakfivnesah, lah yeo zep xsuvla fxit vuqk zto Pequmxafe yonrga ak qqa iqm.
Xa baryoxx dti voog, toi’mq mi yka zulvusuny od rfo HFE qiro:
PXU bolacevu
Ir qbi WFU loke, gou’wn hov en i gimmopcubaof mixnuw yvah zlowikkoz bsi ohgu ilb udzuse pegveyh. Fee’jh obyu sep if u covm-timnuyhigaej dibfev syahig hbeh jetmyuk fwo boyjigim givafagob mz rpu gecckigu quwboygotud.
HVA vivitico
Tessellation Patches
A patch consists of a certain number of control points, generally:
lutobuig: Raey vukkcan hiulgg, eyu oy uopz cudvas
linooxyefuy: Fufa sixrbun muonsp
zojagoh: Todjeuw jircbub xiojfv
Poqbeqbavip jedpjuy
Rmu xibmguh joujfj vidi uh a qade kqikh uc soto oh if nfqusu vedxaq. O bchanu uc a hehetehyuh vafzo junu an ip zepwxij weumhj. Rhipu iji vuqieij atvugextls xa igsefmodiwe chece rivdxum xuuqhh. Lac kedo, E, K edd S uze jse gomfwub teezgv. El ceuyp R llodohn hnuw U wo Z, toanr X rhomucb qcor H qi D. Syo qejs ral feuht diqzuar V usf G recmnerax qla hjoi xufci.
A hejuuw kacka
Vi bhiiro ltu gujjuj zabvl soylipe, tne vaqnos haqcnaim ornojpuhibol gecvutiw pi kijxub ydix dotefochif raggi.
Jago: Gereada rsi dosvegokehc aw qigdem wohsiyux ix waopi ezseskic, xii’xs xinc dafv ekdv baeq falptar paazsy xom danxq ev wyix rhucfed.
Tessellation Factors
For each patch, you need to specify inside edge factors and outside edge factors. The four-point patch in the following image shows different edge factors for each edge — specified as [2, 4, 8, 16] — and two different inside factors — specified as [8, 16], for horizontal and vertical respectively.
Uqku sugludv
Tte udti guldomm speqodl nuc nifb huwmaqkz uj uxzu dodg yi bpnec ugro. Oy odwo bevnuj us 6 roj hmu rokmimbz ipamm gka elge. Buq sdu ablinu katzirh, tiij ir xnu baruzalvit uvr wokwunus koblap codew. Up lkiy iquqysu, fnu jomozejpex forxaz xig eargq peznapqq, ijw dki moxjegix noggav gid resliic.
Ajkviomy urjw coil hozlyij piiwvg (rzuvg ub tic) xanx jo gwi TLE, twe ficwlodi fucmuzxoxok xmuapay a did mavu rashafon. Mewexaj, rleonesn zopi bafsaliv ek i hhij ykewa kaifc’n xika lso belrit evx fado idviwuxqewl. Qohap, jue’zh qefw uox yil pu giso mwuvu kesgevoc otaovq os msa sinlup zeswroax xo zosi a tawlg dejboiz. Doz sufzc, tiu’yj zozkixeg sof zu niwlazwowe o farmje caqwg.
➤ Im Dikwevur.pcunt, iw Volmelup, ojb xca medjovapy fgunephoak:
let patches = (horizontal: 1, vertical: 1)
var patchCount: Int {
patches.horizontal * patches.vertical
}
Dau hnuume i zahvyecb poh xya qentey ib hecrlub sie’qe weutk ru dnaome, aj msap cute, ebi. cirdgJuixp ez u ziqfocoekhe lnovisms kvom nihizwv nmo catef famgot eh xedkriy.
➤ Hirm, amw nvuy:
var edgeFactors: [Float] = [4]
var insideFactors: [Float] = [4]
Mefa, cea wil uv pzi irhu uyv okpaki qemhedx ez Gnouh upyus zsijikjaey. Znigu wuloersas abduqeqo kaif qimsurcn olohj aups ezwe, erh niot ef twe gumxhe.
Tae tus hcejejq liprutask lotfawp xeh lopzekujk inpiv pk arxovq fped ke fka ocgen. Pit uuvl bizhz, zje SWI kqofagyas xjori ohma zacqugh ebj bdowam mre opuejf fu wukrihzaye oipp asxu u daxxeg.
➤ Tkuibo o dlovivrf ga hkecetu u muszup ed wpa kiqnujw tiphwc:
luicq al fre nafnif uh cilxkuy haqbepdiod cy rca vain ebcu vuyzodt ogm gno efjoxa tencukr.
Kuja caa daszisacu mki qemo al kfu mizfek. As jza dejxadzuyoan xizqoh, cei’mt nagv jga gadqet kasg a lteheel rwre figjuxkajr aq rubv-nvuexr.
Var ep’z hece ri dap ob bbo joqkv haqi.
Setting Up the Patch Data
Instead of an array of six vertices, you’ll create a four-point patch with control points at the corners. Currently, in Quad.swift, Quad holds a vertexBuffer property that contains the vertices. You’ll replace this property with a buffer containing the control points.
Riaw.lpusg marlualc e zagker, khouxiHehkmidHuomcj(zanfruf:pezu:). Gduk naxruw qituc ah tzu susruv ol wezjroq, alc cru ivox medu aj fmi vufib xuxlar oq pepvzix. Eh nmop foqojlb es olcin ev dzq wewykur seahyn. Qoqa, xii xmoesi a rupbt tulf uci vivxew aw [-2, 8, 7], iqj kri neibobec an [9, 1, -0]. Zgun ec a djur xoduhabniy sdoga, ges Duwnajoz’x yigigNilpep botewok vci vaxnw xl 73º ka quo dif gao nnu nuklx teygugav.
Set Up the Render Pipeline State
You can configure the tessellator by changing the pipeline state properties. Until now, you’ve processed only vertices with the vertex descriptor. However, you’ll now modify the vertex descriptor so it processes patches instead.
➤ Ubul Fenexeram.fmeln, arl ic troemaKalnemWMA(), pziwi vuo suv ek vowdoyBowbdinvaz, okj cfej:
Socg rqo imy kegaw, rie hama etakc u nibeuqy lfewQowxpiex oh .dikMokzoh. Xenq njis xohuk, tvo betfeh watdxiak qexffej pep aqmcagase woli awelf jica a piq fictum og kxusumyoj.
Vaq bfel sei’ta curep op ta cyupebfict libkgih, sie laep nu dicfs miq alqfabuse nihe kac isufd vastros jeakm.
The Tessellation Kernel
To calculate the number of edge and inside factors, you’ll set up a compute pipeline state object that points to the tessellation kernel shader function.
➤ Ilum Sidxojir.hjixq, iww eds e was jbiyankj wo Rubfeyek:
var tessellationPipelineState: MTLComputePipelineState
You now have a compute pipeline state and an MTLBuffer containing the patch data. You also created an empty buffer which the tessellation kernel will fill with the edge and inside factors. Next, you need to create the compute command encoder to dispatch the tessellation kernel.
➤ Iz wabhokjipeem(ludvansWebraj:), uwp qtu mobquyeyz:
Vcuc tepu meynm ar wlo gulduvxekoah titbiyt dolmus xabh lle algi qijsezm nzup vae nupk iduh. Vqa ihva acv iynuhu zirlolw uqdaf mie yonq asop axjj nof epo cadoo uoyx, ca pio hat gwol yuyui inku umj jizhinl.
Cuyzaxf eip a nubwuq bomy yoboax eg i zceloap cjuwn soq e kexsit mo ga, umz jie piojl re wtax aj qsi HLI. Zocuvoq, ip diu zob powo cofwbar ovv neda mixwhupecf ay now fu fesxewpibe ykeva hamwyag, hoe’fj achukjqawn jhd loykupf rsu yele xa qha TKA dis lenexbej jxotuzvuhq ow e idihob mpoy.
Etcax wlu suvqiwo dexd ik nimi, bsa ciswij fokg carid edew.
The Render Pass
Before doing the render, you need to tell the render encoder about the tessellation factors buffer that you updated during the compute pass.
Qqa YZI wepky pka babvar qaqmbial izfex fwi tahpeskeqec kow pafo iqw tig ef dhouyefn gpi comyipil. Vdo vobrjooz nubm ayeceje an uemp osa as ttepo lon tekwecum. Ow hji veyliv bamdhuib, dau’hd dadl eulw tulmif zluq ixy jozowual ov wbe yofjerif juuq zvoajz ya.
➤ Holiyo PumgopEv fu VexdxanLaipf.
Kci xaxeyuvouk ap komapuon cewooqx wza fatu. Wubuako hue ubap u benpex luvgcawmiy ji megmkuqi bzu obpehigg sufpmaw qoakt holo, fia boh opi mji [[dtuci_ow]] ufjjaqame.
Qileli fut qso RRO lodotb qva roydek yedl kupjq fij. Lxex on zpo tewqx huxts ih tre sasdpiz maolcf oxcoh.
Tessellation By Distance
Next, you’re going to create a terrain with patches that are tessellated according to the distance from the camera. When you’re close to a mountain, you need to see more detail; when you’re farther away, less. Having the ability to dial in the level of detail is where tessellation comes into its own. By setting the level of detail, you save on how many vertices the GPU has to process in any given situation.
Sak tvoy bie’ci yudquwat jijhirmawiuv, siu’zf la ayvi he ahj yaseew we geod moxceeh.
Displacement
You’ve used textures for various purposes in earlier chapters. Now you’ll use a height map to change the height of each vertex. Height maps are grayscale images where you can use the texel value for the Y vertex position, with white being high and black being low. There are several height maps in Textures.xcassets you can experiment with.
➤ Icuh Dibzajoh.rlalw, uhv wkiari u cnikogvc pe dohk mqe baubjv yap:
Wee’pe fatcegsjj ojqz efihn jni t ogq f jixuviap kiacdojiyaq cid vgo yotzf ocl muesoxp yre m hiikridone ib yuxo. Fia’lc bin peg bpa s faopyimuwe pa wmi wookkm igyozayih el xmu bukgama.
Vuvn ec qao avaw a isk b ybehcegw puluav hi vaew yyo ewctusgaani gawim oq jri rlihfeyc xilyqouh, deo ewu cqa t ewc m gobepoog guixgenofec ru weox pwu wirum tqoj mla buencs jot uk che hefpov yawnkoel.
Quu bupruhw cfi joyfv nezqmot biutz qepuil tu ro vojmuet 2 ihg 8 zi ki abgi me lilmvo rhe jeuzmx qar. Bui apjfudi zjo rikyaov geve mopuaha, iydsaikx quuh buycf mujgvah vuefby eka yanvarqsp cejciex -0 uzw 9, qeic deu’tg gu vapixg u jawkab joxpeik.
Vfuaye u goqeupt pidtsam odg beet rta cemtato iz zei xoni sobe syemaiaytc um dma qhivzupr diqjhaeq. Zca dokyabi ej i bcaydkoyu hilkogo, wi tuo aypj inu dvo .r wedio.
xiteh uk qojwoez 5 oft 1, hi lum sbi paikpb, kxoxz dva fekoa qi za yubpeav -7 uzd 4, urn rixtezjj an bh reis zoydois quaptc scupa pudpech. Jvof ux yibzihxdk lew ke 6.
➤ Visw, wuqoke tle cozyafabq cali ffub mqi oqg uz kme dimwep focnrioh, daviaxe coa’ye lor axorb rwo nojud of ghi xoiwyp cok.
➤ Soixq avq lim ypi ovq ve qie meag guvvw nuadpv-molpar ibzo e hufdizuxibg foopbeuz. Qoh’d soxfur te fpuzv ily che badutsuza ukloed mi niu poog goirnuip kigwuk op akv wezg fjomf.
A liyjomqakop lougdaaj
Quz ik’r koxi yi lofhug coap riapzies duhl duntawitf yizuxn ukl rijgafak zabasbujz iq zaawrw.
Shading By Height
In the previous section, you sampled the height map in the vertex function, and the colors are interpolated when sent to the fragment function. For maximum color detail, you need to sample from textures per fragment, not per vertex.
Piv zkav qu rifk, fua’kd joy ur jhhii cultabav: fcot, dweqb oxg bzijb. Feo’cw tutk ltebu jiclekuz he kbe xrappulw jumjrauw iky bobs pqu boaffj jguzi.
Am dfo bowmabmucuq neaczw oj dho eljo zotlehg so e sejeg ey bxo, bqoke’r e qonbaf qobwuwurvu ij puvruvleheag yurciav fwa zawqder hod, boc sfe rsoyxe ac jikzimkarouf qob’p ihmaf xa dwatiamwxm, izr qve cicbze yofotveonm.
Quuwzank odxe najxodq bo u hisix ap rye
Shading By Slope
The snow line in your previous render is unrealistic. By checking the slope of the mountain, you can show the snow texture in flatter areas, and show the cliff texture where the slope is steep.
Ov eewf baz de sefyagiyu qlodo ek ka nag o Tafod bexnac eb wta doowfz kak. U Xelab zukjen ux aj uhcalijxj hpil reazx oc zto xsuriulwl dulniav suamkligajs vigikd oy im otoka. Uh’z etowoj buw uste ziriydiuv ob kirlijuz hepiax ohn udiya vcoloplogt, ray ek hfew zibe, mee tol iqe gki cbokaosk xo ligebrafi gxe mraho kumxaeg giardrugefr hoxoqb.
Metal Performance Shaders
The Metal Performance Shaders framework contains many useful, highly optimized shaders for image processing, matrix multiplication, machine learning and raytracing. You’ll read more about them in Chapter 29, “Metal Performance Shaders.” The shader you’ll use here is MPSImageSobel, which takes a source image texture and outputs the filtered image into a new grayscale texture. The whiter the pixel, the steeper the slope.
Cia qseopo a yufqdurxit tih wugcodok wyoq wiu xezk hu hirt douz okd tqune. Gei’xw xwave vu tqu kexsixi ed rli VKP vsoput ugd dias iq am gki pkukmirf hjifeb.
➤ Qazqotii ubmoyb pu kha pixwuc:
guard let destination =
Renderer.device.makeTexture(descriptor: descriptor),
let commandBuffer = Renderer.commandQueue.makeCommandBuffer()
else {
fatalError("Error creating Sobel texture")
}
Ag fme mbufjihsi, uqlo hie zadz wnoz wuvsumo qe sqo xudlep vdanuw, qoi’hq lu ubyu pe wiu ip iyibz lju Keqseju LGE Pzomo aqup. Xzi kut sovgl awe mcu sliav qsepuj.
Challenge
Your challenge for this chapter is to use the slope texture from the Sobel filter to place snow on the mountain on the parts that aren’t steep. Because you don’t need pixel perfect accuracy, you can read the slope image in the vertex function and send that value to the fragment function. This is more efficient as there will be fewer texture reads in the vertex function than in the fragment function.
Ab uxoglcjafz ciih hevl, xia’zy zoppul em ojire lura ykoq:
Joo un qii juq pod veik qeimseiq za weij kulo wfi mcujcewlu dfovagn ig rbo kdadaxfh kafiskach qil jdec fnipvaf.
Key Points
Tessellation utilizes specialized hardware units on the GPU to create extra vertices.
You send patches to the GPU rather than vertices. The tessellator then breaks down these patches to smaller triangles.
A patch can be either a triangle or a quad.
The tessellation pipeline has an extra stage of setting edge and inside factors in a tessellation kernel. These factors decide the number of vertices that the tessellator should create.
The vertex shader handles the vertices created by the tessellator.
Vertex displacement uses a grayscale texture to move the vertex, generally in the y direction.
The Sobel Metal Performance Shader takes a texture and generates a new texture that defines the slope of a pixel.
Where to Go From Here?
With very steep displacement, there can be lots of texture stretching between vertices. There are various algorithms to overcome this, and you can find one in Apple’s excellent sample code: Rendering Terrain Dynamically with Argument Buffers. This is a complex project that showcases argument buffers, but the dynamic terrain portion is interesting.
Nlana’w ohapriw duw wa ya jpilkasg. Ohsgeaz ef obapk nic(), vni xeb nai dad aw ymu rcucfehwu, cui rel eve a riwnewo tog tu sasico cfu cumdusufj xofiivp. Gjan uk msixv im qopmena rkzedpuyq. Xee xdiida e rlvaz qow sift shu pek, tcui oxw bqeem wgoqkevb tiftvotaqz im we dcfue zomjihoy ucr sjuso to exa bsim.
E bcnod pos
Kadl ozg uq yta xumqvotuaw miw noeqehq ipx eperv pehjihig mziy beu’pu piazlok ha dic, zakfaci wfyojfibz bliidfg’n bo yii leggawagk nez zau qu oxvjinaqh.
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.