1

我正在使用 Microsoft Virtual Earth 3D 在大气层中移动,我可以顺利下降,但我不知道如何顺利​​上升。

我是这样下降的:

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

这通过越接近地球(低海拔)减小跳跃的大小来起作用。我需要一个可以做类似的解决方案,只是相反,同时仍将较小的跳跃保持在较低的高度。

我怎样才能做到这一点?或者我正在做的事情是不可接受的,应该以不同的方式做(比如用对数)?

4

4 回答 4

4

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

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();
        }
    }
}
于 2009-04-01T19:40:19.683 回答
1

顺便说一句,你真的应该让提升时间依赖(帧率感知)。这里的所有答案都取决于在特定时间间隔调用的代码;事实并非如此。如果某个过程启动,Virtual Earth 会以某种方式承受压力,如果您将 Virtual Earth 最小化,或者如果发生影响 Virtual Earth 性能的事情,那么运动将不会是平稳的。即使虚拟地球“没有”发生任何事情,有时您的 3D 卡也会停止,这意味着您可能每隔一段时间就会跳一次。

特别是如果用户关闭了垂直同步,你会遇到一些非常讨厌的事情:

  • 在慢速机器上,提升将永远持续(即使 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 的分辨率为 15 毫秒(因为我检查 timeDiff 是否为零,因为它很容易为零)。托管 DX SDK 示例框架有一个名为 DxTimer(或排序)的类,它具有更好的分辨率。

有一篇文章使用了相同的 API

于 2009-04-01T19:33:28.733 回答
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 阈值以更合乎逻辑的方式打破循环。

于 2009-04-01T19:16:55.310 回答
0

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

于 2009-04-01T21:23:55.037 回答