Unity

[Unity][개념,방법] Rotation과 캐릭터 회전

usingsystem 2022. 10. 4. 21:28
728x90

Unity에서는 Quaternion을 사용하여 회전을 하는데 Vector3와 다르게 W 값이 추가로 존재한다.

이는 짐벌락이란 문제를 해결하기 위해 나온 방법이라고 한다.

Quaternion과 짐벌락 관계는 이런 내용이다

1.x축, y축, z축 각각의 회전행렬을 만든다.yaw(y축 회전각) pitch(x축), roll(z축)
2. 회전 행렬을 객체의 변환행렬과 각각 순서대(x, y, z)로 곱한다.(오일러각)
3.x축을 90도 틀고난 후 y축으로 90도 튼 것과   y축을 90도 틀고난 후 z 축으로 90도 튼 것과의 회전 값이 같다.
4. 세 개의 축 각을 이용하여 항상 순서대로 회전을 하면 위와 같이 한 개의 축이  쓸모없게 된다. 이 현상이 짐벌락이다.
5. 이 문제는 계산을 한 번에 하지 않아서(세 번으로 나누어서)이다. 쿼터니온을 쓰면 한 번에 계산되어 문제가 해결된다.

eulerAngles

eulerAngles키워드를 사용하면 vector3을 사용할 수 있다.

  • ※사용 주의 사항 -키워드와 +키워드를 사용하지말자 360도가 넘어가면 오작동할 수 있다. vector3을 =으로 넣어주자.
  • 보통 절대 회전값을 사용 하기위해 사용하는 키워드
    float _yAngle = 0.0f;
    _yAngle += Time.deltaTime;
    transform.eulerAngles = new Vector3(0.0f, _yAngle, 0.0f);

Rotate

Rotate상시회전

  • 특정축을 기준으로 얼마만큼 회전하고 싶을 때 사용하는 키워드
       transform.Rotate(new Vector3(0.0f, Time.deltaTime * 100.0f , 0.0f));

Euler 

Euler 상시회전 

  • Vector3의 값을 Quaternion으로 변경시켜 준다.
    float _yAngle += Time.deltaTime * 100.0f;
    transform.rotation = Quaternion.Euler(new Vector3(0.0f, _yAngle, 0.0f));

LookRotation

※LookRotation을 사용하여 캐릭터 이동방향으로 회전

if (Input.GetKey(KeyCode.W))
    transform.rotation =  Quaternion.LookRotation(Vector3.forward);//앞으로
else if (Input.GetKey(KeyCode.S))
    transform.rotation = Quaternion.LookRotation(Vector3.back);//뒤로
else if (Input.GetKey(KeyCode.A))
    transform.rotation = Quaternion.LookRotation(Vector3.left);//왼쪽
else if (Input.GetKey(KeyCode.D))
    transform.rotation = Quaternion.LookRotation(Vector3.right);//오른쪽

Slerp

※Slerp를 사용하여 부드럽게 캐릭터 이동

Slerp(현재위치, 목적위치, 이동수치) 

  • 호를 그리며 이동함, 균일한 변화를 주는 것이 가능하다 부드럽게 이동. 하지만 삼각함수가 사용되므로 선형보간 lerp에 비해 느리다.
 if (Input.GetKey(KeyCode.W))
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.1f );
else if (Input.GetKey(KeyCode.S))
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.1f);
else if (Input.GetKey(KeyCode.A))
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.1f);
else if (Input.GetKey(KeyCode.D))
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.1f);

 

캐릭터 이동과 동시에 돌아볼 때 조금 더 부드럽게 움직이는 방법 

-  position을 쓰는 게   transform.Translate((Vector3.right * Time.deltaTime * _speed)); 을 쓰는 것보다 조금 더 부드럽게 보인다. translate은 로컬위치 postion은 word위치이다.

 if (Input.GetKey(KeyCode.W))
{
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.1f);
    transform.position += (Vector3.forward * Time.deltaTime * _speed);
}
else if (Input.GetKey(KeyCode.S))
{
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.1f);
    transform.position += (Vector3.back * Time.deltaTime * _speed);
}
else if (Input.GetKey(KeyCode.A))
{
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.1f);
    transform.position += (Vector3.left * Time.deltaTime * _speed);
}
else if (Input.GetKey(KeyCode.D))
{
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 1.0f);
    transform.position += (Vector3.right * Time.deltaTime * _speed);
}

Lerp

※※Lerp를 사용하여 일직선 이동

Lerp(현재위치, 목적위치, 이동수치) 

  • 선형보간으로 Slerp에 비해 빠르지만 부드럽게 이동은 안됨. 각 상황에 맞게 써야 함.
Vector3 dir = _lockTarget.transform.position - transform.position;
Quaternion quat = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.Lerp(transform.rotation, quat, 20 * Time.deltaTime);

 

프레임당 캐릭터 이동과 회전

    void UpdateMove()
    {
        Vector3 moveDirect = _targetPosition - transform.position; //  목적지 - 현재위치     1. 거리, 2. 방향
        float distance = moveDirect.magnitude;//거리추출

        if (distance < _speed * Time.deltaTime)//목적지에 근접했을 경우
        {
            transform.position = _targetPosition;
        }
        else
        {
            Vector3 direct = moveDirect.normalized;//방향정규화  Vector3.forward;와 같은 의미
            transform.position += direct * _speed * Time.deltaTime;// 방향 * 속도 * 프레임시간
           
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(direct), 7f * Time.deltaTime);
            #region
            /*
             * 1. 바로뒤돌기 - LookAt
             * 2. 바로뒤돌기2 - direct
             * 3. 천천히돌기 - Slerp 구면선형보간 -  그려진 가상의 호를 그대로의 거리
             * 4. 천천히돌기2 - Lerp 선형보간 - 그려진 가상의 호에서의 직선 거리,
            */
            //transform.LookAt(_targetPosition);
            //transform.rotation = Quaternion.LookRotation(direct);
            //transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direct), 7f * Time.deltaTime);
            #endregion
        }
    }

 

728x90