Rotate around the roll axis or pitch axis, but the object rotates around the pitch axis

The issue is as follows:

I send the roll, pitch, and yaw of a real camera in world coordinates to Unity. In Unity, I receive these values and make a virtual object move in the same way.

This works well when the yaw value is 0. However, when the yaw value rotates to approximately 90 degrees or -90 degrees, whether I rotate around the roll axis or the pitch axis, the object moves along the pitch axis.

update data

void Update()
{
    if (positionUpdated)
    {
        if (Mathf.Abs(bRoll_ - Roll_) > 150 && flag == 2)
        {
            print("flag = 1 and bRoll_ - Roll_ : " + (bRoll_ - Roll_));
            flag = 1;//바꾸기
        }
        else if (Mathf.Abs(bRoll_ - Roll_) > 150 && flag == 1)
        {
            print("flag = 2 and bRoll_ - Roll_ : " + (bRoll_ - Roll_));
            flag = 2;//그대로
        }

        if (flag == 1)
        {
            Roll_2 = Roll_ + 180;
            //bPitch_ 150
            //Pitch_ 30
            if (Pitch_ > 0)
            {
                Pitch_ = 180 - Pitch_;
            }
            else if (Pitch_ < 0)
            {
                Pitch_ = -180 - Pitch_;
            }
            //bYaw_: 150                           bYaw : -30
            //Yaw: 151 + 180 --> -29               Yaw : - 31 + 180  -> 149
            //Yaw_ = Yaw_ - 180;
            if (Yaw_ > 0)
            {
                Yaw_ = Yaw_ - 180;
            }
            else if (Yaw_ < 0)
            {
                Yaw_ = Yaw_ + 180;
            }

            print("flag = 1 : Rotate");
            print("Roll_2 : " + Roll_2);
            transform.position = targetPosition;
            //transform.eulerAngles = targetRotation;
            transform.eulerAngles = new Vector3(0, 0, 0);
            print(" Pitch_ : " + Pitch_ + " Yaw_ : " + Yaw_ + " Roll_2 : " + -Roll_2);
            transform.Rotate(Pitch_, 0.0f, 0.0f, Space.World);
            transform.Rotate(0.0f, Yaw_, 0.0f, Space.World);
            transform.Rotate(0.0f, 0.0f, -Roll_2, Space.World);

            bRoll_ = Roll_2 - 180;
            bPitch_ = Pitch_;
            bYaw_ = Yaw_;
            positionUpdated = false;
        }
        else
        {
            print("flag = 2 : Rotate");
            transform.position = targetPosition;
            //transform.eulerAngles = targetRotation;
            transform.eulerAngles = new Vector3(0, 0, 0);
            print(" Pitch_ : " + Pitch_ + " Yaw_ : " + Yaw_ + " Roll_ : " + -Roll_);
            transform.Rotate(Pitch_, 0.0f, 0.0f, Space.World);
            transform.Rotate(0.0f, Yaw_, 0.0f, Space.World);
            transform.Rotate(0.0f, 0.0f, -Roll_, Space.World);

            bRoll_ = Roll_;
            bPitch_ = Pitch_;
            bYaw_ = Yaw_;
            positionUpdated = false;
        }
    }
    else
    {
        transform.Rotate(0.0f, 0.0f, 0.0f, Space.World);
        transform.Rotate(0.0f, 0.0f, 0.0f, Space.World);
        transform.Rotate(0.0f, 0.0f, 0.0f, Space.World);
    }
}

receive data

void ParseData(string data)
{
    string[] values = data.Split(',');
    Vector3 position = new Vector3(
        -Convert.ToSingle(values[0]) + 0,
        Convert.ToSingle(values[1]) + 0,
        Convert.ToSingle(values[2]) + 0);

    //Vector3 rotation = new Vector3(
    //    Convert.ToSingle(values[4]),
    //    -Convert.ToSingle(values[5]),
    //    -Convert.ToSingle(values[3]));
    Roll_ = Convert.ToSingle(values[3]);
    Pitch_ = Convert.ToSingle(values[4]);
    Yaw_ = -Convert.ToSingle(values[5]);

    targetPosition = position;
    //targetRotation = rotation;

    positionUpdated = true;
}

Rotating by Roll ⇒ The x-coordinate is the pitch, but the pitch has a Roll value:

Rotating by Pitch ⇒The x-coordinate is the pitch, so the pitch has a Pitch value:

What did I do wrong??? Is this a gimbal lock???


This is my issue page, and there are videos, and all codes.

thank you

You may have to flip the sign of some of these values because I don’t know if your device considers looking to the right as a positive change in yaw or a negative one. Same goes for pitch and roll.

// TODO: These values are currently hardcoded. Use the received data to populate the variables
float deviceYaw   = 90; // If 0 is North, then the device is pointing East
float devicePitch = 45; // Looking 45 deegrees down
float deviceRoll  = 20; // Tilting 20 degrees to the left

// The order of these is VERY IMPORTANT.
// Notice how only the first one rotates in WORLD space. The next two rotate in LOCAL space
Quaternion unityWorldRotation =
    Quaternion.Euler(0,            deviceYaw,  0         ) *   // Yaw   in Unity World space
    Quaternion.Euler(devicePitch,  0,          0         ) *   // Pitch in Unity Local space
    Quaternion.Euler(0,            0,          deviceRoll);    // Roll  in Unity Local space

transform.rotation = unityWorldRotation;

I do not recommend calling transform.Rotate() multiple times because it causes the hierarchy to update every time you call it, but if you insist on doing it, then at least remember what I wrote earlier:

  1. The order is important: Yaw then Pitch then Roll
  2. Only the Yaw is allowed to be performed in World space. Pitch and roll should be done in Local space.

Example:

transform.Rotate(0,       Yaw_,  0,      Space.World); // World space
transform.Rotate(Pitch_,  0,     0,      Space.Self);  // Local space
transform.Rotate(0,       0,     -Roll_, Space.Self);  // Local space

For some reason, I cannot edit my first answer, so I had to post a new one.

Thank you very much for the new video. It was really nice to be able to see all the values as you move the camera.

Please try this:

As before, let Roll_, Pitch_, Yaw_ be the raw values received from the device.

void Update()
{
    if (positionUpdated)
    {
        transform.rotation = DeviceWorldRotation_to_UnityWorldRotation_v2(Roll_, Pitch_, Yaw_);
        positionUpdated = false;
    }
}

public Quaternion DeviceWorldRotation_to_UnityWorldRotation_v2 (float roll, float pitch, float yaw)
{
    return
        Quaternion.Euler(0,      0,     -roll) *
        Quaternion.Euler(pitch,  0,     0    ) *
        Quaternion.Euler(0,      -yaw,  0    );
}