FPSを作ってみる@wiki
07)
最終更新:
slice
-
view
(2015/07/19)
今回はプログラムがメインで絵は全く進展なし。珍しい。
ゲーム
ライブラリばかり整備してないでいい加減、ゲーム作ってみようかという事で
少し前から上から視点の全方位シューティングっぽいものを組んでいるんだが
ふと、どの位動くのかなと思ってそれぞれ独立に動く火花パーティクルを出してみたら
150個程度出した所で60fpsを維持できなくなった。
少し前から上から視点の全方位シューティングっぽいものを組んでいるんだが
ふと、どの位動くのかなと思ってそれぞれ独立に動く火花パーティクルを出してみたら
150個程度出した所で60fpsを維持できなくなった。
これが多いか少ないかはゲームに依るところだが、デバッグビルドとはいえちょっと遅すぎでは?という。
今までパフォーマンス関係の調整はなるべく後回しにして来たものの、流石に遅すぎて気になった…
初代Xboxクラスの性能でもこの程度は余裕だろうと。
今までパフォーマンス関係の調整はなるべく後回しにして来たものの、流石に遅すぎて気になった…
初代Xboxクラスの性能でもこの程度は余裕だろうと。
さっそく先日作ったプロファイラで調べてみるとオブジェクトのアップデート処理(位置計算)と描画処理にそれぞれ8ms程度かかっている。
これだけで既に16msなので仮に他で何も処理を行わなくても60fpsは厳しい計算。遅すぎる。
(本当にやるならパーティクルはそれ専用にマネージャを作ると思うがそれはともかく)
これだけで既に16msなので仮に他で何も処理を行わなくても60fpsは厳しい計算。遅すぎる。
(本当にやるならパーティクルはそれ専用にマネージャを作ると思うがそれはともかく)
結論から言うと原因は主に2つで、1つ目はゲームスレッドと描画スレッド間で共用する変数の同期ミス。
描画スレッドが共用変数をロックしたまま描画を始めてしまい、描画の間はゲームスレッドが無駄に待たされていた。
これではスレッドを分けた意味が全くない。
という訳でアップデート処理に8msかかってるのは殆ど待たされた分で
パーティクルの移動処理自体は1ms行くかどうかだった。
描画スレッドが共用変数をロックしたまま描画を始めてしまい、描画の間はゲームスレッドが無駄に待たされていた。
これではスレッドを分けた意味が全くない。
という訳でアップデート処理に8msかかってるのは殆ど待たされた分で
パーティクルの移動処理自体は1ms行くかどうかだった。
もう一つは、new/deleteの呼び過ぎ。
ゲームスレッドは描画すべきリソースやOpenGL APIコマンドをTokenという形にして一旦バッファに置き、
それを描画スレッドが読み取って順に処理する形にしてある。
1つのTokenはテクスチャをシェーダーの何番にセットする、頂点バッファをセットするなどごくシンプルな処理を担い、
これらをいくつか繋げてスプライトやポリゴンが描画される。
で、コードを書いてる時に面倒だったのでこれら1つ1つを全部動的にメモリ確保していた。
するとどうなるか。
ゲームスレッドは描画すべきリソースやOpenGL APIコマンドをTokenという形にして一旦バッファに置き、
それを描画スレッドが読み取って順に処理する形にしてある。
1つのTokenはテクスチャをシェーダーの何番にセットする、頂点バッファをセットするなどごくシンプルな処理を担い、
これらをいくつか繋げてスプライトやポリゴンが描画される。
で、コードを書いてる時に面倒だったのでこれら1つ1つを全部動的にメモリ確保していた。
するとどうなるか。
スプライト一枚にしてもざっと思いつくだけで頂点バッファ、インデックスバッファ、テクスチャ、頂点フォーマット、
アルファブレンドやブレンド関数の指定、シェーダーのセット、シェーダー変数のセット、そして描画コール…
とりあえずざっくり考えて10Tokenとすると150枚描画したら1500Tokenで、
毎フレーム1500回も確保、解放するのは幾らC++とはいえちょっとやり過ぎ。
纏めるか使いまわすかしなければ。
アルファブレンドやブレンド関数の指定、シェーダーのセット、シェーダー変数のセット、そして描画コール…
とりあえずざっくり考えて10Tokenとすると150枚描画したら1500Tokenで、
毎フレーム1500回も確保、解放するのは幾らC++とはいえちょっとやり過ぎ。
纏めるか使いまわすかしなければ。
という訳で、いきなりバッファ一本にするのも大変なので
ひとまず描画コール1つにつき一本の配列バッファにまでは纏めてみた。
結果は8ms -> 6ms程度の高速化。労力の割に思ったほど行かないなーと思ったが
実は4ms程がプロファイル文字列描画で使う頂点の計算などに費やされていて
今回そこはノータッチなのでそれを加味するとまずまずといったところだろうか。
ひとまず描画コール1つにつき一本の配列バッファにまでは纏めてみた。
結果は8ms -> 6ms程度の高速化。労力の割に思ったほど行かないなーと思ったが
実は4ms程がプロファイル文字列描画で使う頂点の計算などに費やされていて
今回そこはノータッチなのでそれを加味するとまずまずといったところだろうか。
ま、そんな感じです…
(2015/07/15)
絵
主に練習。もふもふ毛並みの塗り方やオリキャラを幾つか模索してみたりとか。
ま、そうでなくとも特にアテもなく落書きするのは楽しい事に気付いた。
特に胸から上だけのバストアップ構図を塗りまでやらずに線画だけというのは
要は顔周辺と一部手だけなのでどんどん行ける。
無論、背景や全身像もやらないとガッツリ描く時に困るのはわかるが…
ま、そうでなくとも特にアテもなく落書きするのは楽しい事に気付いた。
特に胸から上だけのバストアップ構図を塗りまでやらずに線画だけというのは
要は顔周辺と一部手だけなのでどんどん行ける。
無論、背景や全身像もやらないとガッツリ描く時に困るのはわかるが…
ゲーム
自作ライブラリResonantであるが、
今までテストコードと称してシェーダーコードやその他画像等のリソースを全く同梱してなくって
ライブラリを試そうという人が居てもほぼ不可能であり、
いわばテスト詐欺になってしまっているなぁという。
かれこれ1年くらい前から認識はしていたものの。
まぁ出来たとこでねぇとか、リソースの著作権関係が面倒くさいのもあって放置していた。
今までテストコードと称してシェーダーコードやその他画像等のリソースを全く同梱してなくって
ライブラリを試そうという人が居てもほぼ不可能であり、
いわばテスト詐欺になってしまっているなぁという。
かれこれ1年くらい前から認識はしていたものの。
まぁ出来たとこでねぇとか、リソースの著作権関係が面倒くさいのもあって放置していた。
それを、この度重い腰を上げて公開に乗り切った。
Resonant/resourceがそれである。
といっても実際やった事といえば
フォントはIPAGothicを使っていて、これはライセンス文章ファイルを同梱しただけだし
画像数点は全て自前のに差し替え、音楽も海外のパブリックドメインのとこから持ってきた。
一応入手元のURLも明記しておいた。
Resonant/resourceがそれである。
といっても実際やった事といえば
フォントはIPAGothicを使っていて、これはライセンス文章ファイルを同梱しただけだし
画像数点は全て自前のに差し替え、音楽も海外のパブリックドメインのとこから持ってきた。
一応入手元のURLも明記しておいた。
実行時はプログラムが置いてある場所にresourceディレクトリをコピーし、
引数として resource/pathlistを与えれば動くはず。
ってこれもReadmeとかに書いておくべきだったか。
引数として resource/pathlistを与えれば動くはず。
ってこれもReadmeとかに書いておくべきだったか。
(2015/07/10)
絶賛放置中になってしまった…
にも関わらず絵だけ着々とアップされていて、もういっそゲーム制作という看板を外した方が
色々とスッキリするんじゃないか。
な〜んて思ったが、それにしちゃぁ量が足りないし
お絵かきブログにつきもののオリキャラも居ない。中途半端過ぎて困る。
オリキャラは幾つか考えてあるものの、画力がどうかな〜という感じで何時になるかわからん。
にも関わらず絵だけ着々とアップされていて、もういっそゲーム制作という看板を外した方が
色々とスッキリするんじゃないか。
な〜んて思ったが、それにしちゃぁ量が足りないし
お絵かきブログにつきもののオリキャラも居ない。中途半端過ぎて困る。
オリキャラは幾つか考えてあるものの、画力がどうかな〜という感じで何時になるかわからん。
絵
とりあえずドラゴンが朝起こしてくれれば気持ちよく起きられるよねって事で描いた。
一応、ドラゴンはオリジナルだけどキャラという程でもない。
彼(女?)には申し訳ないが。
とりあえずうなじ良いですよね。うなじ。
一応、ドラゴンはオリジナルだけどキャラという程でもない。
彼(女?)には申し訳ないが。
とりあえずうなじ良いですよね。うなじ。
いつもアニメ塗りもいいなぁと思いつつ、
なんかしっくり来なくて結局水彩ツールの塗りで誤魔化してしまうクセがあるので
今回は背景を水彩、手前のキャラクターその他は絶対にアニメ塗りと決めてかかった。
カーテンの皺を描いてる時に死にそうになったのと、
左の時計は今でこそそれなりに満足だが、ほんとに最後の最後までイメージ通りに塗れなくて絶望してた。
窓の外の背景はまぁ、手間とクオリティと自分のスキル的にこんなもんかなぁって感じで。
空の色は夏っぽくて結構好きですね。
なんかしっくり来なくて結局水彩ツールの塗りで誤魔化してしまうクセがあるので
今回は背景を水彩、手前のキャラクターその他は絶対にアニメ塗りと決めてかかった。
カーテンの皺を描いてる時に死にそうになったのと、
左の時計は今でこそそれなりに満足だが、ほんとに最後の最後までイメージ通りに塗れなくて絶望してた。
窓の外の背景はまぁ、手間とクオリティと自分のスキル的にこんなもんかなぁって感じで。
空の色は夏っぽくて結構好きですね。
プログラム
う〜んと、まぁ一言で言えばゲームをゲームとして動かす際の
シーン遷移やオブジェクトのステート管理周辺がバグバグだったので直してた。
シーン遷移やオブジェクトのステート管理周辺がバグバグだったので直してた。
当たり判定に関しては2Dの凸形状でない凹ポリゴンを凸ポリゴンに分割するルーチンの実装。
これはシンプルで遅いアルゴリズムでやれば大して難しくないのだが
何を思ったか速い方に挑戦してしまった為、無駄に時間を食った。
そして「そもそもあまり使わないのでは」という事実から目をそらした。
ランダムマップ生成なら凸を組み合わせて作るだろうし。ユーザーがエディタでマップを編集する時くらいしか思いつかん。
でもそれだったら事前に計算しておける訳だし遅いアルゴリズムで良かったよね?みたいな。
これはシンプルで遅いアルゴリズムでやれば大して難しくないのだが
何を思ったか速い方に挑戦してしまった為、無駄に時間を食った。
そして「そもそもあまり使わないのでは」という事実から目をそらした。
ランダムマップ生成なら凸を組み合わせて作るだろうし。ユーザーがエディタでマップを編集する時くらいしか思いつかん。
でもそれだったら事前に計算しておける訳だし遅いアルゴリズムで良かったよね?みたいな。
ぶっちゃけ3Dの凹 -> 凸分割の方が有用なのだが、こちらはこれといったアルゴリズムが存在しておらず
要はBSPで地道にやってねという雰囲気。ぐだぐだ。
要はBSPで地道にやってねという雰囲気。ぐだぐだ。
あとゲームのエフェクトで付き物のフレームバッファやレンダーバッファの切り替えとかをテストしたりとか。
レンダリングという部分だけで見れば前の描画結果を重ねてるだけで今更どうという事もないけれど
内部的には単なるデモとは違う。少なくとも自分にとっては。
内部的には単なるデモとは違う。少なくとも自分にとっては。
添付ファイル