1. 벡터 정규화(Normalization)란?
정규화는 벡터의 길이를 1로 만드는 연산이다.
어떤 벡터 v=(x,y)가 있을 때, 그 길이는 ∥v∥=x2+y2로 표현된다.
이를 정규화하면
v^=∥v∥v=(x2+y2x,x2+y2y)
처럼 길이가 1인 단위 벡터(Unit Vector)가 된다.
v^는 v의 방향만 유지한 채, 크기(길이)만 1로 만든 벡터이다.
2. 정규화의 필요성
2.1 방향과 크기의 분리
벡터에는 크기(Magnitude)와 방향(Direction)이 동시에 존재한다.
게임 개발에서는 종종 방향만 필요로 하거나, 방향과 크기를 따로 다룰 때가 많다.
- 카메라 이동: 원하는 방향으로 초점을 맞추고 싶을 때, 방향만 유지한 상태에서 카메라가 일정 속도로 이동하도록 만들 수 있다.
- 조준/명중 판정: 총알(투사체)을 발사할 때, 투사체가 일정 속도로 날아가도록 방향 벡터는 정규화하고, 속도(스칼라)만 따로 곱해준다.
2.2 안전한 계산
- 거리나 충돌 판정에서 불필요하게 큰 값을 다루지 않고, 크기를 1로 맞춰놓은 후 필요하면 다시 스칼라를 곱해 사용하는 방식을 택하면 수식이 단순해진다.
3. 주의할 점
-
길이가 0인 벡터(Zero Vector)
v=(0,0)인 경우 분모가 0이 되어 정규화를 할 수 없다.
따라서, 코드에서 정규화를 구현할 때는 보통 벡터의 길이가 0인지 먼저 확인하고,
0이면 그대로 (0,0)을 반환하거나 에러 처리를 하는 등의 분기 처리가 필요하다.
-
연산 비용
정규화 과정에서는 x2+y2 연산이 들어간다. 제곱근 연산은 비교적 비용이 큰 편이므로,
성능에 민감한 곳에서는 가능한 한 중복 계산을 피하기 위해 캐싱하거나, 적절한 타이밍에만 정규화하는 전략이 필요하다.
4. 간단한 예시
#include <iostream>
#include <cmath>
struct Vector2D {
float x, y;
};
float magnitude(const Vector2D& v) {
return std::sqrt(v.x * v.x + v.y * v.y);
}
Vector2D normalize(const Vector2D& v) {
float len = magnitude(v);
if (len == 0.0f) {
return {0.0f, 0.0f};
}
return { v.x / len, v.y / len };
}
int main() {
Vector2D v = { 3.0f, 4.0f };
Vector2D normV = normalize(v);
std::cout << "원본 벡터: (" << v.x << ", " << v.y << ")\n";
std::cout << "정규화된 벡터: (" << normV.x << ", " << normV.y << ")\n";
std::cout << "정규화된 벡터 길이: " << magnitude(normV) << "\n";
return 0;
}
실행 결과:
- 원본 벡터 (3,4)의 길이: 5
- 정규화된 벡터: (53,54)=(0.6,0.8)
- 정규화 벡터의 길이: 1
5. 게임 내 예시
-
캐릭터 이동 방향
- 플레이어 입력(왼쪽/오른쪽/위/아래)을 기반으로 이동 벡터를 만든 뒤, 그 길이가 1이 되도록 정규화한 후, 속도를 곱해 이동한다.
- 예) moveDir=normalize(inputVector); → position+=moveDir×speed×Δt.
-
투사체 발사
- 발사 각도나 마우스 클릭 위치를 통해 벡터 v를 구한 뒤, v^로 정규화해서 일정 속도로 발사.
- 예) bulletVelocity=normalize(targetPos−playerPos)×bulletSpeed;
-
오브젝트 간 거리 측정
- 거리는 (x2−x1)2+(y2−y1)2로 구하지만, 어떤 연산을 위해 방향(단위 벡터)만 필요하다면, 정규화를 통해 계산 과정을 단순화할 수 있다.