게임 수학 정리
게임 수학
게임 프로그래밍에 주로 쓰이는 수학 개념을 정리하고자 합니다.
벡터와 행렬을 중심으로, 게임에서 자주 사용되는 수학적 연산과 개념을 다룹니다.
벡터(Vector)
정의
단일 값으로 표현할 수 없는 다차원 데이터를 표현하는 수학적 객체입니다.
간혹 "방향과 크기"를 가진 화살표로 비유되기도 합니다.
게임에서는 위치, 방향, 속도 등을 표현하는 데 사용됩니다.
더 읽어보기: https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics)
연산
- 덧셈(Addition): 두 벡터의 각 성분을 더합니다.
- 뺄셈(Subtraction): 두 벡터의 각 성분을 뺍니다.
- 스칼라 곱(Scalar Multiplication): 벡터의 각 성분에 스칼라 값을 곱합니다.
- 내적(Dot Product): 두 벡터의 내적은 스칼라 값을 반환하며, 두 벡터 사이의 각도와 관련이 있습니다.
- 외적(Cross Product): 두 벡터의 외적은 새로운 벡터를 생성하며, 이 벡터는 두 벡터에 수직입니다. 특히 3차원 벡터끼리의 외적은 3차원 공간에서 정의됩니다.
크기(Magnitude)
벡터의 크기는 피타고라스 정리를 사용하여 계산합니다.
단위 벡터(Unit Vector)
크기가 1인 벡터로, 주어진 벡터를 그 크기로 나누어 구합니다.
이 과정을 정규화(normalization)라고 합니다.
벡터의 회전(Rotation)
3차원 공간에서 벡터를 회전시키려면 회전 행렬을 사용합니다.
회전 행렬은 회전 축과 회전 각도에 따라 달라집니다.
예를 들어, Z축을 중심으로 θ만큼 회전하는 행렬은 다음과 같습니다.
게임에서는 객체나 카메라의 회전을 구현할 때 벡터의 회전을 사용합니다.
Unity 처럼 게임 엔진에 따라 사원수(quaternion)를 사용하여 회전을 표현하기도 합니다.
using UnityEngine;
public class RotateVector : MonoBehaviour
{
public Vector3 vector = new Vector3(1, 0, 0); // 회전할 벡터
public float angle = 90f; // 회전 각도
void Start()
{
Quaternion rotation = Quaternion.Euler(0, angle, 0); // Y축을 중심으로 회전
Vector3 rotatedVector = rotation * vector; // 벡터 회전
Debug.Log("Rotated Vector: " + rotatedVector);
}
}벡터의 투영(Projection)
투영이란 한 벡터를 다른 벡터에 "투사"하는 것을 의미합니다.
벡터 (\mathbf{a})를 벡터 (\mathbf{b})에 투영하는 공식은 다음과 같습니다.
게임에서는 물체가 다른 물체에 대해 어떻게 움직이는지, 충돌을 감지하는 데 벡터의 투영을 사용합니다.
using UnityEngine;
public class VectorProjection : MonoBehaviour
{
public Vector3 vectorA = new Vector3(3, 4, 0);
public Vector3 vectorB = new Vector3(1, 2, 0);
void Start()
{
Vector3 projection = Project(vectorA, vectorB);
Debug.Log("Projection of A onto B: " + projection);
}
Vector3 Project(Vector3 a, Vector3 b)
{
return (Vector3.Dot(a, b) / b.sqrMagnitude) * b;
}
}벡터의 거리(Distance)
두 벡터 사이의 거리는 두 벡터의 차이를 계산한 후 크기를 구합니다.
벡터의 각도(Angle)
두 벡터 사이의 각도는 내적을 사용하여 계산할 수 있습니다.
각도는 두 벡터의 내적을 크기의 곱으로 나눈 후 아크코사인 함수를 적용하여 구합니다.
내적을 이용하면 두 벡터 사이의 각도를 쉽게 구할 수 있습니다.
대표적으로 내적을 이용해 부채꼴의 범위의 시야를 구현할 수 있습니다.
using UnityEngine;
public class FieldOfView : MonoBehaviour
{
public float viewAngle = 110f; // 시야각
public float viewDistance = 10f; // 시야 거리
void CheckFieldOfView(Transform target)
{
Vector3 directionToTarget = (target.position - transform.position).normalized;
float angleToTarget = Vector3.Angle(transform.forward, directionToTarget);
if (angleToTarget < viewAngle / 2f && Vector3.Distance(transform.position, target.position) <= viewDistance)
{
Debug.Log("Target is in field of view");
}
else
{
Debug.Log("Target is out of field of view");
}
}
}벡터의 보간(Interpolation)
보간은 두 벡터 사이의 중간 값을 계산하는 방법입니다.
가장 일반적인 방법은 선형 보간(linear interpolation)입니다.
선형 보간은 두 벡터 (\mathbf{a})와 (\mathbf{b}) 사이의 중간 값을 다음과 같이 계산합니다.
여기서 (t)는 0과 1 사이의 값으로, (t = 0)일 때 (\mathbf{L} = \mathbf{a}), (t = 1)일 때 (\mathbf{L} = \mathbf{b})가 됩니다.
Unity에서는 Vector3.Lerp 함수를 사용하여 벡터를 보간할 수 있습니다.
게임에서는 객체의 위치를 부드럽게 이동시키거나 애니메이션을 구현할 때 사용됩니다.
using UnityEngine;
public class VectorLerp : MonoBehaviour
{
public Vector3 start = new Vector3(0, 0, 0);
public Vector3 end = new Vector3(10, 10, 10);
public float t = 0.5f; // 0.0f ~ 1.0f 사이의 값
void Update()
{
Vector3 result = Vector3.Lerp(start, end, t);
Debug.Log("Interpolated Vector: " + result);
}
}벡터의 반사(Reflection)
벡터의 반사는 주로 충돌 처리에 사용됩니다.
만약 법선 벡터 (\mathbf{n})이 단위 벡터(크기가 1인 벡터)라면, 반사 벡터는 다음과 같습니다:
법선 벡터 (\mathbf{n})이 단위 벡터가 아닐 경우, 일반적인 공식은 다음과 같습니다:
아래 C# 코드는 법선 벡터 n이 단위 벡터라고 가정합니다. Unity의 Vector3.Reflect 메소드는 정규화되지 않은 법선 벡터도 처리합니다.
using UnityEngine;
public class VectorReflection : MonoBehaviour
{
public Vector3 incomingVector = new Vector3(1, -1, 0);
public Vector3 normalVector = new Vector3(0, 1, 0);
void Start()
{
Vector3 reflectedVector = Reflect(incomingVector, normalVector.normalized); // 법선 벡터를 정규화
Debug.Log("Reflected Vector: " + reflectedVector);
}
Vector3 Reflect(Vector3 v, Vector3 n)
{
return v - 2 * Vector3.Dot(v, n) * n;
}
}예시: 추적 및 회전
게임에서 객체가 다른 객체를 추적하는 경우, 벡터를 사용하여 목표 위치로 이동하는 방향을 계산합니다.
1차원적인 추적은 단순히 목표 위치로 이동하는 것입니다.
using UnityEngine;
public class ObjectTracker : MonoBehaviour
{
public Transform target; // 추적할 대상
void Update()
{
Vector3 direction = (target.position - transform.position).normalized; // 목표 방향
transform.position += direction * Time.deltaTime; // 이동
}
}각속도의 변화를 통해 회전하는 추적은 벡터의 회전을 사용합니다.
using UnityEngine;
public class ObjectRotator : MonoBehaviour
{
public Transform target; // 추적할 대상
public float rotationSpeed = 5f; // 회전 속도
void Update()
{
Vector3 direction = (target.position - transform.position).normalized; // 목표 방향
Quaternion targetRotation = Quaternion.LookRotation(direction); // 목표 회전
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime); // 부드러운 회전
}
}행렬(Matrix)
정의
행렬은 숫자나 변수를 직사각형 형태로 배열한 것입니다.
게임에서 변환(translation), 회전(rotation), 크기 조정(scaling) 등을 표현하는 데 사용됩니다.
더 읽어보기: https://en.wikipedia.org/wiki/Matrix_(mathematics)
행렬 연산
- 덧셈(Addition): 두 행렬의 대응하는 성분을 더합니다.
- 뺄셈(Subtraction): 두 행렬의 대응하는 성분을 뺍니다.
- 곱셈(Multiplication): 두 행렬의 곱셈은 각 행렬의 행과 열을 곱하여 새로운 행렬을 만듭니다.
- 전치(Transpose): 행렬의 행과 열을 바꿉니다.
- 역행렬(Inverse): 행렬 의 역행렬 은 다음과 같은 조건을 만족합니다.
- 행렬식(Determinant): 2x2 행렬의 행렬식은 다음과 같이 계산됩니다. 일반화된 행렬식은 더 큰 행렬에 대해서도 정의되지만, 여기서는 2x2 행렬에 대해서만 설명합니다.
변환 행렬(Transformation Matrix)
변환 행렬은 객체의 위치, 회전, 크기 조정을 표현하는 데 사용됩니다.
- 이동(Translation): 객체를 3D 공간에서 이동시키는 행렬입니다.
- 회전(Rotation): Z축을 중심으로 θ만큼 회전하는 행렬입니다.
- 크기 조정(Scaling): 객체의 크기를 조정하는 행렬입니다.
위와 같은 변환 행렬들을 행렬의 곱셈을 통해 적용할 수 있습니다.
행렬의 곱셈은 결합법칙이 성립하기에, 여러 변환을 하나의 행렬로 결합하는 것도 가능합니다.
역행렬의 성질과 활용
역행렬로 행렬의 곱 연산을 적용하게 되면, 항등원인 단위 행렬이 됩니다.
따라서, 역행렬을 사용하여 변환을 되돌릴 수 있습니다.
예를 들어, 객체가 이동한 후 원래 위치로 되돌리려면 이동 행렬의 역행렬을 곱하면 됩니다.
using UnityEngine;
public class MatrixInverseExample : MonoBehaviour
{
public Vector3 translation = new Vector3(2, 3, 4);
void Start()
{
// 이동 행렬 생성
Matrix4x4 translationMatrix = Matrix4x4.Translate(translation);
// 이동 행렬의 역행렬 계산
Matrix4x4 inverseTranslationMatrix = translationMatrix.inverse;
Debug.Log("Original Translation Matrix: " + translationMatrix);
Debug.Log("Inverse Translation Matrix: " + inverseTranslationMatrix);
// 원래 위치로 되돌리기
Vector3 originalPosition = inverseTranslationMatrix.MultiplyPoint3x4(translation);
Debug.Log("Original Position: " + originalPosition);
}
}Unity에서 행렬 사용 예시
Unity에서는 Matrix4x4 클래스를 사용하여 행렬을 다룰 수 있습니다.
(일반적으로 4x4 행렬을 사용하여 3D 공간에서의 변환을 표현합니다.)
using UnityEngine;
public class MatrixExample : MonoBehaviour
{
public Vector3 translation = new Vector3(1, 2, 3);
public float rotationAngle = 45f; // 회전 각도
public Vector3 scale = new Vector3(2, 2, 2);
void Start()
{
// 이동 행렬
Matrix4x4 translationMatrix = Matrix4x4.Translate(translation);
// 회전 행렬 (Z축을 중심으로 회전)
Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 0, rotationAngle));
// 크기 조정 행렬
Matrix4x4 scalingMatrix = Matrix4x4.Scale(scale);
// 전체 변환 행렬
Matrix4x4 transformationMatrix = translationMatrix * rotationMatrix * scalingMatrix;
Debug.Log("Transformation Matrix: " + transformationMatrix);
}
}이외의 수학 활용
게임 프로그래밍에서는 벡터와 행렬 외에도 다양한 수학적 개념이 사용됩니다.
- 확률과 통계: 게임 AI, 난수 생성, 게임 밸런싱 등에 사용됩니다. 대표적으로는 의사 난수 생성(Pseudo-Random Number Generation)이 있습니다.
- 물리학: 충돌 감지, 중력, 마찰 등 물리적 현상을 모델링하는 데 사용됩니다.
- 기하학: 3D 모델링, 충돌 처리, 경로 찾기 등에 사용됩니다. Convex Hull, AABB(축 정렬 경계 상자) 등의 기하학적 알고리즘이 있습니다.
- 신호 처리: 오디오 처리, 이미지 필터링 등에서 사용됩니다. Fast Fourier Transform(FFT)와 같은 알고리즘이 있습니다.
- 경로 탐색: 이동 경로나 AI 행동을 결정하는 데 사용됩니다. A* 알고리즘, Dijkstra 알고리즘 등이 있습니다.
- 애니메이션: 스켈레톤 애니메이션, 키프레임 애니메이션 등에서 사용됩니다. 보간(interpolation) 기법이 많이 사용됩니다.