gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 02:06:23 25 4
gpt4 key购买 nike

我正在构建一个 VR 交互系统,并添加一个 throw 组件。

它的设置是为了让我有一个不断更新的持有对象的位置数组,当我释放持有的对象时,它会计算最后 5 个位置之间每个时间步长的增量位置,并将它们取平均值。这给我留下了一个平滑的冲击力 throw 矢量,而不会因释放时无意的手腕轻弹而引入任何抖动。该系统已实现并且运行良好。

我现在正尝试对旋转做同样的事情,并在释放时添加扭力。 但是,在我当前的实现中,它似乎只是选择一个随机轴在释放时旋转。

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

以下是我计算增量旋转的方法。请注意,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];
}

以下是我对增量旋转进行平均的方法。

Quaternion avgRot = Quaternion.identity;

int quatCount = 0;

foreach (Quaternion quat in deltaRotations)
{
quatCount ++;
avgRot = Quaternion.Slerp(avgRot, quat, 1 / quatCount);
}

来自 Rigidbody.addTorque(avgRot, ForceMode.Impulse) 的合力将其设置为看似随机的方向旋转。

你们有什么明显错误的地方吗?

编辑

根据 Ruzihim 的回答,我已将代码转换为使用旋转的角度/轴表示并对它们进行平均。这在物体释放时确定了正确的旋转轴,但似乎每次都给我相同的旋转强度。下面新的计算旋转力方法的代码,不是我将 deltaRotations 数组传递给这个函数,而不是传递原始旋转数组并在事后计算增量旋转:

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

将 Ruzihim 的答案标记为正确,当我使用他的方法 Debug.Log 抛出旋转的结果时,它们看起来是正确的,问题一定在那个和脉冲扭矩之间的某个地方

最佳答案

使用 slerp 来平均四元数可能会导致一些意外行为。例如,如果您有 2 个增量旋转,一个绕 y 轴旋转 180 度,一个绕 y 轴旋转 -180 度,从一个旋转到另一个旋转永远不会产生恒等旋转(旋转 0 度绕 y 轴轴)。它实际上总是在某个方向上旋转 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);

因此,相反,我建议平均旋转轴和角度,特别是使用全局旋转轴。要获得全局轴中的增量旋转,请从 global axis delta rotation * start rotation = next rotation 开始并代数求解:

                globalAxesDelta * startRot = nextRot
globalAxesDelta * startRot * inv(startRot) = nextRot * inv(startRot)
globalAxesDelta = nextRot * inv(startRot)

因此,要使用全局轴计算旋转增量,请使用 deltaRotation = rotations[i+1] * Quaternion.Inverse(rotations[i]) 而不是 deltaRotations[i] = Quaternion .Inverse(rotations[i]) * rotations[i+1].然后,使用 ToAngleAxis 将它们转换为轴/角度形式:

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

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

关于c# - 平均一系列旋转并使用它们来施加扭矩,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62785867/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com