我正在使用Microsoft Virtual Earth 3D在大气中移动,我可以顺利下降,但我不知道顺利提升的数学。
我是这样下降的:
for(int curAlt = startAlt; curAlt < endAlt; curAlt--){
//do something
curAlt -= curAlt/150
}
这可以通过减小跳跃的大小来降低我到达地球(较低的高度)。我需要一个类似的解决方案,只是反过来,同时仍然保持较低的高度跳跃。
我该怎么做?或者我正在做的是不可接受的,应该采用不同的方式(比如对数)?
答案 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,你会得到一些非常讨厌的东西:
在你班上:
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(或排序)的类,它具有更好的分辨率。
答案 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进行升序?