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으로 표현 가능함
- Position: 위치 상태
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 회전 (즉, 한 점이 고정된 상태의 모든 움직임)은
항상 회전 축과 그 축을 중심으로 하는 회전 각도를 찾을 수 있음
: 회전 각도
: 회전 축 (단위 벡터)
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
- 축 기준으로 만큼 회전
- 새로운 기준축 기준으로 만큼 회전
- 다시 새로운 축 기준으로 만큼 회전
각 회전 행렬은 다음과 같음:
Example: Yaw-Pitch-Roll Convention
(ZYX Euler Angles)
- 항공기 방향 표현 시 일반적으로 사용됨
- 축 기준으로 yaw 회전
- 새 기준의 축 기준으로 pitch 회전
- 새 기준의 축 기준으로 roll 회전
Recall: 3D Rotation Matrix about Principle Axes
- 축 회전:
- 축 회전:
- 축 회전:
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)
- 축-각 표현(axis-angle)
: 회전 각도
: 회전 축 (단위 벡터)
Rotation Vector (Axis-Angle)
- 회전 벡터는 exponential coordinates 라고도 불림
- 명칭 유래가 궁금하다면 다음을 참고:
Modern Robotics, Section 3.2.3
Rotation Matrix
- 회전 행렬 은 다음을 정의함:
- 새로운 회전된 좌표계의 방향
- 또는 기존 world frame에서 해당 좌표계로의 회전
정방 행렬 이 회전 행렬이기 위한 조건은 다음 두 가지를 모두 만족해야 함:
회전 행렬은 orthogonal matrix 이며, 행렬식이 1인 경우는 특별히 special orthogonal matrix 라고 부름
3차원 회전 행렬의 집합은 , 즉 special orthogonal group을 구성함
Geometric Properties of Rotation Matrix
는 의 역회전임
또한 회전 행렬임 (회전의 합성)
- 증명:
- 증명:
회전 행렬을 적용하더라도 벡터의 길이는 변하지 않음
- 증명:
- 증명:
복소수(complex number)는 2D 회전을 표현 가능
- ,
Quaternion은 이를 3D로 확장한 개념임
기본 표현:
규칙:
Quaternions
일반적인 표현:
여기서:
- : 실수 부분 (real part, 또는 scalar part)
- : 허수 부분 (imaginary part, 또는 vector part)
표기 방법:
Unit Quaternions
Unit quaternion은 3D 회전을 표현함
- 조건:
형태의 복소수와 유사하게, 2D 회전을 표현함
축을 기준으로 각 만큼 회전하는 쿼터니언은 다음과 같음:
또는
Unit Quaternions
3차원 위치 는 pure imaginary quaternion 로 표현됨
이 벡터가 축을 기준으로 각 만큼 회전하면, 새로운 위치 는 다음과 같음:
단, 회전 쿼터니언은 다음과 같음:
Unit Quaternions
항등원 (Identity):
곱셈 (Multiplication):
역원 (Inverse 또는 Conjugate):
의미:
- : 먼저 로 회전하고, 그다음 로 회전 (body frame 기준)
또는 반대로 로 회전하고 그다음 로 회전 (world frame 기준)
- : 먼저 로 회전하고, 그다음 로 회전 (body frame 기준)
회전 적용:
Which Representation to Use?
1) "Addition" of Rotations
✅ Rotation matrix, Unit quaternion:
- 후에 적용하면 (현재 기준) body frame 기준 회전
- 단, 요소 단위 덧셈은 회전 행렬이나 쿼터니언을 보장하지 않음
❌ Euler angles:
- 단순 덧셈은 실제 회전의 합을 의미하지 않음
❌ Rotation vector:
- 는 로 이어서 회전한다는 의미가 아님
2) "Subtraction" of Rotations
✅ Rotation matrix, Unit quaternion:
- 회전 차이 = 프레임 를 과 일치시키는 회전
- 증명: →
- 요소 단위 차는 여전히 유효한 회전 아님
❌ Euler angles:
- 단순 차이는 실제 회전 차이를 반영하지 않음
❌ Rotation vector:
- 두 회전의 차이를 의미하지 않음
3) Interpolation of Rotations
각 구성 요소를 선형 보간(linear interpolation)해도 괜찮을까?
- Euler angles
- Rotation vector
- Rotation matrix
- Unit quaternion
- ...?
👉 안 된다!
Interpolating Each Element of Rotation Matrices / Unit Quaternions?
- 예: 단위 행렬 과 축으로 90도 회전한 행렬 의 보간을 시도
⛔ 이는 회전 행렬이 아님! 전혀 의미 없는 결과
- 마찬가지로, unit quaternion의 값을 단순히 보간해도 의미 없음
Interpolating Rotation Vectors?
동일한 길이의 두 회전 벡터 , 가 있다고 가정
, 를 선형 보간하면 간격이 균등해 보일 수 있음
하지만 실제 방향의 변화 측면에서는 균등하지 않음
👉 올바른 방식 아님
Interpolating Euler Angles?
두 Euler 각 튜플을 선형 보간하면 정확한 결과를 얻지 못함
- ❌ 각속도(angular velocity)가 일정하지 않음
- ❌ gimbal lock 발생 영역에서는 부자연스러운 끊김이 발생
Slerp
정답: Slerp (Shoemake, 1985)
- Spherical linear interpolation
- 두 방향의 구면상 선형 보간 방식
수식:
여기서 는 지수(power) 연산이며 전치(transpose)가 아님
Slerp with Rotation Matrices
의미:
- : 에서 로의 회전 차이
- : 회전 차이를 만큼 스케일
- : 에서 시작해 로 점진적 회전
등가식:
: 회전 벡터 → 회전 행렬
: 회전 행렬 → 회전 벡터
Exp & Log Details
Exp (지수 변환): 회전 벡터 → 회전 행렬
- 단위 회전축 와 회전각 에 대해:
(Rodrigues 공식)
- 단위 회전축 와 회전각 에 대해:
Log (로그 변환): 회전 행렬 → 회전 벡터
- 의 회전각 및 축 계산 공식 생략
공식을 외울 필요는 없음
- 자세한 내용은 Modern Robotics, Section 3.2.3 참고
Exp & Log
- 실습 팁:
pyglm,scipy(Python),Eigen(C++) 등 라이브러리에서 , 함수 사용 가능- 본 실습에서는
pyglm사용
- 직접 구현도 가능하며 복잡하지 않음
Slerp with Quaternions
- 쿼터니언 기반 slerp:
- 등가 기하학적 표현:
단, 는 두 쿼터니언 사이의 각도:
- Euler 각이나 회전 벡터에 대해서는 직접 slerp 불가
→ 회전 행렬이나 unit quaternion으로 변환 후 적용 필요
Comparison of Interpolation Methods
시작 방향 (ZYX Euler angles):
종료 방향 (ZYX Euler angles):
[Demo] Slerp
https://nccastaff.bournemouth.ac.uk/jmacey/WebGL/QuatSlerp/
- "Start Rotation" 및 "End Rotation" 변경
- "Interpolate" 슬라이더 이동해보기
3) Interpolation of Rotations: Summary
✅ Rotation matrix, Unit quaternion:
- 또는
- 요소별 보간은 회전 행렬 또는 쿼터니언 자체도 아님 (의미 없음)
❌ Euler angles:
- 두 회전 사이의 선형 보간이 아님
❌ Rotation vector:
- 두 회전 사이의 선형 보간이 아님
4) Continuity / Correspondence
- ❌ Euler angles, Rotation vector:
- 회전을 3개의 매개변수로 표현함
- 이로 인해 다음 문제 발생:
- 불연속성: 연속적인 방향도 불연속적으로 표현됨
- 다대일 대응: 하나의 방향에 여러 표현이 가능함
예시: 하나의 방향이 여러 Euler 각도로 표현됨
시간에 따라 방향이 부자연스럽게 튀는 현상
△ Unit quaternion:
- 4개의 매개변수 사용
- 연속 표현 가능
- 이중 일치(two-to-one mapping)
- 와 는 같은 회전을 의미
- → 이 특성을 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 $는 에서 까지의 호에 대응하는 각도입니다.)
- 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)

