C# & Unity

[C# / Unity] Unity의 'Quaternion.Euler' C# 코드로 만들기

김먼저 2022. 9. 23. 14:30

 

IMU센서에서 출력되는 쿼터니언 값을 Euler_Angle, 즉, 우리가 흔히 접하는 각도로 나타내기 위한

 

여러가지 방법이 있지만, 저는

 

Unity에서 작업한 코드 → 다른언어로 변환

 

할 수 있도록 1차적으로 C# 코드로 구현하려고 했습니다.(구글링으로도 찾기 힘들더라구요...)

 

 

 

1. Unity의 Quaternion 구조체 → Class로 작성

 

 

Quaternion a_quat = new Quaternion(x, y, z, w);	// Unity

clsQuat b_quat = new clsQuat(w, x, y, z);

 

clsQuat 는 4개의 float값을 저장하는 간단한 클래스입니다.

 

  x, y, z, w 순서 주의해 주세요!

 

 

2.  쿼터니언 → 라디안 → Degree

 

 

protected static clsPoint Q2E(clsQuat qt)
    {

        clsPoint euler = new clsPoint(0, 0, 0);

        float unit = (qt.qx * qt.qx) + (qt.qy * qt.qy) + (qt.qz * qt.qz) + (qt.qw * qt.qw);

        // this will have a magnitude of 0.5 or greater if and only if this is a singularity case
        float test = qt.qx * qt.qw - qt.qy * qt.qz;

        if (test > 0.4995f * unit) // singularity at north pole
        {
            euler.x = (float)(Math.PI / 2);
            euler.y = (float)(2f * Math.Atan2(qt.qy, qt.qx));
            euler.z = 0;
        }
        else if (test < -0.4995f * unit) // singularity at south pole
        {
            euler.x = (float)(-Math.PI / 2);
            euler.y = (float)(-2f * Math.Atan2(qt.qy, qt.qx));
            euler.z = 0;
        }
        else // no singularity - this is the majority of cases
        {
            euler.x = (float)(Math.Asin(2f * (qt.qw * qt.qx - qt.qy * qt.qz)));
            euler.y = (float)(Math.Atan2(2f * qt.qw * qt.qy + 2f * qt.qz * qt.qx, 1 - 2f * (qt.qx * qt.qx + qt.qy * qt.qy)));
            euler.z = (float)(Math.Atan2(2f * qt.qw * qt.qz + 2f * qt.qx * qt.qy, 1 - 2f * (qt.qz * qt.qz + qt.qx * qt.qx)));
        }

        // all the math so far has been done in radians. Before returning, we convert to degrees...
        euler.x *= 57.29578f;
        euler.y *= 57.29578f;
        euler.z *= 57.29578f;

        //...and then ensure the degree values are between 0 and 360
        euler.x %= 360;
        euler.y %= 360;
        euler.z %= 360;

        return Internal_MakePositive(euler);
    }

 

clsPoint는 clsQuat와 마찬가지로 3개의 float값을 저장하는 class이고,

 

return 부분의 Internal_MakePositive() 메서드는 계산된 degree를 나름 보기 좋게 만드는 역할을 합니다.

 

 

3. 출력된 값 보기 좋게 변환하기 → Internal_MakePositive()

 

 

private static clsPoint Internal_MakePositive(clsPoint euler)
    {
        float negativeFlip = -0.0001f * Mathf.Rad2Deg;
        float positiveFlip = 360.0f + negativeFlip;

        if (euler.x < negativeFlip)
            euler.x += 360.0f;
        else if (euler.x > positiveFlip)
            euler.x -= 360.0f;

        if (euler.y < negativeFlip)
            euler.y += 360.0f;
        else if (euler.y > positiveFlip)
            euler.y -= 360.0f;

        if (euler.z < negativeFlip)
            euler.z += 360.0f;
        else if (euler.z > positiveFlip)
            euler.z -= 360.0f;

        return euler;
    }

 

 

* clsPoint, clsQuat는 단지 값을 저장하는 용도이며,

 

 

Unity의 Vector3 → clsPoint

            Quaternion → clsQuat

 

으로 대체했다고 보시면 됩니다.

 

 

double이 아닌 float로 작성한 이유는 IMU센서에서 출력되는 값이 float이기 때문입니다.

 

다른언어로 변환하는데 전혀 어려움이 없을거 같네요:)

 

p.s. IMU 센서 버리고싶...

 

Ref :

https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Quaternion.cs

 

GitHub - Unity-Technologies/UnityCsReference: Unity C# reference source code.

Unity C# reference source code. Contribute to Unity-Technologies/UnityCsReference development by creating an account on GitHub.

github.com

https://stackoverflow.com/questions/12088610/conversion-between-euler-quaternion-like-in-unity3d-engine

 

Conversion between Euler <=> Quaternion like in Unity3d engine

I've used two examples (from this site too), but results are not the same as those that said Unity. Quaternion.Euler and .eulerAngles are Unity functions. FromQ doesn't perform singularity check, ...

stackoverflow.com

 

'C# & Unity' 카테고리의 다른 글

[C#] 날짜/시간 차이 구하기 - DateTime  (0) 2022.10.31