Split quaternion into axis rotations

爷,独闯天下 提交于 2019-12-02 08:58:05

Here's a way to get the local rotation of just the y-axis. This function can be modified to get the x or z-axis.

/// <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));
}

You can verify the result in the Unity inspector by converting to Euler:

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

I have worked with IMUs before and to my knowledge with Unity if the object is reading in the IMU data as quaternions, then you will not encounter the gimbo lock problem. So you can indeed create a reference to the object's rotation and convert those to euler angels, and then convert back to Quaternions before applying it to the object.

However, if you are simply wanting to limit rotation I would do something like this:

//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);       
}

This locks its rotation to only be pointing at the grey cube. This should help you a lot, you just need to get the point that the IMU data is reading in at and is on the same plane as the grey cube's center.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!