FPSを作ってみる@wiki
11)
最終更新:
slice
-
view
(2013/11/29)
当たり判定の部分って重要だけど地味過ぎてテンション保つの大変である・・
当たり判定
とりあえずと言おうか、やっとこさという感じか。2Dと3Dの当たり判定は一段落。
GJKのルーチンが2Dは直前まで使ってたから良しとして3Dのはちょうど去年の今頃触ったきりなので信頼性が微妙。
古いソースそのまま持ってきて文法エラーのとこだけ手直しって経験上あんまり良くないんだよねぇ・・
多分これから足りない関数がボチボチ出てくると思うけどそれはその時で。
BroadPhase判定は予定通り総当りのみ。これも後で必要になり次第もっと効率の良い物に変える。
GJKのルーチンが2Dは直前まで使ってたから良しとして3Dのはちょうど去年の今頃触ったきりなので信頼性が微妙。
古いソースそのまま持ってきて文法エラーのとこだけ手直しって経験上あんまり良くないんだよねぇ・・
多分これから足りない関数がボチボチ出てくると思うけどそれはその時で。
BroadPhase判定は予定通り総当りのみ。これも後で必要になり次第もっと効率の良い物に変える。
で、次何しようとしてたっけ?と一瞬悩んだが
そうだ、3D空間でカメラを動かすプログラムだった。
そうだ、3D空間でカメラを動かすプログラムだった。
(2013/11/27)
2D & 3D
ずっと当たり判定関係をやってる。
2D形状は一つ前のソースから、3D形状は更に前のから移植。
ソースの再利用と言えば聞こえはいいがそりゃぁ期間が空けばスキルもちっとは上がっとりますから、
インタフェースも所々変わってるし部品持ってきてはめ込めば終わりとはなりませんわな。
2Dの剛体運動云々はとりあえず使わなそうなので省いた。
衝突判定は全部の形状がサポート写像を実装する物として専用ルーチンが用意されていればそれを、無ければGJKアルゴリズムを使うように。
2D形状は一つ前のソースから、3D形状は更に前のから移植。
ソースの再利用と言えば聞こえはいいがそりゃぁ期間が空けばスキルもちっとは上がっとりますから、
インタフェースも所々変わってるし部品持ってきてはめ込めば終わりとはなりませんわな。
2Dの剛体運動云々はとりあえず使わなそうなので省いた。
衝突判定は全部の形状がサポート写像を実装する物として専用ルーチンが用意されていればそれを、無ければGJKアルゴリズムを使うように。
で、大体移植が終わったのだけどまだBroadPhaseの当たり判定クラスが残ってて、
こいつも例によってテンプレートで入り組んでる関係上時間食いそうだ。
こいつも例によってテンプレートで入り組んでる関係上時間食いそうだ。
いわゆるリファクタリングは定期的にやっておいた方がいいのかもね。
確かに一見無駄な時間かかるけど騙し騙し増改築の後で一気にと思ってもやる気しない=そのまま破棄になる。
それだったらキリのいいところでリファクタリングした方が結果的にソースが長持ちする。
ま、そんな事を思いつつ・・
一先ず総当りのBroadPhase判定を組み込んだら一旦動くかテストしないと。
確かに一見無駄な時間かかるけど騙し騙し増改築の後で一気にと思ってもやる気しない=そのまま破棄になる。
それだったらキリのいいところでリファクタリングした方が結果的にソースが長持ちする。
ま、そんな事を思いつつ・・
一先ず総当りのBroadPhase判定を組み込んだら一旦動くかテストしないと。
(2013/11/19)
形状クラスキャッシュ
例えば円柱の形状クラスがあったとしてその体積なんていうのは必要になった時に計算したいし、大きさが変わらない限り体積も不変だから
その値を取っておいて次からの問い合わせで使いたい。
こういうのは中心座標や重心、物理シミュレーターの慣性テンソルにも言えることで
従って形状クラスを内包した「キャッシュ付きクラス」を定義する。ここまではいい。
その値を取っておいて次からの問い合わせで使いたい。
こういうのは中心座標や重心、物理シミュレーターの慣性テンソルにも言えることで
従って形状クラスを内包した「キャッシュ付きクラス」を定義する。ここまではいい。
もちろん形状は3Dに限っても球、カプセル、円錐、四角錐、点、ボックス、凸包・・・など様々な訳で
これら全てに専用のキャッシュを付加管理していたのではコードが重複するし、かといって全く同一でもない。
これら全てに専用のキャッシュを付加管理していたのではコードが重複するし、かといって全く同一でもない。
例えば球の場合は内部に中心座標 + 半径という形で持っているので中心座標のキャッシュは必要ないが
凸包だったら計算が必要だ。
キャッシュが必要ない場合はキャッシュに使うメモリは不要なので確保したくない。
ここまでで十分面倒くささが伝わると思うのだが更に形状によっては
幾つかの値が同時に求まる(体積の計算過程で中心座標を出すなど)時もあって
そういった場合は当然両方共キャッシュしておきたいし、フラグの更新も自動でやりたい。
ある演算がキャッシュを無効化するようなら中心座標タグ、体積タグなどを指定するだけでフラグを下ろせれば便利だ。
凸包だったら計算が必要だ。
キャッシュが必要ない場合はキャッシュに使うメモリは不要なので確保したくない。
ここまでで十分面倒くささが伝わると思うのだが更に形状によっては
幾つかの値が同時に求まる(体積の計算過程で中心座標を出すなど)時もあって
そういった場合は当然両方共キャッシュしておきたいし、フラグの更新も自動でやりたい。
ある演算がキャッシュを無効化するようなら中心座標タグ、体積タグなどを指定するだけでフラグを下ろせれば便利だ。
以上の要件をメモリや処理効率を犠牲にせず上手く実装する術は?
と、いうような事をこの2日間ずっと考えていた。
(正確には前に一度実装してたけど使い勝手悪過ぎで今回却下)
実装のメドが立ったので今実装中なのだが・・どうなることか
(正確には前に一度実装してたけど使い勝手悪過ぎで今回却下)
実装のメドが立ったので今実装中なのだが・・どうなることか
boomstick作り直しの原因って主にコレだから後は判定ルーチンをコピペするなり
総当り判定になってるBroad Phase判定をもうちょっとマシな8分木にするか位の作業になる予定
総当り判定になってるBroad Phase判定をもうちょっとマシな8分木にするか位の作業になる予定
(2013/11/17)
当たり判定が・・
とりあえず3D空間で視点を動かしたいのでカメラ、その前に視錐台など3Dの判定を移植せねば。
と、久々にboomstickのソースを眺めてみたらこれは酷い。
まずもって2Dしか考慮されておらずそれもこの前作った2D物理を完成させるために一見汎用的なようで使えないという感じで
一言で言えばゴミだった。どうすんだこれ。
多分、設計からやり直した方が良いパターンだ。
と、久々にboomstickのソースを眺めてみたらこれは酷い。
まずもって2Dしか考慮されておらずそれもこの前作った2D物理を完成させるために一見汎用的なようで使えないという感じで
一言で言えばゴミだった。どうすんだこれ。
多分、設計からやり直した方が良いパターンだ。
まぁ頑張るしかない
(2013/11/16)
やっとポリゴン表示出来ましたー o(^◇^)o
プログラミングの初心に返るべく初めてポリゴンを表示した時の感動を少しでも再現できればと
普段使わない顔文字を入れてみた。
普段使わない顔文字を入れてみた。
非常に申し訳ないことをしたと思う。
正直な話「それ何回目だよ!」である。
思えば
DirectXで初めて表示したのと、その後へちょいフレームワーク作って表示したの、
GBAで自力ポリゴン描画やってたの、OpenGLとQtを使ったの、
AndroidでJava使って表示したの、AndroidのNDKでサンプルコード丸写しで表示したの、
WebGLでキューブ回したの・・と
思えば
DirectXで初めて表示したのと、その後へちょいフレームワーク作って表示したの、
GBAで自力ポリゴン描画やってたの、OpenGLとQtを使ったの、
AndroidでJava使って表示したの、AndroidのNDKでサンプルコード丸写しで表示したの、
WebGLでキューブ回したの・・と
7回目位?ここまで来ると感動も何もないですな。
ちなみに今回は「SDLを使ったマルチプラットフォームな自作フレームワークでポリゴン表示」という題目。
で、ゲーム完成させたの何回だっけ?無いとか、もうね。程度が知れるわ。
ちなみに今回は「SDLを使ったマルチプラットフォームな自作フレームワークでポリゴン表示」という題目。
で、ゲーム完成させたの何回だっけ?無いとか、もうね。程度が知れるわ。
裏で色々と
ミップマップに画像読み込みにフォーマット変換、Android用にデバイスロスト対応。
ベクトルや行列計算なども作り直したけどマクロの使い過ぎが原因かコード補完効きづらくて結局微妙だったり。
サウンドにも本格的に対応したしフォント描画をQtからlibfreetypeに変えたり
インプットもSDLベースに変更、マルチコアCPUが当たり前の時代だから
GUIスレッドとゲームスレッドと描画スレッドの3つに分け、それぞれ独立に動くようにとか。
とりあえず今使ってるライブラリにGPLやLGPLの物が無くなり、マルチプラットフォーム対応にしたしで
これ以上他をベースにして作り直すのはもう無いかなと。
ベクトルや行列計算なども作り直したけどマクロの使い過ぎが原因かコード補完効きづらくて結局微妙だったり。
サウンドにも本格的に対応したしフォント描画をQtからlibfreetypeに変えたり
インプットもSDLベースに変更、マルチコアCPUが当たり前の時代だから
GUIスレッドとゲームスレッドと描画スレッドの3つに分け、それぞれ独立に動くようにとか。
とりあえず今使ってるライブラリにGPLやLGPLの物が無くなり、マルチプラットフォーム対応にしたしで
これ以上他をベースにして作り直すのはもう無いかなと。
けど依然としてやる事が沢山ある。
DirectXEffectのOpenGL版みたいな位置付けのGLEffectが
DirectXEffectのOpenGL版みたいな位置付けのGLEffectが
- エフェクト記述文の途中にコメント挟む(行単位ならOK)とエラーになるからそれの修正
- OpenGLレンダラへの値設定が一部上手く行ってない(glEnable(GL_DEPTH_TEST)とかglBlendEquation(...)を呼ぶ類)
- シェーダー関数の引数として1次元の値=floatがセットできない
他には圧縮テクスチャの対応、タスクシステムの組み込み、WindowsやAndroidでの動作確認(特にサウンド)、
3Dモデル読み込みと表示、スキンメッシュ対応、FramebufferObjectの動作確認、タッチパネルのジェスチャ対応
3Dモデル読み込みと表示、スキンメッシュ対応、FramebufferObjectの動作確認、タッチパネルのジェスチャ対応
あとOpenGL2.0(ES含む)と3.0以降はGLSLやその他OpenGL-APIの仕様が少し異なっていたりして修正が必要だとか。
面倒だから当分2.0仕様(DirectX9相当)で行くけど。
面倒だから当分2.0仕様(DirectX9相当)で行くけど。
(2013/11/14)
テクスチャ
QtライブラリのQImageに依存しないようにSDLの関数だけで何とかしようとテクスチャクラスを書き換え。例によって半分くらい別物に。
いやー、Qtって便利だねホント。ツール用途ではベストかもしれんね。
そもそもSDL_imageを使わなくたって要はPNGとJPGとBMPが読めれば十分だからlibpngとlibjpgがあればいいんじゃないの?と思ったり思わなかったり。
ファイル全体を読まずに先に画像サイズと色深度だけ取りたい時があって歯痒い。が、ぐぐぐっと堪える。
いやー、Qtって便利だねホント。ツール用途ではベストかもしれんね。
そもそもSDL_imageを使わなくたって要はPNGとJPGとBMPが読めれば十分だからlibpngとlibjpgがあればいいんじゃないの?と思ったり思わなかったり。
ファイル全体を読まずに先に画像サイズと色深度だけ取りたい時があって歯痒い。が、ぐぐぐっと堪える。
(2013/11/13)
OpenGLのミップマップ
OpenGLを利用する時に割とセットで使ってる人が多そうなOpenGL Utility (libglu)というライブラリ。
これには射影や回転行列を定義してくれる便利な関数が揃っているがAndroidに標準で用意されていない。
もちろんAndroid向けにコンパイルすることは出来る。
が、行列の演算とかは既に自前のライブラリでやってるし
使いたいのはミップマップ生成関数1つだけなので出来るなら自分でやってしまえばわざわざ組み込まなくて良くなる。
これには射影や回転行列を定義してくれる便利な関数が揃っているがAndroidに標準で用意されていない。
もちろんAndroid向けにコンパイルすることは出来る。
が、行列の演算とかは既に自前のライブラリでやってるし
使いたいのはミップマップ生成関数1つだけなので出来るなら自分でやってしまえばわざわざ組み込まなくて良くなる。
という訳でちょっとググッて調べてみたら、その物ズバリなPDFがヒットした。
https://www.cs.uiowa.edu/~cwyman/classes/fall04-22C151/handouts/OGLmipmap.pdf
何のことはない、テクスチャを4分の1に縮小しつつ1x1になるまで繰り返しglTexImage2D()でセットしていくだけだった。
元のテクスチャが2の冪乗サイズでない、例えば300x300とかの時は
300x300 -> 256x256 -> 128x128 ... とやればいいかな。
GPUによってはサーフェスが2の冪乗サイズでないといけないので、そういう場合は最初に最寄りのサイズにスケーリングして
(300x300を512x512に伸ばしたもの) -> 256x256 -> 128x128 ...
上か下かどっちに合わせるかはメモリ消費量や品質と相談という感じで。
画像のスケーリングはSDLの関数でやるつもりだ。
https://www.cs.uiowa.edu/~cwyman/classes/fall04-22C151/handouts/OGLmipmap.pdf
何のことはない、テクスチャを4分の1に縮小しつつ1x1になるまで繰り返しglTexImage2D()でセットしていくだけだった。
元のテクスチャが2の冪乗サイズでない、例えば300x300とかの時は
300x300 -> 256x256 -> 128x128 ... とやればいいかな。
GPUによってはサーフェスが2の冪乗サイズでないといけないので、そういう場合は最初に最寄りのサイズにスケーリングして
(300x300を512x512に伸ばしたもの) -> 256x256 -> 128x128 ...
上か下かどっちに合わせるかはメモリ消費量や品質と相談という感じで。
画像のスケーリングはSDLの関数でやるつもりだ。
ところでOpenGLのミップマップのサイズって別にどんなサイズでもいいの?と思ったので調べたら
OpenGL ES2においては基本的に2の冪乗でなきゃ駄目だそうで。GL_NV_texture_npot_2D_mipmapがあれば良いとか、なんとか・・・
横長テクスチャ用に128x64とかも駄目なのかはやってみないとわからんね。
OpenGL ES2においては基本的に2の冪乗でなきゃ駄目だそうで。GL_NV_texture_npot_2D_mipmapがあれば良いとか、なんとか・・・
横長テクスチャ用に128x64とかも駄目なのかはやってみないとわからんね。
(2013/11/12)
間が空いたのでGitHubの履歴を見て思い出しつつ書く。
FreeType
特に詰まった箇所もなくFreeTypeを使ったフォント描画を一先ず実装。バグ云々は後で気づいたら直す。
太字フォントや斜体フォントの検索とかは面倒なのでしてない。文字を変形させるだけの手抜き対応。
太字フォントや斜体フォントの検索とかは面倒なのでしてない。文字を変形させるだけの手抜き対応。
Assert
エラーチェックの為のマクロを強化。
https://github.com/degarashi/resonant/blob/master/error.hpp
https://github.com/degarashi/resonant/blob/master/error.hpp
基本的には
Assert(挙動クラス, 条件式, (オプションでprintf形式のメッセージ、引数など...))
と記述して、条件式がtrueでなかったらエラーメッセージを出す。
標準のassert()は本当にエラーを発生させるだけでメッセージを出力できず不便なので。
Assert(挙動クラス, 条件式, (オプションでprintf形式のメッセージ、引数など...))
と記述して、条件式がtrueでなかったらエラーメッセージを出す。
標準のassert()は本当にエラーを発生させるだけでメッセージを出力できず不便なので。
挙動クラスというのはアサート条件に引っかかった時に実行する動作を定義するクラスで今の所
Trap: メッセージ出力後、デバッガをブレーク
Throw: メッセージ出力後、例外を投げる
Warn: メッセージ出力のみ
の3つを用意してあるが実際の所こうだというポリシーはなく、適当だ。
アウトプットへは実行した箇所の行番号、ファイル、関数とエラー詳細、それとオプションで指定した文字列がひと塊で出力される。
ちなみにリリースビルド時にはチェックを行いたくない箇所はAssertP(...)というマクロを使えば綺麗サッパリ無くなるようにした。
Throwで投げる例外クラスを指定するにはAssertT(...)っていうのを使う。説明は省略
Trap: メッセージ出力後、デバッガをブレーク
Throw: メッセージ出力後、例外を投げる
Warn: メッセージ出力のみ
の3つを用意してあるが実際の所こうだというポリシーはなく、適当だ。
アウトプットへは実行した箇所の行番号、ファイル、関数とエラー詳細、それとオプションで指定した文字列がひと塊で出力される。
ちなみにリリースビルド時にはチェックを行いたくない箇所はAssertP(...)というマクロを使えば綺麗サッパリ無くなるようにした。
Throwで投げる例外クラスを指定するにはAssertT(...)っていうのを使う。説明は省略
最後のprintf形式メッセージはオプションなので省ける。通常、引数付きマクロで
引数がある時はこうで、そうでない時はといったオーバーロードは出来ないのだがそこはboost::preprocessorを用いて何とかした。
引数がある時はこうで、そうでない時はといったオーバーロードは出来ないのだがそこはboost::preprocessorを用いて何とかした。
他にはGLEC(挙動クラス, OpenGL関数, 引数...) という
OpenGL関数を呼んでその後にエラーチェックをするマクロを定義したり。
これもGLEC_P(...)とやればリリース時には単にOpenGL関数を呼ぶだけになる。
なんでPがつくかっていうとParanoiaの略だったりするが、これも適当なので(略
OpenGL関数を呼んでその後にエラーチェックをするマクロを定義したり。
これもGLEC_P(...)とやればリリース時には単にOpenGL関数を呼ぶだけになる。
なんでPがつくかっていうとParanoiaの略だったりするが、これも適当なので(略
後で気づいたけど大まかなデバッグはPCでするのだからOpenGL4.3で追加されたDebugOutputというのを使えば
エラーがあった時にコールバック関数を呼んでくれるみたいだから要らないっちゃあ要らない・・
でもOpenGL4.3ではない環境でテストする時に使えるし
同じ様な書き方でOpenSLやOpenALやFreeTypeにも対応出来ているので、良かった事にする。
エラーがあった時にコールバック関数を呼んでくれるみたいだから要らないっちゃあ要らない・・
でもOpenGL4.3ではない環境でテストする時に使えるし
同じ様な書き方でOpenSLやOpenALやFreeTypeにも対応出来ているので、良かった事にする。
SDL_SurfaceとGLTexture
最初にSDL_Surfaceラッパークラスを書いて後から別に作っていたOpenGLのTextureを扱うクラスを合わせたせいで
テクスチャに関する扱いが微妙な事になっている。
要するに両方とも画像を扱う訳だがフォーマットに互換性はなく、使うなら明示的な変換が必要。
SDL_Surfaceの方はSDL_imageライブラリを用いて様々な画像フォーマットからの読み込みをサポートしているが
文字通り一枚の絵に過ぎず、OpenGLのテクスチャとしては使えない。
対するOpenGL_Textureは今の所、生のピクセルデータからの入力しかできない。
テクスチャに関する扱いが微妙な事になっている。
要するに両方とも画像を扱う訳だがフォーマットに互換性はなく、使うなら明示的な変換が必要。
SDL_Surfaceの方はSDL_imageライブラリを用いて様々な画像フォーマットからの読み込みをサポートしているが
文字通り一枚の絵に過ぎず、OpenGLのテクスチャとしては使えない。
対するOpenGL_Textureは今の所、生のピクセルデータからの入力しかできない。
SDL_Surfaceとは別にSDL_TextureというのもあってコイツはSDL_Rendererと合わせてテクスチャのように使える。
が、SDL自体はDirect3DでもOpenGLでも意識せず使えるような設計なので中身がOpenGLのテクスチャだとは保証されないしそもそもTextureIDを取り出す術がない。
GLSL(Shader)やFramebuffer等を使いたくても現時点では無理、従って除外。
が、SDL自体はDirect3DでもOpenGLでも意識せず使えるような設計なので中身がOpenGLのテクスチャだとは保証されないしそもそもTextureIDを取り出す術がない。
GLSL(Shader)やFramebuffer等を使いたくても現時点では無理、従って除外。
・・・ぐだぐだと書いていたら至極真っ当な結論に至った。
メインで使うのはOpenGL_Textureにして内部でSDL_Surfaceを使って画像ファイルのロードなり又は保存なりすればいいね。
テクスチャ間の矩形コピーなんかは一旦SDL_Surfaceに変換なんかしたら重くて仕方ないのでFramebufferを使って色々する必要がありそうだけど。
テクスチャ間の矩形コピーなんかは一旦SDL_Surfaceに変換なんかしたら重くて仕方ないのでFramebufferを使って色々する必要がありそうだけど。
(2013/11/05)
フォント描画
そういえばフォント描画はQtに頼りきりだったのでこれはイカンと、
SDL_ttfを試した。これはtrue typeフォントをレンダリングするlibfreetypeのラッパーで
他のSDL_imageやSDL_mixer等とインタフェースを似せて使いやすくした物である。
SDL_ttfを試した。これはtrue typeフォントをレンダリングするlibfreetypeのラッパーで
他のSDL_imageやSDL_mixer等とインタフェースを似せて使いやすくした物である。
暫しリファレンスを眺めさあ実装といった段階であることに気づいた。
TTF_RenderGlyphで指定する文字コードの型がUint16、つまりサロゲートペアが使えない。困った。
いや、ゲーム用途としては十分だけどtwitter clientやゲーム内チャットを作った時に
フォントが対応していない以外の原因で文字化けしたり表示崩れを起こすのはちと不味い。
よく見るとUtf16文字列とUtf8文字列を描画する関数があって、1文字でもこれを呼べば行けるかな?・・・と思って試してみた。
例えば丈(U+4E08) とその異体字である(U+2000B)・・・って、atwikiがsurrogate pairに対応してないらしい。webでこれは如何に?
TTF_RenderGlyphで指定する文字コードの型がUint16、つまりサロゲートペアが使えない。困った。
いや、ゲーム用途としては十分だけどtwitter clientやゲーム内チャットを作った時に
フォントが対応していない以外の原因で文字化けしたり表示崩れを起こすのはちと不味い。
よく見るとUtf16文字列とUtf8文字列を描画する関数があって、1文字でもこれを呼べば行けるかな?・・・と思って試してみた。
例えば丈(U+4E08) とその異体字である(U+2000B)・・・って、atwikiがsurrogate pairに対応してないらしい。webでこれは如何に?
ともかくTTF_RenderUNICODE_Solid(Uint16*を受け取る方)で文字列描画を試みる。
(U+4E08)の方は・・・勿論OK
(U+4E08)の方は・・・勿論OK
(U+2000B)は・・・駄目
surrogate pairのそれぞれが無効な文字と判定されているっぽい。
ならばTTF_RenderUTF8_Solid()ならばどうか。
やはり駄目。点が1つになったという事は1バイト目で判断している?
FreeType
そんな訳でlibfreetypeを直接使用する。
まずはソースを取ってきてビルド、インストール。チュートリアルとリファレンスを眺めて以下略
SDL_ttfの方がインタフェースが整ってて好きだったけどsurrogate pairが使えないUNICODEとか、ちょっとね。
まずはソースを取ってきてビルド、インストール。チュートリアルとリファレンスを眺めて以下略
SDL_ttfの方がインタフェースが整ってて好きだったけどsurrogate pairが使えないUNICODEとか、ちょっとね。