HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2008
0313
Shinya固定FPS10解決


Shinya

リンク

2008/3/13(Thu) 20:43:11|NO.14158

FPSを、はてなダイアリーで検索すると
>Frame Per Secondの略。動画のなめらかさを表す指標。1秒間に何枚の画像を表示しているかを示す。
とあります.
#include "d3m.hsp"
repeat title "1秒間に fps:"+d3getfps()+" 回ループ(表示)しています."+cnt await 1 loop
固定FPSは「FPSの固定」とググれば色々出てきますが,皆さんはどのような方法でFPSを固定しますか.
オリジナルや既知の物を含めご意見お待ちしています.



この記事に返信する


As

リンク

2008/3/14(Fri) 00:19:16|NO.14180

FPS120の場合、

FPS120以上にならないように、
GetSystemTimeを使い60/120のタイミングで描画するように調節

FPS120以下になる場合、
無視



Shinya

リンク

2008/3/14(Fri) 09:01:15|NO.14197

>GetSystemTimeを使い60/120のタイミングで描画するように調節
その場合の調節は await で行うということでしょうか.
それにしてもGetSystemTimeを使うというのは驚きです.(timeGetTimeかQueryPerformanceCounterしか思い浮かばなかった)



Shinya

リンク

2008/3/14(Fri) 12:35:09|NO.14199

以下のようなマクロでFPSを固定しようと思いましたが,あまり精度が高くありません.
awaitの精度が1msなので計算上の値と誤差が出てしまいます.
それからプログラムのループ中に await 1 を置くだけで 64 FPS しか出ないのはなぜだろう...

#include "d3m.hsp" #define ctype limitFPS(%1, %2) 1000.0*%1/(%2*%2) repeat ; ; 何らかの処理 ; repeat 10 color 255, 255, 255 boxf loop ; ; fps=d3getfps() wt=limitFPS(fps, 32) await wt title "fps:"+fps+", wait:"+int(wt) loop
FPSが下がると誤差率が上がってしまうのでとことんプログラムを高速化させるか,awaitの精度をどうにかして高められないかと検討しています.
とりあえずそのためのモジュールを1つ拵えました,引き続き何か意見をお待ちしています.

#module #uselib "ntdll.dll" #func ZwQueryPerformanceCounter "ZwQueryPerformanceCounter" #uselib "kernel32.dll" #func VirtualProtect "VirtualProtect" int,int,int,int #defcfunc timer /* | 【概要】 | システム起動時からの経過時間を秒単位マイクロ秒まで得る */ if(get_time==0) { get_time=$83ec8b55,$458df8c4,$78bb50f8,$53123456,$345678b8,$dfd0ff12,$f875da2b,$c3c91bdd ddim time, 1 lpoke get_time, 11, varptr(time) lpoke get_time, 17, varptr(ZwQueryPerformanceCounter) VirtualProtect varptr(get_time), length(get_time)*4, 0x40, varptr(res) } res=callfunc(res, varptr(get_time), 0) return time #global offset_time=timer() repeat title ""+(timer()-offset_time) await 1 loop



As

リンク

2008/3/14(Fri) 21:18:14|NO.14217

別にGetSystemTimeとかはどうでもいいのですが^^;



処理が重けりゃ処理するな、処理が早けりゃ負荷かけろってことです^^;




#define fp 32 #include "d3m.hsp" #define ctype limitFPS(%1, %2) 1000.0*%1/(%2*%2) repeat ; ; 何らかの処理 ; //デフォルトFPS値よりも低い if fps<=fp{ redraw 0 repeat 10 color 255, 255, 255 boxf loop color pos 0,0 mes "fps:"+fps+", wait:"+int(wt) redraw 1 title "fps:"+fps+", wait:"+int(wt) }else{ await wt } ; ; fps=d3getfps() wt=limitFPS(fps, fp) loop



Shinya

リンク

2008/3/14(Fri) 23:04:05|NO.14233

Asさんスクリプトまで有難うございます.具体的にFPSの調節方法が分かりました.
//デフォルトFPS値よりも低い
if fps<=default_fps{ ; ;処理 }else{ ; await wt }
プログラムを実行してみたところ,確かにFPSをデフォルト値に制限させるという面ではよい方法かもしれませんが,鉢△任1秒間にかかるウェイトが違いすぎてFPSが揺らいでしまいます.
ウェイトを均等にする工夫が必要のようですが,まだ処理速度とawaitの精度に問題があるようです.

#define fp 25 #include "d3m.hsp" #define ctype limitFPS(%1, %2) 1000.0*%1/(%2*%2) repeat ; ; 何らかの処理 ; //デフォルトFPS値よりも低い if fps<=fp{ redraw 0 repeat 10 color 255, 255, 255 boxf loop color pos 0,0 mes "fps:"+fps+", cnt:"+cnt redraw 1 title "fps:"+fps+", wait:"+int(wt) }else{ await wt } ; ; fps=d3getfps() wt=limitFPS(fps, fp) loop
awaitの誤差を計測して統計的にウェイトの精度を高められないか検討してみます.



Shinya

リンク

2008/3/14(Fri) 23:47:43|NO.14237

FPSの計測間隔を細かくすれば,ウェイトのかかりすぎによるFPSの揺らぎ等は軽減されるはずなのでFPSを100ms秒毎に計測するようにしてみました.

#module "bkfps" #uselib "ntdll.dll" #func ZwQueryPerformanceCounter "ZwQueryPerformanceCounter" #uselib "kernel32.dll" #func VirtualProtect "VirtualProtect" int,int,int,int #defcfunc timer /* | 【システム起動時からの経過時間を1秒単位マイクロ秒の精度で得る】 */ if(get_time==0) { get_time=$83ec8b55,$458df8c4,$78bb50f8,$53123456,$345678b8,$dfd0ff12,$f875da2b,$c3c91bdd ddim time, 1 lpoke get_time, 11, varptr(time) lpoke get_time, 17, varptr(ZwQueryPerformanceCounter) VirtualProtect varptr(get_time), length(get_time)*4, 0x40, varptr(res) } res=callfunc(res, varptr(get_time), 0) return time #defcfunc getfps /* | 【FPSを取得する】 */ if(get_fps==0) { get_fps.0=$53ec8b55,$08758b56,$463b068b,$892f7404,$d2330446,$b9085689,$0000000a,$834bd88b get_fps.8=$548b3fe3,$56010c9e,$b9f3e208,$00000028,$d233d88b,$3fe38343,$0c9e5489,$e083f6e2 get_fps.16=$8644ff3f,$08468b0c,$c3c95b5e VirtualProtect varptr(get_fps), length(get_fps)*4, 0x40, varptr(res) dim structFPS, 67 prm=varptr(structFPS) } structFPS=int(timer()*10) return callfunc(prm, varptr(get_fps), 1) // ループの先頭に定義(limitFPSを使う場合) #define global limitEntryFPS offset_time=timer() // FPSを固定するためのウェイトを返す #define global ctype limitFPS(%1, %2) 1000.0*(double(%1)/(%2*%2)+offset_time-timer()) ;1000.0*(double(%1)/(%2*%2) + offset_time-timer() − awaitの誤差) ; limitFPS(fps, fmax) ; fps : FPS値 ; fmax : 制限する値 #global #define fp 25 repeat limitEntryFPS fps=getfps() ; ; 何らかの処理 ; //デフォルトFPS値よりも低い if fps<=fp{ redraw 0 repeat 10 color 255, 255, 255 boxf loop color pos 0,0 mes "fps:"+fps+", cnt:"+cnt redraw 1 title "fps:"+fps+", wait:"+int(wt) }else{ wt=limitFPS(fps, fp) await wt } loop
効果はあまり得られませんでしたが少しはよくなっています.



As

リンク

2008/3/14(Fri) 23:56:06|NO.14239

ウェイトの位置をグローバルに変えたら安定したみたいです。
ただ、規定のFPS値と実際のFPS値が違うのですが・・



#define fp 40 #include "d3m.hsp" #define ctype limitFPS(%1, %2) 1000.0*%1/(%2*%2) repeat ; ; 何らかの処理 ; //デフォルトFPS値よりも低い if fps<=fp{ redraw 0 repeat 10 color 255, 255, 255 boxf loop color pos 0,0 mes "fps:"+fps+", cnt:"+cnt redraw 1 title "fps:"+fps+", wait:"+int(wt) } ; ; fps=d3getfps() wt=limitFPS(fps, fp) await wt loop



Shinya

リンク

2008/3/15(Sat) 02:24:18|NO.14246

Asさん返事どうも有難うございます.解決しました!
>ウェイトの位置をグローバルに変えたら安定したみたいです。
>ただ、規定のFPS値と実際のFPS値が違うのですが・・
FPSが規定に合わなかったのは,

 limitFPS(%1, %2)	1000.0*(double(%1)/(%2*%2) + offset_time-timer() - awaitの誤差)

でawaitの誤差を含めない分 「offset_time-timer() − awaitの誤差」を0とみなし
◆limitFPS(%1, %2)	1000.0*%1/(%2*%2)
としていたのが原因です.

 実際これである程度動いていたので△蓮offset_time-timer()=awaitの誤差
がうまく成り立っていると思っていたのですが,とんだ勘違いをしていました.
ウェイトの値を計算した後loop命令からrepeat命令に移る間とtimer()関数を呼び出す間の時間を無視していましたwww
で、これをαとすると△
 offset_time−timer()−awaitの誤差−α=0
が成り立っていたときの計算式ですね.αを測定していればawaitの誤差も分かるのに...とんだ見落としをしていましたorz



naznyark

リンク

2008/3/15(Sat) 02:43:32|NO.14247

参考までにこんなのも。穴があるけど。

#define fp 33 #include "d3m.hsp" #const BASEWAIT 1000.0 / fp basetime = d3timer() skip = 0 repeat ; ; 何らかの処理 ; fps = d3getfps() targettime = basetime + BASEWAIT * cnt //デフォルトFPS値よりも低い if ( d3timer() < targettime ) { redraw 0 repeat 10 color 255, 255, 255 boxf loop color pos 0,0 mes "fps:"+fps+", cnt:"+cnt + ", skip:" + skip redraw 1 title "fps:"+fps repeat await 1 if ( d3timer() >= targettime ) : break loop } else { skip++ await 1 } loop



Shinya

リンク

2008/3/15(Sat) 13:14:37|NO.14271

naznyarkさん有難うございます.
>参考までにこんなのも。穴があるけど。
時間は一定に過ぎるので処理時間を制限して固定FPSを作り出すのですか...
時間が過ぎる速さよりもプログラムが走る速さがずっと上回っているときはとてもFPSは安定しています.実際にここまで安定するのかと驚きました.とても参考になります.

 スキップ無しの方法ではこんな感じになりました.
#module "bkfps"
#uselib "ntdll.dll" #func ZwQueryPerformanceCounter "ZwQueryPerformanceCounter" #uselib "kernel32.dll" #func VirtualProtect "VirtualProtect" int,int,int,int #defcfunc timer /* | 【システム起動時からの経過時間を1秒単位マイクロ秒の精度で得る】 */ if(get_time==0) { get_time=$83ec8b55,$458df8c4,$78bb50f8,$53123456,$345678b8,$dfd0ff12,$f875da2b,$c3c91bdd ddim time, 1 lpoke get_time, 11, varptr(time) lpoke get_time, 17, varptr(ZwQueryPerformanceCounter) VirtualProtect varptr(get_time), length(get_time)*4, 0x40, varptr(res) } res=callfunc(res, varptr(get_time), 0) return time #defcfunc getfps /* | 【FPSを取得する】 */ if(get_fps==0) { get_fps.0=$53ec8b55,$08758b56,$463b068b,$892f7404,$d2330446,$b9085689,$0000000a,$834bd88b get_fps.8=$548b3fe3,$56010c9e,$b9f3e208,$00000028,$d233d88b,$3fe38343,$0c9e5489,$e083f6e2 get_fps.16=$8644ff3f,$08468b0c,$c3c95b5e VirtualProtect varptr(get_fps), length(get_fps)*4, 0x40, varptr(res) dim structFPS, 67 prm=varptr(structFPS) } structFPS=int(timer()*10) return callfunc(prm, varptr(get_fps), 1) // ループの先頭に定義(WaitOflimitFPSを使う場合) #define global limitEntryFPS offset_time=timer() // FPSを固定する #define global WaitOflimitFPS(%1, %2) _wait@bkfps=1000.0*(double(%1)/(%2*%2)+offset_time-timer()):\ offset_time=timer()+_wait@bkfps/1000.0 : await _wait@bkfps ; WaitOflimitFPS fps, fmax ; fps : FPS値 ; fmax : 制限する値 #global #define FPSMAX 33 limitEntryFPS repeat ; ; 何らかの処理 ; redraw 0 color 255, 255, 255 boxf color pos 0, 0 mes "cnt:"+cnt redraw title "FPSを"+FPSMAX+"に固定 fps:"+fps ; ; fps=getfps() WaitOflimitFPS fps, FPSMAX ; ; 何らかの処理 ; wait 1 loop



ONION software Copyright 1997-2023(c) All rights reserved.