본문 바로가기

Unity/▶ Unity Composition

[Unity Composition]#7. 공간과 움직임

728x90
반응형

공간

3D 공간에 배치하는 3D 오브젝트는 위치를 표현한 값인 좌표를 가진다. 원점을 기준으로 (x, y, z)에서 X 방향은 오른쪽, Y방향은 위쪽, Z 방향은 앞쪽으로 이동한 위치이다.

출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=nanzz200x&logNo=120189517700 

X 방향 오른쪽
Y 방향 위쪽
Z 방향 앞쪽

 

이렇게 좌표를 측정할 기준이 될 원점의 위치와 X, Y, Z 축 방향을 설정하여 물체가 어디에 배치되어있는지 표현하는 기준과 체계를 좌표계라고 한다. 좌표계공간에서 어떤 방향으로 얼마큼 이동한 거리에 배치할 것인지 결정하는 기준이다.

좌표계는 공간에서 어떤 방향으로 얼마큼 이동한 거리에 배치할 것인지 결정하는 기준이다.

좌표계는 여러 종류가 존재하는데, 어떤 좌표계를 사용하고 어떤 방향을 X, Y, Z 방향으로 정의하느냐에 따라 표현하는 좌표가 달라진다. 여기서 공간좌표계를 사용하여 물체를 배치하는 틀이며, 어떤 좌표계를 사용하느냐에 따라 공간의 종류가 달라진다.

 
공간은 좌표계를 사용하여 물체를 배치하는 틀이다.

하지만 유니티 속의 게임 월드는 하나이지만 좌표계로는 게임 월드의 모든 속성을 표현할 수 없다. 즉 앞으로 다룰 전역 공간과 오브젝트 공간, 자식 공간은 하나의 게임 월드를 서로 다른 좌표계에서 관측하여 표현한 것이다.

 

따라서 우리는 하나의 게임 월드를 상황에 따라 서로 다른 공간, 즉 하나의 좌표계 혹은 기준에서 관측해야 한다.

 

전역 공간

전역 공간은 월드의 중심이라는 절대 기준이 존재하는 공간이며 월드 공간이라고 부르기도 한다.

전역 공간에서 X, Y, Z 방향을 정하고 좌표를 계산하는 기준은 전역 좌표계라고 한다.

 

전역 공간에는 게임 월드의 원점이 존재하며 모든 오브젝트가 원점에서 얼마큼 떨어져 있냐가 오브젝트의 좌표가 된다.

전역 공간 전역 공간은 월드의 중심이라는 절대 기준이 존재하는 공간
전역 좌표계 전역 공간에서 X, Y, Z 방향을 정하고 좌표를 계산하는 기준
rotation: (0,0,0) rotation: (0,60,0)

유니티의 공간 모드를 지역에서 전역을 변경한다.

Pivot/Center 전환의 기본값은 Pivot이며, Local/Global의 기본값은 Local이다. 일반적으로 Pivot | Local을 사용한다.

피벗과 센터

Pivot 오브젝트의 실제 기준점을 기준으로 오브젝트를 배치
모델의 실제 위치에 편집 도구가 표시

일반적으로 사용되는 형태
Center 눈에 보이는 중점을 가준으로 오브젝트를 배치
오브젝트의 실제 위치를 무시하고 겉으로 보이는 형태의 중심에 편집 도구가 표시

전역과 로컬

Global 특정 오브젝트의 공간이 아닌 전역 공간의 X,Y,Z의 방향을 좌표계의 기준으로 삼음.
Local 특정 오브젝트의 공간의 X,Y,Z 방향을 좌표계의 기준으로 삼음.

지역 공간

지역 공간은 게임 월드나 오브잭트 자신이 아닌 자신의 부모 오브젝트를 기준으로 한 지역 좌표계로 좌표를 측정한다. 그리고 인스펙터 창에서 표시되는 게임 오브젝트의 우치, 회전, 스케일은 모두 지역 공간에서 측정된 것이다.

 

하지만 부모 오브젝트가 존재하지 않으면 지역 좌표계와 전역 좌표계가 일치하므로 지역 공간상의 위치가 곧 전역 공간상의 위치가 된다.

따라서 위의 사진(3D cube)의 공간은 지역공간이자 전역 공간이 되는 것이다.

큐브의 자식 생성하기

  1. 인스펙터 > Cube 오브젝트의 Transform 컴포넌트의 톱더보기 클릭 > Reset
  2. Sphere 오브젝트 생성: 위치 (2,0,0)
  3. 하이어 라키 > Sphere를 Cube에 드래그&드롭

큐브의 자식 오브젝트인 Sphere은 큐브의 위치를 옮겨도 Sphere의 위치는 변경되지 않는 것을 알 수 있다. Sphere의 지역 공간은 변하지 않았기 때문이다.

 

오브젝트의 자식부모 오브젝트위치와 회전, 스케일을 함께한다. 부모 오브젝트의 위치와 회전, 스케일을 기본적으로 따라지만 자식 오브젝트의 위치와 회전, 스케일의 설정도 별개로 설정 가능하며 이때의 기준은 부모 오브젝트를 따른다.

큐브의 자식 해제

하이어 라키에서 Sphere를 밖으로 드래그&드롭하면 부모로부터 공간이 해제된다. 이후 Sphere는 전역 공간이 지역공간으로서 작용한다.

 

모든 게임 오브젝트는 자신의 부모 오브젝트를 세상의 중심으로 여기고 좌표를 측정한다. 이것이 지역 공간이며, 인스펙터 창에 보이는 위치, 회전, 스케일은 언제나 지역 공간으로 표시된다.

지역 공간과 오브젝트 공간의 차이

전역 공간 게임 월드의 원점을 기준으로 위치를 측정한다.
지역 공간 자신의 부모 게임 오브젝트를 기준으로 위치를 측정한다.
오브젝트 공간 자기 자신을 기준으로 위치를 측정한다.

유니티는 편의상 지역 공간과 오브젝트 공간을 합쳐 지역 공간으로 부른다. 인스펙터 창에 표시되는 트랜스폼 컴포넌트의 위치, 회전, 스케일은 부모에 상대적이다.

 

지역 공간에서 앞쪽으로 평행이동하면 게임 오브젝트 자신이 아닌 부모 게임 오브젝트의 앞쪽으로 이동한다. 반면 Local 모드를 사용하면 부모 게임 오브젝트의 앞쪽이 아닌 실제 자기 자신의 오브젝트의 앞쪽으로 이동하게 된다. 즉, 평행이동에 대해서 지역공간(Local)이라고 표기하지만 실제로는 오브젝트 공간을 사용하는 것이다.

 

  • 지역 공간에서의 위치, 회전, 스케일 값 측정: 부모 게임 오브젝트 기준
  • 지역 공간에서의 평행 이동: 게임 오브젝트 자신의 방향을 기준으로 평행 이동

오브젝트의 이동과 회전

앞선 포스팅에서 우리는 리지드 바디 컴포넌트를 이영하여 게임 오브젝트의 위치를 제어해 보았다.

 

하지만 리지드 바디 컴포넌트를 사용한 이동은 실제 위치를 직접 변경하지 않고 물리적인 상호작용을 이용한 것이므로 의도한 위치에 물체를 정확히 배치하기 어렵다는 단점이 있다.

 

이러한 문제점을 해결하기 위해 물리 처리를 거치지 않고 트랜스폼 컴포넌트의 위치나 회전 값을 직접 변경하여 게임 오브젝트를 움직일 수 있다.

Move Script 생성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move : MonoBehaviour
{   
    public Transform Sphere;
    // Start is called before the first frame update
    void Start()
    {
        transform.position = new Vector3(0,-1,0);
        Sphere.localPosition = new Vector3(0,2,0);

        transform.rotation = Quaternion.Euler(new Vector3(0,0,30));
        Sphere.localRotation = Quaternion.Euler(new Vector3(0,60,0));
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKey(KeyCode.UpArrow)){
            transform.Translate(new Vector3(0,1,0)*Time.deltaTime);
        }
        if(Input.GetKey(KeyCode.DownArrow)){
            transform.Translate(new Vector3(0,-1,0)*Time.deltaTime);
        }
        if(Input.GetKey(KeyCode.LeftArrow)){
            transform.Rotate(new Vector3(0,0,180)*Time.deltaTime);
            Sphere.Rotate(new Vector3(0,180,0)*Time.deltaTime);
        }
        if(Input.GetKey(KeyCode.RightArrow)){
            transform.Rotate(new Vector3(0,0,-180)*Time.deltaTime);
            Sphere.Rotate(new Vector3(0,-180,0)*Time.deltaTime);
        }

    }
}

코드 설명

public Transform Sphere;

public 타입으로 Sphere 게임 오브젝트의 트랜스폼 컨포넌트를 Transform 변수로 접근하여 사용한다.

트랜스폼으로 접근한 오브젝트를 선택한다.

transform.position = new Vector3(0,-1,0);
Sphere.localPosition = new Vector3(0,2,0);
  • 자신(Cube)의 전역 좌표를 (0,-1,0)으로 설정한다.
  • 자식 오브젝트(Sphere)의 지역 좌표를 (0,2,0)으로 설정한다.
transform.rotation = Quaternion.Euler(new Vector3(0,0,30));
Sphere.localRotation = Quaternion.Euler(new Vector3(0,60,0));
  • 자신(Cube)의 전역 좌표 회전을 (0,0,30)으로 설정한다.
  • 자식 오브젝트(Sphere)의 좌표 회전을 (0,60,0)으로 설정한다.

[평행이동]

if(Input.GetKey(KeyCode.UpArrow)){
    transform.Translate(new Vector3(0,1,0)*Time.deltaTime);
}
if(Input.GetKey(KeyCode.DownArrow)){
    transform.Translate(new Vector3(0,-1,0)*Time.deltaTime);
}

Translate() 메서드는 입력으로 Vector3 값을 받는다. Translate() 메서드가 실행되면 트랜스폼 컴포넌르가 현재 위치에서 입력받은 Vector3값만큼 상대적으로 더 이동한다.

 

만약 Time.deltaTime를 곱하지 않으면 1초에 1만큼 이동하지 않고 한 프레임에 1만큼 증가한다.

전역 공간 기준으로 평행 이동 transform.Translate(new Vector3(x,y,z)*Time.deltaTime,Space.World);
지역 공간 기준으로 평행 이동 transform.Translate(new Vector3(x,y,z)*Time.deltaTime,Space.Self);

[회전]

if(Input.GetKey(KeyCode.LeftArrow)){
    transform.Rotate(new Vector3(0,0,180)*Time.deltaTime);
    Sphere.Rotate(new Vector3(0,180,0)*Time.deltaTime);
}
if(Input.GetKey(KeyCode.RightArrow)){
    transform.Rotate(new Vector3(0,0,-180)*Time.deltaTime);
    Sphere.Rotate(new Vector3(0,-180,0)*Time.deltaTime);
}

Rotate() 메서드는 입력으로 Vector3 값을 받는다. Rotate() 메서드가 실행되면 트랜스폼 컴포넌르가 현재 위치에서 입력받은 Vector3값만큼 게임 오브젝트를 더 회전한다.

728x90
반응형
댓글