[Unity] Transform 알아보기
Unity의 Transform에 대해 알아 보자

둠칫둠칫
Unity의 Transform은 실제 행렬로 이루어져 있습니다.
Position, Rotation, Scale 모두 3차원 Vector기 때문에 행렬은 4x4가 됩니다.
왜인지는 나중에 수학 공부를 다시 해야 할 듯...
Unity는 열 기준 행렬 방식을 채택하고 있습니다.
오브젝트가 회전할 경우 행렬의 변화를 알아봅시다!
↓ 오브젝트를 z축으로 90도 회전
z축으로 -90도 회전 후 x축은 -y방향으로 y축은 x방향으로 변하였습니다.
using TMPro;
using UnityEngine;
public class DisplayMatrix : MonoBehaviour {
public TextMeshProUGUI txtMatrix;
private void Update() {
var m = gameObject.GetComponent<Transform>().localToWorldMatrix;
var txt = $"{m.m00:0.00} {m.m01:0.00} {m.m02:0.00} {m.m03:00} \n";
txt += $"{m.m10:0.00} {m.m11:0.00} {m.m12:0.00} {m.m13:00} \n";
txt += $"{m.m20:0.00} {m.m21:0.00} {m.m22:0.00} {m.m23:00} \n";
txt += $"{m.m30:0.00} {m.m31:0.00} {m.m32:0.00} {m.m33:00}";
txtMatrix.text = txt;
}
}
다음 코드로 회전하는 동안의 행렬의 변화를 살펴봅시다.
각각 x축, y축, z축으로 회전시 변화하는 행렬의 값을 확인 할 수 있습니다.
자세한 내용은 좀 더 공부하고 링크 걸어두는걸로...
그래서 Unity는 어떻게 오브젝트의 Transform 변화를 나타내는가?
우선 Unity는 세 공간으로 분류 되어 있습니다.
C# API : 유저 스크립트를 작성하고 접근 할 수 있는 공간 (Transfrom)
C++ Engine : 엔진 내부 렌더링 공간
Physics Box2D/Physx : 물리 엔진 공간 (RIgidBody)
C#에서 Translate를 호출 할 경우를 내부 코드 따라가면 TrnasformDirection까지 도달하는데 이는 엔진 내부 코드로 동작합니다.
public void Translate(Vector3 translation)
{
Translate(translation, Space.Self);
}
// Moves the transform in the direction and distance of /translation/.
public void Translate(Vector3 translation, [UnityEngine.Internal.DefaultValue("Space.Self")] Space relativeTo)
{
if (relativeTo == Space.World)
position += translation;
else
position += TransformDirection(translation);
}
// Transforms direction /x/, /y/, /z/ from local space to world space.
public Vector3 TransformDirection(float x, float y, float z) { return TransformDirection(new Vector3(x, y, z)); }
Box 2D는 오픈 소스 물리 시뮬레이터 엔진입니다.
GameObject에 RigidBody2D를 붙히면 유니티 내부에서 Box 2D 공간에 물리 공간을 따로 만듭니다.
한 공간이 변경되면 나머지 두 공간이 데이터 씽크를 맞춰주어야 합니다.
ex) trnasform.position .... / Animator / rigidbody.Addforce
Transform을 사용할 때 주의 할 점.
1. Position과 Rotation을 동시에 변경한다면 SetPositionAndRotation 함수를 사용하자.
위에서 언급 했듯이 Transform은 4x4 행렬, 따라서 서로 영향을 미치게 됩니다.
void Update()
{
transform.positiion += new Vector3(1f, 1f, 1f);
transform.rotation += Quaternion.Euler(45f, 45f, 45f);
}
void Update()
{
transform.SetPositionAndRotation(
transform.positiion + new Vector3(1f, 1f, 1f);
transform.rotation + Quaternion.Euler(45f, 45f, 45f);
);
}
위의 코드가 아래의 코드보다 약 2배의 연산을 처리하게 될 것입니다.
2. 많은 시스템에서 Transform을 업데이트 하고 있다면 모든 변경 사항들을 모아서 한 군데서 처리하자.
ex) Jump.cs, Run.cs, Dash.cs ... -> 하나로
[RequireComponent(typeof(Rigidbody))]
class MyMonoBehaviour : MonoBehaviour
{
void Update()
{
transform.SetPositionAndRotation(...);
}
}
다음 코드는 비효율적 입니다.
Transform을 움직이면 RigidBody가 갱신되고 Physics 공간이 업데이트 됩니다.
RigidBody가 존재하면 물리 공간이 스스로 Transform 공간을 업데이트 합니다.
한 공간이 주체가 되지 않고 서로 상호 작용을 하면서 서로 업데이트가 되면서 연산 낭비로 이루어집니다.
하지만 게임 로직상 그럴 수 밖에 없다면?
3. Physics -> Auto Sync Transforms 옵션 사용하기.
Transform을 변경했을 때 물리 공간을 항상 씽크를 맞춰서 업데이트 해줄 것인지 , 물리 업데이트 주기에 맞출 것인지 고를 수 있습니다.
Transform은 객체로 존재하여 움직인다면 하위 로드에 있는 모든 오브젝트의 Transform을 갱신하게 됩니다.
따라서 동적인 오브젝트들은 계층 구조를 단순화 해야합니다.
하지만 계층 구조가 깊어질 수 밖에 없는 캐릭터같은 경우가 있습니다.
4. Optimize Game Objects 체크하자.
엔진 내부에서만 사용하고 하이어라키 노출에서는 생략되는 기능입니다.
스켈레톤이 빠지고 api로 접근 안되며 그만큼 성능을 높히는 기능입니다.
보통 스크립트에서 접근을 안 하기 때문에 체크하는게 좋습니다.
만약 스크립트에서 접근 해야 하는 경우는 Extra Transforms to Expose에 추가하면 됩니다.
참고 자료 출처
https://www.youtube.com/watch?v=QtmGT-22PqA
https://www.youtube.com/watch?v=hmRpaNphiJI
지금 보니까 동일인물이시네...?

오랜만에 공부하고 블로그 글 쓰니까 재밌어서 시간 가는 줄 몰랐다 헤헷😆
정리를 나름 한다고 했는데 엉망진창이네 ㅋㅋㅋ 다음에 더 잘 써야징...