2017-01-19 18 views
0

現在、私は1秒あたりのフレーム数を制限したいゲームを作っていますが、問題があります。C言語でのFPS制限

を、私は、各フレームを実行され、この方法でdeltaTimeを取得しています:

void Time::calc_deltaTime() { 
    double currentFrame = glfwGetTime(); 
    deltaTime = currentFrame - lastFrame; 
    lastFrame = currentFrame; 
} 

deltaTimeは0.016に.... 0.012周り(私は期待値を持っているここで私がやってんですよ...)

よりも私はこのようなスリープ窓関数を介してフレームを遅らせるためにdeltaTimeを使用しています:

void Time::limitToMAXFPS() { 

    if(1.0/MAXFPS > deltaTime) 
     Sleep((1.0/MAXFPS - deltaTime) * 1000.0); 
} 

MAXFPSが60に等しく、私はセコを変換するために1,000を掛けていますnds〜ミリ秒。

void Time::limitToMAXFPS() { 

    double diff = 1.0/MAXFPS - deltaTime; 

    if(diff > 0) { 

     double t = glfwGetTime(); 

     while(glfwGetTime() - t < diff) { } 

    } 

} 

しかし、それでもまだ、私はより多くを取得しています:すべてが正しいようだけど、私は60以上のfps(私は周りに72 FPSを取得しています)

私もループしながら使用して、この方法を試してみましたが敷居抱えています60 fps、まだ約72 fpsになっています...私は何か間違っているのですか、これを行うにはよりよい方法がありますか?

+2

現在のfpsはどのように計算されますか? – SingerOfTheFall

+0

私は個人的に、 'Sleep(1000/MAXFPS - deltaTime * 1000)'のような 'Sleep'式を書いていますが、それほど違った動作をしてはいけません。 –

+0

@AlgirdasPreidžius: 'MAXFPS'が整数型の場合はどうなりますか? – IInspectable

答えて

-1

Sleep関数が浮動小数点値を受け入れることは確実ですか? intのみを受け入れる場合、睡眠は睡眠(0)になり、問題が説明されます。

+3

私はペンと紙を使わずに正しく計算していれば、Sleepに20-40 0. –

+0

@doronはい、それは問題です。私はSleep doubleに、符号なしintであるDWORDを期待しています。私はこれ(DWORD)((1.0/MAXFPS - deltaTime)* 1000.0)のようなDWORDにキャストしようとしています。私はSven Nilssonが正しいと思います。私はSleepの代わりを探す必要があります。 –

+0

@ MagnoSilva:通常は、高解像度のタイマーをポーリングして、必要な時間が経過するまでビジー待機する方法があります。一般に、プロセスをスリープさせる(すなわち、そのCPUサイクルをシステムの残りの部分に与える)ことは、むしろ粗い時間分解能をもたらすことになる。最新のデスクトップシステムでは、スケジューラタイマーは250Hz〜1000Hzの間で実行されるため、1ms〜5msの間の有効なタイミング精度が得られます。これに加えて、プロセスが直ちに再スケジュールされることはないため、約10msのスケジューリング精度が期待できます。 – datenwolf

3

睡眠は非常に不正確なことがあります。一般的な現象として、実際の睡眠時間は14〜15ミリ秒の解像度で、フレームレートは約70になります。

Is Sleep() inaccurate?

+0

それは彼の2番目の(スピンループ)解決策には影響しないはずです。 – ltjax

1

あなたは、Windowsがスリープと非常に矛盾して言ったように私は...このようなFPSを制限しようとするのをあきらめました。私のfps平均は常に60 fpsではなく64 fpsです。問題はSleepが整数(または長整数)を引数としてとり、static_castでキャストしていたことです。しかし、私はそれを二重として渡す必要があります。 16ミリ秒毎のフレームは16.6666とは違っています...おそらくこの余分な4フレーム/秒の原因です(私は思う)。

私も試してみました:

std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<long>(1.0/MAXFPS - deltaTime) * 1000.0)));

と同じことがsleep_forで起こっています。それから、ミリ秒の残りの10進数値をchrono::microsecondschrono::nanosecondsに渡して、より良い精度を得るためにそれらを3つ一緒に使ってみましたが、私はまだ64fpsという驚くべきものを得ています。

1000.0をconst整数に変更して式を(1.0/MAXFPS - deltaTime)にすると、もう一つ変わったことが(1.0/MAXFPS - deltaTime * 1000.0)時には(はい、これは完全にランダムです)* 1000)my fpsは何らかの理由で74に単純にジャンプしますが、式は完全に等しく、何も起こらないでしょう。どちらも二重表現で、私はここでタイププロモーションが起こっているとは思わない。

私は関数wglSwapIntervalEXT(1)を使ってV-syncを強制することにしました。画面の裂けを防ぐためです。そして、私はdeltaTimeに、ゲームを実行しているコンピュータの速度に非常に依存するすべての値を乗算する方法を使用します。いくつかの価値を掛け合わせて自分のコンピュータに気づかずに矛盾を作り出すことを忘れるかもしれないので、苦痛になるかもしれませんが、他の方法はありません。

2

サイクルをCPUに戻すことの重要性はどれくらいですか?私には、睡眠を全く使うのは悪い考えです。私が間違っていると誰かが私を修正してくださいが、私は睡眠機能を避けるべきだと思います。

単純に、一定時間以上経過した場合に実行される無限ループを使用しないでください。試してみてください:

const double maxFPS = 60.0; 
const double maxPeriod = 1.0/maxFPS; 

// approx ~ 16.666 ms 

bool running = true; 
double lastTime = 0.0; 

while(running) { 
    double time = glfwGetTime(); 
    double deltaTime = time - lastTime; 

    if(deltaTime >= maxPeriod) { 
     lastTime = time; 
     // code here gets called with max FPS 
    } 
} 

最後にGLFWを使用していましたが、とにかく60fpsに自己制限されているようでした。高性能なもの(ゲームや3Dグラフィックス)を行う場合は、マルチスレッドを使用しない限り、眠るものは避けてください。

+0

ありがとう、私はそれが動作する場合に表示されます。 –

0

私は最近、私が働いている小さなサイドプロジェクトのためGLFWを使用し始めました、と私はあなたが簡単でFPSの好みを調整することができます追加するには60fpsの

auto start = std::chrono::steady_clock::now(); 
while(!glfwWindowShouldClose(window)) 
{ 
    ++frames; 
    auto now = std::chrono::steady_clock::now(); 
    auto diff = now - start; 
    auto end = now + std::chrono::milliseconds(16); 
    if(diff >= std::chrono::seconds(1)) 
    { 
     start = now; 
     std::cout << "FPS: " << frames << std::endl; 
     frames = 0; 

    } 
    glfwPollEvents(); 

    processTransition(countit); 
    render.TickTok(); 
    render.RenderBackground(); 
    render.RenderCovers(countit); 

    std::this_thread::sleep_until(end); 
    glfwSwapBuffers(window); 
} 

を達成するためにサイドstd::this_thread::sleep_until沿っstd::chronoを使用してきましたendを調整する。 これで、glfwが60fpsに制限されていたことがわかりましたが、whileループの直前にglfwSwapInterval(0);で制限を無効にしなければなりませんでした。