1

Microsoft Virtual Earth 3D で大気中を移動しており、スムーズに下降できますが、スムーズに上昇するための計算がわかりません。

私はこのように降りています:

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

これは、地球に近づく (高度が低い) ほどジャンプのサイズを小さくすることで機能します。小さなジャンプを低い高度に保ちながら、逆に同様のことを行うソリューションが必要です。

これどうやってするの?それとも、私がやっていることは受け入れられず、別の方法で行う必要がありますか (対数で言う)?

4

4 に答える 4

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

ちなみに、アセンションを時間依存 (フレームレート対応) にする必要があります。ここでのすべての答えは、特定の間隔で呼び出されるコードに依存します。そうではありません。なんらかのプロセスが開始されると、何らかの形で Virtual Earth に負荷がかかり、Virtual Earth を最小化すると、または Virtual Earth のパフォーマンスに影響を与える何かが発生すると、動きが滑らかではなくなります。Virtual Earth に「何も」起こらない場合でも、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 の分解能は 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 に到達することはありません。反復ごとに 1 つの追加の高さ単位を減算するため、コードは機能します。これが仕様によるものなのか、バグを防ぐためのエラーなのかはわかりません。イプシロンのしきい値を追加すると、より論理的な方法でループが中断されます。

于 2009-04-01T19:16:55.310 に答える
0

降順で curAlt -= curAlt/150 を使用しているので、昇順で curAlt += curAlt*150 を使用しないのはなぜですか?

于 2009-04-01T21:23:55.037 に答える