将四元数拆分为轴旋转

时间:2017-04-25 09:03:58

标签: unity3d split rotation quaternions euler-angles

我有一个四元数,表示一个物体的方向(黄色框和球体)。我想知道是否可以将该四元数分割成其他四元数,使我们能够旋转每个局部轴(X,Y和Z)。

Due to I do not have enough reputation to post images directly, I have to put just the link of the image

到目前为止我一直在做的是获取Euler表示并使用它,但它不是我特定情况的正确解决方案:

给定两个点(蓝色方框),我想限制对象的方向,使其无法指向灰色平面,即使我的四元数看起来超出了那个平面。
我想拆分(分解)四元数,因为当我的对象达到平面的极限(例如,右边)时,我想让它停留在那里(在那个组件中),然后在垂直组件中旋转我的对象,使用一个新的分裂四元数。

我正在与Unity合作。

我希望我的问题是可以理解的:)

2 个答案:

答案 0 :(得分:1)

这是一种获得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));
}

您可以通过转换为Euler:

来验证Unity检查器中的结果
public float yLocal;
void Update()
{
    yLocal = yRotation(this.transform.rotation).eulerAngles.y;
}

答案 1 :(得分:0)

如果对象在IMU数据中作为四元数读取,我之前和我一起使用过IMU,那么你就不会遇到gimbo锁定问题了。因此,您确实可以创建对象旋转的引用并将其转换为euler天使,然后在将其应用于对象之前转换回Quaternions。

但是,如果你只想限制旋转,我会做这样的事情:

//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数据正在读取的点,并且与灰色立方体的中心位于同一平面上。