Deo zbornika Teorija razvoja igara

Matrica rotacije

Matrica rotacije služi za okretanje predmeta ili celokupnog prostora oko određene tačke ili ose. Podrazumevano, matrica rotacije rotira objekat u odnosu na ishodište.

U dve dimenzije postoji samo jedna moguća osa rotacije, pa nam je potreban samo ugao. U 3D je dosta složenije: postoje tri primarne ose rotacije, a telo može rotirati i oko bilo koje proizvoljne ose.

2D rotacija

2D rotacija oko ishodišta u smeru kazaljke:

cos(θ), -sin(θ)
sin(θ),  cos(θ)

2D rotacija oko ishodišta u smeru suprotnom od kazaljke:

 cos(θ) sin(θ)
-sin(θ) cos(θ)

Posebni slučajevi

Obzirom da je cos(90) = 0, a sin(90) = 1, postoje posebne rotacije koje samo obrću unete vrednosti:

rotacija 90°  = (x, y) => (-y, x)
rotacija 180° = (x, y) => (-x, -y)
rotacija 270° = (x, y) => (y, -x)

Objašnjenje: Kada zamenimo vrednosti sin i cos u matrici rotacije dobijemo:

R(90°) = 0, -1
         1,  0

Množenje ove matrice sa (x, y) daje (-y, x).

3D rotacija

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 z ose za ugao θ:

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

Homogeni zapis

Matrica rotacije oko x-ose:

1    0       0    0  
0   cosθ  -sinθ   0  
0   sinθ   cosθ   0  
0    0       0    1

Matrica rotacije oko y-ose:

cosθ   0   sinθ   0  
0      1      0    0  
-sinθ  0   cosθ   0  
0      0      0    1

Matrica rotacije oko z-ose:

cosθ  -sinθ   0    0  
sinθ   cosθ   0    0  
0      0      1    0  
0      0      0    1

Primer: Tarzan

Recimo da igrač treba da se ljulja na lijani. Možemo primeniti rotaciju oko tačke gde je lijana pričvršćena. Dakle, treba izračunati ugao između igrača i centra rotacije, povećavati ga i sledstveno ažurirati poziciju igrača.

Ugao između igrača i centra rotacije računamo pomoću atan2(). Nakon što povećamo ugao, možemo izračunati nove x i y koordinate sa sin i cos:

ugao = atan2(y, x)
duzina = sqrt(x * x + y * y)
ugao += 1
nov_x = duzina * cos(ugao)
nov_y = duzina * sin(ugao)

Pošto konvertujemo iz kartezijanskih koordinata u polarne, i ponovo nazad, možemo izgubiti preciznost. Bolji način je matrica rotacija, koja omogućuje rotiranje bez međukoraka:

nov_x = x * cos(ugao) - y * sin(ugao)
nov_y = x * sin(ugao) + y * cos(ugao)

Optimizacija: razumno je unapred izračunati cos i sin, jer nam treba dvaput.

Primer: Svemirski brod

Recimo da pravimo igru Asteroidi, i imamo jednostavan 2D svemirski brod koji se može slobodno rotirati. Model broda izgleda ovako:

Kako crtati brod rotiran za proizvoljan ugao, na primer za 49 stepeni u smeru suprotnom od kazaljke? Pomoću trigonometrije možemo napraviti funkciju koja prima tačku i ugao, te vraća rotiranu tačku:

vec2 rotate(vec2 point, float angle){
   vec2 rotated_point;
   rotated_point.x = point.x * cos(angle) - point.y * sin(angle);
   rotated_point.y = point.x * sin(angle) + point.y * cos(angle);
   return rotated_point;
}

Primenom funkcije na tri tačke broda dobijamo sledeći oblik:

Operacije kosinusa i sinusa su prilično spore, ali smo ih radili samo na tri tačke. Međutim, sada odlučujemo da nadogradimo brod da izgleda ovako:

Sada je stara funkcija prespora! Elegantno rešenje bi bilo da umesto svake tačke ponaosob rotiramo samo x i y osu modela.

Objašnjenje: Pozicija (3,2) znači 3 * x osa plus 2 * y osa. Podrazumevano, x osa = (1,0), y osa = (0,1), pa dobijamo 3(1,0) + 2(0,1). Međutim, ako rotiramo ose, lako ćemo izračunati svaku tačku koja zavisi od njih.

rotiranje (1,0) za 49 stepeni = (0,66, 0,75) // nova x osa
rotiranje (0,1) za 49 stepeni = (-0,75, 0,66) // nova y osa

Za modifikovane ose (a,b) i (c,d), novu tačku (x,y) možemo naći pomoću ovog izraza:

x(a,b) + y(c,d)