【问题标题】:Split quaternion into axis rotations将四元数拆分为轴旋转
【发布时间】:2017-04-25 09:03:58
【问题描述】:

我有一个四元数表示对象的方向(黄色框和球体)。我想知道是否可以将该四元数拆分为其他四元数,从而为我们提供每个局部轴(X、Y 和 Z)的旋转。

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

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

我正在使用 Unity。

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

【问题讨论】:

  • Quaternion rotation = Quaternion.Euler(new Vector3(transform.eulerAngles.x, 0, 0)); 是否适用?
  • 感谢@Peh 的编辑。谢谢 Ryan,但我想避免欧拉角,因为原始四元数来自外部 IMU,并且用欧拉角限制方向我遇到了一些麻烦
  • Quaternion.eulerAngles 是一个东西,但我怀疑这就是你已经在使用的东西。我知道 wxyz 值根本无济于事,因为它们不完整。我能想到的最好的方法是在两个蓝色框上计算 Euler AngleTo()(您必须编写此方法),并检查其 X 和 Y 分量是否大于 0(或小于,视情况而定)。
  • stackoverflow.com/questions/3684269/… 1.Decompose 2 Limit 3. Compose

标签: unity3d split rotation quaternions euler-angles


【解决方案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;
}

【讨论】:

    【解决方案2】:

    我之前使用过 IMU,据我所知,如果对象以四元数形式读取 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 数据正在读取的点,并且与灰色立方体的中心位于同一平面上。

    【讨论】:

    • 感谢@dan 的回答。这真的很接近我的预期,但我想更进一步。我的旋转仅限于灰色平面的区域,好的,但现在的问题是当我的立方体指向平面外时(我的意思是原始旋转),它卡在平面的一侧。例如,如果我将立方体从平面的右侧取出并垂直移动,它仍然停留在最后允许的位置,而不是沿着右边缘上下移动。容易到达吗?再次感谢。
    • @javinair 看看我所做的最新编辑,我没有足够的时间来完成最后一步,即完成 getPointerOnPlane 但如果你弄清楚了,那么你就得到了你想要的。在重新阅读您的问题后,我进行了这些编辑。我也很高兴它起作用了,因为我无法对其进行测试 XD。
    猜你喜欢
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 2018-04-05
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多