平稳运动,通过大气层上升

时间:2009-04-01 19:09:39

标签: c# math .net-3.5 virtual-earth

我正在使用Microsoft Virtual Earth 3D在大气中移动,我可以顺利下降,但我不知道顺利提升的数学。

我是这样下降的:

for(int curAlt = startAlt; curAlt < endAlt; curAlt--){
    //do something
    curAlt -= curAlt/150
}

这可以通过减小跳跃的大小来降低我到达地球(较低的高度)。我需要一个类似的解决方案,只是反过来,同时仍然保持较低的高度跳跃。

我该怎么做?或者我正在做的是不可接受的,应该采用不同的方式(比如对数)?

4 个答案:

答案 0 :(得分:4)

更好的解决方案可能是使用像Logistic function这样的函数。

Double minAlt = 0.0;
Double maxAlt = 500000.0;

Int32 numberSteps = 1000;

Double boundary = +6.0;

for (Int32 step = 0; step < numberSteps; step++)
{
   Double t = -boundary + 2.0 * boundary * step / (numberSteps - 1);
   Double correction = 1.0 / (1.0 + Math.Exp(Math.Abs(boundary)));
   Double value = 1.0 / (1.0 + Math.Exp(-t));
   Double correctedValue = (value - correction) / (1.0 - 2.0 * correction);
   Double curAlt = correctedValue * (maxAlt - minAlt) + minAlt;
}

因为显式计算了当前的高度,所以您不必依赖迭代计算来引入各种精度相关误差。

请参阅示例代码,了解如何调整功能形状。


以下是显示该功能的示例控制台应用程序。您可以使用参数进行一些操作,以了解行为。

using System;

namespace LogisticFunction
{
    class Program
    {
        static void Main(string[] args)
        {
            Double minAlt = 5.0;
            Double maxAlt = 95.0;

            Int32 numberSteps = 60;

            // Keep maxAlt and numberSteps small if you don't want a giant console window.
            Console.SetWindowSize((Int32)maxAlt + 12, numberSteps + 1);

            // Positive values produce ascending functions.
            // Negative values produce descending functions.
            // Values with smaller magnitude produce more linear functions.
            // Values with larger magnitude produce more step like functions.
            // Zero causes an error.
            // Try for example +1.0, +6.0, +20.0 and -1.0, -6.0, -20.0
            Double boundary = +6.0;

            for (Int32 step = 0; step < numberSteps; step++)
            {
                Double t = -boundary + 2.0 * boundary * step / (numberSteps - 1);
                Double correction = 1.0 / (1.0 + Math.Exp(Math.Abs(boundary)));
                Double value = 1.0 / (1.0 + Math.Exp(-t));
                Double correctedValue = (value - correction) / (1.0 - 2.0 * correction);
                Double curAlt = correctedValue * (maxAlt - minAlt) + minAlt;

                Console.WriteLine(String.Format("{0, 10:N4} {1}", curAlt, new String('#', (Int32)Math.Round(curAlt))));
            }

            Console.ReadLine();
        }
    }
}

答案 1 :(得分:1)

顺便说一句,你应该真正使提升时间依赖(帧率感知)。这里的所有答案都取决于在特定时间间隔内调用的代码;它不是。如果某些过程开始,虚拟地球会以某种方式受到压力,如果你最小化虚拟地球,或者如果某些影响虚拟地球性能的事情发生,那么这种运动将是平稳的。即使虚拟地球发生“什么都没有”,有时你的3D卡也会失速,这意味着你可能偶尔会跳一次。

特别是如果用户关闭了VSync,你会得到一些非常讨厌的东西:

  • 在慢速机器上,提升将永远持续(即使启用了VSync)。
  • 在快速机器上它会如此之快,你甚至可能都没注意到它。

在你班上:

private int lastTime;

在你的循环/事件中:

if(lastTime == 0)
{
    lastTime = Environment.TickCount;
    return;
}

int curTime = Environment.TickCount; // store this baby.
int timeDiff = lastTime - curTime;

if(timeDiff == 0)
   return;

curAlt += (maxAlt - curAlt) * timeDiff / (150000); // TickCount reports
                                                   // time in Ticks
                                                   // (1000 ticks per second)

lastTime = curTime;

如果您想获得想象力,可以从DX SDK插入代码。 Environment.TickCount的分辨率为15ms(因为我检查timeDiff为零,因为它很容易)。托管DX SDK示例框架有一个名为DxTimer(或排序)的类,它具有更好的分辨率。

There is an article that uses the same API

答案 2 :(得分:0)

这取决于你想通过顺利提升来实现的目标。您可以将高度限制为某个最大值maxAlt,并以与对地面相同的方式平滑接近该值。

curAlt += (maxAlt - curAlt) / 150

但是如果最大高度无限制,你必须清楚你想要平滑的是什么。

另请注意,您的代码仅适用于某些副作用。你接近无限循环。我建议如下。

epsilon = 0.1; // A small value that fits your needs

curAlt = startAlt;

while (curAlt > endAlt + epsilon)
{
   curAlt -= (curAlt - endAlt) / 150;
}

curAlt - =(curAlt - endAlt)/ 150的迭代在理论上永远不会达到endAlt,并且最多只能通过路由错误实现。您的代码仅有效,因为每次迭代减去一个额外的高度单位。我不确定这是设计还是防止错误的错误。添加epsilon阈值会以更合理的方式打破循环。

答案 3 :(得分:0)

由于您使用curAlt - = curAlt / 150进行降序,为什么不使用curAlt + = curAlt * 150进行升序?