쿼터니언을 오일러각으로 변환 > IT Note

본문 바로가기
사이트 내 전체검색

IT Note

쿼터니언을 오일러각으로 변환
2

View 12,617  | 작성일2018.03.03 16:19

본문

쿼터니언(사원수) 회전이 짐벌락이 없고 매우 효율적인건 분명하나 

모든 프로그래머가 쿼터니언을 수학적인 이해를 바탕으로 사용하는건 아닙니다.

 특히나 일반적인 상황에서는 오일러 방식이 이해하기 단순합니다. 

 

그래서 내부적으로는 쿼터니언을 쓰고 외부에서는 오일러 개념으로만 운용하는 클래스를 만들어 보고 싶었습니다.

 

언리얼 엔진에서 차용하는 방식인데 Rotator 클래스에서 Yaw, Pitch, Roll 로 제어를 하지만 

내부에서는 쿼터니언을 사용해서 계산합니다. 

 

그리고 그렇게 계산된 Rotation을 언제고 Yaw, Pitch, Roll 오일러 각으로 분해하는것을 보고 

저도 해보고 싶어서 쿼터니언을 오일러각으로 변환하고 싶었습니다만...

 

당췌 키워드를 뭘 찾아야 할지도 모르겠고 의외로 관심이 없어서 놀랐습니다...

둘중 하나인거 같은데 

 

1. 당연한걸 왜 굳이...

2. 나만 못찾는거..

 

여튼 거의 하루종일 찾은거 같습니다. 

답은 찾았는데 왜 이렇게 돌아가는지는 잘 모르겠습니다....

 

여튼 한 유저가 찾은 방법이고 착안은 유니티에서 .ToEuler() 펑션에서 한것으로알고 있습니다.

 

 public static Quaternion ToQ (Vector3 v)

{

    return ToQ (v.y, v.x, v.z);

}

 

public static Quaternion ToQ (float yaw, float pitch, float roll)

{

    yaw *= Mathf.Deg2Rad;

    pitch *= Mathf.Deg2Rad;

    roll *= Mathf.Deg2Rad;

    float rollOver2 = roll * 0.5f;

    float sinRollOver2 = (float)Math.Sin ((double)rollOver2);

    float cosRollOver2 = (float)Math.Cos ((double)rollOver2);

    float pitchOver2 = pitch * 0.5f;

    float sinPitchOver2 = (float)Math.Sin ((double)pitchOver2);

    float cosPitchOver2 = (float)Math.Cos ((double)pitchOver2);

    float yawOver2 = yaw * 0.5f;

    float sinYawOver2 = (float)Math.Sin ((double)yawOver2);

    float cosYawOver2 = (float)Math.Cos ((double)yawOver2);

    Quaternion result;

    result.w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2;

    result.x = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2;

    result.y = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2;

    result.z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2;

 

    return result;

}

 

public static Vector3 FromQ2 (Quaternion q1)

{

    float sqw = q1.w * q1.w;

    float sqx = q1.x * q1.x;

    float sqy = q1.y * q1.y;

    float sqz = q1.z * q1.z;

    float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor

    float test = q1.x * q1.w - q1.y * q1.z;

    Vector3 v;

 

    if (test>0.4995f*unit) { // singularity at north pole

        v.y = 2f * Mathf.Atan2 (q1.y, q1.x);

        v.x = Mathf.PI / 2;

        v.z = 0;

        return NormalizeAngles (v * Mathf.Rad2Deg);

    }

    if (test<-0.4995f*unit) { // singularity at south pole

        v.y = -2f * Mathf.Atan2 (q1.y, q1.x);

        v.x = -Mathf.PI / 2;

        v.z = 0;

        return NormalizeAngles (v * Mathf.Rad2Deg);

    }

    Quaternion q = new Quaternion (q1.w, q1.z, q1.x, q1.y);

    v.y = (float)Math.Atan2 (2f * q.x * q.w + 2f * q.y * q.z, 1 - 2f * (q.z * q.z + q.w * q.w));     // Yaw

    v.x = (float)Math.Asin (2f * (q.x * q.z - q.w * q.y));                             // Pitch

    v.z = (float)Math.Atan2 (2f * q.x * q.y + 2f * q.z * q.w, 1 - 2f * (q.y * q.y + q.z * q.z));      // Roll

    return NormalizeAngles (v * Mathf.Rad2Deg);

}

 

static Vector3 NormalizeAngles (Vector3 angles)

{

    angles.x = NormalizeAngle (angles.x);

    angles.y = NormalizeAngle (angles.y);

    angles.z = NormalizeAngle (angles.z);

    return angles;

}

 

static float NormalizeAngle (float angle)

{

    while (angle>360)

        angle -= 360;

    while (angle<0)

        angle += 360;

    return angle;

}

 

 

여기서 봐야할건 FromQ 이고요.

FromQ함수에서 변환할때 주의점은 쿼터니언은 기본적으로 360를 표현하지 못한다 합니다.

180기준으로 판별할수 밖에 없어서 180도가 넘어가는 경우 마이너스 각도로 판별하는것 까진 알겠는데..

 

왜 쿼터니언의 xyzw 를 뒤집에서 계산하는지는 제 수학력의 한계입니다.

 

어쨌든 다행히도 몇개의 각을 테스트 해보고 조합해서 결과값을 뽑아보니 아주 훌륭하게 오일러 각으로 잘 변환했습니다. 

 

하... 왜 이거 한국문서나 영어문서 전부 이렇게 찾기 힘들었던 걸까요...

 

찾고나니 좀 허무해졌습니다. 

 

댓글목록

요즘 잘 안 찾아지는건 트랜드가 지나버렸기 때문이겠죠..

다렉 9.x 사용해 개발하던 시절만 해도 직접 바닥부터 개발하거나 미들웨어 정도의 라이브러리를 가져다가 조합해서 자체 엔진을 구성하던 환경이라 본문의 내용이 많은 관심을 받는 주요 기술이었죠.

감자님 (이성수님? 맞나..;;;;;) 블로그도 많이 핫했었고요..
근데 이제는 유니티나 언리얼 같은 엔진이 대부분 커버해버리다 보니 개략적인 개념만 알고 지나가는게 아닌가 하는 생각이 듭니다.

7,8 년 전 쯤만해도 검색하면 어렵지 않게 검색 결과에 노출되던 내용들인 거로 기억합니당.. 'ㅅ'a

IT Tip&Tech 목록

게시물 검색

접속자집계

오늘
830
어제
522
최대
6,399
전체
660,288
Copyright © LittleCandle All rights reserved.
문의메일 : littlecandle99@gmail.com
모바일 버전으로 보기