Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 平均一系列旋转并使用它们施加扭矩_C#_Unity3d_Quaternions - Fatal编程技术网

C# 平均一系列旋转并使用它们施加扭矩

C# 平均一系列旋转并使用它们施加扭矩,c#,unity3d,quaternions,C#,Unity3d,Quaternions,我正在构建一个虚拟现实交互系统,并添加一个投掷组件 它的设置使我有一个不断更新的被保持对象的位置数组,当我释放被保持对象时,它会计算最后5个位置之间每个时间步的增量位置,并对它们进行平均。这给我留下了一个平滑的投掷矢量,可以产生脉冲力,而不会因释放时无意的手腕轻弹而产生任何抖动。该系统已实施,效果良好 我现在试着做同样的事情,旋转,在释放时增加一个扭矩然而,在我当前的实现中,它似乎只是选择了一个随机轴在发布时旋转 我的四元数更新数组的实现方式与位置相同,没有问题,问题在于四元数平均代码或增量旋转

我正在构建一个虚拟现实交互系统,并添加一个投掷组件

它的设置使我有一个不断更新的被保持对象的位置数组,当我释放被保持对象时,它会计算最后5个位置之间每个时间步的增量位置,并对它们进行平均。这给我留下了一个平滑的投掷矢量,可以产生脉冲力,而不会因释放时无意的手腕轻弹而产生任何抖动。该系统已实施,效果良好

我现在试着做同样的事情,旋转,在释放时增加一个扭矩然而,在我当前的实现中,它似乎只是选择了一个随机轴在发布时旋转

我的四元数更新数组的实现方式与位置相同,没有问题,问题在于四元数平均代码或增量旋转计算代码:

下面是我计算三角形旋转的方法。请注意,
rotations
是从最后一帧开始的
n
旋转数组,最近的在
0
处,最早的在
n

Quaternion[] deltaRotations = new Quaternion[rotations.Length - 1];

for (int i = 0; i < deltaRotations.Length; i++)
{
    deltaRotations[i] = Quaternion.Inverse(rotations[i]) * rotations[i+1];
}
Rigidbody.addTorque(avgRot,ForceMode.pulse)产生的力
使其在看似随机的方向上旋转

你们有什么大错特错的事吗

编辑

根据Ruzihim的回答,我已将代码转换为使用旋转的角度/轴表示,并对其进行平均。当物体被释放时,这会为旋转锁定正确的轴,但似乎每次都会给我相同的旋转强度。下面是新的计算旋转力方法的代码,并不是说我将delta旋转数组传递到此函数中,而是传递原始旋转数组并在事实发生后计算delta旋转:

    Vector3 averageRotationsAngleAxis(Quaternion[] rotations) // returns an angle / axis representation of averaged rotations[]
    {
        Vector3[] deltaAxes = new Vector3[rotations.Length];

        for (int i = 0; i < rotations.Length; i++)
        {
            float angle;
            Vector3 axis;
            rotations[i].ToAngleAxis(out angle, out axis);

            deltaAxes[i] = angle * axis;
        }

        Vector3 returnVec = averageVector3(deltaAxes);

        return returnVec;
    }
Vector3 averageRotationsAngleAxis(四元数[]旋转)//返回平均旋转的角度/轴表示法[]
{
Vector3[]三角轴=新Vector3[rotations.Length];
对于(int i=0;i

将Ruzihim的答案标记为正确,当我使用他的方法调试.Log时,投掷旋转的结果看起来是正确的,问题一定在这两者之间,使用slerp平均四元数的脉冲扭矩可能会导致一些意外行为。例如,如果有两个三角形旋转,一个绕y轴旋转180度,另一个绕y轴旋转-180度,则从一个旋转到另一个旋转将永远不会产生同一旋转(绕y轴旋转0度)。它实际上总是在某个方向上旋转180度。你自己试试吧:

Quaternion a = Quaternion.AngleAxis(180f, Vector3.up); 
Quaternion b = Quaternion.AngleAxis(-180f, Vector3.up); 
Quaternion c = Quaternion.Slerp(a, b, 0.5f)

float angle; 
Vector3 axis; 
c.ToAngleAxis(out angle, out axis); 
Debug.Log(angle); 
Debug.Log(axis);
因此,相反,我建议平均轴和旋转角度,特别是使用全局旋转轴。要获得全局轴上的增量旋转,请从开始并以代数方式求解:

                globalAxesDelta * startRot = nextRot
globalAxesDelta * startRot * inv(startRot) = nextRot * inv(startRot)
                           globalAxesDelta = nextRot * inv(startRot)
因此,要使用全局轴计算旋转增量,请使用
deltaRotation=rotations[i+1]*四元数.Inverse(rotations[i])
而不是
deltaRotations[i]=四元数.Inverse(rotations[i])*rotations[i+1]
。然后,使用以下命令将其转换为轴/角度形式:


然后,您可以使用类似于AddTorque(avgAxis*someTorqueFactor)的方法来应用扭矩,沿全局轴应用扭矩。

一般来说,关于四元数
请认真听^^


作为另一种选择,你也可以平均欧拉角,如

Quaternion[] deltaRotations = new Quaternion[rotations.Length - 1];

for (int i = 0; i < deltaRotations.Length; i++)
{
    deltaRotations[i] = Quaternion.Inverse(rotations[i]) * rotations[i+1];
}

var averageEuler = Vector3.zero;
foreach(var rot in deltaRotations)
{
    averageEuler += rot.eulerAngles;
}
averageEuler /= deltaRotations.Length;


return Quaternion.Euler(averageEuler);
Quaternion[]deltaRotations=新的四元数[rotations.Length-1];
for(int i=0;i
由于Unity API已经“规范化”了
eulerAngles
,因此这也可以解决
180
vs
-180
度的问题



在智能手机上打字,但我希望这个想法变得清晰。。实际上是这样的;)

您可以发布您正在使用的旋转数组吗?你的for循环比它应该做的多了一个。将deltaRotations.Length更改为deltaRotations.Length-1,因为您有i和(i+1)。@jdweng
deltaRotations.Length
=
rotations.Length-1
。这一部分在我看来很好,我想OP会有一个运行时异常,如果这是一个issue@jdweng你可能在这里发现了什么,我正在尝试调试。记录旋转数组,它只显示一个,而不是我所期望的5个。但是是的,数组长度很好,它的旋转。长度-1,因为在5个旋转之间有4个增量旋转。好的,我已经解决了四元数太少的问题,但是有同样的问题,这里有一组典型的四元数,它们被输入到增量转换和平均代码中:(-0.02236,0.02097,-0.04850,0.99835)(-0.01765,0.03755,-0.03795,0.9984)(-0.01765,0.03755,-0.03795,0.99867)(-0.01576,0.03766,-0.03136,0.99867)(-0.02256,0.03473,-0.02588,0.99880)如果使用
三角旋转=旋转[i+1]*四元数反转(旋转[i
=四元数。逆(旋转[i])*旋转[i+1]
。我不是100%赞成使用slerp来“平均”它们,所以我在下面提供了一个替代答案。当然,slerp肯定不是最好的方法。如果有两个三角形旋转,其中一个是围绕t的180度
Vector3[] deltaAxes = new Vector3[rotations.Length - 1];

for (int i = 0; i < deltaRotations.Length; i++)
{
    Quaternion deltaRotation = rotations[i+1] * Quaternion.Inverse(rotations[i]);
    float angle;  
    Vector3 axis;
    deltaRotation.ToAngleAxis(out angle, out axis);
    deltaAxes[i] = angle * axis;
}
Vector3 avgAxis = Vector3.zero;

foreach (Vector3 angleAxis in deltaAxes)
{
    avgAxis += (1f/deltaRotations.Length) * angleAxis;
}
Quaternion[] deltaRotations = new Quaternion[rotations.Length - 1];

for (int i = 0; i < deltaRotations.Length; i++)
{
    deltaRotations[i] = Quaternion.Inverse(rotations[i]) * rotations[i+1];
}

var averageEuler = Vector3.zero;
foreach(var rot in deltaRotations)
{
    averageEuler += rot.eulerAngles;
}
averageEuler /= deltaRotations.Length;


return Quaternion.Euler(averageEuler);