• Mindscape 🔥
    • Playlist 🎧
    • Vim 사용 매뉴얼
  • 🧠 Algorithm

    • Python 시간 초과 방지를 위한 팁
    • 1966번: 프린터 큐
    • 1018번: 체스판 다시 칠하기
  • 💰 Finance

    • 비트코인(Bitcoin)
  • 🏛️ Humanities

    • Nordvik, Russia
    • North Sentinel Island
    • 롱고롱고(Rongorongo)
  • 🏋️ Wellness

    • 🫒 엑스트라 버진 올리브유 (Extra Virgin Olive Oil)
    • 차전자피(Psyllium Husk)
  • 🖥️ Computer Graphics

    • 8 - Lighting
    • 9 - Orientation & Rotation
    • 10 - Character Animation
    • 11 - Curves
    • 12 - More Lighting, Texture
  • 🗂️ Operating System

    • 7. Deadlocks
    • 8. Memory Management(1)
    • 9. Memory Management(2)
    • 10. Virtual Memory(1)
    • 11. Virtual Memory(2)
    • 12. File System
    • 13. Mass Storage Management
    • 14. I/O Systems
  • 🔣 Programming Language Theory

    • 13. FPL(1)

9 - Orientation & Rotation

Outline

  • Basic Concepts

    • Orientation vs. Rotation
    • Degrees of Freedom
    • Euler's Rotation Theorem
  • 3D Orientation & Rotation Representations

    • Euler Angles
    • Rotation Vector (Axis-Angle)
    • Rotation Matrix
    • Unit Quaternion
  • Which Representation to Use?

    • 다양한 관점에서의 고려
    • 3D Orientation / Rotation의 보간
    • 각 표현 방식의 장단점

Basic Concepts

State vs Movement

  • position : translation
    • position = 객체의 3차원 위치
    • translation = 선형 이동 (linear movement)

기준 좌표계: Some reference frame

  • (position : translation)
  • (orientation : rotation)
  • → (state : movement)
  • orientation = 객체의 3차원 “방향 상태”
  • rotation = 각운동 (angular movement)

기준 좌표계: Some reference frame

Orientation vs. Rotation

(and Position vs. Translation)

  • Orientation & Position - state

    • Position: 위치 상태
      • 좌표계가 주어졌을 때, 어떤 객체의 위치는 기준 위치로부터의 translation으로 표현 가능함
    • Orientation: 방향 상태 (각 위치)
      • 좌표계가 주어졌을 때, 객체의 방향은 기준 방향으로부터의 rotation으로 표현 가능함
  • Rotation & Translation - movement

    • Translation: 선형 이동 (위치 간 차이)
    • Rotation: 각운동 (방향 간 차이)
  • 이 관계는 점(point) 과 벡터(vector) 관계와 유사함

    • 점(point): 위치
    • 벡터(vector): 두 점 사이의 차이

Similarity in Operations

  • Point & vector
    • (point) + (point) → (정의되지 않음)
    • (vector) ± (vector) → (vector)
    • (point) ± (vector) → (point)
    • (point) - (point) → (vector)

※ 벡터의 덧셈/뺄셈이 아님에 주의

  • Orientation & rotation
    • (orientation) + (orientation) → (정의되지 않음)
    • (rotation) ± (rotation) → (rotation)
    • (orientation) ± (rotation) → (orientation)
    • (orientation) ∘ (rotation) → (orientation)
    • (orientation) ∘ (orientation⁻¹) → (rotation)

Degrees of Freedom (DOF)

  • 어떤 고유한 상태(configuration) 를 정의하기 위한 독립적인 매개변수의 수

  • 예시:

    • 한 방향으로의 이동: 1 DOF
    • 한 축을 중심으로 하는 회전: 1 DOF
  • 평면 상 이동 → 2 DOFs

  • 두 축을 중심으로 하는 회전 → 2 DOFs

  • 3D 공간 이동 → 3 DOFs

  • 3D 공간에서의 회전 → 3 DOFs

  • 3D 공간에서의 임의의 강체 운동
    → 6 DOFs
    (이동 3개 + 회전 3개)

Euler's Rotation Theorem

  • 정리 (Theorem)

    When a sphere is moved around its centre it is always possible to find a diameter whose direction in the displaced position is the same as in the initial position.
    — Leonhard Euler (1707–1783)

  • 3차원 공간에서,
    강체(rigid body)의 임의의 이동 중 물체의 한 점이 고정되어 있다면,
    이는 항상 어떤 축을 중심으로 하는 단일 회전으로 표현 가능하다.

Euler's Rotation Theorem

  • 3D 회전 (즉, 한 점이 고정된 상태의 모든 움직임)은
    항상 회전 축과 그 축을 중심으로 하는 회전 각도를 찾을 수 있음

θ\thetaθ: 회전 각도
nnn: 회전 축 (단위 벡터)

3D Orientation & Rotation Representations

Describing 3D Rotation & Orientation

  • 3D 회전과 방향 표현은 2D 경우보다 직관적이지 않음

  • 3D 방향을 기술하는 여러 방법

    • Euler angles
    • Rotation vector (Axis-angle)
    • Rotation matrices
    • Unit quaternions

Euler Angles

  • 임의의 3차원 회전은 세 개의 주축(principal axis)에 대한 회전각으로 표현 가능함

  • 가능한 조합 12가지:

    • XYZ, YYX, XZY, XZX
    • YZX, YZY, ZXY, YXZ
    • ZXY, ZXZ, ZYX, ZYZ

단, 같은 축이 연속해서 나타나지 않는 한 조합은 가능

Example: ZXZ Euler Angles

  1. ZZZ축 기준으로 α\alphaα만큼 회전
  2. 새로운 기준축 XXX 기준으로 β\betaβ만큼 회전
  3. 다시 새로운 ZZZ축 기준으로 γ\gammaγ만큼 회전

R=Rz(α)⋅Rx(β)⋅Rz(γ)R = R_z(\alpha) \cdot R_x(\beta) \cdot R_z(\gamma) R=Rz​(α)⋅Rx​(β)⋅Rz​(γ)

각 회전 행렬은 다음과 같음:

Rz(α)=[cos⁡α−sin⁡α0sin⁡αcos⁡α0001]Rx(β)=[1000cos⁡β−sin⁡β0sin⁡βcos⁡β]Rz(γ)=[cos⁡γ−sin⁡γ0sin⁡γcos⁡γ0001]R_z(\alpha) = \begin{bmatrix} \cos \alpha & -\sin \alpha & 0 \\ \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 1 \end{bmatrix} \quad R_x(\beta) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos \beta & -\sin \beta \\ 0 & \sin \beta & \cos \beta \end{bmatrix} \quad R_z(\gamma) = \begin{bmatrix} \cos \gamma & -\sin \gamma & 0 \\ \sin \gamma & \cos \gamma & 0 \\ 0 & 0 & 1 \end{bmatrix} Rz​(α)=​cosαsinα0​−sinαcosα0​001​​Rx​(β)=​100​0cosβsinβ​0−sinβcosβ​​Rz​(γ)=​cosγsinγ0​−sinγcosγ0​001​​

Example: Yaw-Pitch-Roll Convention

(ZYX Euler Angles)

  • 항공기 방향 표현 시 일반적으로 사용됨
  1. ZZZ축 기준으로 yaw 회전
  2. 새 기준의 YYY축 기준으로 pitch 회전
  3. 새 기준의 XXX축 기준으로 roll 회전

R=Rz(yaw)⋅Ry(pitch)⋅Rx(roll)R = R_z(\text{yaw}) \cdot R_y(\text{pitch}) \cdot R_x(\text{roll}) R=Rz​(yaw)⋅Ry​(pitch)⋅Rx​(roll)

Recall: 3D Rotation Matrix about Principle Axes

  • xxx축 회전:

Rx(θ)=[1000cos⁡θ−sin⁡θ0sin⁡θcos⁡θ]R_x(\theta) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos \theta & -\sin \theta \\ 0 & \sin \theta & \cos \theta \end{bmatrix} Rx​(θ)=​100​0cosθsinθ​0−sinθcosθ​​

  • yyy축 회전:

Ry(θ)=[cos⁡θ0sin⁡θ010−sin⁡θ0cos⁡θ]R_y(\theta) = \begin{bmatrix} \cos \theta & 0 & \sin \theta \\ 0 & 1 & 0 \\ -\sin \theta & 0 & \cos \theta \end{bmatrix} Ry​(θ)=​cosθ0−sinθ​010​sinθ0cosθ​​

  • zzz축 회전:

Rz(θ)=[cos⁡θ−sin⁡θ0sin⁡θcos⁡θ0001]R_z(\theta) = \begin{bmatrix} \cos \theta & -\sin \theta & 0 \\ \sin \theta & \cos \theta & 0 \\ 0 & 0 & 1 \end{bmatrix} Rz​(θ)=​cosθsinθ0​−sinθcosθ0​001​​

Gimbal Lock

  • Euler 각을 사용할 경우, 두 회전 축이 정렬되면 일시적으로 자유도(DOF)를 잃게 됨
  • 정상 구성 (Normal configuration):
    • 물체는 자유롭게 회전 가능
  • Gimbal lock 구성:
    • 특정 방향으로의 회전이 불가능해짐

[Demo] Euler Angles

![Euler Angle Demo 이미지]

https://compsc290-s2016.github.io/CoursePage/Materials/EulerAnglesViz/index.html

  • yaw, pitch, roll 값을 직접 바꿔보기
  • 세 회전 축을 정렬시켜 gimbal lock 상태 만들기
    • 예: pitch를 90도로 설정

Rotation Vector (Axis-Angle)

  • 회전 벡터(rotation vector)
    • v=θ v^=(x,y,z)\mathbf{v} = \theta \, \hat{\mathbf{v}} = (x, y, z)v=θv^=(x,y,z)
  • 축-각 표현(axis-angle)
    • (θ,v^)(\theta, \hat{\mathbf{v}})(θ,v^)

θ\thetaθ: 회전 각도
v^\hat{\mathbf{v}}v^: 회전 축 (단위 벡터)

Rotation Vector (Axis-Angle)

  • 회전 벡터는 exponential coordinates 라고도 불림
  • 명칭 유래가 궁금하다면 다음을 참고:
    Modern Robotics, Section 3.2.3

Rotation Matrix

  • 회전 행렬 RRR은 다음을 정의함:
    • 새로운 회전된 좌표계의 방향
    • 또는 기존 world frame에서 해당 좌표계로의 회전

R=[r11r12r13r21r22r23r31r32r33](expressed in the world frame)R = \begin{bmatrix} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \end{bmatrix} \quad \text{(expressed in the world frame)} R=​r11​r21​r31​​r12​r22​r32​​r13​r23​r33​​​(expressed in the world frame)

  • 정방 행렬 RRR이 회전 행렬이기 위한 조건은 다음 두 가지를 모두 만족해야 함:

    1. RRT=RTR=IRR^T = R^TR = IRRT=RTR=I
    2. det⁡(R)=1\det(R) = 1det(R)=1
  • 회전 행렬은 orthogonal matrix 이며, 행렬식이 1인 경우는 특별히 special orthogonal matrix 라고 부름

  • 3차원 회전 행렬의 집합은 SO(3)SO(3)SO(3), 즉 special orthogonal group을 구성함

Geometric Properties of Rotation Matrix

  • RTR^TRT는 RRR의 역회전임

    • RRT=I  ⟺  R−1=RTRR^T = I \iff R^{-1} = R^TRRT=I⟺R−1=RT
  • R1R2R_1 R_2R1​R2​ 또한 회전 행렬임 (회전의 합성)

    • 증명:
      (R1R2)T(R1R2)=R2TR1TR1R2=R2TR2=I(R_1 R_2)^T (R_1 R_2) = R_2^T R_1^T R_1 R_2 = R_2^T R_2 = I(R1​R2​)T(R1​R2​)=R2T​R1T​R1​R2​=R2T​R2​=I
      det⁡(R1R2)=det⁡(R1)⋅det⁡(R2)=1\det(R_1 R_2) = \det(R_1) \cdot \det(R_2) = 1det(R1​R2​)=det(R1​)⋅det(R2​)=1
  • 회전 행렬을 적용하더라도 벡터의 길이는 변하지 않음

    • 증명:

      ∥Rv∥2=(Rv)T(Rv)=vTRTRv=vTv=∥v∥2\|R \mathbf{v}\|^2 = (R \mathbf{v})^T (R \mathbf{v}) = \mathbf{v}^T R^T R \mathbf{v} = \mathbf{v}^T \mathbf{v} = \|\mathbf{v}\|^2 ∥Rv∥2=(Rv)T(Rv)=vTRTRv=vTv=∥v∥2

  • 복소수(complex number)는 2D 회전을 표현 가능

    • z=x+yiz = x + yiz=x+yi, i2=−1i^2 = -1i2=−1
    • z=rcos⁡φ+irsin⁡φz = r \cos \varphi + i r \sin \varphiz=rcosφ+irsinφ
  • Quaternion은 이를 3D로 확장한 개념임

  • 기본 표현:

    q=w+xi+yj+zkq = w + xi + yj + zk q=w+xi+yj+zk

  • 규칙:

    i2=j2=k2=ijk=−1ij=k,jk=i,ki=jji=−k,kj=−i,ik=−j\begin{aligned} i^2 = j^2 = k^2 &= ijk = -1 \\ ij = k,\quad jk = i,\quad ki = j \\ ji = -k,\quad kj = -i,\quad ik = -j \end{aligned} i2=j2=k2ij=k,jk=i,ki=jji=−k,kj=−i,ik=−j​=ijk=−1

Quaternions

  • 일반적인 표현:

    q=w+xi+yj+zkq = w + xi + yj + zk q=w+xi+yj+zk

  • 여기서:

    • www: 실수 부분 (real part, 또는 scalar part)
    • xi+yj+zkxi + yj + zkxi+yj+zk: 허수 부분 (imaginary part, 또는 vector part)
  • 표기 방법:

    q=w+v=(w,x,y,z)=(w,v)q = w + \mathbf{v} = (w, x, y, z) = (w, \mathbf{v}) q=w+v=(w,x,y,z)=(w,v)

Unit Quaternions

  • Unit quaternion은 3D 회전을 표현함

    • q=w+xi+yj+zkq = w + x i + y j + z kq=w+xi+yj+zk
    • 조건: x2+y2+z2=1x^2 + y^2 + z^2 = 1x2+y2+z2=1
  • z=cos⁡φ+isin⁡φz = \cos \varphi + i \sin \varphiz=cosφ+isinφ 형태의 복소수와 유사하게, 2D 회전을 표현함

  • u^\hat{\mathbf{u}}u^ 축을 기준으로 각 θ\thetaθ 만큼 회전하는 쿼터니언은 다음과 같음:

q=(cos⁡θ2,  u^sin⁡θ2)q = \left( \cos \frac{\theta}{2}, \; \hat{\mathbf{u}} \sin \frac{\theta}{2} \right) q=(cos2θ​,u^sin2θ​)

또는

q=w+xi+yj+zk=(w,v)q = w + x i + y j + z k = (w, \mathbf{v}) q=w+xi+yj+zk=(w,v)

Unit Quaternions

  • 3차원 위치 p=(x,y,z)\mathbf{p} = (x, y, z)p=(x,y,z) 는 pure imaginary quaternion (0,x,y,z)(0, x, y, z)(0,x,y,z)로 표현됨

  • 이 벡터가 u^\hat{\mathbf{u}}u^ 축을 기준으로 각 θ\thetaθ 만큼 회전하면, 새로운 위치 p′=(x′,y′,z′)\mathbf{p'} = (x', y', z')p′=(x′,y′,z′) 는 다음과 같음:

p′=q p q−1\mathbf{p'} = q \, \mathbf{p} \, q^{-1} p′=qpq−1

단, 회전 쿼터니언은 다음과 같음:

q=(cos⁡θ2,  u^sin⁡θ2)q = \left( \cos \frac{\theta}{2}, \; \hat{\mathbf{u}} \sin \frac{\theta}{2} \right) q=(cos2θ​,u^sin2θ​)

Unit Quaternions

  • 항등원 (Identity):

    q=(1,0,0,0)q = (1, 0, 0, 0) q=(1,0,0,0)

  • 곱셈 (Multiplication):

    q1q2=(w1,v1)(w2,v2)=(w1w2−v1⋅v2,  w1v2+w2v1+v1×v2)q_1 q_2 = (w_1, \mathbf{v}_1)(w_2, \mathbf{v}_2) = (w_1 w_2 - \mathbf{v}_1 \cdot \mathbf{v}_2,\; w_1 \mathbf{v}_2 + w_2 \mathbf{v}_1 + \mathbf{v}_1 \times \mathbf{v}_2) q1​q2​=(w1​,v1​)(w2​,v2​)=(w1​w2​−v1​⋅v2​,w1​v2​+w2​v1​+v1​×v2​)

  • 역원 (Inverse 또는 Conjugate):

    q−1=(w,−x,−y,−z)q^{-1} = (w, -x, -y, -z) q−1=(w,−x,−y,−z)

  • 의미:

    • q1q2q_1 q_2q1​q2​: 먼저 q1q_1q1​로 회전하고, 그다음 q2q_2q2​로 회전 (body frame 기준)
      또는 반대로 q2q_2q2​로 회전하고 그다음 q1q_1q1​로 회전 (world frame 기준)
  • 회전 적용:

    p′=q1q2 p (q1q2)−1=q1(q2 p q2−1)q1−1\mathbf{p'} = q_1 q_2 \, \mathbf{p} \, (q_1 q_2)^{-1} = q_1 (q_2 \, \mathbf{p} \, q_2^{-1}) q_1^{-1} p′=q1​q2​p(q1​q2​)−1=q1​(q2​pq2−1​)q1−1​

Which Representation to Use?

1) "Addition" of Rotations

  • ✅ Rotation matrix, Unit quaternion:

    • R2R1,  q2q1R_2 R_1,\; q_2 q_1R2​R1​,q2​q1​
    • Rx(θ1)R_x(\theta_1)Rx​(θ1​) 후에 Ry(θ2)R_y(\theta_2)Ry​(θ2​) 적용하면 (현재 기준) body frame 기준 회전
    • 단, 요소 단위 덧셈은 회전 행렬이나 쿼터니언을 보장하지 않음
  • ❌ Euler angles:

    • (α1,β1,γ1)+(α2,β2,γ2)≠(α1+α2,β1+β2,γ1+γ2)(\alpha_1, \beta_1, \gamma_1) + (\alpha_2, \beta_2, \gamma_2) \ne (\alpha_1 + \alpha_2, \beta_1 + \beta_2, \gamma_1 + \gamma_2)(α1​,β1​,γ1​)+(α2​,β2​,γ2​)=(α1​+α2​,β1​+β2​,γ1​+γ2​)
    • 단순 덧셈은 실제 회전의 합을 의미하지 않음
  • ❌ Rotation vector:

    • v1+v2\mathbf{v}_1 + \mathbf{v}_2v1​+v2​는 v2\mathbf{v}_2v2​로 이어서 회전한다는 의미가 아님

2) "Subtraction" of Rotations

  • ✅ Rotation matrix, Unit quaternion:

    • R1TR2,  q1−1q2R_1^T R_2,\; q_1^{-1} q_2R1T​R2​,q1−1​q2​
    • 회전 차이 = 프레임 R2R_2R2​를 R1R_1R1​과 일치시키는 회전
    • 증명: R1TR2=RR_1^T R_2 = RR1T​R2​=R → R1R=R2R_1 R = R_2R1​R=R2​
    • 요소 단위 차는 여전히 유효한 회전 아님
  • ❌ Euler angles:

    • (α2,β2,γ2)−(α1,β1,γ1)≠(α2−α1,β2−β1,γ2−γ1)(\alpha_2, \beta_2, \gamma_2) - (\alpha_1, \beta_1, \gamma_1) \ne (\alpha_2 - \alpha_1, \beta_2 - \beta_1, \gamma_2 - \gamma_1)(α2​,β2​,γ2​)−(α1​,β1​,γ1​)=(α2​−α1​,β2​−β1​,γ2​−γ1​)
    • 단순 차이는 실제 회전 차이를 반영하지 않음
  • ❌ Rotation vector:

    • v2−v1\mathbf{v}_2 - \mathbf{v}_1v2​−v1​
    • 두 회전의 차이를 의미하지 않음

3) Interpolation of Rotations

  • 각 구성 요소를 선형 보간(linear interpolation)해도 괜찮을까?

    • Euler angles
    • Rotation vector
    • Rotation matrix
    • Unit quaternion
    • ...?
  • 👉 안 된다!

Interpolating Each Element of Rotation Matrices / Unit Quaternions?

  • 예: 단위 행렬 R0R_0R0​ 과 xxx축으로 90도 회전한 행렬 R1R_1R1​의 보간을 시도

lerp([100010001],[10000−1010],  0.5)=[10000.5−0.500.50.5]\text{lerp}\left( \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}, \begin{bmatrix} 1 & 0 & 0 \\ 0 & 0 & -1 \\ 0 & 1 & 0 \end{bmatrix},\; 0.5 \right) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 0.5 & -0.5 \\ 0 & 0.5 & 0.5 \end{bmatrix} lerp​​100​010​001​​,​100​001​0−10​​,0.5​=​100​00.50.5​0−0.50.5​​

⛔ 이는 회전 행렬이 아님! 전혀 의미 없는 결과

  • 마찬가지로, unit quaternion의 (w,x,y,z)(w, x, y, z)(w,x,y,z) 값을 단순히 보간해도 의미 없음

Interpolating Rotation Vectors?

  • 동일한 길이의 두 회전 벡터 v1\mathbf{v}_1v1​, v2\mathbf{v}_2v2​가 있다고 가정

  • v1\mathbf{v}_1v1​, v2\mathbf{v}_2v2​를 선형 보간하면 간격이 균등해 보일 수 있음

하지만 실제 방향의 변화 측면에서는 균등하지 않음
👉 올바른 방식 아님

Interpolating Euler Angles?

  • 두 Euler 각 튜플을 선형 보간하면 정확한 결과를 얻지 못함

    • ❌ 각속도(angular velocity)가 일정하지 않음
    • ❌ gimbal lock 발생 영역에서는 부자연스러운 끊김이 발생

Slerp

  • 정답: Slerp (Shoemake, 1985)

    • Spherical linear interpolation
    • 두 방향의 구면상 선형 보간 방식
  • 수식:

slerp(R1,R2,t)=R1(R1TR2)t=R1exp⁡(t⋅log⁡(R1TR2))\text{slerp}(R_1, R_2, t) = R_1 \left( R_1^T R_2 \right)^t = R_1 \exp \left( t \cdot \log \left( R_1^T R_2 \right) \right) slerp(R1​,R2​,t)=R1​(R1T​R2​)t=R1​exp(t⋅log(R1T​R2​))

여기서 ttt는 지수(power) 연산이며 전치(transpose)가 아님

Slerp with Rotation Matrices

  • slerp(R1,R2,t)=R1(R1TR2)t\text{slerp}(R_1, R_2, t) = R_1 (R_1^T R_2)^tslerp(R1​,R2​,t)=R1​(R1T​R2​)t

  • 의미:

    • R1TR2R_1^T R_2R1T​R2​: R1R_1R1​에서 R2R_2R2​로의 회전 차이
    • (R1TR2)t(R_1^T R_2)^t(R1T​R2​)t: 회전 차이를 ttt만큼 스케일
    • R1(R1TR2)tR_1 (R_1^T R_2)^tR1​(R1T​R2​)t: R1R_1R1​에서 시작해 R2R_2R2​로 점진적 회전
  • 등가식:

    slerp(R1,R2,t)=R1exp⁡(t⋅log⁡(R1TR2))\text{slerp}(R_1, R_2, t) = R_1 \exp \left( t \cdot \log(R_1^T R_2) \right) slerp(R1​,R2​,t)=R1​exp(t⋅log(R1T​R2​))

  • exp⁡()\exp()exp(): 회전 벡터 → 회전 행렬

  • log⁡()\log()log(): 회전 행렬 → 회전 벡터

Exp & Log Details

  • Exp (지수 변환): 회전 벡터 → 회전 행렬

    • 단위 회전축 u=(ux,uy,uz)\mathbf{u} = (u_x, u_y, u_z)u=(ux​,uy​,uz​) 와 회전각 θ\thetaθ에 대해:

      R=cos⁡θI+(1−cos⁡θ)uuT+sin⁡θu^R = \cos\theta I + (1 - \cos\theta) \mathbf{u} \mathbf{u}^T + \sin\theta \hat{\mathbf{u}} R=cosθI+(1−cosθ)uuT+sinθu^

      (Rodrigues 공식)
  • Log (로그 변환): 회전 행렬 → 회전 벡터

    • RRR의 회전각 θ\thetaθ 및 축 u\mathbf{u}u 계산 공식 생략
  • 공식을 외울 필요는 없음

    • 자세한 내용은 Modern Robotics, Section 3.2.3 참고

Exp & Log

  • 실습 팁:
    • pyglm, scipy (Python), Eigen (C++) 등 라이브러리에서 exp⁡\expexp, log⁡\loglog 함수 사용 가능
    • 본 실습에서는 pyglm 사용
  • 직접 구현도 가능하며 복잡하지 않음

Slerp with Quaternions

  • 쿼터니언 기반 slerp:

slerp(q1,q2,t)=q1(q1−1q2)t\text{slerp}(q_1, q_2, t) = q_1 (q_1^{-1} q_2)^t slerp(q1​,q2​,t)=q1​(q1−1​q2​)t

  • 등가 기하학적 표현:

slerp(q1,q2,t)=sin⁡((1−t)φ)sin⁡φq1+sin⁡(tφ)sin⁡φq2\text{slerp}(q_1, q_2, t) = \frac{\sin((1 - t)\varphi)}{\sin \varphi} q_1 + \frac{\sin(t \varphi)}{\sin \varphi} q_2 slerp(q1​,q2​,t)=sinφsin((1−t)φ)​q1​+sinφsin(tφ)​q2​

단, φ\varphiφ는 두 쿼터니언 사이의 각도:

cos⁡φ=q1⋅q2\cos \varphi = q_1 \cdot q_2 cosφ=q1​⋅q2​

  • Euler 각이나 회전 벡터에 대해서는 직접 slerp 불가
    → 회전 행렬이나 unit quaternion으로 변환 후 적용 필요

Comparison of Interpolation Methods

  • 시작 방향 (ZYX Euler angles):
    Rz(−90∘) Ry(90∘) Rx(0∘)R_z(-90^\circ) \, R_y(90^\circ) \, R_x(0^\circ)Rz​(−90∘)Ry​(90∘)Rx​(0∘)

  • 종료 방향 (ZYX Euler angles):
    Rz(0∘) Ry(0∘) Rx(90∘)R_z(0^\circ) \, R_y(0^\circ) \, R_x(90^\circ)Rz​(0∘)Ry​(0∘)Rx​(90∘)

https://youtu.be/YX0AMKMnGkU

[Demo] Slerp

https://nccastaff.bournemouth.ac.uk/jmacey/WebGL/QuatSlerp/

  • "Start Rotation" 및 "End Rotation" 변경
  • "Interpolate" 슬라이더 이동해보기

3) Interpolation of Rotations: Summary

  • ✅ Rotation matrix, Unit quaternion:

    • slerp(R1,R2,t)\text{slerp}(R_1, R_2, t)slerp(R1​,R2​,t) 또는 slerp(q1,q2,t)\text{slerp}(q_1, q_2, t)slerp(q1​,q2​,t)
    • 요소별 보간은 회전 행렬 또는 쿼터니언 자체도 아님 (의미 없음)
  • ❌ Euler angles:

    • lerp((α1,β1,γ1),(α2,β2,γ2))\text{lerp}((\alpha_1, \beta_1, \gamma_1), (\alpha_2, \beta_2, \gamma_2))lerp((α1​,β1​,γ1​),(α2​,β2​,γ2​))
    • 두 회전 사이의 선형 보간이 아님
  • ❌ Rotation vector:

    • lerp(v1,v2)\text{lerp}(\mathbf{v}_1, \mathbf{v}_2)lerp(v1​,v2​)
    • 두 회전 사이의 선형 보간이 아님

4) Continuity / Correspondence

  • ❌ Euler angles, Rotation vector:
    • 회전을 3개의 매개변수로 표현함
    • 이로 인해 다음 문제 발생:
      • 불연속성: 연속적인 방향도 불연속적으로 표현됨
      • 다대일 대응: 하나의 방향에 여러 표현이 가능함

예시: 하나의 방향이 여러 Euler 각도로 표현됨
시간에 따라 방향이 부자연스럽게 튀는 현상

△ Unit quaternion:

  • 4개의 매개변수 사용
  • 연속 표현 가능
  • 이중 일치(two-to-one mapping)
    • qqq와 −q-q−q는 같은 회전을 의미
    • → 이 특성을 antipodal equivalence라 함

✅ Rotation matrix:

  • 9개의 매개변수 사용
  • 일대일 대응 및 연속 표현 가능

Again: Which Representation to Use?

  • 일반적인 조언:
    • 회전 행렬 또는 unit quaternion 사용
  • 고급 조언:
    • 하나의 표현만 고집하지 말 것 (각각 장단점 존재)
    • 표현 간 변환을 통해 상황에 맞는 최적 방식 선택 가능

Pros & Cons of Euler Angles

🔻 단점:

  • 정확한 덧셈, 뺄셈, 보간 연산이 불가능
  • 불연속성과 다대일 표현
  • Gimbal lock 문제

🔺 장점:

  • 직관적인 조작 가능 (3D 툴에서 널리 사용되는 이유)
  • 실제 기구(hardware)의 3축 조인트 상태 표현에 적합
    (예: 로봇 관절이나 짐벌 등)

Pros & Cons of Rotation Vector

🔻 정확한 "덧셈", "뺄셈", 보간 연산이 불가능
🔻 불연속성 및 다대일 대응

🔺 회전 시각화에 용이

  • 회전 축과 각도를 직관적으로 표현 가능

🔺 3개의 매개변수로 가장 간결한 표현 가능

  • Euler angle도 3개지만 gimbal lock 문제 존재

Pros & Cons of Rotation Matrix

🔺 정확한 "덧셈", "뺄셈", 보간 연산 가능
🔺 연속적인 일대일 대응 (매우 좋음)
🔺 방향 시각화에 용이

  • 각 행(또는 열)을 x, y, z 축으로 시각화 가능
    🔺 4x4 아핀 변환 행렬로 쉽게 확장 가능 (회전 + 이동 통합 표현)

🔻 매개변수 수가 많음 (9개)
🔻 계산 비용이 조금 더 크며, 수치적으로 약간 덜 안정적 (unit quaternion 대비)

Pros & Cons of Unit Quaternion

🔺 정확한 "덧셈", "뺄셈", 보간 연산 가능
🔺 연속 표현 가능
🔺 4개의 매개변수만 사용
🔺 회전 행렬보다 계산이 빠르고 수치적으로 안정적

🔻 두 쿼터니언이 하나의 회전을 표현 (two-to-one, antipodal equivalence)
🔻 숫자 체계가 직관적이지 않음

Conversion between Representations

  • 다음 간의 변환에 대한 이론이 잘 정립되어 있음:

    • Euler angles
    • Rotation vector
    • Rotation matrix
    • Unit quaternion
  • 변환을 위해 다음과 같은 라이브러리 사용 가능:

    • pyglm, scipy (Python)
    • Eigen (C++)
    • ※ pyglm은 일부 변환만 제공함
  • 이론을 참고해 직접 구현도 가능

    • (검색 등을 통해) 필요한 수식 참고하여 구현 가능

9 - Lab - Orientation & Rotation

개요

  • Euler Angles (오일러 각)
  • Slerp

Euler Angles (오일러 각)

[코드] Euler-angles

  • 이 예제는 ZYX Euler 각을 구현합니다.

  • 하지만 곱셈 순서를 변경하여 Euler 각의 유형을 쉽게 변경할 수 있습니다.

  • 회전하는 큐브

  • 각기 다르게 움직이는 두 그룹 렌더링:

    • 월드 프레임
    • 네 개의 큐브
  • 두 개의 VAO

    • prepare_vao_frame()
      • 이전 예제로부터: 프레임을 그리는 코드
    • prepare_vao_object()
      • 이전 예제로부터: 큐브를 그리는 코드
  • 두 개의 셰이더 프로그램

    • 프레임용 셰이더 - shader_color
      • 정점 속성으로 지정된 정점 색상 사용
      • 셰이더 코드는 8-Lab-lighting-4-all-component-phong-licensora.py 에서 가져옴
    • 큐브용 셰이더 - shader_lighting
      • Phong 조명 모델을 사용하여 모델 표면을 셰이딩
      • 셰이더 코드는 8-Lab-lighting-4-all-component-phong-licensora.py 에서 가져옴
def draw_frame(vao, MVP, unif_locas):
    glUniformMatrix4fv(unif_locas['MVP'], 1, GL_FALSE, glm.value_ptr(MVP))
    glBindVertexArray(vao)
    glDrawArrays(GL_LINES, 0, 8)

def draw_cube(vao, MVP, M, matcolor, unif_locas):
    glUniformMatrix4fv(unif_locas['MVP'], 1, GL_FALSE, glm.value_ptr(MVP))
    glUniformMatrix4fv(unif_locas['M'], 1, GL_FALSE, glm.value_ptr(M))
    glUniform3f(unif_locas['material_color'], matcolor.x, matcolor.y, matcolor.z)
    glBindVertexArray(vao)
    glDrawArrays(GL_TRIANGLES, 0, 36)

def main():
    # load shaders & get uniform locations
    shader_lighting = load_shaders(g_vertex_shader_src_lighting, g_fragment_shader_src_lighting)
    unif_names = ['MVP', 'M', 'view_pos', 'material_color']
    unif_locs_lighting = {}
    for name in unif_names:
        unif_locs_lighting[name] = glGetUniformLocation(shader_lighting, name)
    
    shader_color = load_shaders(g_vertex_shader_src_color, g_fragment_shader_src_color)
    unif_names = ['MVP']
    unif_locs_color = {}
    for name in unif_names:
        unif_locs_color[name] = glGetUniformLocation(shader_color, name)

    # ... a while loop would be here ...
while not glfw.window_should_close(window):
    # projection matrix
    P = glm.perspective(45, 1, 1, 20)

    # view matrix
    view_pos = glm.vec3(sin(g_cam_ang), g_cam_height, cos(g_cam_ang))
    V = glm.lookAt(view_pos, glm.vec3(0,0,0), glm.vec3(0,1,0))

    # draw world frame
    glUseProgram(shader_color)
    draw_frame(vao_frame, P*V, unif_locs_color)

    # ZYX Euler angles
    t = glfw.GetTime()
    xang = t
    yang = glm.radians(90)
    zang = glm.radians(90)
    Rx = glm.rotate(xang, (1,0,0))
    Ry = glm.rotate(yang, (0,1,0))
    Rz = glm.rotate(zang, (0,0,1))
    M = glm.mat4(Rx * Ry * Rz)
    
    # set view pos uniform in shader_lighting
    glUseProgram(shader_lighting)
    glUniform3f(unif_locs_lighting['view_pos'], view_pos.x, view_pos.y, view_pos.z)

    # draw cubes
    M = M * glm.scale((.25, .25, .25))
    
    Mo = M * glm.mat4()
    draw_cube(vao_cube, P*V*Mo, Mo, glm.vec3(.5,.5,.5), unif_locs_lighting)
    
    Mx = M * glm.translate((2.5,0,0))
    draw_cube(vao_cube, P*V*Mx, Mx, glm.vec3(1,0,0), unif_locs_lighting)
    
    My = M * glm.translate((0,2.5,0))
    draw_cube(vao_cube, P*V*My, My, glm.vec3(0,1,0), unif_locs_lighting)
    
    Mz = M * glm.translate((0,0,2.5))
    draw_cube(vao_cube, P*V*Mz, Mz, glm.vec3(0,0,1), unif_locs_lighting)

Slerp

Recall: Slerp

  • $ \text{slerp}(R_1, R_2, t) = R_1(R_1^T R_2)^t = R_1 \exp(t \cdot \log(R_1^T R_2)) $
  • 이 예제는 이 공식을 구현합니다.

대안 (Alternatives)

다음과 같은 대안들을 직접 구현하고 테스트해 볼 수 있습니다.

  • 쿼터니언(Quaternion) slerp:
    • $ \text{slerp}(q_1, q_2, t) = q_1 (q_1^{-1} q_2)^t $
  • 기하학적(Geometric) slerp (동일한 결과):
    • $ \text{slerp}(q_1, q_2, t) = \frac{\sin((1-t)\varphi)}{\sin\varphi}q_1 + \frac{\sin(t\varphi)}{\sin\varphi}q_2 $
    • (이때 $ \varphi $는 q1q_1q1​에서 q2q_2q2​까지의 호에 대응하는 각도입니다.)
  • glm 라이브러리 함수:
    • glm.slerp(x: quat, y: quat, a: float) -> quat

Exp & Log

이 예제는 지수 함수 exp()와 로그 함수 log()를 구현하기 위해 PyGLM 함수를 사용합니다. 하지만 log()의 경우, PyGLM 라이브러리에는 회전 행렬(rotation matrix)을 회전 벡터(rotation vector)로 직접 변환하는 함수가 없습니다.

따라서 다음과 같은 순서로 변환을 수행합니다. 회전 행렬 ➡️ 단위 쿼터니언(unit quaternion) ➡️ 회전 벡터

[코드] 2-slerp

다음은 slerp를 구현하는 전체 Python 코드 예제입니다.

# ZYX 오일러 각을 회전 행렬로 변환하는 함수
def ZYXEulerToRotMat(angles):
    xang, yang, zang = angles
    Rx = glm.rotate(xang, (1,0,0))
    Ry = glm.rotate(yang, (0,1,0))
    Rz = glm.rotate(zang, (0,0,1))
    return glm.mat3(Rz * Ry * Rx)

# 두 회전 행렬 사이를 구면 선형 보간하는 함수
def slerp(R1, R2, t):
    R = R1 * exp( t * log(glm.transpose(R1) * R2) )
    return R

# 회전 벡터를 회전 행렬로 변환하는 지수 함수 (exp)
def exp(rotvec):
    eps = 1e-6
    angle = glm.length(rotvec)
    if angle > eps: # 원본 코드의 angle < eps는 오타로 보이며, angle > eps가 일반적입니다.
        axis = glm.normalize(rotvec)
        return glm.mat3(glm.rotate(angle, axis))
    else:
        return glm.mat3()

# 회전 행렬을 회전 벡터로 변환하는 로그 함수 (log)
def log(rotmat):
    quat = glm.quat(rotmat)
    return glm.angle(quat) * glm.axis(quat)

# --- 메인 렌더링 루프 ---

# 시작 방향: ZYX 오일러 각 - x축 -90도, y축 90도, z축 0도 회전
R1 = ZYXEulerToRotMat((-np.pi*.5, np.pi*.5, 0))
# 끝 방향: ZYX 오일러 각 - x축 0도, y축 0도, z축 90도 회전
R2 = ZYXEulerToRotMat((0, 0, np.pi*.5))

while not glfw.windowShouldClose(window):
    # t는 0.0에서 1.0까지 반복적으로 증가
    t = glfw.GetTime() % 2 / 2
    
    # slerp
    R = slerp(R1, R2, t)
    H = glm.mat4(R)

    # 큐브 그리기
    M = H * glm.scale((.25,.25,.25))
    
    Mo = M * glm.mat4()
    draw_cube(vao_cube, P*V*Mo, Mo, glm.vec3(.5,.5,.5), unif_locs_lighting)

    Mx = M * glm.translate((2.5,0,0)) # 원본 슬라이드와 다르게 X축으로 이동시켜 구별
    draw_cube(vao_cube, P*V*Mx, Mx, glm.vec3(1,0,0), unif_locs_lighting)
최근 수정:: 25. 6. 19. 오후 8:26
Contributors: kmbzn
Prev
8 - Lighting
Next
10 - Character Animation

BUILT WITH

CloudflareNode.jsGitHubGitVue.jsJavaScriptVSCodenpm

All trademarks and logos are property of their respective owners.
© 2025 kmbzn · MIT License