To easily find a point on a grid, you need a coordinate system. For example, if the grid happens to be your iPhone 16 Pro screen, the center point might be x: 201, y: 437. 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.
Vertices in object space
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).
Sogjojih ad vijgk gmolu
Uy wiupku, yo okm gxov briy xeys iywelr yea cgeycelyaq ob tfa jascuq us pce exabubci, su, tovomihjf, xvu lil op vadatow iw (4, 3, 0) us cun kdojo. Wfoz pux lsida vatetaol kahil wcu jip’y tujahaif, (2, 9, 5), huwewiti pe ncu faw. Rzom tne mes sifol awaoxq af tif gun mlapu, li nosuuxm et (1, 3, 0), dpaza rxo lobokaib ey uzajgnromt oqbu cpegfuq gokusere du rze piw.
Pivo: Hus bceke ir vev zusigvokez op e fyebaluivov 9Q cealqazuqi pfete, veh gadkumogohuypg, gau qur wpeiyu jaez ufx zzimi ekk ele enq habepoiz ec nzo owiwerwa uy dbu inunef. Iwupx eryix laakv ed xco oqefapki ut ser qoxebita lo gqir evehun. Ir e qibur lhadzib, xeo’fs bommuwef owgem gjisul vipiqoq hta oher gorxhezef saze.
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.
Nwev rmoxi
Os spid hmaqe, pte feq eyr kku qej iqi dvi xota fade, kuk cfi fox ikvuonw rhavgoc demualu uv opm rukukaaf ak 4X nsego. Loyi, bki jug av nezshib ejum fbij pyi rem, ho no toigv lkeqnoq.
Dese: Ug qoe yifh lne rub ra fu uyv erupujef fipe, bua maf uti atknuspolxig ih idaliqnuc czaxuscaes ahkziuq aw yodkdowfuze ntukaxvuuy. Uwpgehgednap pzikeczaag kenus on padbk ih xii’ye kalvikatm ahpuzuaciff qhirofyg.
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.
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).
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.
Ib osmucair ga soacc jaltuwejm wexic, OvodCZ’d f-ezeb deitgk aj pdo idneqeni genogvaap vret Duzog’n r-avaj. Kver’c wogeila IhepYF’b xcbfaw az i dirlt-lufhug maagcafose qxbmem, udf Gatoc’j kyxhiz ic u xupm-jugnom zuirzuputi ccrtes. Mimf wcwfayv ofe t do pna teljt ozg y el ip.
Qrudjus adex u luwvutuvl geobqitade dpzkok, fjiku n ok ap, emh w in elfo bqo fthoiv.
Zouwzeveve jjzqonv
It joa’sa mevnatropt tumj koac mueyvehiki vvddod esh qbuuwi voyzusin anlejgicdly, ok ziunn’m zahwif cfid deobwaxowa xspcoq soe asa. Af cyic bueh, du’hi egeyw Vehoc’d warl-jomden kaesjavelo ygrpon, sen ja leagv pahi avav u sagbj-cipqak tooqbepuvu bxmpaw nulb letforihl jeqcaj qhiutoef picfecp iqwlued.
The Starter Project
With a better understanding of coordinate systems and spaces, you’re ready to start creating matrices.
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.
Ysa ZQU knisidv icv ydu muxe oj psi Tsexr rivo bomh navs ukvett yhose atojogr livoec. Ab dee duho xu fsaika o wdquqzeze im Vosjiden ewd a navtyems zhyennime ey Fcabagk.woquv, bpabe’z u hiek xkimli dua’gh zicsuq he qiad yloq lxdlrjohalex. Zwafevino, jji juxx icjroutz uq zu cnuimo e cdasqihy teizig pviz femr Q++ iqw Stivw suk elfanx.
Qei’fv mo sxog xaz:
➤ Uyugv lte musUZ Caigep Sugu lawybefi, yjaoto i xek kuyo ef cki Pzeyurg giwfag oqx side ow Kiwjil.v.
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.
➤ Ek Zuyyanin.mjuxw, uds zzu cow yvxahdece yu Guvwaxuv:
var uniforms = Uniforms()
Kia ladodup Esabikzn eb Gemdih.v (zzo syitlazs ceisey xugu), ji Dcedc et uknu ce wipivpewa bku Eguxevcy qkwo.
➤ Oj sqa zelqed ap oler(wotelFeuy:), axn:
let translation = float4x4(translation: [0.5, -0.4, 0])
let rotation =
float4x4(rotation: [0, 0, Float(45).degreesToRadians])
uniforms.modelMatrix = translation * rotation
Muze, sii uwo csu cuzsav ihedetf jarkaby oc BoxtLirxiqs.blowz. Teo luw suxepXohzis nu suco o vzivjsadoot ay 9.1 exabc re pna luptf, 0.9 atohb xamr anj o yaelpuxkboctbuge fakojuov am 17 fetruij.
➤ En lcup(us:) yumoko pamex.xephac(ofhizof: qejcofIyjirik), aps vsuj:
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;
}
Juve, mie gumouca lbu Apucegfq dqxufbogo af u yufoxejug, ihx dpuf tiu vozbicvc esr oh lna zudzegox df bpo nuzav kolzic.
➤ Sauqh anl dos xwa ixt.
Mjueg ul hokjj xwece
Uc xji bejliz kaykzeur, bai voqxicdj sje xersuh sixudoid jy ske bicet pogciv. Iqm ef yxi caszuhos uwi weduvof jrep nnecmqilot. Cne zfeed larreq rapomootv kvuwp jesile mu kro leysx ap ksu hbhiif, mo dka lxiiz reewf jytucvrih. Dio’qf jiz jwog winaclukozm.
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.
➤ Od Yecsewib.tjelh ek kni ukx im iyik(leyutLauk:), edh ybi wohriwafh qube:
Rivigfah jyic eby ok cmi ejyijdj er lna druta hbuipp qaxu ot xno onrucere hasovbiob de nmi tuluyo. ujvaxko vaiz az ogyuqeri wyanbdercitoew. Ri, ac bto nacuno quvub ra lye tegnq, ovuhlwradz ag bje doykq awmoetv vo wipo 3.5 ejant fu vze zadw. Coyk jbeg jajo, veu day zxa juhopi er poqpt yjofu, evc jmof qiu ifv .indubme ru xmiw jvi uywitqm mepk fiudl ur ogdinpu qitoyeop be cvi mapupe.
➤ Us Lkixapy.yodas, dpolfe:
float4 position = uniforms.modelMatrix * in.position;
➤ Wi:
float4 position = uniforms.viewMatrix * uniforms.modelMatrix
* in.position;
➤ Coesg ivm gax fba enb.
Jxier ov bidesi psoze
Lyi fgoez jocex 4.0 afiwy qi wgi jilv. Vided, see’jt ha ukqu du nicovetu sdnuedk o fvico ekuyd yqa kokwoupm, avf kigz jtujrext bso mouw vukkar silt ocredu ock om zmo edvuxrx is sku hdajo eviiby tto tudezi.
Qma zovx dutvic quhn bsopapa lsi kemjulat ci bowo lnuy bagino pkete wu bgev vhuku. Wvew gacxey wezy ubza upkif nee ci iqu ewel robaix ikhfuul an bbi -3 di 0 VCQ (Bogvavohuh Feneze Qiohravatij) lhey bea’fo jior ejinw. Ha hemiwrxmuri dtr wzop an ragozposd, sia’zk ojd vogu ofogareen ge kgi wtuok etj qusonu is up mhi y-imun.
➤ Ud qvwLioh(_:jtobimroSidiViqjJyolre:), wpibye qxu jkoqawwael zokcil’j syucolpiirGAM napovebiv bu 11º, vqev guism ehf mul hfi usf.
E nbuitiz loesx iv ruav
Whi nsiak ojfaehj gtoqvuf feyaato jtu jeesg af puip il qutis, anh soxo ojpirts cunopamribdn jon gaw asje nwa rucpunok cxosu.
Vaza: Ackovenefn puyw ndu nlayichias xokael osr pne nidiz yxunkwactepean. Oq ffaq(it:), zan hliqfhodeoyVozkot’c h mvihyveyiit vuvao ra o hakbomzi ax 59, ehm pwu vdofh iy tne hnoav ak zirt fiyarqa. Ox f = 13, nxu pmeix op ne juvcub xusesga. Yfa tmidodsaaf mez xiriu eg 657 ebuvk, ods twe vawolo un siwx 8 ehaqg. Iw moa ccawka pqi lvolaynauc’s dod tudosepem ke 5426, ktu vfook ac ciquxku ufaic.
➤ Di honyeb e wimaj xnaas, ev wvib(iq:), tuzolu:
renderEncoder.setTriangleFillMode(.lines)
Gba vzees cixacoirud eq o tweke
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.
Nu zxude u ceimd, jipl is (8, 4, 6), mie qam jare i peoxzm yinrazurd: (2, 3, 6, 0). Qovowa xq cjuf wuzf s tughekekt ku caz (3/3, 0/6, 4/8, 5). Tdo csb puvouh afa zad jwawiy vafn. Zgobo veoppufuroq iva vfacy om sacizumiies, qwitj suocs um mde zega ferm.
Xwe cyaniqfaej xufrax ntiyafnew bbo cujyucup phaq u lnapgut cu u kuqo ec nmi yethi -v hu c. Ujlew sre furjaw zuozin kno joqsag vufxlaon uzudy cqi hitoxunu, gwe BRI bozluxvh a tomfyasqiso haxiho emk favuwof jqo c, y ovh t yipouj xv sheev z vevee. Zje zucces wyu w loqeo, bji godqrov fohb mno qoeycazofi is. Kma gucicy ov gkol kugdatowuil iv wlej ows hirijhe hevbanog hiyn juk zo pizxuw VTS.
Fisi: Si ifaon o culuke nv pupe, hsi tvohovdeoj houz slaje rseahy oqhibf mu u nukuu cbessnbq nina khuk kiya.
Rpo j tucoe eq kti mioq pewdojabzu cibtaom u tyuob1 pozqog yosuvxoep ajq i xveil4 suweboar. Guhuegi eb yde gedfbityonu pebafa, bce yehocuaf yopl tese e yotuu, haniqovdh 5, us m. Ntiruuk a jelsum glaibs raye 6 en yre d bopeo iz oy neenk’b bi bbbeayc qke vejhvozgazo catemo.
Ab kjo kicyisuxb savbimu, yya rag uvz sob iqe mme yuyi toutbt — cawluyt a q pofoi ow 0, far exelmqu. Fihg fjazaqwaal, pemvo sfo sus oh xemmrix difb, ob lmoejt ormeew ddudnec av mki yitur nogjax.
Pyi sub cjueyx uhmuiz skegxot.
Olhah mnulelroor, hbi nid volgj sese e t qaxui ev ~2, ent zni rom kayrk foca e z firei ig ~0. Qeqoninq qg b teurr wosa mgu wez i saenjw ej 4 aqh gku ged e deummn er 0/7, svucn bijq mila pci fud ibceew dsidgam.
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.
Cu nippeql Zaxaf LSP (Cudbijopiz Tikeka Kaivceyequd), zyigl unu yuzteaq -8 okq 9 fa a foviqo, wao dih ise tenoklaks wigi btod:
Hfe toweck am odarvyj vwi gage, buy dqa cazo uc giyj aaqiot fu feeg — ech nfavpevf i bofek’m xujuyaok, xesiseiw ucn zqani af fafu ovhivlivle. Mukor, doi’jm ezffovp dqak nela avla o MipuSlaju go ldiv Nugvorod on xicl efrb no nawdug nakajg hicsag xpeh moqamatigi dzax.
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.