Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
벡터 수학
소개
이 튜토리얼은 게임 개발에 적용되는 선형대수에 대한 짧고 실용적인 소개입니다. 선형 대수란 벡터와 벡터 사용에 대한 학문입니다. 벡터는 2D 및 3D 개발 모두에서 많은 응용방법이 있으며 Godot는 이를 광범위하게 사용합니다. 벡터 수학에 대한 올바른 이해는 강력한 게임 개발자가 되기 위해 필수적입니다.
참고
이 튜토리얼은 선형대수에 관한 공식 교과서가 절대 아닙니다. 우리는 단지 그것이 어떻게 게임 개발에 적용되는지 지켜볼 것입니다. 수학에 대한 자세한 내용은 https://www.khanacademy.org/math/linear-algebra을 참조하세요
좌표계 (2D)
2차원 공간에서, 좌표계들은 가로축(x)과 세로축(y)을 사용하여 정의됩니다. 2차원 공간에서의 특정한 위치는 (4,3)과 같이 한 쌍의 값으로 쓰여집니다.
참고
컴퓨터 그래픽을 처음 접하는 사람이라면 아마 수학 수업에서 배웠듯이 양의``y``축이 위쪽이 아니라 아래쪽을 가리키는 것이 이상하게 보일지도 모릅니다. 그러나 대부분의 컴퓨터 그래픽 응용 프로그램에서는 일반적으로 이러한 현상이 발생합니다.
2D 평면의 모든 위치는 이러한 방식으로 한 쌍의 수들로 식별할 수 있습니다. 그러나 우리는 또한 (4, 3)의 위치를 (0, 0)또는 원점으로부터의 오프셋으로 생각할 수 있습니다. 원점에서 점까지 점을 가리키는 화살표를 그리세요:
이것은 벡터입니다. 벡터는 유용한 많은 정보들을 보여줍니다. 점이 (4, 3)에 있다고 알려줄 뿐 아니라, 우리는 각도 θ (세타) 그리고 길이 (또는 크기) m 또한 생각해낼 수 있습니다. 이러한 경우 화살표는 위치 벡터로, 원점에 상대적인 공간의 위치를 나타냅니다.
벡터에 대해 고려해야 할 매우 중요한 점은 벡터가 상대적인 방향과 크기만 나타낸다는 것입니다. 벡터의 위치에 대한 개념이 없습니다. 다음 두 벡터는 동일합니다:
두 벡터 모두 시작점으로부터 오른쪽으로 4만큼 아래쪽으로 3만큼의 단위를 나타냅니다. 평면에서 벡터를 그리는 것은 중요하지 않습니다. 이것은 항상 상대적인 방향과 크기를 나타냅니다.
벡터 연산
당신은 둘 중 하나의 방법(x 및 y 좌표 또는 각도 및 크기)을 사용하여 벡터를 참조할 수 있지만, 프로그래머는 편의를 위해 일반적으로 좌표 표기법을 사용합니다. 예를 들어, Godot에서 원점은 화면의 왼쪽 상단 모서리이고, Node2D라는 2차원의 노드를 400픽셀 오른쪽, 300픽셀 아래로 배치하려면 다음 코드를 사용하세요:
$Node2D.position = Vector2(400, 300)
var node2D = GetNode<Node2D>("Node2D");
node2D.Position = new Vector2(400, 300);
Godot는 2D 및 3D 사용 시 각각 :ref: Vector2 <class_Vector2>와 :ref:`Vector3 <class_Vector3>를 지원합니다. 이 문서에서 논의된 동일한 수학적 규칙은 두 가지 유형 모두에 적용됩니다.
멤버 접근
벡터의 각각의 컴포넌트는 이름으로 직접 접근할 수 있습니다.
# Create a vector with coordinates (2, 5).
var a = Vector2(2, 5)
# Create a vector and assign x and y manually.
var b = Vector2()
b.x = 3
b.y = 1
// Create a vector with coordinates (2, 5).
var a = new Vector2(2, 5);
// Create a vector and assign x and y manually.
var b = new Vector2();
b.X = 3;
b.Y = 1;
벡터의 합
두 벡터를 더하거나 뺄 때, 해당하는 컴포넌트는 더해집니다:
var c = a + b # (2, 5) + (3, 1) = (5, 6)
var c = a + b; // (2, 5) + (3, 1) = (5, 6)
첫번째 벡터의 끝에 두번째 벡터를 더함으로써 우리는 시각적으로도 이것을 확인할 수 있습니다:
a + b를 더하는 것은 b + a를 더하는 것과 같은 결과를 가져온다는 점을 참고하세요.
스칼라 곱
참고
벡터는 방향과 크기 둘 다를 나타냅니다. 크기만 나타내고 있는 값을 스칼라라고 합니다. 스칼라는 Godot에서 float 유형을 사용합니다.
벡터는 스칼라에 의해 곱해질 수 있습니다:
var c = a * 2 # (2, 5) * 2 = (4, 10)
var d = b / 3 # (3, 6) / 3 = (1, 2)
var e = d * -2 # (1, 2) * -2 = (-2, -4)
var c = a * 2; // (2, 5) * 2 = (4, 10)
var d = b / 3; // (3, 6) / 3 = (1, 2)
var e = d * -2; // (1, 2) * -2 = (-2, -4)
참고
벡터에 스칼라를 곱하는 것은 벡터의 방향을 바꾸지는 않고, 이것의 크기만 바꿉니다. 이것이 바로 벡터의 크기를 조절하는 방법입니다.
실용적인 응용
벡터 덧셈과 뺄셈의 두 가지 일반적인 용법을 살펴보자.
이동
벡터는 크기와 방향을 가진 모든 양을 나타낼 수 있습니다. 대표적인 예로는 위치, 속도, 가속도, 힘이 있습니다. 이 이미지에서 1단계의 우주선은 위치 벡터 (1,3)과 속도 벡터 (2,1)을 가지고 있습니다. 속도 벡터는 배가 각 단계마다 이동하는 정도를 나타냅니다. 현재 위치에 속도를 더함으로써 2단계의 위치를 찾을 수 있습니다.
팁
속도는 시간 단위당 위치의 변화를 측정합니다. 새로운 위치는 이전 위치에 속도를 더함으로써 찾을 수 있습니다.
일반적인 2D 게임 시나리오에서는 초당 픽셀 단위의 속도를 갖고 이를 _process() 또는 _physics_process() 콜백의 delta 매개변수(이전 프레임 이후 경과된 시간)로 곱합니다.
표적을 향하기
이 시나리오에서, 당신은 회전 포탑을 로봇에게 겨누고자 하는 탱크를 가지고 있습니다. 로봇의 위치에서 탱크의 위치를 빼면 탱크에서 로봇을 가리키는 벡터를 얻을 수 있습니다.
팁
"A"에서 "B"로 향하는 벡터를 찾으려면 "B - A"를 사용합니다.
단위 벡터
크기 가 1인 벡터를 단위 벡터 라고 합니다. 또한 이러한 벡터는 방향 벡터 또는 법선벡터 라고도 합니다. 단위 벡터는 방향을 추적해야 할 때 유용합니다.
표준화
벡터를 표준화 한다는 것의 의미는 벡터의 방향은 유지하면서 벡터의 길이를 1로 줄이는 것입니다. 이것은 각 벡터를 그것의 크기로 나누면서 이루어집니다:
a = a.normalized()
a = a.Normalized();
경고
표준화는 벡터 길이로 나누어지기 때문에 길이 "0"의 벡터를 표준화할 수 없습니다. 이렇게 시도한다면 오류가 발생할 것입니다.
반사
단위벡터의 일반적인 용도는 법선 벡터 를 나타내는 것입니다. 법선 벡터는 표면에 수직으로 정렬된 단위 벡터를 말하며, 방향을 정의합니다. 이 장치는 일반적으로 조명, 콜리전 및 표면과 관련된 기타 작업에 사용됩니다.
예를 들어, 우리가 벽이나 다른 물체에서 튀기길 원하는 움직이는 공을 가지고 있다고 상상해 보세요:
이 표면은 수평면이기 때문에 표면 법선벡터 값은 (0, -1)입니다. 공이 충돌할 때, 우리는 그것의 남은 운동(표면에 부딪힐 때 남은 양)을 취하고 이것을 법선벡터를 이용해 반사시킵니다. Godot에서 :ref :vector2 <class_Vector2> 클래스는 이것을 다루는 bounce() 메서드를 가지고 있습니다. 위 다이어그램의 KinemicalBody2D를 이용하는 GDScript 예제입니다:
var collision: KinematicCollision2D = move_and_collide(velocity * delta)
if collision:
var reflect = collision.get_remainder().bounce(collision.get_normal())
velocity = velocity.bounce(collision.get_normal())
move_and_collide(reflect)
KinematicCollision2D collision = MoveAndCollide(_velocity * (float)delta);
if (collision != null)
{
var reflect = collision.GetRemainder().Bounce(collision.GetNormal());
_velocity = _velocity.Bounce(collision.GetNormal());
MoveAndCollide(reflect);
}
내적
내적은 벡터 수학에서 가장 중요한 개념 중 하나이지만 종종 잘못 이해됩니다. 내적은 두 벡터를 스칼라 로 반환해주는 연산입니다. 크기와 방향 모두를 포함하는 벡터와는 다르게 스칼라 값은 오직 크기만 갖습니다.
내적의 공식은 두가지 형태를 취한다:
그리고
수학적 표기법 ||A||*는 벡터 ``A``의 크기를 나타내고, *Ax`는 벡터 ``A``의 ``x` 구성 요소를 의미합니다.
그러나, 대부분의 경우 내장된 메서드를 사용하는 것이 가장 쉽습니다. 두 벡터의 순서는 중요하지 않습니다:
var c = a.dot(b)
var d = b.dot(a) # These are equivalent.
float c = a.Dot(b);
float d = b.Dot(a); // These are equivalent.
내적은 첫 번째 공식을 cosθ로 줄이므로 단위 벡터와 함께 사용할 때 가장 유용합니다. 즉, 내적을 사용하면 두 벡터 사이의 각도에 대해 설명할 수 있습니다:
단위벡터를 사용할때, 결과는 항상 -1(180°)에서 1(0°) 사이일 것이다.
직면
우리는 이 사실을 어떤 물체가 다른 물체를 향하고 있는지 감지하는 데 이용할 수 있습니다. 아래 그림에서 P 선수는 좀비 A와 B를 피하려고 합니다. 좀비의 시야각이 180°라고 가정하면 플레이어를 볼 수 있을까요?
녹색 화살표 fA와 fB는 좀비들이 마주보는 방향을 나타내는 단위 벡터이고 파란 반원형은 좀비의 시야를 나타냅니다. 좀비 A의 경우 P - A값을 정규화해 만든 방향 벡터인 AP가 보입니다. Godot는 direction_to라고 부르는 도우미 메서드를 가지고 있습니다. 만약 이 벡터와 마주보는 벡터 사이의 각도가 90° 미만일 경우 좀비는 플레이어를 볼 수 있습니다.
코드에서는 이렇게 보일 것이다:
var AP = A.direction_to(P)
if AP.dot(fA) > 0:
print("A sees P!")
var AP = A.DirectionTo(P);
if (AP.Dot(fA) > 0)
{
GD.Print("A sees P!");
}
외적
내적과 같이, 외적은 두 벡터사이의 연산입니다. 그러나 외적의 결과는 양쪽과 수직의 방향을 가진 벡터입니다. 그것의 크기는 그것들의 상대적인 각도에 의존합니다. 만약 두 벡터가 평행이라면, 외적의 결과는 0벡터일 것입니다.
외적은 이렇게 계산된다:
var c = Vector3()
c.x = (a.y * b.z) - (a.z * b.y)
c.y = (a.z * b.x) - (a.x * b.z)
c.z = (a.x * b.y) - (a.y * b.x)
var c = new Vector3();
c.X = (a.Y * b.Z) - (a.Z * b.Y);
c.Y = (a.Z * b.X) - (a.X * b.Z);
c.Z = (a.X * b.Y) - (a.Y * b.X);
Godot에서는 내장 Vector3.cross() 메서드를 사용할 수 있습니다:
var c = a.cross(b)
var c = a.Cross(b);
외적은 2D에서 수학적으로 정의되지 않습니다. Vector2.cross() 메서드는 2D 벡터에 대한 3D 외적의 일반적으로 사용되는 아날로그입니다.
참고
외적에서는, 순서가 중요합니다. a.cross(b)` 는 b.cross(a)와 같은 결가가 나오지 않습니다. 결과 벡터는 반대쪽 방향을 가리킵니다.
법선 계산하기
외적의 일반적인 용도는 3D 공간에서 표면 또는 평명의 법선 표면을 찾는 것입니다. 삼각형 "ABC"가 있다면 벡터 뺄셈을 사용하여 "AB"와 "AC"의 두 가장자리를 찾을 수 있습니다. 외적을 이용하여 "AB x AC"는 두 가지 모두에 수직인 벡터를 생성합니다: 표면에 수직방향.
이것은 삼각형에 수직인 평면을 계산하는 함수이다:
func get_triangle_normal(a, b, c):
# Find the surface normal given 3 vertices.
var side1 = b - a
var side2 = c - a
var normal = side1.cross(side2)
return normal
Vector3 GetTriangleNormal(Vector3 a, Vector3 b, Vector3 c)
{
// Find the surface normal given 3 vertices.
var side1 = b - a;
var side2 = c - a;
var normal = side1.Cross(side2);
return normal;
}
대상 가리키기
위의 내적 섹션에서, 우리는 두 벡터 사이의 각도를 찾는 데 어떻게 이것을 이용할 수 있는지 확인했습니다. 그러나 3차원에서는 정보가 충분하지 않습니다. 우리는 또한 어떤 축을 중심으로 회전해야 하는지 알아야 합니다. 우리는 현재 마주보는 방향과 목표 방향의 외적을 계산함으로써 그것을 발견할 수 있습니다. 그 결과인 수직 벡터는 회전의 축입니다.
추가 정보
Godot에서 벡터 수학을 사용하는 것에 대한 자세한 정보는 다음 기사를 참조하세요: