벡터 정규화

김민수·2025년 2월 11일
0

게임수학

목록 보기
3/8

1. 벡터 정규화(Normalization)란?

정규화는 벡터의 길이를 1로 만드는 연산이다.
어떤 벡터 v=(x,y)\mathbf{v} = (x, y)가 있을 때, 그 길이는 v=x2+y2\|\mathbf{v}\| = \sqrt{x^2 + y^2}로 표현된다.
이를 정규화하면

v^=vv=(xx2+y2,yx2+y2)\displaystyle \hat{\mathbf{v}} = \frac{\mathbf{v}}{\|\mathbf{v}\|} = \left(\frac{x}{\sqrt{x^2 + y^2}}, \frac{y}{\sqrt{x^2 + y^2}}\right)

처럼 길이가 1인 단위 벡터(Unit Vector)가 된다.

v^\hat{\mathbf{v}}v\mathbf{v}방향만 유지한 채, 크기(길이)만 1로 만든 벡터이다.


2. 정규화의 필요성

2.1 방향과 크기의 분리

벡터에는 크기(Magnitude)방향(Direction)이 동시에 존재한다.
게임 개발에서는 종종 방향만 필요로 하거나, 방향과 크기를 따로 다룰 때가 많다.

  1. 카메라 이동: 원하는 방향으로 초점을 맞추고 싶을 때, 방향만 유지한 상태에서 카메라가 일정 속도로 이동하도록 만들 수 있다.
  2. 조준/명중 판정: 총알(투사체)을 발사할 때, 투사체가 일정 속도로 날아가도록 방향 벡터는 정규화하고, 속도(스칼라)만 따로 곱해준다.

2.2 안전한 계산

  • 거리나 충돌 판정에서 불필요하게 큰 값을 다루지 않고, 크기를 1로 맞춰놓은 후 필요하면 다시 스칼라를 곱해 사용하는 방식을 택하면 수식이 단순해진다.

3. 주의할 점

  1. 길이가 0인 벡터(Zero Vector)
    v=(0,0)\mathbf{v} = (0,0)인 경우 분모가 0이 되어 정규화를 할 수 없다.
    따라서, 코드에서 정규화를 구현할 때는 보통 벡터의 길이가 0인지 먼저 확인하고,
    0이면 그대로 (0,0)을 반환하거나 에러 처리를 하는 등의 분기 처리가 필요하다.

  2. 연산 비용
    정규화 과정에서는 x2+y2\sqrt{x^2 + y^2} 연산이 들어간다. 제곱근 연산은 비교적 비용이 큰 편이므로,
    성능에 민감한 곳에서는 가능한 한 중복 계산을 피하기 위해 캐싱하거나, 적절한 타이밍에만 정규화하는 전략이 필요하다.


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);

    // 길이가 0이면 정규화 불가능하므로 예외 처리
    if (len == 0.0f) {
        // 원하는 방식대로 반환. 여기서는 (0,0) 그대로 돌려줌.
        return {0.0f, 0.0f};
    }
    // 길이가 0이 아니면 x와 y를 길이로 나눠 정규화
    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)(3,4)의 길이: 5
  • 정규화된 벡터: (35,45)=(0.6,0.8)\left(\frac{3}{5}, \frac{4}{5}\right) = (0.6, 0.8)
  • 정규화 벡터의 길이: 1

5. 게임 내 예시

  1. 캐릭터 이동 방향

    • 플레이어 입력(왼쪽/오른쪽/위/아래)을 기반으로 이동 벡터를 만든 뒤, 그 길이가 1이 되도록 정규화한 후, 속도를 곱해 이동한다.
    • 예) moveDir=normalize(inputVector);\text{moveDir} = \text{normalize}(\mathbf{inputVector});position+=moveDir×speed×Δt.\mathbf{position} += \text{moveDir} \times \text{speed} \times \Delta t.
  2. 투사체 발사

    • 발사 각도나 마우스 클릭 위치를 통해 벡터 v\mathbf{v}를 구한 뒤, v^\hat{\mathbf{v}}로 정규화해서 일정 속도로 발사.
    • 예) bulletVelocity=normalize(targetPosplayerPos)×bulletSpeed;\text{bulletVelocity} = \text{normalize}(\mathbf{targetPos} - \mathbf{playerPos}) \times \text{bulletSpeed};
  3. 오브젝트 간 거리 측정

    • 거리는 (x2x1)2+(y2y1)2\sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}로 구하지만, 어떤 연산을 위해 방향(단위 벡터)만 필요하다면, 정규화를 통해 계산 과정을 단순화할 수 있다.
profile
안녕하세요

0개의 댓글