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...
행렬과 변환
소개
본 튜토리얼을 읽기 전에 벡터 수학 에 대한 이전 튜토리얼을 읽어 보는 것이 좋습니다.
이 튜토리얼은 *변환*과 행렬을 사용하여 Godot에서 이를 표현하는 방법에 관한 것입니다. 행렬에 대한 완전하고 심층적인 가이드는 아닙니다. 변환은 대부분 평행 이동, 회전, 크기 조정으로 적용되므로 이를 행렬로 표현하는 방법에 중점을 두겠습니다.
이 가이드의 대부분은 Transform2D 및 :ref:`class_Vector2`를 사용하여 2D에 중점을 두지만 3D에서 작동하는 방식은 매우 유사합니다.
참고
이전 튜토리얼에서 언급했듯이, Godot에서 Y축은 2D에서 *아래쪽*을 가리킨다는 것을 기억하는 것이 중요합니다. 이는 대부분의 학교에서 Y축이 위를 향하도록 선형 대수학을 가르치는 방식과 반대입니다.
참고
관례적으로 X축은 빨간색, Y축은 녹색, Z축은 파란색입니다. 이 튜토리얼은 이러한 규칙에 맞게 색상으로 구분되어 있지만 원점 벡터도 파란색으로 표시합니다.
행렬 구성 요소 및 항등 행렬
단위 행렬은 변환, 회전, 크기 조정이 없는 변환을 나타냅니다. 먼저 항등 행렬을 살펴보고 해당 구성 요소가 시각적으로 나타나는 방식과 어떤 관련이 있는지 살펴보겠습니다.
행렬에는 행과 열이 있으며 변환 행렬에는 각 기능에 대한 특정 규칙이 있습니다.
위 이미지에서 빨간색 X 벡터가 행렬의 첫 번째 열로 표시되고 녹색 Y 벡터도 마찬가지로 두 번째 열로 표시되는 것을 볼 수 있습니다. 열을 변경하면 이러한 벡터도 변경됩니다. 다음 몇 가지 예에서 이들이 어떻게 조작될 수 있는지 살펴보겠습니다.
일반적으로 열을 사용하므로 행을 직접 조작하는 것에 대해 걱정할 필요가 없습니다. 그러나 행렬의 행은 어떤 벡터가 주어진 방향으로 이동하는 데 기여하는지 보여주는 것으로 생각할 수 있습니다.
``t.x.y``와 같은 값을 참조하는 경우 이는 X 열 벡터의 Y 구성 요소입니다. 즉, 행렬의 왼쪽 하단입니다. 마찬가지로 ``t.x.x``는 왼쪽 위, ``t.y.x``는 오른쪽 위, ``t.y.y``는 오른쪽 아래입니다. 여기서 ``t``는 Transform2D입니다.
애니메이션 만들기
척도를 적용하는 것은 이해하기 가장 쉬운 작업 중 하나입니다. 개체에 대한 효과를 시각적으로 볼 수 있도록 벡터 아래에 Godot 로고를 배치하는 것부터 시작하겠습니다.
이제 행렬의 크기를 조정하려면 각 구성 요소에 원하는 크기를 곱하기만 하면 됩니다. 2만큼 확대해 보겠습니다. 1 곱하기 2는 2가 되고, 0 곱하기 2는 0이 됩니다. 따라서 다음과 같이 끝납니다.
코드에서 이를 수행하기 위해 각 벡터를 곱합니다.
var t = Transform2D()
# Scale
t.x *= 2
t.y *= 2
transform = t # Change the node's transform to what we calculated.
Transform2D t = Transform2D.Identity;
// Scale
t.X *= 2;
t.Y *= 2;
Transform = t; // Change the node's transform to what we calculated.
원래 크기로 되돌리려면 각 구성 요소에 0.5를 곱하면 됩니다. 이것이 변환 행렬의 크기를 조정하는 데 필요한 전부입니다.
기존 변환 행렬에서 객체의 크기를 계산하려면 각 열 벡터에 ``length()``를 사용할 수 있습니다.
참고
실제 프로젝트에서는 scaled() 방법을 사용하여 스케일링을 수행할 수 있습니다.
애니메이션 만들기
우리는 항등 행렬 아래에 Godot 로고를 사용하여 이전과 같은 방식으로 시작할 것입니다:
예를 들어, Godot 로고를 시계 방향으로 90도 회전시키고 싶다고 가정해 보겠습니다. 현재 X축은 오른쪽을 가리키고 Y축은 아래를 가리킵니다. 머리에서 이를 회전하면 논리적으로 새 X축이 아래쪽을 가리키고 새 Y축이 왼쪽을 가리켜야 한다는 것을 알 수 있습니다.
Godot 로고와 벡터를 모두 잡고 중앙을 중심으로 회전시키는 것을 상상할 수 있습니다. 회전이 끝나면 벡터의 방향에 따라 행렬이 결정됩니다.
일반 좌표에서 "아래쪽"과 "왼쪽"을 나타내야 하므로 X를 (0, 1)로 설정하고 Y를 (-1, 0)으로 설정해야 합니다. 이는 Vector2.DOWN 및 ``Vector2.LEFT``의 값이기도 합니다. 이렇게 하면 객체를 회전하여 원하는 결과를 얻을 수 있습니다.
위 내용을 이해하는 데 어려움이 있다면 다음 연습을 시도해 보세요. 정사각형 종이를 자르고 그 위에 X 및 Y 벡터를 그린 다음 모눈종이 위에 놓고 회전시켜 끝점을 확인하세요.
코드에서 회전을 수행하려면 프로그래밍 방식으로 값을 계산할 수 있어야 합니다. 이 이미지는 회전 각도에서 변환 행렬을 계산하는 데 필요한 공식을 보여줍니다. 이 부분이 복잡해 보이더라도 걱정하지 마세요. 여러분이 알아야 할 가장 어려운 부분이라고 약속합니다.
참고
Godot는 각도가 아닌 라디안으로 모든 회전을 나타냅니다. 1회전은 TAU 또는 PI*2 라디안이고, 90도 1/4회전은 TAU/4 또는 PI/2 라디안입니다. `TAU`를 사용하면 일반적으로 더 읽기 쉬운 코드가 생성됩니다.
참고
재미있는 사실: Godot에서 Y가 아래로 있는 것 외에도 회전은 시계 방향으로 표시됩니다. 이는 모든 수학 및 삼각 함수가 Y-is-up CCW 시스템과 동일하게 작동한다는 것을 의미합니다. 왜냐하면 이러한 차이가 "상쇄"되기 때문입니다. 두 시스템 모두에서 "X에서 Y로"의 회전을 생각할 수 있습니다.
0.5 라디안(약 28.65도)의 회전을 수행하기 위해 위 공식에 0.5 값을 대입하고 실제 값이 무엇인지 평가합니다.
코드에서 수행되는 방법은 다음과 같습니다(Node2D에 스크립트 배치).
var rot = 0.5 # The rotation to apply.
var t = Transform2D()
t.x.x = cos(rot)
t.y.y = cos(rot)
t.x.y = sin(rot)
t.y.x = -sin(rot)
transform = t # Change the node's transform to what we calculated.
float rot = 0.5f; // The rotation to apply.
Transform2D t = Transform2D.Identity;
t.X.X = t.Y.Y = Mathf.Cos(rot);
t.X.Y = t.Y.X = Mathf.Sin(rot);
t.Y.X *= -1;
Transform = t; // Change the node's transform to what we calculated.
기존 변환 행렬에서 객체의 회전을 계산하려면 ``atan2(t.x.y, t.x.x)``를 사용할 수 있습니다. 여기서 t는 Transform2D입니다.
참고
실제 프로젝트에서는 rotated() 방법을 사용하여 회전을 수행할 수 있습니다.
변환 행렬의 기초
지금까지 우리는 회전, 크기 조정 및/또는 전단(고급, 마지막에 설명)을 나타내는 벡터인 x 및 ``y``만 사용해 왔습니다. X와 Y 벡터를 함께 변환 행렬의 *기초*라고 합니다. "기저"와 "기저 벡터"라는 용어를 아는 것이 중요합니다.
class_Transform2D`에는 실제로 세 개의 :ref:`class_Vector2 값(x, y 및 origin)이 있음을 알 수 있습니다. origin 값은 기저의 일부가 아니지만 변환의 일부이며 위치를 나타내는 데 필요합니다. 이제부터 모든 예제에서 원점 벡터를 추적하겠습니다. 원점을 또 다른 열로 생각할 수도 있지만, 완전히 별개로 생각하는 것이 더 나은 경우가 많습니다.
3D에서 Godot는 기본의 3개의 Vector3 값을 유지하기 위해 별도의 Basis 구조를 가지고 있습니다. 코드가 복잡해질 수 있고 코드를 :ref:`class_Transform3D`(원점에 대해 하나의 :ref:`class_Basis`와 하나의 추가 :ref:`class_Vector3`로 구성됨)와 분리하는 것이 합리적이기 때문입니다.
애니메이션 만들기
origin 벡터를 변경하는 것을 변환 행렬 *변환*이라고 합니다. 변환은 기본적으로 객체를 "이동"하는 기술 용어이지만 명시적으로 회전을 포함하지는 않습니다.
이해를 돕기 위해 예를 들어보겠습니다. 이번에는 원점 벡터를 추적한다는 점을 제외하면 지난번과 마찬가지로 항등 변환부터 시작하겠습니다.
객체를 (1, 2) 위치로 이동하려면 origin 벡터를 (1, 2)로 설정해야 합니다.
origin``를 직접 추가하거나 변경하는 것과 다른 작업을 수행하는 ``translated_local() 메서드도 있습니다. translated_local() 메소드는 자체 회전을 기준으로 객체를 변환합니다. 예를 들어 시계 방향으로 90도 회전한 개체는 ``translated_local()``와 ``Vector2.UP``를 함께 사용하면 오른쪽으로 이동합니다. 전역/상위 프레임을 기준으로 변환하려면 대신 ``translated()``를 사용하세요.
참고
Godot의 2D는 픽셀 기반의 좌표를 사용하므로 실제 프로젝트에서는 수백 단위로 변환하고 싶을 것입니다.
대상 가리키기
지금까지 언급한 모든 내용을 하나의 변환에 적용하겠습니다. 계속하려면 Sprite2D 노드로 프로젝트를 생성하고 텍스처 리소스에 Godot 로고를 사용하세요.
변환을 (350, 150)으로 설정하고 -0.5 rad로 회전하고 3으로 크기를 조정하겠습니다. 스크린샷과 이를 재현할 수 있는 코드를 게시했지만 코드를 보지 않고 스크린샷을 재현해 보시기 바랍니다!
var t = Transform2D()
# Translation
t.origin = Vector2(350, 150)
# Rotation
var rot = -0.5 # The rotation to apply.
t.x.x = cos(rot)
t.y.y = cos(rot)
t.x.y = sin(rot)
t.y.x = -sin(rot)
# Scale
t.x *= 3
t.y *= 3
transform = t # Change the node's transform to what we calculated.
Transform2D t = Transform2D.Identity;
// Translation
t.Origin = new Vector2(350, 150);
// Rotation
float rot = -0.5f; // The rotation to apply.
t.X.X = t.Y.Y = Mathf.Cos(rot);
t.X.Y = t.Y.X = Mathf.Sin(rot);
t.Y.X *= -1;
// Scale
t.X *= 3;
t.Y *= 3;
Transform = t; // Change the node's transform to what we calculated.
변환 행렬의 밀림 (고급)
참고
변환 행렬을 *사용*하는 방법만 찾고 있다면 튜토리얼의 이 섹션을 건너뛰어도 됩니다. 이 섹션에서는 변환 행렬에 대한 이해를 구축하기 위해 변환 행렬의 일반적으로 사용되지 않는 측면을 살펴봅니다.
Node2D는 기본적으로 밀림 속성을 제공합니다.
위 작업을 조합한 것보다 변환의 자유도가 더 높다는 사실을 눈치채셨을 것입니다. 2D 변환 행렬의 기본은 2개의 Vector2 값에 총 4개의 숫자가 있는 반면, 회전 값과 축척용 Vector2에는 3개의 숫자만 있습니다. 누락된 자유도에 대한 상위 수준 개념을 *전단*이라고 합니다.
일반적으로 기본 벡터는 항상 서로 수직입니다. 그러나 기울이기는 상황에 따라 유용할 수 있으며, 기울이기를 이해하면 변환이 작동하는 방식을 이해하는 데 도움이 됩니다.
어떻게 보일지 시각적으로 보여주기 위해 Godot 로고 위에 그리드를 오버레이해 보겠습니다:
이 그리드의 각 점은 기본 벡터를 함께 추가하여 얻습니다. 오른쪽 하단 모서리는 X + Y이고 오른쪽 상단 모서리는 X - Y입니다. 기본 벡터를 변경하면 그리드가 기본 벡터로 구성되므로 전체 그리드가 함께 이동합니다. 현재 평행한 그리드의 모든 선은 기본 벡터를 어떻게 변경하더라도 평행을 유지합니다.
예를 들어 Y를 (1, 1)로 설정해 보겠습니다.
var t = Transform2D()
# Shear by setting Y to (1, 1)
t.y = Vector2.ONE
transform = t # Change the node's transform to what we calculated.
Transform2D t = Transform2D.Identity;
// Shear by setting Y to (1, 1)
t.Y = Vector2.One;
Transform = t; // Change the node's transform to what we calculated.
참고
편집기에서 Transform2D의 원시 값을 설정할 수 없으므로 개체를 기울이려면 반드시 코드를 사용해야 합니다.
벡터가 더 이상 수직이 아니기 때문에 객체가 잘렸습니다. 그리드 자체를 기준으로 (0, 1)인 그리드의 하단 중앙은 이제 (1, 1)의 월드 위치에 있습니다.
객체 내 좌표는 텍스처에서 UV 좌표라고 부르므로 여기서는 해당 용어를 빌려보겠습니다. 상대 위치에서 월드 위치를 찾으려면 공식은 U * X + V * Y입니다. 여기서 U와 V는 숫자이고 X와 Y는 기본 벡터입니다.
항상 (1, 1)의 UV 위치에 있는 그리드의 오른쪽 하단 모서리는 (2, 1)의 월드 위치에 있으며, 이는 X*1 + Y*1에서 계산됩니다. 이는 (1, 0) + (1, 1) 또는 (1 + 1, 0 + 1) 또는 (2, 1)입니다. 이는 이미지의 오른쪽 하단 모서리가 어디에 있는지 관찰한 것과 일치합니다.
마찬가지로 항상 (1, -1)의 UV 위치에 있는 그리드의 오른쪽 상단 모서리는 (0, -1)의 월드 위치에 있으며, 이는 X*1 + Y*-1에서 계산됩니다. 이는 (1, 0) - (1, 1) 또는 (1 - 1, 0 - 1) 또는 (0, -1)입니다. 이는 이미지의 오른쪽 상단 모서리가 어디에 있는지 관찰한 것과 일치합니다.
이제 변환 행렬이 객체에 어떤 영향을 미치는지, 기본 벡터 간의 관계와 객체의 "UV" 또는 "내부 좌표"가 월드 위치를 변경하는 방법을 완전히 이해하셨기를 바랍니다.
참고
Godot에서 모든 변환 수학은 상위 노드를 기준으로 수행됩니다. "세계 위치"를 참조할 때 이는 노드에 상위가 있는 경우 대신 노드의 상위를 기준으로 합니다.
추가 설명을 원하시면 선형 변환에 대한 3Blue1Brown의 뛰어난 비디오: https://www.youtube.com/watch?v=kYB8IZa5AuE를 확인하십시오.
실용적인 응용
실제 프로젝트에서는 일반적으로 여러 Node2D 또는 Node3D 노드를 서로 상위로 지정하여 변환 내부의 변환 작업을 수행하게 됩니다.
그러나 필요한 값을 수동으로 계산하는 방법을 이해하는 것은 유용합니다. Transform2D 또는 :ref:`class_Transform3D`를 사용하여 노드의 변환을 수동으로 계산하는 방법을 살펴보겠습니다.
변환 간 위치 변환
변환 안팎으로 위치를 변환하려는 경우가 많이 있습니다. 예를 들어 플레이어를 기준으로 한 위치가 있고 월드(부모 기준) 위치를 찾고 싶거나 월드 위치가 있고 플레이어를 기준으로 어디에 있는지 알고 싶은 경우입니다.
* 연산자를 사용하여 플레이어와 관련된 벡터가 월드 공간에서 정의되는 것을 찾을 수 있습니다.
# World space vector 100 units below the player.
print(transform * Vector2(0, 100))
// World space vector 100 units below the player.
GD.Print(Transform * new Vector2(0, 100));
그리고 * 연산자를 반대 순서로 사용하여 플레이어를 기준으로 정의된 경우 월드 공간 위치가 무엇인지 찾을 수 있습니다.
# Where is (0, 100) relative to the player?
print(Vector2(0, 100) * transform)
// Where is (0, 100) relative to the player?
GD.Print(new Vector2(0, 100) * Transform);
참고
변환이 (0, 0)에 위치한다는 것을 미리 알고 있는 경우 변환 처리를 건너뛰는 "basis_xform" 또는 "basis_xform_inv" 메서드를 대신 사용할 수 있습니다.
자신을 기준으로 객체 이동
특히 3D 게임에서 일반적인 작업은 개체 자체를 기준으로 개체를 이동하는 것입니다. 예를 들어, 1인칭 슈팅 게임에서 :kbd:`W`을 누르면 캐릭터가 앞으로(-Z축) 이동하도록 할 수 있습니다.
기본 벡터는 부모를 기준으로 한 방향이고 원점 벡터는 부모를 기준으로 한 위치이므로 기본 벡터의 배수를 추가하여 객체를 자신을 기준으로 이동할 수 있습니다.
이 코드는 객체를 오른쪽으로 100단위 이동합니다.
transform.origin += transform.x * 100
Transform2D t = Transform;
t.Origin += t.X * 100;
Transform = t;
3D로 이동하려면 "x"를 "basis.x"로 바꿔야 합니다.
참고
실제 프로젝트에서는 3D에서 translate_object_local``를 사용하거나 2D에서 ``move_local_x 및 ``move_local_y``를 사용하여 이를 수행할 수 있습니다.
변환에 변환 적용
변환에 대해 알아야 할 가장 중요한 것 중 하나는 여러 변환을 함께 사용하는 방법입니다. 상위 노드의 변환은 모든 자식 노드에 영향을 미칩니다. 예를 분석해 보겠습니다.
이 이미지에서 자식 노드는 상위 노드와 구별하기 위해 구성 요소 이름 뒤에 "2"가 있습니다. 숫자가 너무 많아서 다소 부담스러워 보일 수 있지만 각 숫자는 두 번 표시되며(화살표 옆과 행렬에도) 숫자의 거의 절반이 0이라는 점을 기억하세요.
여기서 진행되는 유일한 변환은 상위 노드에 (2, 1)의 척도가 부여되고 하위에 (0.5, 0.5)의 척도가 부여되었으며 두 노드에 위치가 부여되었다는 것입니다.
모든 하위 변환은 상위 변환의 영향을 받습니다. 자식의 척도는 (0.5, 0.5)이므로 1:1 비율의 제곱이 될 것으로 예상할 수 있지만 이는 부모에 대해서만 상대적입니다. 자식의 X 벡터는 부모의 기본 벡터에 따라 크기가 조정되므로 월드 공간에서 결국 (1, 0)이 됩니다. 마찬가지로, 자식 노드의 origin 벡터는 (1, 1)로 설정되어 있지만 실제로는 상위 노드의 기본 벡터로 인해 월드 공간에서 (2, 1)로 이동합니다.
하위 변환의 월드 공간 변환을 수동으로 계산하기 위해 다음 코드를 사용합니다.
# Set up transforms like in the image, except make positions be 100 times bigger.
var parent = Transform2D(Vector2(2, 0), Vector2(0, 1), Vector2(100, 200))
var child = Transform2D(Vector2(0.5, 0), Vector2(0, 0.5), Vector2(100, 100))
# Calculate the child's world space transform
# origin = (2, 0) * 100 + (0, 1) * 100 + (100, 200)
var origin = parent.x * child.origin.x + parent.y * child.origin.y + parent.origin
# basis_x = (2, 0) * 0.5 + (0, 1) * 0
var basis_x = parent.x * child.x.x + parent.y * child.x.y
# basis_y = (2, 0) * 0 + (0, 1) * 0.5
var basis_y = parent.x * child.y.x + parent.y * child.y.y
# Change the node's transform to what we calculated.
transform = Transform2D(basis_x, basis_y, origin)
// Set up transforms like in the image, except make positions be 100 times bigger.
Transform2D parent = new Transform2D(2, 0, 0, 1, 100, 200);
Transform2D child = new Transform2D(0.5f, 0, 0, 0.5f, 100, 100);
// Calculate the child's world space transform
// origin = (2, 0) * 100 + (0, 1) * 100 + (100, 200)
Vector2 origin = parent.X * child.Origin.X + parent.Y * child.Origin.Y + parent.Origin;
// basisX = (2, 0) * 0.5 + (0, 1) * 0 = (0.5, 0)
Vector2 basisX = parent.X * child.X.X + parent.Y * child.X.Y;
// basisY = (2, 0) * 0 + (0, 1) * 0.5 = (0.5, 0)
Vector2 basisY = parent.X * child.Y.X + parent.Y * child.Y.Y;
// Change the node's transform to what we calculated.
Transform = new Transform2D(basisX, basisY, origin);
실제 프로젝트에서는 * 연산자를 사용하여 하나의 변환을 다른 변환에 적용하여 어린이의 세계 변환을 찾을 수 있습니다.
# Set up transforms like in the image, except make positions be 100 times bigger.
var parent = Transform2D(Vector2(2, 0), Vector2(0, 1), Vector2(100, 200))
var child = Transform2D(Vector2(0.5, 0), Vector2(0, 0.5), Vector2(100, 100))
# Change the node's transform to what would be the child's world transform.
transform = parent * child
// Set up transforms like in the image, except make positions be 100 times bigger.
Transform2D parent = new Transform2D(2, 0, 0, 1, 100, 200);
Transform2D child = new Transform2D(0.5f, 0, 0, 0.5f, 100, 100);
// Change the node's transform to what would be the child's world transform.
Transform = parent * child;
참고
행렬을 곱할 때는 순서가 중요합니다! 그것들을 섞지 마십시오.
마지막으로 항등 변환을 적용하면 항상 아무 일도 일어나지 않습니다.
추가 설명을 원하시면 매트릭스 구성에 대한 3Blue1Brown의 뛰어난 비디오: https://www.youtube.com/watch?v=XkY2DOUCWMU를 확인하십시오.
번역 가져오기
"affine_inverse" 함수는 이전 변환을 "실행 취소"하는 변환을 반환합니다. 이는 일부 상황에서 유용할 수 있습니다. 몇 가지 예를 살펴보겠습니다.
역변환에 일반 변환을 곱하면 모든 변환이 취소됩니다.
var ti = transform.affine_inverse()
var t = ti * transform
# The transform is the identity transform.
Transform2D ti = Transform.AffineInverse();
Transform2D t = ti * Transform;
// The transform is the identity transform.
변환을 통해 위치를 변환하고 그 역을 수행하면 동일한 위치가 생성됩니다.
var ti = transform.affine_inverse()
position = transform * position
position = ti * position
# The position is the same as before.
Transform2D ti = Transform.AffineInverse();
Position = Transform * Position;
Position = ti * Position;
// The position is the same as before.
3D에서는 어떻게 작동하나요?
변환 행렬의 가장 큰 장점 중 하나는 2D 변환과 3D 변환 간에 매우 유사하게 작동한다는 것입니다. 2D에 사용된 모든 코드와 공식은 3가지 예외를 제외하고 3D에서도 동일하게 작동합니다: 세 번째 축의 추가, 각 축은 Vector3 유형이고 Godot는 :ref:`class_Basis`를 :ref:`class_Transform3D`와 별도로 저장합니다. 왜냐하면 수학이 복잡해질 수 있고 분리하는 것이 합리적이기 때문입니다.
3D에서 변환, 회전, 크기 조정 및 기울이기가 작동하는 방식에 대한 모든 개념은 2D와 모두 동일합니다. 규모를 조정하기 위해 각 구성 요소를 가져와서 곱합니다. 회전하려면 각 기본 벡터가 가리키는 위치를 변경합니다. 번역하기 위해 우리는 원점을 조작합니다. 그리고 전단을 위해 기본 벡터를 수직이 아닌 것으로 변경합니다.
원할 경우 변환을 실험하여 작동 방식을 이해하는 것이 좋습니다. Godot를 사용하면 인스펙터에서 직접 3D 변환 행렬을 편집할 수 있습니다. Basis 벡터와 원점을 2D 및 3D로 시각화하는 데 도움이 되는 컬러 선과 큐브가 있는 이 프로젝트를 다운로드할 수 있습니다. https://github.com/godotengine/godot-demo-projects/tree/master/misc/matrix_transform
참고
Godot 4.0의 검사기에서는 Node2D의 변환 행렬을 직접 편집할 수 없습니다. 이는 Godot의 향후 릴리스에서 변경될 수 있습니다.
추가 설명을 원하시면 3D 선형 변환에 대한 3Blue1Brown의 뛰어난 비디오: https://www.youtube.com/watch?v=rHLEWRxRGiM를 확인하십시오.
3D로 회전 표현(고급)
2D 변환 행렬과 3D 변환 행렬의 가장 큰 차이점은 기본 벡터 없이 회전 자체를 표현하는 방법입니다.
2D를 사용하면 변환 행렬과 각도 사이를 전환하는 쉬운 방법(atan2)이 있습니다. 3D에서는 회전이 너무 복잡해서 하나의 숫자로 표현하기 어렵습니다. 회전을 3개 숫자의 집합으로 표현할 수 있는 오일러 각도(Euler angles)라는 것이 있지만, 이는 제한적이고 사소한 경우를 제외하면 별로 유용하지 않습니다.
3D에서 우리는 일반적으로 각도를 사용하지 않고, 변환 기반(Godot의 거의 모든 곳에서 사용됨)을 사용하거나 쿼터니언을 사용합니다. Godot는 Quaternion 구조체를 사용하여 쿼터니언을 표현할 수 있습니다. 제가 제안하는 것은 내부적으로 작동하는 방식을 완전히 무시하라는 것입니다. 왜냐하면 매우 복잡하고 직관적이지 않기 때문입니다.
그러나 이것이 어떻게 작동하는지 정말로 알아야 한다면 다음의 몇 가지 훌륭한 리소스를 순서대로 따라해 볼 수 있습니다.
https://www.youtube.com/watch?v=mvmuCPvRoWQ