2012/06/28

Perlin Noise を実装中

結局、自動生成や様々なシミュレーションの簡易さを考慮し、当面は heightmap からの地形生成のまま進めることにしました。そこで、自分のアプリケーションから heightmap を生成して編集できるようにしようと思い、Perlin noise (パーリン ノイズ) を調べて実装している最中です (過去作成した地形では L3DT で出力した heightmap を利用していました)。

Heightmap や procedural texture を調べると、頻繁に Perlin noise という言葉が出てきます。このため、アルゴリズムの説明や公開コードも豊富であろうと考え、気楽に実装を始めたのですが・・・想定外のハマり方をしました。

結論からは、Perlin noise の説明や実装は簡単に見つかります。しかし、その多くが 「Perlin noise ではない」のです。この答えに到達するまでに随分時間が掛かりました。

Perlin noise は、gradient と呼ばれる擬似乱数のベクトルをグリッド上に配置し、任意の位置 (グリッドに沿っているとは限らない) のノイズ値を、それを取り囲む 4 点にある gradient から重み付けを考えて算出する仕組みかと思います。
恐らく、Perlin noise を理解しようとした場合、Matt Zucker による The Perlin noise math FAQ を読むことがベストだと思います。

Perlin noise は、gradient を元にしたアルゴリズムであることから、gradient noise として分類されるそうです。
Gradient noise: http://en.wikipedia.org/wiki/Gradient_noise
上記ページには、興味深いことが書かれています。「しょっちゅう value noise と混同されます」と。事実、Perlin noise 実装を謳ったコードの多くが、この value noise に分類されるものです。Wikipedia の記述からは、あまりに混同されるために gradient noise と value noise という分類を作ったという印象を受けます。
Value noise: http://en.wikipedia.org/wiki/Value_noise
上記ページには、Perlin noise ではないにもかかわらず Perlin noise として説明している某サイトへのリンクが value noise の説明として貼られています。
厄介なことに、Perlin noise を検索すると、このサイトが上位に現れます。このサイトでは、擬似乱数のスカラー値をグリッド上に配置し、それらにブラーをかけ、更に補間を行ない、滑らかなノイズとしているようです。

このサイトの内容は非常に有益でしたが、誤ったタイトルを付けたことで、Perlin noise ではないものを Perlin noise であると解釈した人が大量に生まれたのではないかと推測します。
僕も Ken Perlin にのみ従っていれば良かったのですが、誰かの C# コード丸パクリで済まそうとしたことで、この混乱の渦へ自ら身を投じてしまったようです。

と言うことで、Ken Perlin によるオリジナル コード、および、 Matt Zucker によるらしい C++ コードを見つけたので (見つけた場所が怪しいためリンクを貼りません) 、それらを元に XNA で実装しています。
先行して、Ken Perlin による Improved Noise reference implementation (Java 実装) を C# へ移植したのですが、ちょっと gradient の式が理解できていません・・・。

他には、libnoise というノイズ生成のためのオープンソース ライブラリも参考にして進めています。libnoise のコードはクラス設計が綺麗に纏められており、コードを読んでいて心地良いです。

2012/05/14

FF13&FF13-2

結局開発はせずに FF13 & FF13-2 をやり、FF13-2 を今クリアした所です。

Skyrim は面白いのですが、クエストは極めて退屈で、僕は内容を無視し、アイテムや能力取得のために取捨選択というプレイです。で、そうこうしているうちに、久しぶりに凝ったシナリオの RPG をプレイしてみたいと感じ、思い出したのが FF13-2 で、FF13 合わせて GW 頭辺りからひたすらプレイしていました。まぁ、昨今の FF のようなゲーム形式を RPG と呼ぶのかどうかという問題はありますが。

本当は、FF13 を買いたくなかったです。買いたくないと思った FF は、オンラインも含めて FF13 が初めて・・・ですが、FF13-2 のタイムトラベルのシナリオに興味があり、FF13-2 を楽しむには FF13 を買わざるを得ず。

FF13 はネットで言われる数多の批判そのままですかね。3000 円程で Collection 版を買いましたが、それなら見合う額かな?(中古ならもっと安いかな?)。

FF13-2 は期待した質で楽しめました。アマゾンで 2000 円強でしたが、ちょっとこの額ではスクエニに気の毒な感じもします。まぁ僕はタイムトラベルというだけで楽しいので、ちょっと観点が違うかもしれない。FF13 の続編と考えると、そりゃそうだろうという気もします。

ED は真 ED や DLC の類ではなく、続編への布石と解釈しましたが、出せるのですかねぇ・・・。

とりあえず、後少し FF13-2 のクリア後要素を楽しみ、開発に戻ろうと思いつつも、Mass Effect 3 もやりたいのに放置状態で、どうしようかなぁ・・・。
ゲームをやりながらも、コードを書くための準備として調べ物などは行なっていますが、どうにも気持ちが入ってこないことが問題で。

2012/05/07

近況

先の動画投稿の辺りから胃の上部に違和感があり、全く集中できない状態であったため、開発は停止していました。集中できないどころか生活そのものに影響が出ていたというか。
数週間症状が緩和しないので病院に行き、採血、胃カメラ、検便の調査を待ちつつ、薬を飲みつつ、何をしても辛いので Skyrim 廃人となって養生(?)していました。

GW 中に出た検査結果は「健康そのもの」。原因不明なものの投薬で緩和されてもいて、もうしばらく投薬を続けて終了のようです。違和感もほぼ無くなってきたので、そろそろ開発を再開しても大丈夫かなと。

しかし、開発のリズムを完全に失ったことが問題で、これを取り戻すことが案外大変。

2012/04/09

モデルの非同期&分割ロード

先日上げたデモ動画では、モデルのロードで非同期処理と分割処理を組み合わせています。ここでは、それらの実装について書いてみようかなと。

最初は、モデル ファイルの読み込みから VertexBuffer の作成までを 1 つの処理とし、Game Thread とは別の Thread へ渡してみましたが、上手く動きませんでした。Game Thread が呼び出す Game.Draw() では SpriteBatch などが描画処理を行いますが、その最中に別の Thread が VertexBuffer.SetData() を呼び出すと、どちらかの Thread の処理がコケます。
僕は GPU が絡む部分がよくわからないので、詳しい人からのツッコミが欲しい所ですが、恐らく、どちらも GPU へ命令を渡す部分であり、そこでの競合が発生するのだと思います。

こういう問題があったため、モデルのロード処理を、まずは以下の 2 つに分割しています。

  1. モデル ファイル読み込みから頂点データを作成
  2. 1 で作成された頂点データから VertexBuffer を作成

こうしておき、1 だけを別の Thread へ渡します。この時、コールバック メソッドも同時に渡し、1 を終えたら呼び出されるようにします。そして、コールバック メソッドは 2 を Game Thread で管理するキューへ入れます。
この時、更に 2 を分割してからキューに入れます。僕の用いるモデルは複数の VertexBuffer を用いるため、VertexBuffer の単位で処理を分割してキューに入れます。XNA の Model クラスで喩えるならば、ModelMeshPart を個別に構築する感じです。

キューに入れられた処理は、Game Thread が呼び出す Game.Update() で順に取り出され、VertexBuffer を作成します。そして、何度かの Game.Update() の呼び出しで全ての VertexBuffer の作成が完了したら、モデルのロードが完了したということになります。

要するに、1 だけを非同期にし、2 を Game.Update() 内で行うようにしたわけです。そして、2 を可能な限り細分化し、Game.Update() での負荷を下げたという感じです。

1 の非同期処理は、僕は ThreadPool を利用して Thread に割り当てています。ただし、そのまま使うと Thread 数の制御ができないため、ここでもいったんキューに入れ、Thread 数を制御しながら割り当てています。

で、ここまでやってデモ アプリを計測したら、1 を非同期にする程でもなかったというオチでしたが、今後のコード次第ではどうなるか分からないので、このパターンのままやろうかなと。
 ContentManager.Load() でロードする場合でも、その単位でキューに入れれば Game.Update() の負荷を下げられるんじゃないかと思います。

なお、デモ動画の段階では、1 の処理完了で即座にコールバック メソッドを呼び出していますが、今はこれもいったんキューに入れ、Game.Update() 内でコールバックが呼び出されるようにしています。
基本的には、多少回り道をする処理となっても、同期をとる箇所をまとめてしまう方が、他の部分で lock を書いたりせずに済んで見通しが良いのではないかと思います。lock 漏れも怖いですし、それらのデッドロックも怖いですし。

ソースコードの例としては、非同期処理については、以下のコードを HTTP 通信の非同期処理に用いています。

https://github.com/willcraftia/Blocks/tree/master/Framework/Threading

上記はモデルのロード処理ではないですが、同様のパターンを用いて非同期処理を行なっています。
モデルのロード部分は、専用モデルを用いていることから複雑でありオススメできないサンプルですが、興味のある人は以下などをどうぞ。

https://github.com/willcraftia/Blocks/tree/master/Blocks/Content

上記にある InterBlockMeshLoadQueue が非同期処理、BlockMeshLoadQueue が VertexBuffer  分割キューです。
※master にあるコードなのである日突然消えたりするかもしれません。

なるべく短命なオブジェクトが生成されないように工夫してみたつもりですが、どうですかねぇ・・・。

2012/04/03

はじめに

はじめまして、あるいは、こんにちは。

過去、 3D でドット風モデルと物理システムを用いたプログラムを XNA で作成し、それを動画として上げていましたが、3D グラフィックスの分野は全くの素人であったため、試行錯誤により滅茶苦茶なプログラムを書いていました。また、いつしか目的を見失っていた所もありました。

最近は、それらを頭で整理できるようになってきたので「ちょっとブログでもやってみようかな?」という軽い気持ちで始めています。なお、このブログのハンドル名は、Google 先生が最近怪しいので、気持ち程度に本来のものから変更しています。

XNA の話題が多くなるかもしれないですが、XNA の範囲にない技術も使っていくので、色々と雑多な内容になるかと思っています。開発やゲームに関係するという縛りの上で、しょうもない日記も上げるかもしれません。

いずれにせよ、飽きるまではやってみようかな・・・と。

ひとまずは、XNAで作成した UI Framework のデモ動画を用意しているので、近いうちにニコニコ動画へ上げると思います。

それではよろしくお願いします。

libgdx いじり

Google が提供している Java 版の Tango Examples は Rajawali をベースにしているため、自分が仕事で開発する Tango アプリも Rajawali ベースとしていましたが、最近は libGDX への移行を進めています。一応、要点については移行が...