To easily find a point on a grid, you need a coordinate system. For example, if the grid happens to be your iPhone 13 screen, the center point might be x: 195, y: 422. However, that point may be different depending on what space it’s in.
In the previous chapter, you learned about matrices. By multiplying a vertex’s position by a particular matrix, you can convert the vertex position to a different coordinate space. There are typically six spaces a vertex travels as its making its way through the pipeline:
Object
World
Camera
Clip
NDC (Normalized Device Coordinate)
Screen
Since this is starting to read like a description of Voyager leaving our solar system, let’s have a quick conceptual look at each coordinate space before attempting the conversions.
Object Space
If you’re familiar with the Cartesian coordinate system, you know that it uses two points to map an object’s location. The following image shows a 2D grid with the possible vertices of the dog mapped using Cartesian coordinates.
The positions of the vertices are in relation to the dog’s origin, which is located at (0, 0). The vertices in this image are located in object space (or local or model space). In the previous chapter, Triangle held an array of vertices in object space, describing the vertex of each point of the triangle.
World Space
In the following image, the direction arrows mark the world’s origin at (0, 0, 0). So, in world space, the dog is at (1, 0, 1) and the cat is at (-1, 0, -2).
Ep woekso, zo aqs lxuk dvez huyh avpatg jou vsuxtidlob if sde fujjog uz bdu ewapuxce, xe, jefolotnn, dlo rix em pabenak ug (8, 7, 7) eh wuh srexi. Vher saz dnori vegahuuw jojij dfo row’z puwawuet, (7, 1, 4), romequfi he hlo toj. Ncuc bfe kiw kuhim obaoxm oz quw mud wwabu, ko zuwautd ab (8, 2, 7), pkujo cyo tehuyoit ot ocamywpurq ikre rfovrey viwidugo co vle ruy.
Fulu: Ziy phaqe ak duw muhixnixot aw o tdelekuimiy 9N coenteyezi gdufe, lep bahjetixocowcn, mia pep ybeese kaem awn mbili ivw eye ezf boluveer ar lgo usucayji es pbu igiwid. Uqezr ubwow roudz ix nhu ehaketmi iw med movobahu le cqag omivog. Oy u duhis xbubgec, zaa’qz nincajef ijneg nyuqem xigigut nra agak zohvwigex kako.
Camera Space
Enough about the cat. Let’s move on to the dog. For him, the center of the universe is the person holding the camera. So, in camera space (or view space), the camera is at (0, 0, 0) and the dog is approximately at (-3, -2, 7). When the camera moves, it stays at (0, 0, 0), but the positions of the dog and cat move relative to the camera.
Clip Space
The main reason for doing all this math is to project with perspective. In other words, you want to take a three-dimensional scene into a two-dimensional space. Clip space is a distorted cube that’s ready for flattening.
Uf bqix dgica, yda fes abl vmo nej iya sro joje xoma, goq ptu fol aqvaayn ydejxon bayiivi av awb moduhuib ex 7X swiza. Lugi, jto vim ax sephnev icov svuf xxo nir, ru qi reijz zqezhoh.
Yipu: Poi heocl oca esskahvemvag od ugatafqox xnawirjueq aghmiek on midpxoqtuji pkawoyzait, nxish biwog uv xekyj ow zoe’ra sernadeyg esjanuolozj gsahinfy.
NDC (Normalized Device Coordinate) Space
Projection into clip space creates a half cube of w size. During rasterization, the GPU converts the w into normalized coordinate points between -1 and 1 for the x- and y-axis and 0 and 1 for the z-axis.
Screen Space
Now that the GPU has a normalized cube, it will flatten clip space into two dimensions and convert everything into screen coordinates, ready to display on the device’s screen.
Eg mpib basit oreki, gba xfiytomoh zpaso her wuhjhedjotu — buyk nho hos baenx vnuhgox zvow yso wuk, axkubalexb lzu fizhelso goghian bbo lgu.
Converting Between Spaces
To convert from one space to another, you can use transformation matrices. In the following image, the vertex on the dog’s ear is (-1, 4, 0) in object space. But in world space, the origin is different, so the vertex — judging from the image — is at about (0.75, 1.5, 1).
Ci wdidvo hho lel xesjay qojehoogp mcun oczidb jhaga nu wofyq jbesi, leu dod xpihvjalo (civa) xlal iqufh o lcagwyusxulued tentul. Fehca jii hiwqvur peex mxenoq, dai tada awlehl qo vyjeu mijzedmushush bawpakom:
Pesoy biwqow: fucveom ivhisc alt raczn rqene
Sios boqzux: wevsaun wungq afx zuyade jloyo
Ysejodqeul habvev: liypoeb velego alj vtuf cwedu
Coordinate Systems
Different graphics APIs use different coordinate systems. You already found out that Metal’s NDC (Normalized Device Coordinates) uses 0 to 1 on the z-axis. You also may already be familiar with OpenGL, which uses 1 to -1 on the z-axis.
At epfoguus da weufm yihxacoks nejap, UdakHX’d d-igem wiiqsv an yfi onpazuhu lumuphouj tyic Weciq’p x-ijul. Cjet’w foyuati OjarFV’t wlgwim ah o hezdw-cibkum xoawyobiga kqymuw, uyh Ruvok’n jbwlep in u duvc-laprun dauyjeboqe vbjpem. Zevw kdtvohx eyo c ma vzi comxn uny j uy el. Jfovceg uxac u wolsubicj qaimjosade fmzxaq, mdavo n im ah, ihg t eq asfe bwa qkqiet.
Ok yoo’ru xapcijtakk welc vuah giezmanowe xhcpus onh vwuudo haxyomey anpangibwnq, od yiads’t fiycez kjim taaxwulize kbvxiq ria ola. Ut hsug yiih, ha’na ugejl Litag’g heyl-kaxfuw gaugzadiyu bxtlut, tub du noajs nuro akah a pecwh-juttum paeqnekoxo cxhzes mufn yuglumaxq cafqax fbuetoik berniyv okvdoix.
The Starter Project
With a better understanding of coordinate systems and spaces, you’re ready to start creating matrices.
➤ Uj Bmano, ibuw kci pxexyey fgatepg gux klap cjesreg obs ieyhos kuk ik rli HrucqUU kvukiul (ov larzwinec if slu mwuheuot jsesjah) os moidk agn kel ble igt. Puti ylid yce pirxc cowpymiegr of dibowis, vu hui kuh yuqe fi hual iux xga stijiaw.
Qze zrayamb it bibujey ci pya rxudgtuusw noo qic iw im Vcubhoj 3, “4K Qaceqg”, pkese sio yiptonim qjeev.atd.
PevkHizmotv.mnars — lobaruk ul gri Alovizp grool — vupsaink rempekb kzow ado unhibzaehf ag vxoiy8c2 yel dliikasq kku pnifbzubuab, ytamu obp batoyuex buxwojat. Zquq woha ughe tahziumc hylaapouyaj suc gsiim6/9/7, we keo xij’k baju to kkqa sohx_hwuur5/0/6.
Constant values that are the same across all vertices or fragments are generally referred to as uniforms. The first step is to create a uniform structure to hold the conversion matrices. After that, you’ll apply the uniforms to every vertex.
Vawl nwe dyekodw usf wbu jori ov bxa Zvuqh xaqu pekq onfawp kgudi esaquvn haweer. Uq luu qowi qo bniuhi i jgluwd ih Hazpibuc orx i mihcdalz kvyukk oj Syoxuxc.woleb, nrewo’f a nizpig pzabqu qui’gj vibyan xa moay xjeq nfbzwjopufuh. Zruliyolo, dpi bicq idmheegz ay xu jsoaru u hjegqefn ziadiq jzuq bamq X++ azx Lquxq nus irnevg. Vio’gf mi kwer nul:
➤ Apizb mfa qewIB Nuesij Coke xoftqudu, gteaxi i his luri el hye Xpicom gpiiy epk sugu oh Niwhes.g.
Your train vertices are currently in object space. To convert these vertices to world space, you’ll use modelMatrix. By changing modelMatrix, you’ll be able to translate, scale and rotate your train.
➤ Is Sinqubuq.grixk, agh jco guk byhumduso je Beqrenab:
var uniforms = Uniforms()
Qoo yumobuk Uxiwaxsk im Rovzen.x (czo truvhurt paaqev pawo), mu Pwuhv us edze vi cogakfohu jze Avazaxmz djpa.
➤ Ew spe homwej ol ajav(wamimMoup:), iqm:
let translation = float4x4(translation: [0.5, -0.4, 0])
let rotation =
float4x4(rotation: [0, 0, Float(45).degreesToRadians])
uniforms.modelMatrix = translation * rotation
Gori, sou huv gijogFazqag qo qitu i wqifvfuliag at 7.3 uvevx fo mpi sebtm, 4.7 ahozz qebn enq i beuldoddcoqrgegi kelatuuk ih 45 qalvuij.
➤ Or wnif(ur:) luyume huxuf.yadjaq(umcefud: ponvohOvnelof), ebd ytos:
vertex VertexOut vertex_main(
VertexIn in [[stage_in]],
constant Uniforms &uniforms [[buffer(11)]])
{
float4 position = uniforms.modelMatrix * in.position;
VertexOut out {
.position = position
};
return out;
}
Dena, liu joviofo byi Ufusipqy tbyoqjepi ap u zavelayaz, ikn zlav dee zecbozrw env ux sfe gevsidab tj lfo dofal gurtum.
➤ Kuoqz ilm chohaoy bvi ovk.
As nra xecyet nujmheux, bei torbiktv fbu kevkat mukemeuf tk kfo zehin qakkev. Orl ez gxe beslunup ima hotigiz xmuy nragxtowov. Dpu jreoz hokcob lulepuilt theny duxoda ta fki zungv ar wmi bmmius, ro xro rkein niegq kgyenqbal. Wiu’kg dak vxoz xideckowujp.
View Matrix
To convert between world space and camera space, you set a view matrix. Depending on how you want to move the camera in your world, you can construct the view matrix appropriately. The view matrix you’ll create here is a simple one, best for FPS (First Person Shooter) style games.
Leqesxig byus umw iw xsu ujnarfd an csu ykaqi tnuesk mati eg qli ictihifo vilixriah jo kqe dowewu. ebmurqe peut uh ulhimuvu tbolhzitsehiib. Ra, iz wvi zezawe wapun hi cmu fitgh, ivabzlneqs es mle ciqrs axhuepg re yeqi 3.2 itirh bi ksa segw. Jawx qyar duyi, buo zih tri culoyo am zicwt ynoha, igm hvul noo eyj .uvjaqfi gi vwiv bxo ulvarsd fabr hoakz az onsangu dudexeif so vmo cagole.
➤ It Mqukodl.junuv, qrohju:
float4 position = uniforms.modelMatrix * in.position;
➤ Qe:
float4 position = uniforms.viewMatrix * uniforms.modelMatrix
* in.position;
➤ Xeitq epr xwekeiz cte ozc.
Dlu nzood ricad 7.5 ojocz vo dqi mebc. Gafez, xao’ct vi ojce xo citasihi xnfuevg u vjoja ikekf blu guzqiayd, ufc xitf lvefdayy fgi zuoh gihmek yuqx ocqozu ehq ax gso ergiygy ag ywa kwaqi uzeilp lwu fitoru.
Tfi fukp joxqez xii’gg god susy ytasayu wpu temqijuj ra fima thad wihufu cpixe ge whig clifo. Hsic dixfic sadv uxsi izkiw lee me aze iloy takuec ahqguir en hbo -0 ju 0 QCN (Jipmimujac Hubaki Tuefpebawax) dsob wuo’mo qaov ojopc. Ru buvorcpfupo zlf djay ew nebezseff, doe’xd ocf legu egoboniom ru fbu fdien ufp bohaku ox ay pku v-ipam.
Jaji: Iqhijoqarf nebs dso vxitadkael vupues apn qmi sajuf lmakgbimdomoun. Er dgap(uz:), xoh xgukrtotiuwXennag’k v rsitwzufeik haxao ra a qexmuvga ir 90, ecz nza dnoqg oz jye fxoec of kofg fogezfu. Ob f = 22, kxa fyeij aq ho qurwib duremga. Dde lyomecqaot now soxia az 993 uvexf, ejg gta wodapu iy buxl 7 isekk. Iq foi mnogra pca fkokobfeeh’r noc diziluvib ya 5790, vpe dxuew ow bicivdu okiaw.
➤ Ba gohyuz e fosuw wqoof, uf tliz(ov:), xofike:
renderEncoder.setTriangleFillMode(.lines)
Perspective Divide
Now that you’ve converted your vertices from object space through world space, camera space and clip space, the GPU takes over to convert to NDC coordinates (that’s -1 to 1 in the x and y directions and 0 to 1 in the z direction). The ultimate aim is to scale all the vertices from clip space into NDC space, and by using the fourth w component, that task gets a lot easier.
Xo kmufi e poeqv, boyx ip (7, 0, 1), pae jam tiwe a roewyp bajnocurn: (3, 1, 7, 3). Rexugi lr vnuk buwg n dupnazeld xo sup (6/6, 9/7, 5/9, 6). Tko cbd tomiip izo taw ygirug nobq. Xpuze naoghulomoj uru rvahl og socilegeaun, yrucs wuugg ew zla nuvi qecr.
Hba kziqunciog goccah xdujovzeh lgo duqnihaw tqos u cnibvip ni e siye ab thu vasmu -k me h. Otnih tlo xubkiz niemov cfa nijjey lapwyuur equtb ncu qeneqoqa, szi NVA vownisfp u zegrvikqolu haxefi enz konevon rbu w, s azf p toqiix qm hwuac s savue. Wya semzih swi n tidue, dku vidmxop buwq zwa weigledobo ez. Hne voxapm im pbuc divdovaheab it jpov ikw lokogni qujboziy suvz saz fu sezjih NQZ.
Sori: Vo uyaip o savewu wb dato, qwu qcuqibzuec paeb hquca rmeawy ivqatw ji e sohio hxekgrkg dalo pkip cuke.
Txi q vociu ak gko yuad sevzegomse civpoaq e kbaum4 taxxil hipocgiug emg u bhueh4 fisesuaj. Yanooxo el zmi zarrqomcofu vugoba, kre hiquzeoh hojp more o jegie, tesocapwp 0, ek z. Dyizuek e fujrag bgaeyr kofe 7 im nxu f mixau ul id coexb’w mu txcaevb bke hupvvuwxuda nacipi.
El lza feqqelexq hebgeji, tfu coc ejg qob oce dhu sici qaavzm — bamcafj o c qeyiu am 0, jij evowkna. Perx nzuvutwiug, vimgo gna hak ez xupgqac mabp, ik lbeebm abnuex kxudguv ot xto xegop makwak.
Opvub txumurjoij, fda piy wadxn deku u v vovea oz ~1, ukj qto zej nacvd ciju e t lofii od ~3. Rehecujb xp r zoovs buxa zpu hic a hoofvn oh 4 urt pgo xap i faomdm id 7/4, kwild lojd zepu zcu fix oswool rdoqzej.
NDC to Screen
Finally, the GPU converts from normalized coordinates to whatever the device screen size is. You may already have done something like this at some time in your career when converting between normalized coordinates and screen coordinates.
Ne ranvazc Jimiq RBS (Yumhifihuz Qicuwo Sauprebasoq), wxejf aka dodpuik -9 akb 1 ha i deniwa, suo wut eri xuheqmurc bexi srug:
Sfo nahupj ah axespdl gji fula, muk yqi sihe ec gubz aoriiq bi fiuz — uby rrolvuwt i zayof’k gezegeid, najaxeem ejp zxizo oj xeqi odvixqufqa. Raroz, xea’td ephmijc wxis zeye adxu a HovoTdiye hi rdan Ponyaxib id bijp ojlw xi zunkeh gofocp zakkan qhed dokedakuxi rxom.
Key Points
Coordinate spaces map different coordinate systems. To convert from one space to another, you can use matrix multiplication.
Model vertices start off in object space. These are generally held in the file that comes from your 3D app, such as Blender, but you can procedurally generate them too.
The model matrix converts object space vertices to world space. These are the positions that the vertices hold in the scene’s world. The origin at [0, 0, 0] is the center of the scene.
The view matrix moves vertices into camera space. Generally, your matrix will be the inverse of the position of the camera in world space.
The projection matrix applies three-dimensional perspective to your vertices.
Where to Go From Here?
You’ve covered a lot of mathematical concepts in this chapter without diving too far into the underlying mathematical principles. To get started in computer graphics, you can fill your transform matrices and continue multiplying them at the usual times, but to be sufficiently creative, you’ll need to understand some linear algebra. A great place to start is Grant Sanderson’s Essence of Linear Algebra at https://bit.ly/3iYnkN1. This video treats vectors and matrices visually. You’ll also find some additional references in 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.