Poglavlje 2: 3D prostor i matematika

Poglavlje 2: 3D prostor i matematika

U ovom poglavlju učiš matematičke temelje na kojima počiva sve u 3D grafici. Koordinatni sistemi, vektori, matrice i transformacije — ovo je jezik kojim kompjuter opisuje 3D svet. Bez ovoga, ništa što sledi nema smisla. Ali ne brini — objasnićemo sve korak po korak, sa primerima iz realnog sveta.


Zašto je ovo poglavlje važno

Svaki put kad GPU nacrta trougao na ekranu, koristi matematiku iz ovog poglavlja. Svaki put kad pomeriš kameru, rotiraš objekat, ili skaliraj model — matrice. Svaki put kad engine izračuna da li svetlost pogađa površinu — vektori. Svaki put kad shader izračuna boju piksela — dot product.

Matematika 3D grafike nije apstraktna akademska disciplina. Ona je alat. Kao što stolar koristi čekić i testeru, grafički programer (i svako ko želi da razume renderovanje) koristi vektore, matrice i transformacije. Ne moraš da budeš matematičar — ali moraš da razumeš šta ovi koncepti rade i zašto postoje.

Ovo poglavlje pokriva tačno onoliko matematike koliko ti treba za razumevanje ostatka knjige — ni manje, ni više.


Koordinatni sistemi

Šta je koordinatni sistem?

Koordinatni sistem je način da opišeš gde se nešto nalazi u prostoru koristeći brojeve.

Zamisli da si u velikom praznom polju i hoćeš nekome da kažeš gde si. Možeš da kažeš "ispred velikog drveta" ili "blizu reke" — ali to je neprecizno. Koordinatni sistem ti daje precizan način: definišeš referentnu tačku (ishodište, origin), definišeš pravce (ose, axes), i definišeš jedinicu mere — i onda bilo koja pozicija može da se opiše brojevima.

2D koordinatni sistem

Počnimo sa dve dimenzije, jer je intuitivnije.

Dekartov (Cartesian) koordinatni sistem u 2D ima:

Svaka tačka u 2D prostoru može se opisati parom brojeva (x, y):

Na primer, tačka (3, 2) je 3 jedinice udesno i 2 jedinice nagore od ishodišta.

Ovo verovatno već znaš iz škole. Ali postoje detalji koji su bitni za kompjutersku grafiku:

Smer Y ose — u matematici, Y osa ide nagore (veći Y = gore). Ali u mnogim 2D grafičkim sistemima (uključujući većinu monitor koordinatnih sistema), Y osa ide nadole — (0,0) je u gornjem levom uglu ekrana, i veći Y znači niže na ekranu. Ovo je istorijski artefakt iz vremena CRT monitora gde je elektronski snop skenirao od gore ka dole.

Ova naizgled mala razlika je izvor beskonačne konfuzije i bagova. Zapamti je.

3D koordinatni sistem

Za trodimenzionalni prostor, dodajemo treću osu — Z osu — koja predstavlja dubinu.

Svaka tačka u 3D prostoru se opisuje trojkom brojeva (x, y, z).

Ali ovde nastaje problem: postoje dva načina da organizuješ tri ose, i oni nisu ekvivalentni.

Left-hand vs Right-hand koordinatni sistem

Zamislite da stojite u ishodištu koordinatnog sistema. X osa ide udesno, Y osa ide nagore. Pitanje je: kuda ide Z osa?

Right-hand (desnoručni) koordinatni sistem: Uzmi desnu ruku. Ispruži prste u smeru X ose (udesno). Savi ih prema Y osi (nagore). Tvoj palac pokazuje smer Z ose — prema tebi (iz ekrana).

Left-hand (levoručni) koordinatni sistem: Uradi isto sa levom rukom. Sada palac pokazuje od tebe (u ekran). Z osa ide u suprotnom smeru.

Ovo nije trivijalna razlika. Zamena sistema koordinata menja matematiku — cross product menja znak, rotacije idu u suprotnom smeru, normali se okreću. Mnogi bagovi u grafici nastaju kad se pomešaju koordinatni sistemi.

Različiti softveri koriste različite konvencije:

Unreal Engine koristi levoručni koordinatni sistem gde je:

Ovo je bitno zapamtiti jer kad importuješ model iz Blender-a (koji koristi desnoručni sistem sa Z gore) u Unreal (levoručni sa Z gore), engine mora da uradi konverziju. Ponekad ta konverzija nije savršena — objekti se pojave rotirani za 90 stepeni, ili im normali budu okrenuti na pogrešnu stranu. Razumevanje koordinatnih sistema ti pomaže da dijagnostikuješ i rešiš takve probleme.

Zašto je bitan izbor koordinatnog sistema?

U suštini, matematika radi isto u oba sistema — ali se formule malo razlikuju. Kad čitaš dokumentaciju, tutoriale, ili izvorni kod, moraš da znaš koji sistem se koristi, inače ćeš dobiti pogrešne rezultate.

Konzistentnost je ključna. Nije bitno koji sistem koristiš, sve dok ga koristiš konzistentno.


Vektori

Šta je vektor?

Vektor je matematički objekat koji ima pravac i veličinu (magnitude), ali nema fiksnu poziciju.

Zamisli strelicu. Strelica pokazuje u nekom pravcu i ima neku dužinu. Ako pomeriš strelicu na drugo mesto a ne promeniš ni pravac ni dužinu, to je isti vektor. Vektor opisuje "koliko i kuda" — ne "gde".

U 3D grafici, vektor se obično zapisuje kao uređena trojka brojeva: v = (x, y, z). Ovi brojevi su komponente vektora i govore koliko vektor "ide" duž svake ose.

Na primer, vektor (3, 0, 0) ide 3 jedinice duž X ose — čisto horizontalno udesno. Vektor (0, 1, 0) ide jednu jedinicu nagore. Vektor (1, 1, 0) ide dijagonalno — jednu jedinicu udesno i jednu nagore.

Vektor vs tačka

Ovo je izvor česte konfuzije: i vektor i tačka se zapisuju kao trojka brojeva (x, y, z). U čemu je razlika?

Tačka (point) opisuje lokaciju u prostoru — "gde". Tačka (3, 5, 2) je konkretno mesto u 3D prostoru.

Vektor opisuje pomeranje — "koliko i kuda". Vektor (3, 5, 2) kaže "idi 3 udesno, 5 napred, 2 gore" — ali ne kaže odakle.

Veza između njih: ako imaš dve tačke A i B, vektor od A do B je B - A. Na primer, ako je A = (1, 2, 3) i B = (4, 6, 3), vektor od A do B je (4-1, 6-2, 3-3) = (3, 4, 0). Ovaj vektor kaže "da bi stigao od A do B, idi 3 udesno i 4 napred".

U kompjuterskom kodu, tačke i vektori se često čuvaju u istoj strukturi podataka (npr. FVector u Unreal Engine-u), pa je na programeru da vodi računa šta je šta. Ova razlika postaje kritična kad govorimo o homogenim koordinatama (kasnije u ovom poglavlju) i transformacijama.

Operacije sa vektorima

Sabiranje vektora

Ako imaš dva vektora a = (a₁, a₂, a₃) i b = (b₁, b₂, b₃), njihov zbir je:

a + b = (a₁ + b₁, a₂ + b₂, a₃ + b₃)

Vizuelno: staviš kraj prvog vektora na početak drugog, i rezultat ide od početka prvog do kraja drugog. Kao kad ideš 3 koraka napred, pa 2 koraka udesno — ukupno pomeranje je kombinacija oba.

Gde se koristi u grafici: Pomeranje objekata (translacija). Ako imaš poziciju objekta P = (10, 5, 0) i hoćeš da ga pomeriš za vektor v = (0, 0, 3), nova pozicija je P + v = (10, 5, 3).

Oduzimanje vektora

a - b = (a₁ - b₁, a₂ - b₂, a₃ - b₃)

Gde se koristi: Nalaženje pravca od jedne tačke do druge. Ako je igrač na poziciji P i neprijatelj na poziciji E, vektor od igrača do neprijatelja je E - P. Ovo ti daje pravac u kom treba gledati/pucati.

Množenje skalarom

Skalar je običan broj (ne vektor). Množenje vektora skalarom menja njegovu veličinu (dužinu) bez promene pravca:

k · a = (k · a₁, k · a₂, k · a₃)

Ako je k > 1, vektor se "rastegne" (postaje duži). Ako je 0 < k < 1, vektor se "skupi". Ako je k negativan, vektor se okrene u suprotnom smeru.

Gde se koristi: Skaliranje brzine, skaliranje sile, podešavanje intenziteta.

Veličina (magnitude/length) vektora

Dužina vektora a = (a₁, a₂, a₃) je:

|a| = √(a₁² + a₂² + a₃²)

Ovo je direktna primena Pitagorine teoreme, proširena na tri dimenzije. U 2D, Pitagorina teorema kaže da je hipotenuza pravouglog trougla c = √(a² + b²). U 3D, dodajemo treću dimenziju.

Gde se koristi: Izračunavanje udaljenosti između dve tačke (udaljenost = veličina vektora između njih). Provera da li je igrač unutar dometa oružja (da li je udaljenost manja od nekog praga). Normalizacija vektora.

Važna optimizaciona napomena: Izračunavanje korena (√) je relativno spora operacija. Kad samo poređuješ udaljenosti (npr. "da li je A bliže od B"), ne moraš da računaš koren — možeš da porediš kvadrate udaljenosti. Ovo je klasična optimizacija u game development-u:

Umesto: if (distance(A, B) < 100) → računa koren Koristi: if (distanceSquared(A, B) < 10000) → nema korena, brže

Normalizacija

Normalizovan vektor (unit vector) je vektor čija je dužina tačno 1. Dobija se deljenjem vektora svojom dužinom:

â = a / |a|

Normalizovani vektor čuva pravac ali gubi informaciju o veličini. On kaže samo "kuda" — ne i "koliko daleko".

Gde se koristi svuda u grafici:

Normali su toliko fundamentalni za renderovanje da im je posvećen značajan deo poglavlja 3 i poglavlja 10.


Dot product (skalarni proizvod)

Ovo je verovatno najvažnija operacija u čitavoj 3D grafici. Ozbiljno — dot product je svuda.

Definicija

Za dva vektora a = (a₁, a₂, a₃) i b = (b₁, b₂, b₃):

a · b = a₁·b₁ + a₂·b₂ + a₃·b₃

Rezultat je skalar (jedan broj), ne vektor. Zato se zove "skalarni proizvod".

Geometrijsko značenje

Dot product se može izraziti i ovako:

a · b = |a| · |b| · cos(θ)

gde je θ ugao između dva vektora.

Ovo je ključna formula. Ona kaže da je dot product proporcionalan kosinusu ugla između dva vektora. Ako su oba vektora normalizovana (dužine 1), dot product JE kosinus ugla:

â · = cos(θ)

Šta to znači praktično?

Ovo ti daje neverovatno koristan alat: dot product ti govori koliko su dva vektora "usklađena".

Primene u grafici — zašto je ovo toliko bitno

1. Osvetljenje (Lambertian/diffuse lighting)

Najosnovniji model osvetljenja — koliko je površina osvetljena — zavisi od ugla između normale površine (N) i pravca ka svetlu (L). Što svetlo pogađa površinu direktnije (manji ugao), površina je svetlija.

Intenzitet = max(0, N · L)

Jedan dot product. To je cela formula za osnovni diffuse lighting. Kad je normala usmerena direktno ka svetlu (paralelni), rezultat je 1 — potpuna osvetljenost. Kad je svetlo paralelno sa površinom (90°), rezultat je 0 — nema osvetljenja. max(0, ...) osigurava da negativne vrednosti (svetlo pogađa zadnju stranu) budu tretirane kao 0 a ne kao negativno svetlo.

Ovo ćemo detaljno razraditi u poglavlju 10, ali zapamti — dot product je srce osvetljenja.

2. Provera vidljivosti (back-face culling)

Kad renderuješ 3D objekat, ne moraš da crtaš trouglove koji su okrenuti od kamere — ne vide se jer su na "pozadini" objekta. Kako znaš da li je trougao okrenut od kamere?

Izračunaj dot product normale trougla i vektora od trougla do kamere:

Ova jednostavna provera (jedan dot product) eliminiše oko 50% svih trouglova u sceni — ogromna ušteda.

3. Specular refleksije

Spekularne refleksije (sjajni odsjaji na površinama) zavise od toga koliko je vektor refleksije blizu vektoru ka kameri. I to se — pogađaš — računa dot productom.

4. Fresnel efekat

Fresnelov efekat (površine su reflektivnije kad ih gledaš pod strmim uglom) koristi dot product između normale i pravca gledanja. Detaljno u poglavlju 11 o PBR-u.

5. Projekcija

Dot product se koristi za projekciju jednog vektora na drugi — "koliko vektor A ide u pravcu vektora B". Ovo je fundamentalno za mnoge proračune u grafici — od sekvenci, preko okluzije, do svakojakih shader operacija.

Projekcija a na b = (a · ) ·

gde je normalizovani b.

6. Provera "da li je ispred ili iza"

Dot product sa forward vektorom kamere ti kaže da li je objekat ispred ili iza kamere. Pozitivan = ispred, negativan = iza. Korisno za frustum culling i mnoge gameplay mehanike.


Cross product (vektorski proizvod)

Dok dot product daje skalar, cross product daje vektor.

Definicija

Za dva vektora a = (a₁, a₂, a₃) i b = (b₁, b₂, b₃):

a × b = (a₂·b₃ - a₃·b₂, a₃·b₁ - a₁·b₃, a₁·b₂ - a₂·b₁)

Geometrijsko značenje

Rezultat cross producta je vektor koji je normalan (okomit) na oba ulazna vektora. Njegov pravac se određuje pravilom desne ruke (u desnoručnom sistemu) ili leve ruke (u levoručnom), a njegova veličina je:

|a × b| = |a| · |b| · sin(θ)

što je jednako površini paralelograma koji formiraju vektori a i b.

Važno: Cross product NIJE komutativan!

a × bb × a

Zapravo:

a × b = -(b × a)

Rezultat je u suprotnom smeru. Ovo je čest izvor bagova — redosled operanada je bitan.

Primene u grafici

1. Izračunavanje normala

Ovo je najčešća primena. Ako imaš trougao definisan sa tri temena (V₀, V₁, V₂), normalu trougla dobijaš ovako:

  1. Izračunaj dva ivična vektora: E₁ = V₁ - V₀, E₂ = V₂ - V₀
  2. Cross product: N = E₁ × E₂
  3. Normalizuj: = N / |N|

Rezultat je vektor koji je okomit na površinu trougla — normala. Normala govori "na koju stranu gleda" trougao, što je ključno za osvetljenje.

2. Konstruisanje koordinatnog sistema

Ako imaš dva vektora koja definišu dve ose, cross product ti daje treću. Na primer, ako imaš "napred" vektor i "gore" vektor, cross product ti daje "desno" vektor. Ovo se koristi za konstruisanje TBN (Tangent-Bitangent-Normal) matrice koja je ključna za normal mapping (poglavlje 19).

3. Orijentacija (Winding order)

Redosled temena trougla (clockwise vs counter-clockwise) određuje na koju stranu gleda normala. Ovo je fundamentalno za back-face culling i pravilan prikaz geometrije.

4. Torque i rotacija

U fizičkim simulacijama, moment sile (torque) je cross product radijusa i sile.


Matrice

Matrice su alat koji nam omogućava da efikasno opišemo i kombinujemo transformacije u 3D prostoru. Ako su vektori "reči" jezika 3D grafike, matrice su "rečenice" — one opisuju kompleksne operacije u kompaktnom obliku.

Šta je matrica?

Matrica je pravougaona tabela brojeva. U 3D grafici najčešće koristimo:

Na primer, 3×3 matrica izgleda ovako:

| m₀₀  m₀₁  m₀₂ |
| m₁₀  m₁₁  m₁₂ |
| m₂₀  m₂₁  m₂₂ |

gde indeksi predstavljaju red i kolonu (m_{red,kolona}).

Množenje matrice i vektora

Kad pomnožiš matricu M sa vektorom v, dobijaš novi vektor v' — transformisan vektor:

v' = M · v

Za 3×3 matricu i 3D vektor:

| v'x |   | m₀₀  m₀₁  m₀₂ |   | vx |
| v'y | = | m₁₀  m₁₁  m₁₂ | · | vy |
| v'z |   | m₂₀  m₂₁  m₂₂ |   | vz |

Svaka komponenta rezultata je dot product odgovarajućeg reda matrice sa ulaznim vektorom:

Zašto su matrice korisne?

Ključna stvar: kolone matrice definišu novi koordinatni sistem.

Identiteta matrica (identity matrix) ne radi ništa — ulaz = izlaz:

| 1  0  0 |
| 0  1  0 |
| 0  0  1 |

Kolone ove matrice su (1,0,0), (0,1,0), (0,0,1) — standardne ose X, Y, Z. Kad pomnožiš bilo koji vektor ovom matricom, dobiješ isti vektor nazad.

Ali ako promeniš kolone, definišeš nov koordinatni sistem i time transformišeš vektor. Ovo je suština svih transformacija u 3D grafici.

Množenje matrica

Ako imaš dve matrice A i B, njihov proizvod C = A · B je nova matrica koja predstavlja kombinovanu transformaciju — prvo B, pa onda A (redosled je bitan!).

Ovo je izuzetno moćno. Umesto da primenjuješ svaku transformaciju posebno na svaki vertex, možeš da kombinuješ sve transformacije u jednu matricu i primeniš tu jednu matricu. Ako imaš mesh sa 100.000 vertices-a i hoćeš da ga rotiraš, pa skaliraj, pa translatiraš — umesto 3 × 100.000 = 300.000 operacija, izračunaš jednu kombinovanu matricu (3 operacije) i primeniš je 100.000 puta. Ogromna ušteda.

Redosled množenja: A · B ≠ B · A (matrice generalno nisu komutativne). Ovo znači da redosled transformacija menja rezultat — isto kao u realnom svetu: rotiranje pa translacija daje drugačiji rezultat od translacije pa rotacije.


Transformacije

Tri fundamentalne transformacije u 3D grafici su: translacija (pomeranje), rotacija i skaliranje. Svaki objekat u sceni je transformisan nekom kombinacijom ove tri operacije.

Skaliranje (Scale)

Skaliranje menja veličinu objekta. Matrica skaliranja za faktore (sx, sy, sz) duž svake ose:

| sx   0   0 |
|  0  sy   0 |
|  0   0  sz |

Neuniformno skaliranje može da uzrokuje probleme sa normalama — normala se ne transformiše istom matricom kao vertex, već inverznom transponovanom matricom. Ako ovo zvuči komplikovano, ne brini — detaljno u poglavlju 3. Za sada, zapamti: neuniformno skaliranje komplikuje stvari.

Rotacija (Rotation)

Rotacija menja orijentaciju objekta. Postoji matrica za rotaciju oko svake ose:

Rotacija oko Z ose za ugao θ:

|  cos(θ)  -sin(θ)  0 |
|  sin(θ)   cos(θ)  0 |
|    0        0     1 |

Rotacija oko X ose za ugao θ:

| 1    0        0    |
| 0  cos(θ)  -sin(θ) |
| 0  sin(θ)   cos(θ) |

Rotacija oko Y ose za ugao θ:

|  cos(θ)  0  sin(θ) |
|    0     1    0    |
| -sin(θ)  0  cos(θ) |

Rotacija oko proizvoljne ose je kompleksnija — koristi se Rodriguesova formula ili kvaternioni (quaternions).

Gimbal lock — ako rotiraš objekat sekvencijalno oko tri ose (Euler angles), postoji problem: u određenim konfigurcijama dve ose se "poklope" i gubiš jedan stepen slobode. Na primer, ako rotiraš oko Y ose za 90°, X i Z rotacije postaju iste stvar. Ovo je poznat problem u avijaciji i 3D grafici.

Rešenje je korišćenje kvaterniona — matematičke strukture sa 4 komponente (w, x, y, z) koje predstavljaju rotaciju bez problema gimbal lock-a. Kvaternioni su standardni način predstavljanja rotacija u game engine-ima. Unreal Engine koristi FQuat za rotacije i interno konvertuje iz Euler uglova (koji su intuitivniji za ljude) u kvaternione (koji su bolji za računanje).

Kvaternioni imaju još jednu prednost: interpolacija (blending) između dve rotacije je trivijalna sa kvaternionima (Slerp — Spherical Linear Interpolation), a komplikovana i podložna artefaktima sa Euler uglovima. Ovo je ključno za animaciju — kad blenduješ između dva položaja, hoćeš glatku rotaciju.

Translacija (Translation)

I ovde nastaje problem. Translacija je pomeranje — dodavanje vektora na svaki vertex:

v' = v + t (gde je t vektor translacije)

Ali ovo nije matrično množenje! Sa 3×3 matricom, možeš da rotiraš i skaliraš, ali ne možeš da transliraš (pomeriš). Zašto? Jer matrično množenje uvek daje rezultat koji je linearna kombinacija ulaznih komponenti — i (0,0,0) uvek ostaje (0,0,0). Translacija pomera i ishodište, što 3×3 matrica ne može.

Rešenje: homogene koordinate.


Homogene koordinate

Motivacija

Želimo da sve transformacije (translacija, rotacija, skaliranje) možemo da predstavimo kao množenje matricom. To bi nam omogućilo da ih kombinujemo u jednu matricu. Ali 3×3 matrice ne mogu translaciju.

Trik: dodajemo četvrtu koordinatu.

Kako rade

Umesto tačke (x, y, z), koristimo (x, y, z, w).

Za tačke: w = 1 → (x, y, z, 1) Za vektore: w = 0 → (x, y, z, 0)

A umesto 3×3 matrice, koristimo 4×4 matricu:

| m₀₀  m₀₁  m₀₂  tx |
| m₁₀  m₁₁  m₁₂  ty |
| m₂₀  m₂₁  m₂₂  tz |
|  0    0    0    1  |

Gornji levi 3×3 deo je rotacija i skaliranje. Poslednja kolona (tx, ty, tz) je translacija.

Kad pomnožiš ovu matricu sa tačkom (x, y, z, 1):

x' = m₀₀·x + m₀₁·y + m₀₂·z + tx·1
y' = m₁₀·x + m₁₁·y + m₁₂·z + ty·1
z' = m₂₀·x + m₂₁·y + m₂₂·z + tz·1
w' = 1

Translacija (tx, ty, tz) se dodaje! Jer w = 1.

A kad pomnožiš sa vektorom (x, y, z, 0):

x' = m₀₀·x + m₀₁·y + m₀₂·z + tx·0
y' = m₁₀·x + m₁₁·y + m₁₂·z + ty·0
z' = m₂₀·x + m₂₁·y + m₂₂·z + tz·0
w' = 0

Translacija se ne dodaje! Jer w = 0.

Ovo je tačno ono što želimo:

Elegantan trik. Jedna dodatna dimenzija rešava ceo problem.

Perspektivna projekcija i w

Homogena koordinata w ima još jednu ključnu ulogu — perspektivnu projekciju. Kad projeciraš 3D scenu na 2D ekran sa perspektivom (bliže stvari izgledaju veće, daljine manje), delovi perspektivne transformacije koriste w komponentu.

Nakon perspektivne projekcije, w više nije 1 — sadrži informaciju o dubini. Da bi dobio konačne 2D koordinate, deliš x, y, z sa w — ovo se zove perspektivno deljenje (perspective divide) i daje efekt da dalji objekti izgledaju manji. Detaljno o ovome u poglavlju 6 o koordinatnim prostorima.

Zašto se 4×4 matrice koriste svuda

U Unreal Engine-u (i svim modernim engine-ima), gotovo sve transformacije se čuvaju kao 4×4 matrice (FMatrix u UE5). Razlog:

  1. Uniformnost — svaka transformacija (translate, rotate, scale, i njihove kombinacije) može se izraziti kao jedna 4×4 matrica
  2. Kompozicija — više transformacija se kombinuje prostim množenjem matrica u jednu
  3. GPU efikasnost — GPU je dizajniran da veoma brzo množi 4×4 matrice sa 4-komponentnim vektorima. Ovo je jedna od njegovih primarnih operacija.

Ceo rendering pipeline se može posmatrati kao niz matrničnih množenja:

Sve ovo su 4×4 matrice, i mogu se kombinovati u jednu — MVP (Model-View-Projection) matricu — koja jednim množenjem transformiše vertex iz prostora modela u prostor ekrana. O ovome detaljno u poglavlju 6.


Transform hijerarhije (Parent-child relationships)

U game engine-u, objekti često imaju hijerarhiju — "roditelj-dete" odnos. Kad pomeriš roditelja, dete se pomera sa njim.

Primer: auto. Telo auta je roditelj. Točkovi su deca. Kad pomeriš auto, točkovi se pomeraju sa njim. Ali točkovi mogu i da se rotiraju nezavisno (vrte se).

Matematički, ovo funkcioniše tako što svako dete čuva svoju lokalnu transformaciju — poziciju, rotaciju, skaliranje relativno na roditelja. Da bi dobio svetsku (world) transformaciju deteta, množiš njegovu lokalnu transformaciju sa svim roditeljskim transformacijama iznad njega:

WorldTransform(dete) = WorldTransform(roditelj) · LocalTransform(dete)

Ako imaš duboku hijerarhiju (roditelj → dete → unuk → praunuk...), množiš sve matrice niz lanac:

WorldTransform(praunuk) = Transform(roditelj) · Transform(dete) · Transform(unuk) · Transform(praunuk)

Ovo je elegantno i efikasno — kad pomeriš roditelja, ne moraš ručno da ažuriraš svako dete. Samo ažuriraš roditeljevu matricu, i kad ti treba svetska pozicija deteta, pomnožiš matrice.

Ali ovde se krije i performance zamka: duboke hijerarhije zahtevaju više matrničnih množenja. Za skeletal mesh sa stotinama kostiju, ovo može da bude značajan CPU trošak. Zato se u praksi teži "plitkim" hijerarhijama gde je moguće.


Inverzna matrica

Inverzna matrica M⁻¹ je matrica koja "poništava" efekat M:

M⁻¹ · M = I (identitet matrica)

Ako M rotira objekat 30° u smeru kazaljke na satu, M⁻¹ ga rotira 30° u suprotnom smeru. Ako M skalira za faktor 2, M⁻¹ skalira za faktor 0.5.

Gde se koristi:

  1. View matrica — pozicioniranje kamere. Umesto da pomeriš ceo svet da bude ispred kamere, transformišeš sve inverznom transformacijom kamere. Ako je kamera na poziciji (10, 5, 3) i rotirana za 45°, view matrica je inverz te transformacije — pomeri svet za (-10, -5, -3) i rotiraj za -45°.

  2. Unprojection — pretvaranje 2D koordinata ekrana nazad u 3D zrak (ray) u svetu. Ovo se koristi za picking (klik na objekat u sceni) i ray tracing.

  3. Transformacija normala — normali se ne transformišu istom matricom kao verteksi. Koristi se inverzna transponovana matrica — (M⁻¹)ᵀ. Ovo osigurava da normala ostaje okomita na površinu čak i posle neuniformnog skaliranja.

Izračunavanje inverzne matrice je relativno skupa operacija (O(n³) generalno), ali za specifične tipove matrica postoje prečice. Na primer, inverz čiste rotacione matrice je njena transpozicija (zamena redova i kolona), što je trivijalno brzo.


Transponovanje matrice

Transpozicija matrice je zamena redova i kolona:

Originalna:        Transponovana:
| a  b  c |        | a  d  g |
| d  e  f |   →    | b  e  h |
| g  h  i |        | c  f  i |

Za ortogonalnu matricu (matricu čiji su redovi i kolone međusobno okomiti i normalizovani — što važi za čiste rotacione matrice), transpozicija je jednaka inverzu:

Mᵀ = M⁻¹

Ovo je veoma korisno jer je transponovanje trivijalno brza operacija (samo presložiš podatke), dok je pravi inverz skup. U praksi, kad imaš čistu rotacionu matricu i treba ti inverz, samo je transponuješ.


Ostali matematički koncepti

Interpolacija — Lerp

Linearna interpolacija (Lerp) je jedan od najčešće korišćenih koncepata u grafici i game development-u. Formula:

lerp(A, B, t) = A + t · (B - A) = (1 - t) · A + t · B

gde je t vrednost od 0 do 1.

Lerp radi sa brojevima, vektorima, bojama — bilo čim gde ima smisla "tačka između". Koristi se za:

Clamping

Clamping ograničava vrednost na opseg:

clamp(x, min, max) = max(min, min(max, x))

Ako je x ispod min, vraća min. Ako je iznad max, vraća max. Inače vraća x.

Koristi se konstantno — na primer, da se intenzitet svetlosti ne spusti ispod 0 ili da UV koordinate ostanu u opsegu 0-1.

Saturate / Clamp01

Specijalan slučaj clampa — ograničenje na opseg [0, 1]:

saturate(x) = clamp(x, 0, 1)

Toliko je čest u shaderima da ima sopstvenu instrukciju na GPU-u — saturate() u HLSL-u je besplatan (nema dodatni cost).

Trigonometrija

Sin, cos, tan i njihovi inverzi se koriste za rotacije, projekcije, i mnoge druge proračune. Ključne veze:

U shaderima, trigonometrijske funkcije su relativno skupe. Kad je moguće, koriste se aproksimacije ili se rezultati predračunaju.

Radian vs Degree

Postoje dva načina merenja uglova:

Konverzija:

Matematičke funkcije (sin, cos, itd.) u programskim jezicima i shaderima koriste radijane. Unreal Engine GUI prikazuje stepene (intuitivnije za ljude), ali interno radi u radijanima.


Prostori i bazni vektori

Koncept koji povezuje sve prethodno:

Svaki koordinatni sistem može da se opiše sa:

  1. Ishodištem (origin) — tačka (0, 0, 0)
  2. Tri bazna vektora — pravci osa X, Y, Z

Bazni vektori standardnog koordinatnog sistema su:

Svaki vektor u prostoru je linearna kombinacija baznih vektora:

v = v₁ · e₁ + v₂ · e₂ + v₃ · e₃

Kad kažeš "vektor (3, 4, 5)", zapravo kažeš "3 puta X bazni vektor + 4 puta Y bazni vektor + 5 puta Z bazni vektor".

Promena baze (change of basis) je transformacija iz jednog koordinatnog sistema u drugi. I to se radi — pogodioci — množenjem matricom. Kolone matrice su bazni vektori novog koordinatnog sistema izraženi u starom.

Ovo je ključno za razumevanje poglavlja 6 (Coordinate Spaces) — svaki prostor u render pipeline-u (object space, world space, view space...) je definisan svojim baznim vektorima, i prelazak između prostora je matrično množenje.


Matematika u praksi: GPU i preciznost

Postoji praktičan aspekt matematike koji je bitan za real-time grafiku: preciznost brojeva.

Floating-point (decimalni) brojevi

Računari čuvaju decimalne brojeve u formatu koji se zove floating-point (IEEE 754 standard). Postoje tri veličine:

GPU-i su optimizovani za float (32-bit). Double (64-bit) je 2-4x sporiji na većini GPU-a. Half (16-bit) je često 2x brži od float-a i koristi polovinu memorije — pa se koristi kad god je preciznost dovoljna.

Precision problemi u grafici

Floating-point brojevi imaju ograničenu preciznost, i ta preciznost se smanjuje kako brojevi rastu. Broj 1.0 se čuva savršeno precizno, ali broj 16777216.0 (2²⁴) nema preciznost za decimale — dodavanje 1.0 na ovaj broj ne menja ga!

Ovo ima praktične posledice:

Opseg i preciznost depth buffer-a

Depth buffer (Z-buffer) je posebno osetljiv na preciznost jer mora da razlikuje udaljenosti objekata od kamere. Standardni depth buffer koristi floating-point format gde su vrednosti bliže kameri preciznije nego one dalje.

Ovaj nelinearan raspored preciznosti — mnogo preciznosti blizu, malo daleko — je razlog zašto igre imaju "near clip" i "far clip" ravni kamere. Ako staviš near clip na 0.01 i far clip na 100000, skoro sva preciznost otpada na prvih par metara, a na velikim udaljenostima dobijaš Z-fighting.

Reverse-Z je tehnika (koristi se u UE5) gde se depth buffer obrne — 1.0 je blizu, 0.0 je daleko. Ovo bolje raspoređuje preciznost jer floating-point ima više preciznosti oko 0 nego oko 1. Detalji u poglavlju 9.


Rezime ključnih pojmova

Pojam Značenje
Koordinatni sistem Okvir za opisivanje pozicija u prostoru pomoću brojeva
Left-hand / Right-hand Dve konvencije za orijentaciju 3D osa — UE5 koristi left-hand
Vektor Matematički objekat sa pravcem i veličinom
Tačka Pozicija u prostoru
Dot product Operacija koja daje skalar — meri "usklađenost" dva vektora
Cross product Operacija koja daje vektor okomit na dva ulazna vektora
Normalizacija Skaliranje vektora na dužinu 1, čuvajući pravac
Matrica (4×4) Tabela brojeva koja predstavlja transformaciju
Translacija Pomeranje objekta
Rotacija Okretanje objekta
Skaliranje Promena veličine objekta
Homogene koordinate 4-komponentne koordinate (x,y,z,w) koje omogućavaju translaciju kroz matrično množenje
Identitet matrica Matrica koja ne menja ništa — ekvivalent broja 1 za množenje
Inverzna matrica Matrica koja "poništava" drugu matricu
Kvaternion 4-komponentna matematička struktura za predstavljanje rotacija bez gimbal lock-a
Lerp Linearna interpolacija — glatki prelaz između dve vrednosti
Floating-point Format za čuvanje decimalnih brojeva sa ograničenom preciznošću

Sledeće poglavlje ulazi u svet mesh-eva i topologije — šta je zapravo 3D model, kako su organizovani njegovi sastavni delovi, i kako GPU čuva geometriju u memoriji.

📖 Dalje čitanje: