Разделить кватернион на оси вращения

У меня есть кватернион, представляющий ориентацию объекта (желтый прямоугольник и сфера). Я хотел бы знать, возможно ли разделить этот кватернион на другие кватернионы, которые дают нам вращение каждой локальной оси (X, Y и Z).

Из-за того, что мне не хватает репутации, чтобы публиковать изображения напрямую, я должен поставить только ссылку на изображение

То, что я делал до сих пор, это получение представления Эйлера и работа с ним, но это не правильное решение для моего конкретного случая:

Учитывая две точки (синие прямоугольники), я хочу ограничить ориентацию моего объекта так, чтобы он не мог указывать из серой плоскости, даже если мой кватернион смотрит из этой плоскости.
Я хочу разделить (разложить) кватернион, потому что, когда мой объект достигает границы плоскости (например, справа), я хочу, чтобы он оставался там (в этом компоненте), а затем вращал мой объект в вертикальном компоненте., используя один из новых расщепленных кватернионов.

Я работаю с Unity.

Я надеюсь, это понятно, моя проблема:)

2 ответа

Вот способ получить локальное вращение только оси Y. Эту функцию можно изменить, чтобы получить ось x или z.

/// <summary> isolate the y-Component of a rotation </summary>
private Quaternion yRotation(Quaternion q)
{
    float theta = Mathf.Atan2(q.y, q.w);

    // quaternion representing rotation about the y axis
    return new Quaternion(0, Mathf.Sin(theta), 0, Mathf.Cos(theta));
}

Вы можете проверить результат в Инспекторе Unity, преобразовав в Euler:

public float yLocal;
void Update()
{
    yLocal = yRotation(this.transform.rotation).eulerAngles.y;
}

До этого я работал с IMU и, насколько мне известно, с Unity, если объект считывает данные IMU как кватернионы, вы не столкнетесь с проблемой блокировки gimbo. Таким образом, вы действительно можете создать ссылку на вращение объекта и преобразовать ее в эйлеровых ангелов, а затем преобразовать обратно в кватернионы, прежде чем применять ее к объекту.

Однако, если вы просто хотите ограничить вращение, я бы сделал что-то вроде этого:

//the last rotation was pointed at the grey zone.
private Quaternion prevAllowedRotation;

void FixedUpdate(){
    if(!isValidRotation()){
        this.transform.rotation = prevAllowedRotation;
    }else{
        this.transform.lookAt(lockToArea());
    }
}


private bool isValidRotation(){
    //I chose forward based on the image, find the direction that works for you
    Ray ray = new Ray(this.transform.position, this.transform.forward);
    RaycastHit hit;
    if(Physics.Raycast(ray, out hit, 10f){
        if(hit.transform.tag == "wall"){
            return true;
        }
    }
    return false;
}


private Vector3 lockToArea(Gameobject grey){
    Vector3 center = grey.transform.position;
    //figure out how to get the position of the facing direction on the same plane as the grey area.
    Vector3 pointerPosition = getPointerPosition();
    RaycastHit hit;
    if(Physics.Linecast(pointerPosition, center, hit)){
        return hit.point;
    }
    return Vector3.zero;

}

private Vector3 getPointerOnPlane(){
    Ray ray = new Ray(this.transform.position, this.transform.forward);
    // you need to figure out how to dyanmically get the distance so that the ray lands on the same plane as the vector
    float distance = 0; 
    return ray.GetPoint(distance);       
}

Это блокирует его вращение, чтобы указывать только на серый куб. Это должно вам сильно помочь, вам просто нужно понять, что данные IMU считываются в и находятся в той же плоскости, что и центр серого куба.

Другие вопросы по тегам