본문 바로가기

개발/Unity

[Unity] Transform 알아보기

728x90
반응형

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까지 도달하는데 이는 엔진 내부 코드로 동작합니다.

https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Transform/ScriptBindings/Transform.bindings.cs

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 

지금 보니까 동일인물이시네...?


오랜만에 공부하고 블로그 글 쓰니까 재밌어서 시간 가는 줄 몰랐다 헤헷😆

정리를 나름 한다고 했는데 엉망진창이네 ㅋㅋㅋ 다음에 더 잘 써야징...

728x90
반응형