【发布时间】:2020-07-08 00:40:14
【问题描述】:
我正在构建一个 VR 交互系统,并添加一个投掷组件。
它的设置是为了让我有一个持续更新的持有对象的位置数组,当我释放持有的对象时,它会计算最后 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];
}
以下是我平均增量旋转的方法。
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 使用他的方法投掷旋转的结果时,它们看起来是正确的,问题一定是介于这和脉冲扭矩之间
【问题讨论】:
-
你能发布你正在使用的旋转数组吗?你的 for 循环比它应该多一个。将 deltaRotations.Length 更改为 deltaRotations.Length - 1 因为你有 i 和 (i + 1)。
-
@jdweng
deltaRotations.Length=rotations.Length - 1。这部分对我来说看起来不错,我想如果这是一个问题,OP 会有一个运行时异常 -
@jdweng 你可能会在这里做一些事情,我正在尝试调试。记录旋转数组,它只显示一个而不是我期望的一组 5 个。但是是的,数组长度很好,它的 rotations.Length - 1 因为 5 个旋转之间有 4 个增量旋转
-
好吧,我已经解决了四元数太少的问题,但是有同样的问题,这里有一组典型的四元数,它们被输入到增量转换和平均代码中:(-0.02236, 0.02097 ,-0.04850,0.99835)(-0.01765,0.03755,0.03755,0.0355,0.01765,0.03755,0.03755,-0.03795,0.99867)(-0.01576,0.03766,-0.03136,0.99867)(-0.02256,0.03473,-0.02588,0.99880)
-
如果您使用
deltaRotation = rotations[i+1] * Quaternion.Inverse(rotations[i])而不是deltaRotations[i] = Quaternion.Inverse(rotations[i]) * rotations[i+1]计算沿全局轴的增量,这可能会起作用。我不是 100% 关于使用 slerp 来“平均”它们,所以我在下面提供了一个替代答案。
标签: c# unity3d quaternions