티스토리 뷰
이번 포스팅에서는 벡터에 대해서 알아보도록 하겠습니다. 벡터는 위키피디아에서 다음과 같이 정의하고 있습니다 :
벡터(vector)는 크기만으로 나타낼 수 있는 스칼라(scalar)와 달리 방향과 크기를 사용하여 나타낼 수 있다. 일상 적으로 사용하는 벡터는 유향선분(방향이 있는 선분)을 사용하여 표현할 수 있다.
벡터 는 현대적인 비디오 게임들의 공통 요소라 할 수 있는 컴퓨터 그래픽과 충돌 검출, 물리 시뮬레이션에서 핵심적인 역할을 하고 있으며, 이번 포스팅에서는 벡터와 벡터의 응용 방법 등을 알아보겠습니다.
벡터
서론에서 위키를 벡터에 대한 정의를 간략하게 인용하였습니다. 여기서 다시 한 번 정의해보고자 합니다.
벡터(vector, 방향량) 는 크기와 방향을 모두 가진 수량(quantity)을 가리키는 말이다. 크기(magnitude)와 방향(direction)을 모두 가진 수량을 좀 더 공식적으로 벡터값 수량(vector-valued quantity) 이라고 부른다.
벡터의 용도
벡터값 수량의 예로는 힘(force : 힘은 특정한 방향과 세기로 가해지는데, 세기(strength)가 곧 크기이다.), 변위(displacement : 한 입자의 최종적인 이동 방향 및 거리), 속도(빠르기와 방향) 가 있습니다. 또한, 3차원 게임에서 플레이어가 바라보는 방향이나 다각형이 향한 방향, 광선이 이동하는 방향, 한 표면에서 광선이 반사되는 방향 등 순수 방향만 나타날 때에도 벡터를 사용하기도 합니다.
벡터의 상등(equal)
벡터를 기하학적으로 나타내었을 때, 방향이 있는 선분(지향선분,directed line segment)으로 표시할 수 있으며, 선분의 길이는 벡터의 크기를, 선분 끝의 화살표는 벡터의 방향을 뜻합니다. 이 때 벡터의 위치는 죽요하지 않으므로, 만약 길이가 같고 같은 방향을 가리키면 두 벡터는 같습니다.
벡터와 좌표계
컴퓨터는 벡터를 기하학적으로 다룰 수 없으므로, 3차원 좌표계를 도입하고 모든 벡터의 꼬리를 좌표계의 원점과 일치하도록 이동하는 방식으로 벡터를 수치적으로 지정할 수 있습니다.
원점으로 일치하면 하나의 3차원 벡터 v = (x,y,z) 로 표기할 수 있으며 컴퓨터 프로그램 안에서 부동소수점 값 3개로 표현할 수 있습니다(2차원 벡터일 때는 v = (x,y) 로 표기할 수 있습니다).
기준계(frame of reference)
기준계(frame of reference) 는 공간(space), 좌표계(coordinate system) 과 같으며, 벡터를 표현하기 위한 공간입니다. 기준계에 따라서 같은 벡터의 좌표가 달라질 수 있습니다(그림2).
왼손잡이 좌표계 vs 오른손잡이 좌표계
Direct3D는 왼손잡이 좌표계(left-handed coordinate system)를 사용합니다. 왼손잡이 좌표계와 오른손잡이 좌표계의 차이는 다음과 같습니다.
기본적인 벡터 연산들
벡터의 좌표 표현을 이용해서 벡터의 상등, 덧셈, 스칼라 곱셈, 뺄셈을 정의해 보겠습니다. 이 때 두 벡터 u = (ux, uy, uz), v = (vx, vy, vz) 로 정의하겠습니다.
- 상등 : 두 벡터가 대응되는 좌표성분이 같을 때 상등입니다. 즉, ux =vx, uy = vy, uz = vz일 때만 u = v 입니다.
- 덧셈 : 벡터의 덧셈은 벡터의 성분별로 이루어집니다. 즉 u + v = (ux + vx, uy + vy, uz + vz) 입니다. 또한, 벡터간의 덧셈은 같은 차원의 벡터만 가능합니다.
- 곱셈 : 벡터에 스칼라(scalar, 크기만을 나타내는 수. 예로 실수가 있다)를 곱할 수 있으며, 결과는 벡터입니다. k가 스칼라일 때, ku = (k * ux, k * uy, k * uz) 이며, 이를 스칼라 곱셈이라고 부릅니다.
- 뺼셈 : 벡터의 뺄셈은 벡터의 덧셈과 스칼라 곱셈을 통해서 정의됩니다. u - v = u + (-1 * v) = (ux - vx, uy -vy, uz - vz) 입니다.
벡터의 모든 성분이 0일 때, 영 벡터(zero-vector) 라고 부릅니다. 영 벡터를 표기할 때, 0으로 표기합니다.
벡터의 연산을 그려보았을 때 연산의 기하학적 의미를 파악할 수 있습니다.
벡터의 덧셈은 두 벡터를 이었을 때 도착 지점을 시작 지점에서 이은 새로운 벡터와 같습니다.
벡터의 뺄셈은 왼쪽 피연산자(lhs)의 끝 지점을 오른쪽 피연산자(rhs)의 끝 지점에서 이은 벡터를 시작 지점을 왼쪽 피연산자 벡터의 시작 지점으로 옮긴 벡터와 같습니다.
벡터의 스칼라곱에서 음의 곱은 벡터의 방향을 뒤집는 것과 같습니다.
길이와 단위벡터
벡터의 길이
한 벡터의 길이는 해당 지향 선분의 길이와 같습니다. 벡터의 길이를 나타내는 표기법은 '||' 입니다. 벡터 u가 있을 때 u의 크기는 ||u|| 로 표기합니다. 벡터 u = (x,y,z)일 때 u의 길이는 다음과 같이 정의할 수 있습니다.
벡터의 길이 ||u|| = sqrt(x2 + y2 + z2)
단위벡터
벡터가 순전히 방향만을 나타내는 용도 로 사용되는 경우 벡터의 길이가 중요하지 않으며, 벡터의 길이를 단위 길이인 1 로 맞추면 편리합니다. 이렇게 벡터의 크기가 1인 경우, 단위벡터(unit vector) 라고 하며, 임의의 벡터를 단위 벡터로 만드는 것을 정규화(normalization) 라고 합니다. 정규화를 만드는 방법은 벡터의 각 성분에 벡터의 길이로 나누는 것입니다.
벡터의 정규화 공식
u / ||u|| = (ux / ||u||, uy / ||u||, uz / ||u||)
내적
도트곱(dot product)라고도 부르며, 내적(inner product) 은 스칼라값을 결과값으로 하는 벡터 곱셈 입니다. 결과값이 스칼라라는 데서 스칼라 곱(scalar product) 이라고도 합니다. 두 벡터 u = (ux, uy, uz), v = (vx, vy, vz) 에 대해, 내적은 다음과 같이 정의합니다.
벡터의 내적
u · v = ux * vx + uy * vy + uz * vz
즉, 위 내적의 식은 벡터의 대응 성분간의 곱들의 합 으로 요약할 수 있습니다. 하지만 이 정의만으로는 내적의 기하학적 의미가 불분명한데, 코사인 법칙을 적용하면 다음과 같은 관계를 찾아낼 수 있습니다.
벡터의 내적
u · v = ||u|| ||v|| cosΘ ( 0 ≦ Θ ≦ π )
위 식에서 두 벡터의 내적은 두 벡터 사이의 각도의 코사인을 두 벡터의 크기에 곱한 것을 의미합니다. 여기서 두 벡터 모두 단위 벡터일 때, u와 v에 대한 내적 은 두 벡터 사이의 코사인 각입니다.
내적의 기하학적 속성
코사인의 속성 때문에 내적에 대해 다음의 기하학적 속성을 이끌어낼 수 있습니다.
- 만일 u · v = 0 이면, u⊥v이다. (두 벡터는 직교이다.)
- 만일 u · v > 0 이면, 두 벡터 사이의 각도 Θ는 90도보다 작다 (두 벡터의 사이각이 예각이다).
- 만일 u · v < 0 이면, 두 벡터 사이의 각도 Θ는 90도보다 크다 (두 벡터의 사이각은 둔각이다).
직교투영(orthographic projection)
두 벡터 v, n이 존재할 떄, n이 단위벡터이면 v · n은 벡터 n에 대한 v의 직교투영 을 의미합니다. 이 때 이 내적에 벡터 n을 곱한 벡터를 p라 할 때, p는 다음과 같이 표기할 수 있습니다.
직교투영 p = projn(v)
만약 n이 단위벡터가 아니라면, n을 정규화한 후 직교투영을 수행할 수 있습니다. 이 때 p는 다음과 같이 표기할 수 있습니다 :
p = projn(v) = (v · n / ||n||) * n / ||n|| = (v · n) * n // ||n||2
직교화
벡터 집합 {v0, ... vn-1}의 모든 벡터가 단위 벡터이고 서로 직교 일 때, 이 벡터 집합을 정규직교(orthonormal) 집합이라고 부릅니다. 주어진 벡터 집합이 정규직교에 가깝지만 완전한 정규직교가 아닐 때 정규직교 벡터 집합으로 만드는 것을 직교화(orthogonalization) 라고 합니다.
3차원 컴퓨터 그래픽에서 정규직교 집합으로 시작한 벡터 집합이 부동소수점의 수치 정밀도 문제로 점차 정규직교가 아니게 되는 경우가 생기는데, 이 문제에 대해 2차원 및 3차원을 다룹니다.
2차원 직교화
2차원의 경우 벡터 집합 {v0, v1} 을 직교화해서 정규 직교 집합 {w0, w1} 을 얻는 과정을 살펴보겠습니다. 아래의 절차를 통해, 직교 벡터 집합이 만들어지며, {w0, w1} 을 정규화하면 정규직교 집합이 완성됩니다.
2차원 벡터 집합의 직교화
1. w0 = v0으로 설정합니다.
2. v1을 w0에 직교한 w1을 만들기 위해 v1의 성분에서 w0 방향으로 작용하는 성분을 뺍니다.
w1 = v1 - projw0(v1)
3차원 직교화
3차원도 2차원과 같은 원칙이며, 수행 단계가 더 많을 뿐입니다. 아래 절차를 거쳐 만든 직교 벡터 집합 {w0, w1, w2} 을 정규화하면 정규 직교 집합이 됩니다.
3차원 벡터 집합의 직교화
1. w0 = v0으로 설정합니다.
2. v1을 w0에 직교화합니다. w1 = v1 - projw0(v1)
3. v2를 w0과 w1에 직교화합니다. w2 = v2 - projw0(v2) - projw1(v2)
직교 일반화
2차원, 3차원 직교화를 확장하여, n개의 벡터 집합 {v0, v1, ... , vn-1} 을 정규 직교 집합 {w0, ... , wn-1} 으로 직교화한다면 그람-슈미트 직교화(Gram-Schmidt Orthogonalization) 라고 하는 공정을 적용할 수 있습니다.
기본 단계 : w0 = v0으로 설정합니다.
1 <= i <= n-1에 대해 wi = vi - Σ j = 0 ~ i-1 projwj(vi) 로 설정합니다.
정규화 단계 : wi = wi / ||wi||로 설정합니다.
위 공정을 설명하자면, 벡터 집합에서 vi를 선택하고, 이 벡터에 대해 이미 직교 벡터 집합에 들어있는 다른 벡터(w0, ... , wi-1)들의 방향 부분을 뺴서 직교가 되게 만든 다음, 모든 벡터에 대해 직교화가 끝나면 직교 집합의 모든 벡터를 정규화 합니다.
외적
벡터의 또다른 곱셉 방법으로 가위곱(cross product) 또는 외적(outer product) 이 있습니다. 내적의 경우, 결과값이 스칼라였지만 외적의 경우 결과값이 벡터입니다. 또한, 외적은 오직 3차원 벡터에 대해서만 정의됩니다(즉, 2차원 벡터에서는 외적이 존재하지 않습니다).
두 3차원 벡터 u, v에 외적을 취하면 u와 v 모두에 직교인 다른 벡터 w가 나옵니다. 즉, w는 u와도, v와도 직교입니다. u = (ux, uy, uz) 이고, v = (vx, vy, vz) 일 때 u와 v의 외적은 다음과 같이 정의됩니다 :
w = u × v = (uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx)
흔히 외적의 결과는 왼손 좌표계는 왼손 법칙으로, 오른손 좌표계는 오른손 법칙으로 구할 수 있습니다. 외적은 교환 법칙이 성립하지 않으므로 u × v ≠ v × u 입니다.
2차원 유사 외적
2차원에서는 특별한 경우를 제외하고 두 벡터에 대해 수직인 벡터가 존재하지 않습니다. 하지만 하나의 2차원 벡터 u = (ux, uy) 에 수직인 벡터 v는 구할 수 있으며, 이 벡터가 유용하게 쓰이는 경우가 있습니다. 이것을 2차원 유사외적(pseudo 2D cross product) 이라고 합니다.
u의 x, y 성분을 기울기로 생각했을 때, x와 y의 자리를 바꾼 후, x와 y 성분 중 1개에 음수를 곱하면 됩니다. 결과적으로 v = (-uy, ux) 또는 (uy, -ux) 가 됩니다.
외적을 이용한 직교화
그람-슈미트 직교화 공정 이외에도 3차원 비완전 정규직교인 벡터 집합 {v0, v1, v2} 에 대해서 직교화하는 다른 공정이 존재합니다. 아래는 그 공정을 표현한 것입니다.
w0 = v0 / || v0 || 으로 설정합니다.
w2 = w0 × v1 / || w0 × v1 || 로 설정합니다.
w1 = w2 × w0 으로 설정합니다. 여기서 || w2 || = || w0 || = 1 이므로, 이 단계는 정규화가 필요하지 않습니다.주의 : w0에서 직교화를 시작하면 w1 및 w2에 대해서 벡터 방향이 바뀔 수도 있습니다. 직교화 시에 방향이 바뀌지 않는 것이 바람직하므로, 예시와 다르게 v2를 먼저 시작으로, v0과 v1을 수정하여 벡터들을 직교화 하는 것이 바람직합니다.
점
지금까지의 벡터는 위치(position)을 서술하지 않았습니다. 하지만 3차원 그래픽 프로그램에서는 공간 안의 어떤 위치를 지정할 수 있어야 합니다. 이 떄 특정 좌표계를 기준으로 표준 위치에 있는 벡터(원점에서 시작하는 벡터)를 3차원 공간 안의 한 위치를 나타내는 데 사용할 수 있습니다. 이 때 이 벡터를 위치벡터 라고 부릅니다. 위치벡터에서 중요한 것은 방향이나 크기가 아닌, 벡터의 머리 끝 좌표 입니다. 어떤 의미에서 위치벡터와 점은 같은 의미입니다.
단점
점을 벡터로 표현할 때, 점에는 의미없는 벡터 연산을 점에 수행할 수 있는 여지가 생긴다 는 것입니다. 가령, 두 점의 합은 기하학적으로 성립하지 않습니다(물론 특별하게 정의할 수 있습니다, ex) 아핀결합(affine combination)).
하지만, 성립하는 벡터 연산 역시 존재합니다. 예를 들어 벡터의 뺄셈은 점 p, q에 대해 수행(p - q)되었을 떄 p에서 q로 가는 벡터로 정의할 수 있습니다(또는 벡터 v = p - q일 때, p에서 v만큼 가면 점 q라고도 할 수 있습니다).
레퍼런스
정보 출처
한빛미디어 - DirectX 12를 이용한 3D 게임 프로그래밍 입문
위키피디아 - 벡터
나무위키 - 벡터
그림 출처
그림1 출처 - http://localhouse.egloos.com/v/3584363
그림3 출처 - https://www.slideshare.net/QooJuice/ss-80130068
그림4 출처 - https://en.wikipedia.org/wiki/Dot_product
그림5 출처 - https://justicehui.github.io/other-algorithm/2018/06/23/OBB/
그림6 출처 - https://en.wikipedia.org/wiki/Cross_product
- Total
- Today
- Yesterday
- P4 Streams
- c++ 핫 리로드
- Auto
- UE4
- Perforce Stream
- 행렬
- C# 람다식
- 퍼포스 개요
- 알고리즘
- DXGI
- 퍼포스 스트림
- 언리얼 엔진
- code copyright
- C++ Compile error
- visual studio hot reload
- C# lambda expression
- Perforce Streams
- Visual Studio C1083
- 구간합
- 코드 저작권
- visual studio 핫 리로드
- 구글테스트
- P4 Stream
- GoogleTest
- MSVC C1083
- C# 익명함수
- C7568
- C++
- c++ hot reload
- game hot reload
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |