旋转插值

Rob*_*Rob 27 math interpolation rotation

注意:我会在程度上提出这个问题纯粹是为了简单,弧度,度,不同的零轴承,问题基本相同.

有没有人对旋转插值背后的代码有任何想法?给定线性插值函数:Lerp(from,to,amount),其中amount为0 ... 1,返回from和from之间的值.如何将相同的功能应用于0到360度之间的旋转插补?鉴于度数不应该在0和360之外返回.

给定度数的这个单位圆:

单位圈

从= 45到= 315,算法应该采用到角度的最短路径,即它应该经过零,到360然后到315 - 而不是一直到90,180,270到315.

有没有一个很好的方法来实现这一目标?或者它只是一个可怕的if()块?我错过了一些很好理解的标准方法吗?任何帮助,将不胜感激.

use*_*496 34

我知道这已经2年了,但是我最近一直在寻找同样的问题,我没有看到没有ifs贴在这里的优雅解决方案,所以这里有:

    shortest_angle=((((end - start) % 360) + 540) % 360) - 180;
    return start + (shortest_angle * amount) % 360;
Run Code Online (Sandbox Code Playgroud)

而已

ps:当然,%表示模数,shortest_angle是保存整个插值角度的变量

  • 这很好用.那里有一些伏都教. (5认同)
  • [并非所有模数都表现相同](http://stackoverflow.com/q/1907565/190597),但在Python中,这可以简化为`shortest_angle =((end-start)+ 180)%360 - 180` . (2认同)
  • 你能解释一下为什么这些值吗?因此可以将其转换为弧度而不是度数。 (2认同)
  • 对我猜的每个数字执行“N/180*Pi”:) (2认同)
  • @JonathanMee 感谢您的回复!有一阵子了!我已经在 J​​avaScript 中提出了一个解决方案,如果您愿意,可以使用它:http://pastebin.com/wp15rK3v 该函数接受一个布尔值,确定它是角度还是整数值。例如:``var TankRotation = new AnimatedValue(1,true); TankRotation.set(6.2,100);//6.2=弧度,100=100ms时间插值tankRotation.get(); // 返回一个即将趋于 0 的值,达到 0 后继续保持 PI*2``` (2认同)
  • 以前的编辑打破了这个答案。如果您查看这篇文章的先前版本,当 `amount = 0` 时,给出的答案将始终返回 0,而不是 `start` 角度。我已将其改回工作版本。 (2认同)
  • @Jimmio92我认为人们误解了答案。该函数返回您必须更改的角度量。当然,如果你想从该点开始旋转,你可以添加它的起点 (2认同)

Rob*_*Rob 13

对不起,这有点令人费解,这是一个更简洁的版本:

    public static float LerpDegrees(float start, float end, float amount)
    {
        float difference = Math.Abs(end - start);
        if (difference > 180)
        {
            // We need to add on to one of the values.
            if (end > start)
            {
                // We'll add it on to start...
                start += 360;
            }
            else
            {
                // Add it on to end.
                end += 360;
            }
        }

        // Interpolate it.
        float value = (start + ((end - start) * amount));

        // Wrap it..
        float rangeZero = 360;

        if (value >= 0 && value <= 360)
            return value;

        return (value % rangeZero);
    }
Run Code Online (Sandbox Code Playgroud)

谁有更优化的版本?


Pau*_*lby 7

我认为更好的方法是插入sin和cos,因为它们不会受到多重定义的影响.令w ="amount"使得w = 0是角度A并且w = 1是角度B.然后

CS = (1-w)*cos(A) + w*cos(B);
SN = (1-w)*sin(A) + w*sin(B);
C = atan2(SN,CS);
Run Code Online (Sandbox Code Playgroud)

必须根据需要转换为弧度和度数.还必须调整分支.对于atan2 C,回到-pi到pi的范围.如果您想要0到2pi,那么只需将pi添加到C.

  • 仅当a和b相距很远(几乎180度)时,这不起作用,并且不是真正的线性插值. (3认同)
  • 更好(至少对我来说)是我更有可能第一次就正确编码。大多数给出的答案的问题是它们对相关分支进行了多项算术测试。这些测试的边缘条件也增加了一定程度的复杂性,我已经不止一次搞砸了。最初的问题是“我该走哪条路?” 插值或我所在的角度分支从一开始就有独特的答案。 (2认同)