60FPSでない

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

60FPSでない

#1

投稿記事 by dic » 7年前

[1] 質問文
 [1.1] 自分が今行いたい事は何か
  DxLibライブラリを使って安定した60FPSを出したい

 [1.2] どのように取り組んだか(プログラムコードがある場合記載)

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DxLibDLL;

namespace DxLib_60FPS
{
    class Program
    {
        static int m_StartTime;
        static int m_Count;
        static float m_Fps;
        const int N = 60;
        const int FPS = 60;

        static int x = 0;
        static int Handle;
        static int Blue;

        static void Init()
        {
            Handle = DX.LoadGraph("プレイヤー1.bmp");
        }

        static void Update()
        {
            x = x + 2;
            if( m_Count == 0 )
            {
                m_StartTime = DX.GetNowCount();
            }
            if( m_Count == N )
            {
                int t = DX.GetNowCount();
                m_Fps = (float)(1000.0) /( (t-m_StartTime) / (float)N);
                m_Count = 0;
                m_StartTime = t;
            }
            m_Count++;
        }

        static void Draw()
        {
            DX.DrawString(50, 20, "[ " + m_Fps + " FPS ]", DX.GetColor(255, 255, Blue ) );
            DX.DrawGraph(x % 600, 100, Handle, DX.TRUE);
        }

        static void Wait()
        {
            int tookTime = DX.GetNowCount() - m_StartTime;
            int waitTime = m_Count * 1000 / FPS - tookTime;
            Blue = 255;
            if (waitTime > 0)
            {
                Blue = 0;
                DX.WaitTimer(waitTime);
            }
        }

        static int Main(string[] args)
        {
            DX.SetGraphMode(640, 480, 16);
            DX.SetTransColor(0, 255, 0);
            DX.ChangeWindowMode(DX.TRUE);
            DX.SetDrawScreen(DX.DX_SCREEN_BACK);
            DX.DxLib_Init();

            Init();

            while (DX.ScreenFlip() == 0 && DX.ProcessMessage() == 0 && DX.ClearDrawScreen() == 0)
            {
                Update();
                Draw();
                Wait();
            }

            DX.DxLib_End();

            return 0;
        }
    }
}
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
動かすと47FPSぐらいしかでなく、画像ひとつなのにこのパフォーマンスは
どこかわるいのではないかと

 [1.4] 今何がわからないのか、知りたいのか
60FPSになるメインループのソースコードが知りたいです。
 参考にしたのはhttp://csi.nisinippon.com/VS2015IDE/v02.html#topです。
前には、違うウェイトのソースコートがサイトにあったきがするのですが
  みつけれませんでした。

[2] 環境  
 [2.1] OS : Windows, Linux等々
  OS:Windows7 32bit Professional
 [2.2] コンパイラ名 : VC++ 2008EE, Borand C++, gcc等々
VC# 2010 参考にしたホームページにある
  コンソールからウィンドウズのexeにプロパティで変換している
[3] その他
 ・どの程度C言語を理解しているか
  オブジェクト指向を理解、作成できる

 ・ライブラリを使っている場合は何を使っているか
  DxLibライブラリ C# .Net(?)

C6b14

Re: 60FPSでない

#2

投稿記事 by C6b14 » 7年前

お邪魔します。参考にして頂いたホームページを書いてるものです。Windows10,64bit,C++2015コマンドで作れるようなバッチ・ファイルを載せていると思います。もともとWindows10,8.1,7,Vistaだけで出来る(VisualStudioがなくても)C#の(VS2015と同等の)プログラムができますよというページを作っていて、これもバッチ・ファイルを書き換えるだけでVisualStudioがなくてもビルド出来ます。作るときはVC++ 2008EEで検証しています。問題のFPSの表示ですが私の環境では59.88位になります。コードを見て頂くとわかるように待ち時間があれば黄色、なければ白色で表示します。[通常ゲームは30FPSらしいので書き換えればいいかなと思います。] たしかにいわれるように参考にしたページが数か所にあったはずです。もちろんここのホームページを参考にしたので、C++ですがC#と似ているので見て下さい。DxLib本家の質問にも簡単な方法があったように記憶してます。キーワードでGoogleを調べれば見つかると思います。[C++に書き換えれば早く動くとは思いますが。ここのサンプルはVC++2008でそのまま動くのでC#より一寸面倒ですが(個人的な意見。C#に慣れてるから。今はCに慣れてきてそんない面倒でもない。)]
DxLibの本家にLog.txtを見てもらえば改善策を丁寧に教えて頂けます。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#3

投稿記事 by ISLe » 7年前

DxLib_Init関数を呼ぶ前に
DX.SetWaitVSyncFlag(DX.FALSE);
をいれたらある程度安定するのではないでしょうかね。

もっと精度を高めたいというのであれば、さらなる工夫が必要です。
それが何かというのはこの掲示板の過去ログを検索すれば見付かるでしょう。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#4

投稿記事 by ISLe » 7年前

もっと大きな問題を見付けました。

DX.SetDrawScreen(DX.DX_SCREEN_BACK);
をDxLib_Init関数のあとに移動してください。
参考にしたというサイトは正しく書いてありますね。

まとめると
裏画面描画でないと、極端に処理が重くなる場合があります。
VSYNC同期を切ると、ウェイト処理に対して正確なフレームレートになりますが、テアリングが発生します。
環境や設定に影響されない(あるいはそれを考慮に入れつつ)精度の高いフレームレートを実現するには、さらなる工夫が必要であり、その方法はこの掲示板の過去ログにあります。

C6b14

Re: 60FPSでない

#5

投稿記事 by C6b14 » 7年前

お邪魔します。http://dixq.net/forum/viewtopic.php?f=3&t=16224とかhttp://dixq.net/rp/43.htmlとかhttp://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=past&no=483とか、沢山ありますね。難しい。

dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

Re: 60FPSでない

#6

投稿記事 by dic » 7年前

>>ISLe様
コードをおっしゃるとおりに変更したところうまく60FPSでるようになりました。

変更した部分をのせておきます

コード:

        static int Main(string[] args)
        {
            DX.SetGraphMode(640, 480, 32);
            DX.SetTransColor(0, 255, 0);
            DX.ChangeWindowMode(DX.TRUE);
            DX.SetWaitVSyncFlag(DX.FALSE);
            DX.DxLib_Init();
            DX.SetDrawScreen(DX.DX_SCREEN_BACK);

            Init();

            while (DX.ScreenFlip() == 0 && DX.ProcessMessage() == 0 && DX.ClearDrawScreen() == 0)
            {
                Update();
                Draw();
                Wait();
            }

            DX.DxLib_End();

            return 0;
        }
>>C6b14 様
私には手にあまりわかりません。もうしわけありません。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#7

投稿記事 by ISLe » 7年前

余談かもしれませんが、安定したフレームレートのためということで補足しておきます。

配布を前提としない(自分とこでだけ動けばいい)場合、ウェイト処理は必要ありません。
モニタのリフレッシュレートが60Hzであれば(あるいはグラフィックドライバの設定で60Hzに設定すれば)、
DXライブラリのデフォルト動作であるVSYNC同期で自動的に60FPSになります。

最近はグラフィックドライバの設定で、アプリケーションの設定を強制的に上書きできるようになっていますので
配布を前提とするなど環境を特定できない場合は、
VSYNC同期の有無に依存せず、リフレッシュレートにも依存しない
方法でメインループを実装しておかないと動作(ゲームであれば難易度等)が破たんしてしまいます。

ちなみにわたしが使っているNVIDIAのグラフィックドライバだと
・VSYNC同期なし(無制限)
・VSYNC同期あり(リフレッシュレートを上限)
・基本的にVSYNC同期ありだがフレームレートがリフレッシュレートに届かないときVSYNC無視
・リフレッシュレートの半分でVSYNC同期
といった設定があります。
最後の設定は、本来は、3D(立体視)に対応した高リフレッシュレートのモニタで3D対応でないゲームをプレイする場合などに負荷を下げるための機能なのですが
コマ落ち対策してないプログラムだと動作速度が半分になり、一般的なリフレッシュレート60Hzのモニタで30FPSになってしまいます。

コマ落ち対策も含めたフレームレート維持の実装は、過去にC++のコードで紹介しています。

C6b14

Re: 60FPSでない

#8

投稿記事 by C6b14 » 7年前

なるほど。http://dxlib.o.oo7.jp/cgi/patiobbs/pati ... ast&no=483でいってる意味が分かりました。[雑談]

dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

Re: 60FPSでない

#9

投稿記事 by dic » 7年前

>>ISLe様
ごめんなさい、時間の都合上、過去ログを見るのが難しいです。

59~61FPSでてるので、良しとします。
タイトル通りでなくてすいません。

Egg

Re: 60FPSでない

#10

投稿記事 by Egg » 7年前

ISLeさんのフレームレートを維持する実装というものがFPSに依存しない実装のことならば
1フレームの時間を実数で保持して、移動距離にかけるだけです。

こっちのほうがわかりやすいかも
https://docs.unity3d.com/jp/current/Scr ... aTime.html

コード:

/****************************/
/* 1秒で3前に進む場合       */
/****************************/
//FPSに依存する実装
float nowPos;
nowPos += 3.0f * 1.0f / 60.0f; // もしFPSが半分になってしまうと、1秒で1.5しか進まない

//FPSに依存しない実装
float deltaTime; // ゲームループの更新描画1ループに掛かった経過時間が格納されている。単位は秒。
float nowPos;
nowPos += 3.0f * elapseTime; // 途中でFPSが変動しても、1秒で3進む

C6b14

Re: 60FPSでない

#11

投稿記事 by C6b14 » 7年前

[追記]コードやUnityの例まだ教えて頂いてありがとうございます。経過タイムを見てればいいのいいのだといわれているような気がしますがすぐには理解出来ずゆっくり考えて見ます。「パソコンの60FPSは必要ない」ことはこれもでの投稿を注意して読めばわかるはずです。主眼はゲーム進行速度の維持にあって、意外にも考えかたそのものが間違っていた様です。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#12

投稿記事 by ISLe » 7年前

他人が立てたトピで、本旨とはまったく関係のないことで、過去ログも見ないで勝手な解釈をするような他人の話を聞かない相手に続けるのはとても気が引けるのですが、他所でわざわざお望みということを表明されたのでお返事します。
Egg さんが書きました:ISLeさんのフレームレートを維持する実装というものがFPSに依存しない実装のことならば
1フレームの時間を実数で保持して、移動距離にかけるだけです。
「FPSに依存しない実装のことならば」
違います。
勝手に別のものを仮定しないでください。
Eggさんが自らの主張として書くならばわたしには関係のないことなのでかまいませんが、それがわたしの言い出したことと誤解を招くふうに書かないでください。

わたしが過去に投稿した記事では、デルタタイムをフレームレートに換算する方法を紹介しています。
それは、フレームベースで設計されたプログラムにおいて、フレームレートを厳格に守るための方法です。

FPSに依存しないのではなく、FPSに依存した処理を異なる環境で長時間実行しても実時間でズレなくします。
60FPSを想定したプログラムが『コマ落ちするのも含めて』144Hzのモニタの環境であろうともそれを再現します。

デルタタイムを、どう使うかということが主旨であり、Eggさんの紹介したやり方とは主旨がまったく異なります。
Eggさんの紹介したやり方が間違っているということではないですが、用途が違います。



以下はフレームレートに関する興味を持ってこのトピックに辿り着いた方に向けての文章です。

フレームレートを厳格に守るための方法に興味があれば過去ログを探してください。
このトピックでわたししか使ってない単語で過去ログ検索すれば一発で見付かります。

オフトピック
20年以上前にこの実装を考えたときに、グラフィックドライバ側で対応してくれればだいぶ楽できるのになあ、と思ってたことが最近ドライバに実装されたけど、なんでこんなに時間が掛かったのやら。
いまだに認知されてないわけだから推して知るべし。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#13

投稿記事 by ISLe » 7年前

オフトピック
Egg さんが書きました:ISLeさんのフレームレートを維持する実装というものがFPSに依存しない実装のことならば
1フレームの時間を実数で保持して、移動距離にかけるだけです。
仮定表現を含めさえすれば
「ISLeさんのフレームレートを維持する実装というものが、1フレームの時間を実数で保持して、移動距離にかけるだけ(のこと)です。」
という文章を事実とすることができるようなこの掲示板の風潮ってなんなんでしょうね。

C6b14

Re: 60FPSでない

#14

投稿記事 by C6b14 » 7年前

素人にはお二人の話がよく分かってないので想像ですが。60FPSであれば1フレームあたり1000ミリ秒/60つまり[50/3ミリ秒]を厳格にまもればよい。[50/3ミリ秒]をデルタタイムとすればデルタタイムを一定にすればよい。もう一つの考えはデルタタイムの変動を許すが何回かのデルタタイムのトータルを一定になるように制御すればすればよい。その制御に移動距離を利用する。...こんなイメージでよろしいのでしょうか。      

C6b14

Re: 60FPSでない

#15

投稿記事 by C6b14 » 7年前

GPUの能力が追随できない場合はコマ落ちさせてもデルタタイムを守る。..とか想像ですが。

C6b14

Re: 60FPSでない

#16

投稿記事 by C6b14 » 7年前

あ、すみません。http://isle.cocolog-nifty.com/blog/2011 ... -927b.htmlを読んで見ます。

C614b

Re: 60FPSでない

#17

投稿記事 by C614b » 7年前

過去ログの最後の言葉も読ませていただきました。本当にそうなればいいのですが。ありがとうございました。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#18

投稿記事 by ISLe » 7年前

少なくともわたしが見たことのある、ネット上のFPS制御コードは、余った時間待つ、ということしかしません。

リフレッシュレートが60Hzの場合、1フレームの時間は16.66...msですが、リフレッシュレートというハードウェアに合わせたら、1msでも10msでも溢れたら2フレーム分の時間を消費するのが現実です。

ところが、余った時間待つだけだと、溢れた分を積み上げて1フレーム分溜まった時点で1フレーム消費です。
VSYNCが有効な、あるいは実行速度に余裕のある環境でしかテストしていないとなるとほとんどその違いに気付けません。

その違いにより、例えばスクロール型のシューティングゲームでステージ最後でボスBGMに変わる瞬間の通常BGMの再生位置が異なる、といった現象が発生し、そのゲームが好きで何回もプレイしたユーザーほど違和感を覚えるのです。

わたしの紹介した方法では、少しでも溢れた分は、その都度、1フレーム分に切り上げるというのが基本的な考え方です。
そのうえで、誤差が出ず、より高速となるように工夫しています。

この方法は、ドリームキャストやプレイステーション2、auのBREWアプリというガラケーアプリで、わたしがメインプログラムを担当した数十タイトルで実際に使った実績のあるものです。
と、ここに書いても証明できるものはないわけですし、Unityを解説した最新の入門書や、メジャーな(あるいは自分で最初に見付けた)入門サイトに書いてあることを信用なさる方のほうが多いかもしれません。

改めて書くことでもないですが、実際にコードを読んで動かして試してみてください。
使う使わないは別としても、前提となっている考え方とか仕組みとか、何らかの形で役に立つと思います。

C6b14

Re: 60FPSでない

#19

投稿記事 by C6b14 » 7年前

ほんの少し溢れただけでも1フレームのロスがでてそれが蓄積すると”ほんの少しだけの蓄積”ではなく”膨大な蓄積”になる。そこで早めに手を打って”溢れ”を訂正する手段を”考えればよい”。「それは即”1フレーム分に切り上げる」という事ですね。

C6b14

Re: 60FPSでない

#20

投稿記事 by C6b14 » 7年前

すぐには真実はわからず「経験するまでは分からない」事が多いのでそういう状態を作って”証拠”をつかんでみたいと思います。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 60FPSでない

#21

投稿記事 by ISLe » 7年前

これまでの説明で分かるかもしれませんが、固定フレームレートで設計されたプログラムを、Unityに載せたいといったときに使えます。
というか、そういう目的のために開発したものです。

むしろ、ここ数年の世の中の変化で、やっと本領発揮できるようになりました。

Unityではデルタタイムをそのまま使わなければならないのか?
いままでのやり方を捨てなければいけないのか?
といった疑問に対しては「そんなことはない」と断言できます。

C6b14

Re: 60FPSでない

#22

投稿記事 by C6b14 » 7年前

分かりました。面白そうですね。世間の常識が非常識はありえますから。

閉鎖

“C言語何でも質問掲示板” へ戻る