2013/12/24

近況: 主にFF14

仕事では iOS アプリ開発のために Objective-C をやっています。ようやくコツを掴んできたかなという所です。

ゲーム方面では、なんだかんだと FF14 を続けています。

モはスファライ・ゼニスなので、これがメインジョブという気もしていますが、特に拘らずに詩や黒でも遊んでいます。白はもう面倒なので、ほぼ使っていません。ヒーラーは負担が大き過ぎるせいか、他者への批判に心が向かいがちな面があり、あまりやりたくないという感じです。そのような僕の性格では、タンクも恐らく同様であるために敬遠している感じがあります。

バハはやってません。FC で攻略を始めた頃は時間的に合わず、乗り遅れた感じでもあります。今は野良でもやれるそうですが、面倒なイメージが先行してやる気がでませんね・・・。
ただ、v2.1 で追加されたクリスタルタワーは参加が気楽なので周回しています。酒を飲みながらでも遊べる点が大きい気もします。ひとまずは、風魔一式を目的に。

とても奇跡的な事に、ID 内で FF11 時代の友達の知人に遭遇しました。数回一緒にパーティを組んだ程度なので、相手は僕の事を覚えていなかったのですが、キャラクタ名から「もしかして?」と訊ねてみたらビンゴ。

ものすごい確率だなぁと。別鯖との事で、再度出会う可能性は極めて低くて残念ですが、こういう事があると世の中は不思議なものだと感じます。

2013/09/12

FF14: 近況

そろそろ好きに遊んでいられなくなるってことで、急いで攻略を進めていました。

白 Lv50、メイン クエストをクリア、という感じです。

FF14CST のデータ確認に製作クラスを上げておきたかったんですが・・・時間が掛かり過ぎるのでノンビリと上げる事にしました。一つのクラスに絞ればギルもバンバン使えるので、Lv50 到達はそう難しくないと思うのですが、全製作クラスを上げる前提ではそうもできないなぁと。

FF14CST を使いながらデータを確認していると、やはり入力ミスがそれなりにあります。修正すべきと思うんですが、もう面倒になってきました。ツール作成やデータ整理に時間を割くと、当然、その分だけゲームをプレイできないんですよねぇ・・・。

今後は、製作採集を上げながら、そこそこにエンドコンテンツを遊び、気分転換でたまに格闘を上げる感じで行こうかなぁと。

いずれにしても、MH4 が出ちゃうんですよね。MH をやりだすと、しばらくは FF14 放置な予感がします。
MH4 の装備作成用 Android アプリも作ってみたいと常々考えていたのですが、時間はないだろうなぁ・・・。

2013/08/29

軍需品調達での FF14CST

製品版開始早々にグランド カンパニー所属までのクエストを終え、カンパニーの軍需品調達での FF14CST の使い勝手を試していました。
元々、FF14CST を実装したきっかけは『軍需品調達』での利用で、オープンβではクエスト非公開で試せずにモヤモヤしていた所でした。

僕のように、全製作クラスを同時に上げていると、「全調達をまとめて終わらせたい!」と考えると思いますが、この時、製作手帳での確認が結構面倒です。一度見て全てを頭に叩き込める記憶力があれば楽なのでしょうが・・・僕には無理です。

そこで、FF14CST では『製作予定』という機能を実装し、レシピの繰り返し確認を支援できるようにしています。『製作予定』は、一時的なお気に入り登録みたいなものです。

例えば、次のような調達があったとします。



そうしたら、FF14CST で製作レシピを調べ、『製作予定へ追加』ボタンをタッチし、『製作予定』に製作アイテムを追加します。



こうして必要な物を順に『製作予定』へ追加し、『製作予定』からそれらを確認するという感じです。


後は、製作を終えたものから削除します(ゴミ箱アイコンをタッチ)。

序盤だと、調理なんかでは、製作せずに店から買って納品する方が楽な事がありますね。製作レシピ画面では販売価格を表示しているので、ここに価格が表示されていたらショップを確認し、買って済ませるかどうかの判断ができると思います。

2013/08/26

FF14 製作支援ツールβ公開

Android アプリとして実装した FF14 製作支援ツール(FF14CST)ですが、Google ドライブにてβバージョンとして公開しておきます。

スクリーン キャプチャ

製作詳細


ダウンロード

アプリは以下からダウンロードできます。
FF14CST(β) version 1.0.0
公開フォルダは以下です。
FF14CST公開フォルダ

インストール時の注意

Google Play からのダウンロードではないため、Android 端末の設定で『提供元不明のアプリ』の項目を『許可』に設定しなければインストールできません。
なお、アプリからはパーミッション許可を一切要求しません。

データに関する注意

アプリ内データには、
  1. オープンβのデータに基いていること
  2. 自分自身で確認していないデータが大量にあること
という問題があります。つまり、自分でアプリ内データを信頼できない状況です。
オープンβでは、幻術士 Lv20、全製作クラス Lv15、採掘師と園芸師 Lv15 まで上げ、その範囲でデータを自身で確認しましたが、それ以上については下記サイトで公開されている情報を元にしています。
eLeMeN - FF14
FF14 Tamachang
新生 FF14 ギャザクラ生活
もちろん、上記サイト管理者の方々には多大な敬意を払っていますが、やはり人の手でデータを入力していることから入力ミスがあるでしょう。それらを元に僕がデータを複製するため、アプリ内データにはより多くの入力ミスが発生している可能性があるわけです。データベース作成のための専用アプリケーションを Windows で実装して利用しているので、ある程度のミスは軽減できているとは思うのですが、データ入力はちょっと頭がおかしくなりそうな作業でもあり、ミスはどうしても発生するだろうなぁと。

後は、eLeMeN の製作レシピ データでは、完成時の数量が未記載であるため、ここをどうしようかなと思っている所です。
主に、数量が問題となるのは調理レシピですが、今は完成時数量 1 で入力してあります。単にレシピを検索するだけならば、完成時の数量はどうでも良いのですが、アプリで実装した原価計算機能を考えると無視できず、困っている所です。

現状、全レシピを確認できるのはレガシー先輩の一部だけだと思うので、どうしたものですかねぇ・・・。






2013/08/05

FF14 製作支援ツールを開発中

FF14 の製作支援ツールを Android で作っています。ひとまず、製作レシピ、採集場所、各アイテムの販売場所の参照など、基礎部分の実装を終え、データを打ち込んで大雑把にテストを終えた所です。

記念撮影として、画面の雰囲気を以下に貼ってみます。


レベル帯からの製作選択
材料確認
販売品確認

仮想デバイスでのキャプチャなのでチープ感が漂っていますが、実機ではもう少しマシです・・・多分。
基本的には、製作活動の「支援」に特化して設計しています。データの全てを網羅する気はないと言いますか。後は、各アイテムのアイコンを揃えたりなどの、作業量的に無理な部分は諦めています。

技術的な全体像としては、制作関連データは SQLite でデータベース化、Android アプリ側でデータベースを参照して表示、データベースは Windows アプリケーションで構築、という感じです。Windows アプリケーションとして実装したデータベース メンテナンス画面からデータを投入し、Android アプリのアセットへデータベースをそのまま配備し、アプリ起動時に Android 仕様のデータベース位置へ複製という流れですね。メンテナンス アプリケーションは C# WPF で実装しています。
メンテナンス アプリケーションは、下図のような感じです。

製作管理
商品管理

参照系機能の実装が完了しただけであり、これから自分が必要とするプラスアルファの機能を実装することになります。オープン β 中に、ゲームをプレイしながら使いやすさの改善を試みたいので、それまでにプラスアルファの機能の実装を終えてしまいたい所です。まぁ、今はまだ例外で落ちたりするので、デバッグがまだまだ不十分なのですが。

せっかく実装したので、適当なタイミングでストアへ公開するとは思いますが、多くの人には使えないアプリだろうと思っています。僕が FF14 に張り付いてデータのバージョン アップに対応することはできないので、アプリ内データを最新へ保つことが難しいわけで。そもそも僕は飽き症で、そう長くは FF14 をプレイしないであろう事も問題です。

まぁ、おいおい考えていこうかと思っています。

2013/07/16

FF14 新生 β3 が終わった

FF14 新生 β3 テスト、満喫しました。楽しすぎてたまらんという感じです。そもそも、楽しくなければ β テストも機能しないでしょう。

リミットブレイク最高


戦闘職は幻術士をメインとして上げ、公開範囲のシナリオは幻術士で終えましたが、その他もそれなりにレベルを上げ、インスタンスダンジョンの周回は格闘士で参加していました。

格闘士のリミットブレイク、最高ですね!発動直後の気を溜めてる瞬間がたまらんです。僕同様の厨二病患者には、格闘士がオススメです。

F.A.T.E. をソロる


明け方の人の少ない時間帯を狙って、ボス級の幾つかをソロってみました。厳密には、倒す少し前までには援軍が来てくれるので、最後までソロでいた試しは無いですが。まぁ、人口が少ない時にどの程度遊べるかを試すのも重要かなぁと思います。

剣術士と格闘士は普通にガチれました。雑魚が大量に絡んでくる F.A.T.E. は流石に無理。この 2 つでやれるならば、斧術士は可能でしょうし、槍術士もやれそうですよね。まぁ、何度か同じ試みをしている人を見かけました。

試した F.A.T.E. は Lv.20 以下で、より上位では違うのかもしれません。防御力の差が徐々に顕著になりそうですし。
いずれにせよ、程良いバランスだと感じました。フォーラムでは少人数の場合にキツいとのフィードバックが挙がっていましたが、僕はこのバランスが良いなぁ・・・。

クラフター&ギャザラー


クラフターを全職 Lv.20 付近まで試してみました。品質を上げると取得経験値 300%、ギルドリーブなどでも HQ 納品で報酬 300% となるため、これを狙うためにアクションを駆使して確率を上げ、品質上昇行為の回数を上げるなどが楽しいです。
頭を働かせて有利にする、そんな感じですね。Lv.15 で得られるアクションを職をまたいで活用すると、更に面白くなってくるという感じでした。

ギャザラーも 2 職、Lv.20 超えにしてみました。マッタリ感が僕には良かったですが、嫌な人は嫌でしょうねぇこれ。

絶賛もできない


僕にはゲームパッド操作と UI が大きな不満でした。まぁ、MMO で満足できる UI を見たことが無いですけども。MMO の UI って、他のジャンルと比較して独特ですよね。

僕は PC 版ですがゲームパッド派です。徐々に MMO を敬遠し始める事となった理由の一つに、ゲームパッドの問題がありました。ゲームパッド操作のデキは PS3 版の評価に関係するはずなので、更に使いやすくなるであろうと期待しています。

2013/07/08

Android アプリ開発に手を出してみる

思う所があり、Android アプリ開発環境を整えて、少しずつ弄っています。

で、早速詰まっていました。僕は Sony Ericsson Xperia acro SO-02C を使用しているのですが、どうにも ADB が Xperia を認識してくれません(環境は Windows 7 64-bit)。
正確には、adb devices でリストには載りますが、状態が offline のままであり、コマンドを受け付けない状態です。ネットで調べて片っ端から解決策を試してみましたが、どうにもなりません。

そこで、軽く発狂しかけたので、他の手段を講じた所です。

基本的には、プロジェクトのビルドで生成される .apk ファイルを Android 端末に配置できれば実行できるようなので、Web から Android 端末へ .apk ファイルをダウンロードさせる手順としました。
そのためには Web 上のどこかに .apk ファイルを置けば良いので、愛用している Google Drive に配置することにしました。

手順は至極単純で、自分の Google Drive へ .apk ファイルをアップロードし、Android 端末の Google Drive アプリでファイルをクリックしてインストールするだけです。
.apk ファイルの変更を反映させる場合には、Google Drive 上で既存の .apk ファイルの右クリック メニューから [変更内容を管理...] > [新しい版をアップロード] により、ファイルを上書きできます。

基本的には AVD でテストを繰り返し、AVD だけでは確認が甘くなる部分についてのみ実機確認という流れになると考えれば、Google Drive 経由であることが大きな作業負荷にはなることはないかなぁと。

2013/07/01

ブロック地形 SharpDX 版進捗

基本の移植は概ね終わったという感じです。合わせて、SharpDX 用自作フレームワークで作成した各種機能を強引に適用し、フレームワークのデバッグを同時に行なっているという感じです。やはり、単純なサンプル実装では現れないバグがチラホラと出てきますね。

下図、記念撮影。



上図シーンは、Deferred Rendering、PSSM によるシャドウ マップ分割、環境光閉塞、被写界深度、ポストプロセスによる線形フォグ、といった感じです。

この状態で 60 FPS を維持できなくなりました。デバッグ ビルドで 40-50 FPS くらいですね。シャドウ マッピングと環境光閉塞を適用しない、あるいは、チャンク描画範囲をもう少し狭めれば、60 FPS を維持できるのですが、なるべく負荷の高い状態で実装する方が、チューニングについて学ぶことも多いような気がしています。
分かる範囲でも、投影オブジェクトの選別ロジックを大雑把にしていること、オクルージョン カリングを大雑把にしていることなど、問題は多々あります。速度の問題以外にも、期待する影を描画できていない問題もありますが。

期待していたよりも十分な速度を維持しているので、ひとまず自作フレームワークをそのまま使い、品質を上げていく気分になりました。とても大変ですが、自分のコードならば、誤りがあった場合でも原因の特定と修正が容易であるという利点がありますからね。

でまぁ、Minecraft 風地形の実装はここで終わりにし、その実装を通じて本来やってみたかった実装の方法が見えてきたので、そちらに移行しようかなぁ・・・などと考えています。

2013/06/28

Borderlands 2: ゲイジ三周目 DLC4 ソロ クリア

DLC4 が出たので、久々にゲイジ Lv 61 で三周目 DLC4 をプレイしてみました。

雑魚はスラグ SMG と Infinity、クリスタル&魔術師系は Nukem で即座に始末、ボスは Infinity という感じで進めていました。リロードが遅くてイライラするので、いつもロケランは無視していましたが・・・便利な武器だったんですねぇ。

異常に硬い雑魚(レベルの高い雑魚)がいる場合、無限湧き(?)と思われる場所などは、デストラップを置いてスルーしていました。ラスボス エリアも、雑魚を無視してラスボス エリアに突入しました。ドラゴン三体などやる気がしません。
総じて、空を飛ぶ敵が厄介ですね。僕は Infinity で大体の位置へ狙いを定めてトリガーを引いていただけですが、他の武器では残弾が気になり、そう大雑把にもできないよなぁと。

ボス系は、ラスボス以外は苦労することなく進められましたが、まともにやるとドラゴン戦も面倒そうな感じがします。

ドラゴン戦は、橋の奥で戦っていると若干安全のようで(ドラゴンの火球は当たる)、そこから適当に 撃っていたら終わったという感じです。ただ、あまり奥に長く隠れていると、ドラゴンが遠くへ飛んでいった後にライフを全快して戻ってきたので、攻撃を受けない距離の場合には前に出て攻撃していました。

ラスボスは、デストラップ主体で攻撃、クールダウン中はステージをぐるぐるマラソンという戦法でやっていました。
途中で死んでしまったこともあり、召喚されたドラゴンは、復活地点からおびき出して始末しました。復活地点では階段の裏が安地になるため、隠れつつ顔を出しつつ撃つだけです。
ラスボス ステージから飛び降りると階下へ降りられるでの、ドラゴンを召喚されたら一度降り、ドラゴンを始末してから改めてラスボスに挑むと楽かもしれないですね。階下へ降りるとラスボスのライフが全快しますが、ボス級二体を同時にやるよりはマシな気がします。

ドラゴンを始末した後は、ラスボス ステージへ戻り、地道に削ったという感じです。やけに硬かったですねぇ・・・。まぁ、ソロでは仕方のない事という気もします。

2013/06/25

ブロック地形実装を XNA から SharpDX へ移植中

SharpDX ベースの自作フレームワークのために作成したサンプル アプリケーションも問題なく稼働しているように思えたので、XNA で実装したブロック地形プログラムを自作フレームワークへ移植しています。
自作フレームワークは XNA 非互換、および、シェーダ モデル 5.0 が基本である事から、移植作業に難儀していますが、概ね移植を終えて稼働し始めた所です。

まともに稼働し始めて気になる点が、やけに処理が早いという点です。本来ならば喜ぶべき事ですが、納得できる理由が分からないため、逆に怖いという感じです。

少なくとも、XNA 公式のインスタンシング サンプルを自作フレームワークに移植した時に、自作フレームワークは XNA よりも低速である事を、FPS の数値として自分で認識しています。しかし、ブロック地形実装では明らかに XNA よりも高速です。

DirectX 11 では GPU が上手いことやってくれているんですかねぇ・・・。

2013/06/19

Borderlands 2: ゼロ三周目ソロ保護区・・・終わった・・・

ゼロ三周目ソロ保護区を終えました。ブラッドウィングへ到達するまでが辛すぎですよ・・・。

ブラッドウィング戦は、以下のように戦いました。
まず、装備。
  • スラグの Maliwan 製スナイパー ライフル(面倒だからスラグというだけです)
  • リチャージ遅延とリチャージ率の良いシールド
  • Legendary Hunter
  • スナイパー ライフル携行数アップのレリック(クールダウン速度アップの方が良かったかも)
  • ライフ回復系炎グレネード(回復ついでに Skag を倒すために炎)
瀕死状態が頻発するため、迅速にシールドが回復するようにし、レジェンダリ MOD でライフ回復とクールダウン速度を補ってみたという所です。保護区移動中に Legendary Loot Midget から偶然 Legendary Hunter を得たことが幸運でした。もし得ていなかったならば、ライフ回復のために MOD を Survivor にし、レリックをクールダウン速度アップにしていたと思います。

スキルは、スナイピングとカニングからスナイパー向きのスキルを選択していますが、最重要はインナーベイト、他にはヘッドショットとベロシティ辺りが重要かな?と思っています。いずれにせよ、ブラッドウィング戦のためのビルドではなく、ずっと同じビルドで進行しています。

次に、行動。
  • ブラッドウィングが去っていく所から向かってくる所まで射撃
  • 急降下が来るあたりで(可能ならば)デセプションで回避
  • 急降下で瀕死になったらクールダウンを待ってデセプションでライフ回復
  • 地上に降りてきた時はデセプションしてクリティカル狙い
  • 炎雷酸で Skag が強化されている間は回避優先(ブラッドウィングよりも危険)
  • セカンドウィンドは期待しない
つまり、ただ逃げながら撃って倒しただけです・・・。再戦したら勝てるかどうか怪しいですね。

Skag を丁寧に掃除していると、そのうち登場しなくなるので(ブラッドウィングがエレメントを変えると再登場)、Skag 殲滅を優先しても良いのかも?と、終わってから思ったりもしています。ブラッドウィング単体ならば難しくないですからね。

ネットを検索すると、「デセプションからロケット ランチャーで攻撃していれば楽に倒せる」との情報を得たので最初に試しましたが、火力不足で弾切れになった上に死んでしまいました。まぁ、普段、ロケランを使わないので、イマイチよくわかりません。いずれにせよ、ある程度攻撃してから死んでしまうと、特殊なシールドを持参しない限りはロケラン弾の補充が難しいため、リトライが厳しいですね。

ひとまず難所を越えましたが、どうにもゼロだけ三周目を楽しめません。「楽しめていないのに進行させる必要あるの?」と思いながらプレイしています。
二周目は Jakobs 製スナイパー ライフルを携帯し、ヘッドショット一発で雑魚を倒しまくれて楽しかったのですが。Jakobs 製スナイパー ライフルは、あの撃つたびにガチャガチャやってる感じが良いですよね。

2013/06/16

FF14 新生 β に参加していた

金土日と、新生エオルゼア β テストに PC 版で参加していましたが、期待以上であり、三日間ハマっていました。

特に面白かったシステムは、F.A.T.E. (Full Active Time Event) ですね。
FF14 Wiki - Full Active Time Event
FF 11 で喩えるならば、カンパニエバトル、ビシージ、護衛クエストなどを統一化し、任意の PC で束縛なく進行できるようにしたイベント システム、といった所ですか。
言葉を交わさずとも、各 PC が状況から役割を判断して行動し、クリアする、その一体感は最高です。エリアに人が集まらず、少人数で挑むハメになった場合、特にこれは顕著となり面白さが増します。短時間で終わる点も魅力的ですね。

しかし、β 参加者は MMORPG 経験者が多く、攻略上のあるべき振る舞いを自然と行なっているのでしょう。公式サービス開始直後は、こう上手くはいかず、どこまで楽しめるかは分からないですね。まぁ、それはプレイヤ側の問題ですが。

細かい不具合よりも、システムの基本が面白さを提供し得るか否かが重要で、旧 14 では β 段階で既にそれが皆無であった、新 14 にはそれがあると思える、そんな印象です。

2013/06/09

Borderlands 2: アクストン三周目本編ソロを終える

アクストンも三周目本編を終えました。今まで使ったキャラと比べると、飛び抜けて楽でしたねぇ・・・。

ビルドは、スラグを撒くのがダルいのでゲリラ ツリーからダブル アップまで、チキン野朗として戦いたいのでガンパウダー ツリーからロングボウ タレットまで、サバイバル ツリーはプリパレイションのみ、余ったポイントは適当にゲリラとガンパウダーに振ってました。

銃とグレネードはレベルが上がる毎にリバマラでそこそこ整えていましたが、シールドは適当なままでした。他キャラで The Bee を所持しているので、これを装備して進めたらもっと楽だったかな?という気もしますが、無くても十分に強いですよね。タレットが本体なので、MOD とレリックにはクールダウン速度+ をずっと付けていました。

今まで三周目をやった所、二周目クリアで Lv 50、ほぼサイドミッション放置の三周目クリアで Lv 57 という感じですね。DLC 1 をやると約 Lv+1 なので 、やらなければ Lv 55-56 でしょうか。

残りはサルバドールとゼロですが、苦手なゼロの二周目から始めてみました。ゼロの三周目は何かヤバそうな・・・ブラッドウィング戦で詰む予感がしています。

2013/06/07

Borderlands 2: 二周目や三周目本編ソロで自分がやっていること

ゲイジ、マヤ(ボス前放置)、クリーグと三周目本編ソロを終え、今は、初見時に選んだアクストンで三周目保護区ソロを終えた所です。初見時は特に強いキャラではないと思っていたのですが、改めて操作すると異常に強いですねぇ・・・(タレットが)。ブラッドウィング戦もヌルゲーと化していました。

以下、自分が二周目三周目本編ソロでやっていることを纏めておきます。ソロプレイヤの多くが行なっていそうなことではありますが。

1. 最初に DLC1 をクリアする(三周目の場合)

リバマラのためにクリアします。余計なことをしなければ、二時間半程で終わります。Sand Hawk に拘るならばクリアできない事になりますが、僕は要りません。
適度にリバマラで武器を揃えます。次に行うミッションを見据え、主力武器がそこそこ揃えば終わらせています(30 分やるかどうか)。

2. 戦わずにスルーする

殲滅がダルイので、可能ならばスルーしています。

3. スラグ武器を一つ持参する(三周目の場合)

二周目はそこまで硬くも無いですが、三周目はスラグが無いとちょっと硬すぎるかなぁと。
アクストンでは、タレットがスラグをばら撒いてくれるので持参していません。クリーグでも、それ程にはスラグを撒いていなかったような・・・。

4. 自販機前の敵はグレネードをばら撒いて倒す

投げる、購入、投げる、購入。

5. グレネードを積極的にばら撒きながら進む

残弾数が少ない程に敵からのドロップ率と箱からの出現率が上昇するため、常にグレネードをばら撒いて残ゼロ付近にしています。また、ばら撒いている間は、箱を開けずに残しています。
殲滅が一段落し、残数がほぼゼロならば、箱を開けながら出現したグレネードを数えつつ進行逆方向へ戻り、適当な所で拾いながら元の位置まで戻っています。満タンにする必要もないですし。
自販機へ戻る方が早い場合は、とっとと自販機まで戻っています。

6. 炎雷酸のホーミング範囲攻撃型グレネードを常備する

グレネードばら撒きで最も効率の良い型が、ホーミングかつ範囲攻撃型であると感じています。敵が勝手に範囲内に突っ込んでくれますし。COOP では味方を巻き込んで怒られるんですかね?
この型の三属性を常備し、状況に応じて装備変更しながらばら撒いています。装備変更は面倒ですが、闇雲に投げるよりも効率が良いかなぁと。

7. Rabid 系が出たらボス以上であると認識する

ボスよりも Rabid 系雑魚の方がヤバイ。開発者は頭がサイコ。

2013/06/02

Deferred Shadow Mapping を実装していた

Deferred Rendering によるシャドウ マッピングのための機能を、自作フレームワークに実装していました。ただし、MRT は使っていませんし、Deferred Rendering のための綺麗な枠組みも作っていません。ポストプロセスについては一つの枠組みを実装してあるので、これに乗せて動かしているという感じです。

以下、記念撮影です。まず、シーンの深度マップ。

深度マップ

続いて、シャドウ マップを書き込んだ閉塞マップ。

閉塞マップ

閉塞マップと呼ぶべきか否か、専門的な名称が分かりませんが、シャドウ マップから得られる深度と、シーンの深度マップから再構築した座標から得られる深度を比較し、ライトが遮られているか否か、すなわち、影があるか否かを描画したシーンです。生成されるテクスチャは SSAO で生成する閉塞マップと同じであるため、関連する機能の一部を共通化して閉塞マップと呼んでいます。

最後に、影を合成した最終シーン。

最終シーン

シャドウ マップ サイズ 1024x1024、PSSM 分割数 3、一般的なライト カメラを使用、PCF 7x7 適用です。

PCF は過去に実装済みでしたが、モデル描画のためのシェーダに実装すると、関連するシェーダの至る所で冗長に記述することになるため、先のシャドウ マッピングの実装では避けていました。今回は、閉塞マップ描画シェーダにのみ記述すれば済むため、あらためて再実装したという所です。

今回の実装は、それ程には難しいものではなかったはずですが、本筋とは関係ない所で長時間ハマってました。定数バッファへ渡す C# 側構造体のレイアウトを誤り、これに気付かずにハマり続けるという失敗を、これまで何度も繰り返しています・・・。

2013/06/01

簡単な雲を実装

過去行った実装に雲エフェクトがあったので、これも自作フレームワークへ移植していました。しかし、どうやらこれも何かの理由で破棄し、面倒な事にシェーダ コードしか残されていないという有様。元ネタも記録されておらず推測から再実装してみましたが、期待する効果を得られなかったので、結局、一から考えなおして作っていました。

実装の流れは極めて簡単なもので、以下のような手順で行いました。

1. 雲の体積マップ(R 値のみ)をノイズで複数枚生成
2. 各体積マップをテクスチャ座標をずらしながら参照
3. 各体積に密度を掛けつつ合成して色を決定

以下、スクリーン ショットです。

雲エフェクト

極めてチープ感が漂っていますが、「質を問わないので雲が欲しい」という場合に、僕としてはこれで良いかなと。完全な平面へエフェクトを適用しているため、チープ感が増しているのだとは思いますが、曲がった平面のための頂点データを自動作成することが面倒だったので、今はこれで良いかという感じです。

雲の体積マップと呼んでいるものは、雲の高さ、あるいは、雲の密度として置き換えて考えても良い気がします。実際、ハイトマップを生成する手順と同じ手順で体積マップを生成していますし。
ノイズの種類としては、Billow 型フラクタルが雲の雰囲気を出すと良く言われ、実際に雲と見做せる形状でノイズが生成されるものの、僕が作成したエフェクトでの合成には不向きのようで、結局は SumFractal で生成しました。ただし、雲の密度を下げ、塊となった雲を幾つか出すような状況では Billow の方が適していた感じもするので、状況に応じてノイズを調整する事になるのであろうと思います。
何にせよ、ノイズ生成ライブラリを自作したのは本当に良かったですね。簡単に試せる状態は非常に便利です。

で、作成した水面エフェクトへ反射させてみたいという理由も含めて実装したので、反射させてみました。

雲の反射

水面で反射していますが、ほぼ見えず、期待した感じではありません。反射は、水面の法線と視線が垂直に近くなるほどに強くなると思うので、視点付近の水面では雲が弱く映り、遠方で強く映る状態は正しいのだと思いますが・・・もう少し映り込む状態を正直期待していました。そもそも、雲自体の色が薄いので、しょうがない気もします。あるいは、水面に適用する水の色が駄目なんですかねぇ・・・。

強引に調整できそうではあるものの、拘ると時間が掛かりそうなので、今はこれで良いとしました。色と輪郭が明確なオブジェクトの反射は期待した通りに反射されていますし。

Borderlands 2: クリーグ三周目本編ソロを終える

ぴぃ~っかぴかの、い~っちもつぅ~♪(意味深)

クリーグをコツコツと進め、本編三周目をソロで終えました。

ネタキャラかと思いましたが、プレイしてみると非常に面白いキャラですね。レイビング レトリビューションを覚えると、中二病全開ポエムを聞けるのでオススメです。

僕はヘルボーンに偏ったビルドで、マニアのリリース ザ ビーストは取らずに進めましたが、ライト ザ フューズは取得し、セカンド ウィンド用にしていました。三周目ブラッド ウィング戦は、急降下回避に失敗したらスキャッグへ自爆して立て直し、という流れでサクッといけました。なにより、『導火線に火を付けろ!』の表示が燃えてきて良いじゃないですか。

てめぇらまとめて⊂二二二( ^ω^)二⊃ブーン

ヘルボーン ツリーしか分かりませんが、Wiki のクラス解説にあるように、総じて、クリーグのペースにハメられる場合は「俺様 Tsueeeeee!!!」、そうではない場合は「調子に乗って済みませんでしたー!!」という感じですね。巨人に屈服したサシャのように。

ヘルボーン中心では自身の着火状態維持が重要ですが、維持を続けるとなるとシールドはゼロ、ライフは常時減少状態が普通になります。このため、敵をエレメント効果状態にし、エレメンタル エンパシーでライフを回復し続ける流れが必要になります。
この流れにある限りは、他キャラならば引くべき状況でも死ぬことはなく戦い続けられると言いますか、突っ込まないとヘルボーンの意味が無いと言いますか。
逆に、この流れを作れない状態に陥る(作ることに失敗する)と、ヘルボーンの利点が全て失われて雑魚に成り果てるという感じです。

2013/05/30

ポストプロセスでフォグ

水面シェーダにフォグ処理を追加しておこうと試み始めたのですが、それをやり始めると、モデル描画に使用する他の様々なシェーダにおいてもフォグ処理を記述しなければならない状況に陥ります。これは嫌だなぁと。フォグの ON/OFF なども考慮すると、更にコードが汚くなるわけで。

そこで、ポストプロセスによるフォグを実装していました。検索してみると「今時はフォグもポストプロセスですよ」などと書いている海外の人もいましたが、素人の僕には実際がどうなのかは分かりません。

ボリューム フォグは既に実装していたので、線形フォグ、指数フォグ、高さフォグを実装していました。基本は、ポストプロセスのピクセル シェーダにて線形深度マップを参照し、深度からビュー空間における位置を再構築して利用する流れです。ただし、高さフォグでは、ワールド空間における y 値が必要となるため、更に逆ビュー行列を掛けて情報を得ています。

ポストプロセスならば簡単に処理を ON/OFF できるので、各フォグを組み合わせて遊んでみましたが、組み合わせる事により意外な味が出るものですね。

2013/05/29

水面描画、記念撮影。

水面描画への再挑戦ですが、何とか想定した実装になった所です。以下、記念撮影です。


一応、テクスチャ座標を時間でずらして水の流れを起こしていますが、静止画では分かるわけがないですね。
法線マップを手作業で作成することは嫌いであるため、Perlin noise  で生成しています。実装前にはノイズ設定が難しいであろうと想像していたのですが、単純に SumFractal で合成しただけでそれらしくなりました。
ノイズからの法線マップの作成は、ノイズで波を表すハイトマップを作成し、ハイトマップから勾配を算出して法線を構築するという手順です。なお、作成した法線マップはシームレス テクスチャとして自動生成しているので、アドレス モードを Wrap にして貼り付けています。


上図は少し角度を付けてみた状態です。水面は任意の面に描画できるようにしています。
波の影響を大きくしているため見辛いですが、屈折と反射を実装しています。反射の度合いには、Schlick の近似によるフレネルの式 を用いています。
ネット上では、フレネルの式から得られる値を係数として、反射と屈折を線形補間した値を水面の色としているサンプルを多く見かけましたが、僕は反射にのみ適用しています。屈折に関しては、視点から一定の距離が離れる程に、および、視線が水面に並行になる程に減衰するような仕組みにしています。この基本形は、GPU Gems 2 - Chapter 19. Generic Refraction Simulation に従っています。


水面を垂直にしてみると上図のような感じです。だから何だという話ですが。


上図は、書籍『ゲーム エフェクト マニアックス』に掲載されていた波生成の実装です。これは、アプリケーションからテクスチャ上に波紋を発生させて法線マップを作る実装です。JoJo ファンにはたまらない実装ですね。

と、何とか形になったなぁと。

ただ、テストをしていると定期的かつ瞬間的に描画がカクつく現象が起こっていて、フレームワーク側の問題であることが明らかであり、厄介な事になってきたなぁと感じている所です。実際にはとうに気付いていたんですが、見ないふりをしていた所があり、このまま見ないふりを続けるかもしれません。

どうにもならなければ、XNA に戻るだけです。

2013/05/27

水面描画への再挑戦

過去のブロック地形動画の際に、海や湖を表現するために水面のエフェクトを組んでいたのですが、これを汎用化して自作 SharpDX フレームワークに載せようと試みていました。基本的には、波を表すための法線マップを事前にテクスチャとして用意するという方法が嫌いなため、自動生成して利用する枠組みにしています。

過去の実装から思い出していたのですが、元は反射と屈折を考慮した水面を実装していたにも関わらず、何かの理由で反射と屈折を止めた記憶があるなぁ・・・と。

屈折効果に用いる水中シーンを描画するために、GraphicsDevice.ClipPlanes の設定により水面より上をクリップするという XNA のチュートリアル サイトの情報があり、過去の自分はこれを参考に実装したと思われますが、この機能は XNA 4.0 で失われています。恐らく、僕は移行方法が分からずに諦めたのではないかと。

XNA 4.0 における対応としては、クリップ面をシェーダへ渡し、頂点からクリップ面までの距離を算出し、clip 関数を用いて距離が 0 以下 (頂点がクリップ面の裏側) ならばピクセル シェーダの出力を抑制してしまう方法かと思います。
シェーダ モデル 4.0 以上ならば、算出した距離を SV_ClipDistance セマンティクスでピクセル シェーダへ渡せば自動的にクリップしてもらえるようなので、自作フレームワークではこれを利用しました。

他には、頂点シェーダの属性として [clipplanes] でクリップ面を指定すると、SV_ClipDistance に関わるコードを書かずに済むらしいのですが、これは使わない事にしました。僕は、シェーダのコンパイル時警告をエラーとして扱っていますが、clipplanes を指定するとクリッピングに関する頂点シェーダ出力の初期化が完全ではないとの警告が出てしまい、これを解決する術が分からずに断念しました。どうにも、clipplanes 属性の利用に関する情報が少なすぎて。

ひとまず、一般的な水の表現は実装できましたが、水が XZ 平面上にある必要もないと思い、自由に回転させた平面に水面エフェクトを適用しようと試みている所です。

とまぁ、気付いたらまた壮大に脱線し始めたと思うものの、どこかの時点で自身の知識の整理はすべきであり、なおかつ、更に一歩進むべきとの思いもあり。

2013/05/25

新生 FF 14 ベンチマークを実行してみた

友達から「FF 14 の発売日が決まったよ。忘れずに買えよ。」とのメールがまわって来たので、新生 FF14 の状況を調べてまわり、ベンチマークが公開されていたので実行してみました。
FF XIV: 新生エオルゼア ベンチマーク ワールド編
結果:
標準品質プリセット - 125 fps
最高品質プリセット - 60 fps 
PC は、GeForce GTX 560、i7-2600 CPU 3.40GHz、メモリ 8 GB です。

最高品質は確かに綺麗でしたが、標準品質で十分と感じました。標準品質ならば、PC には相当余力があると言えますね。

一応、FF 11 は初期組で解約と再開を繰り返して数年、旧 FF14 は半月程プレイしましたが、雰囲気について、新生 FF 14 は FF 11 の正統進化という印象を受けました。この感じは好きです。

2013/05/20

SSAO に再挑戦していた

数年前に SSAO (Screen Space Ambient Occlusion) を実装しましたが、自身の実装と解釈に誤りがあると認識しつつも放置したので、SharpDX ベースの自作フレームワークに入れるために、再度、納得できる質まで改善していました。

数年前に参考にした実装は下記サイトであり、今回もこれをベースにしました。
Game Rendering - SSAO: http://www.gamerendering.com/2009/01/14/ssao/
大まかな処理の流れは、Ray Marching Ambient Occlusion を基礎とし、法線による平面間に対する判定を除去しているのだと思います (実装上は法線差による閉塞度に対する重み付けの調整)。

今回は、上記サイトの実装をベースにしつつ、深度を線形深度マップ (Linear depth map) へ置き換え、線形深度からビュー空間座標を再構築して判定するような実装を組んでいました。その他、シェーダ内でハードコードされた球面内サンプル点や、テクスチャ ファイルとして用意しているランダム法線マップをなどを C# 側で生成してシェーダへ渡したりしています。

相変わらず、テストに使用しているシーンが簡素過ぎますが、以下、ひとまずは納得できた結果の画像です。
ブラー前 SSAO マップ
ブラー後 SSAO マップ
SSAO 適用シーン
レイによるサンプル数を 8 として SSAO マップを生成しています。生成された SSAO マップへのブラーでは、バイラテラル フィルタの変形バージョンを 3 回適用しています。1 回の適用でもそれなりですが、3 回程適用すると十分な綺麗さが出る感じがします。なお、単純に色の差異でバイラテラル フィルタを適用すると期待するブラーにはならないので、深度マップを参照して深度の差異で重みを変化させています。加えて、法線の差異でも重み付けを変化させているため、厳密にはバイラテラルではないのだろうと思います。法線を考慮せずとも十分なブラーを得られますが、法線差異を制御するための標準偏差を色々と変化させてみると微妙な調整ができるので、これで良いとしています。

負荷を下げるために SSAO マップのサイズを小さくし、シーンと合成する前にアップサンプリングしてみたりなどもしましたが、単純なアップサンプリングではシーンとの合成時に解像度の差異から汚くなる部分が出てくるため、少し考慮が必要なのだろうと感じています。
追記: と思っていたら、どうも僕のダウンサンプリング実装に誤りがあり、修正して適用してみると、悪くない結果でした。3D グラフィックスは、僅かな値の差ではそれなりに稼働してしまうので、デバッグが怖いですね。
何にせよ、納得できる所まで持ってこれて、心底安心できました。

2013/05/12

長らく Bordelands 2 プレイ中

積んでいた Borderlands 2 を 2 月頃からやっているのですが、未だに飽きません。始めた頃は、初代と違いがないように感じたので、早々に飽きるだろうと思いながら進めていたのですが、気付いたらハマっていました。COOP はやらず、常時ソロです。

ゲイジで三周目をクリアし、今はマヤで三周目保護区をクリアした所です。三度、無策で挑み、あっさりと雑魚に追い込まれて絶望したので、用いた攻略方法を記載しておきます。

検索してみると、フリート (スキル) と The Rough Rider (シールド) で攻略した人を見つけることができ、真似てみたら楽に攻略できました。フリートと The Rough Rider の組み合わせで常に移動速度上昇状態にし、高速移動により回避を楽にして戦うという方法です (僕はクラス MOD 含めてフリート 10 でやりました)。

高速移動により、雑魚や地上に降りたブラッドウィングを簡単に振りきれるので、ブラッドウィングの急降下の回避に集中する感じです。急降下回避に自信が無い場合は、適度に雑魚のライフを削っておき、フェーズロックでの回復やセカンドウィンドに備えておけば安全かもしれません。

2013/05/10

Volumetric Light Scattering に再挑戦していた

数年前に公開したブロック地形動画では Volumetric Light Scattering (God Ray、Crepuscular Ray) を実装していましたが、当時はまだ理解できていなかった部分があったため、再実装していました。あれから新たについた知識を元に実装すれば、また新たな側面が見えてくるであろうと考えて。

Volumetric Light Scattering については以下に説明があります。
NVIDIA GPU Gems 3 - Chapter 13. Volumetric Light Scattering as a Post-Process
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch13.html
Volumetric Light Scattering は日本語で何と言うのでしょうか。端的には光芒だとは思いますが。Scatter は散乱なのでしょうか。特に、Volumetric の適切な訳がいつも分かりません。

今回の実装では、ライト閉塞マップを作成し、ライト閉塞マップに対して Volumetric Light Scattering シェーダを適用してライト散乱マップを作成し、ライト散乱マップと通常シーンを加算混合するという手順でシーンを生成しています。
Volumetric Light Scattering 効果なし
Volumetric Light Scattering 効果あり
スカイ スフィアを描画し (方向性光源の方向が示す箇所に太陽をシェーダで描画)、後は立方体を適用に並べています。ライト閉塞マップやライト散乱マップを黒色をベースに生成していますが、これは最後に通常シーンと加算混合するためです。

シーンの選択に問題がある気はしますが、一応、実装は上手くいったようであると感じています。

今回は、SharpDX での自作フレームワーク上で実装しているので、ソースは公開しません。と言っても、GitHub 上でリポジトリが公開状態ではありますが (Libra リポジトリに含まれています)。自作フレームワーク上の実装では SharpDX としてのサンプルにもならないですし、XNA へまた移植するのも疲れるしなぁと。

XNA 上でのサンプルとしては、下記サイトが良いと思います (ソースコードも公開されています)。
XNA-UK: Randomchaos Archivs - 2D Crepuscular (God) Rays
http://xnauk-randomchaosblogarchive.blogspot.co.uk/2012/10/2d-crepuscular-god-rays.html
上記サイトでは 2D アプリケーションとして実装していますが、Volumetric Light Scattering シェーダはテクスチャに対して適用するので、3D でも同じ事です。

他には、ライト閉塞マップに対して Radial Blur を適用してライト放射マップとし、シーンへ混合する方法もあるようです。そもそも、Volumetric Light Scattering シェーダは、ライト関連の調整を行いやすいように Radial Blur を変更した物と見做すこともできるかもしれません。

2013/05/06

XNA PSSM

SharpDX ベースの自作フレームワークで PSSM (Parallel-Split Shadow Maps) 関連のコードを整理したので、これを XNA 実装として公開しておきます。
PSSMDemo
https://github.com/willcraftia/TestXna/tree/20130506/PSSMDemo
ZIP DL はリポジトリから
https://github.com/willcraftia/TestXna/tree/20130506
自作フレームワークからの簡易移植であり、XNA としてコードを綺麗に整理していません。また、TestXna リポジトリには PSSMDemo プロジェクト以外も含まれ、リポジトリの ZIP ダウンロードには関係の無いプロジェクトも含まれます。

PSSMDemo は、先に公開した LiSPSMDemo 同様に、XNA Shadow Mapping サンプルを原型として実装してあります。今回もライトは方向性光源のみです。また、自作フレームワーク側で色々とリファクタリングを行ったので、クラス構造が LiSPSMDemo とは大きく異なります。

なお、ビルドに必要な XNA コンテンツは Git 管理外としているため、別途、XNA 公式サイトより XNA Shadow Mapping をダウンロードし、XNA コンテンツを LiSPSMDemo へコピーしてプロパティを設定する必要があります。
XBOX LIVE indie games - シャドウ シリーズ 1: 基本シャドウ マッピング
http://xbox.create.msdn.com/ja-JP/education/catalog/sample/shadow_mapping_1
PSSM ですが、日本語で纏められたサイトを見つける事ができませんでした。NVIDIA の GPU Gems を参考にしてください。
GPU Gems 3 - Chapter 10. Parallel-Split Shadow Maps on Programmable GPUs
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html
MS の DirectX サンプルなどでは、カスケード シャドウ マップと紹介されています。
簡単に説明すると、カメラの視錐台を分割し、分割された視錐台それぞれについてシャドウ マップを生成し、影付きシーンを描画する際には、描画するオブジェクトの位置から適切なシャドウ マップを選択し、そこから深度を選択するという処理です。
分割された視錐台に対するシャドウ マップの生成では、XNA Shadow Mapping にあるような基礎的なロジックを用いても良いですし、LiSPSM を用いても良いです。
重要な点は、視錐台の分割により、一つのシャドウ マップで対象とするシーンの領域を小さくし、シャドウ マップの品質を向上させる点です。
以下、シャドウ マップを Basic (R 値に深度を書き込んだだけのもの) とし、ライト カメラに LiSPSMLightCameraBuilder (LiSPSM)、UniformLightCameraBuilder (USM)、BasicLightCameraBuilder (Basic ライト: XNA Shadow Mapping とほぼ同じロジック) を用いた比較画像です。いずれも、分割数 3、シャドウ マップ サイズ 2048x2048 (XNA Shadow Mapping と同サイズ) です。
分割3 + LiSPSM ライト + Basic マップ (2048x2048)
分割 3 + USM ライト + Basic マップ (2048x2048)
分割 3 + Basic ライト + Basic マップ (2048x2048)
このように、視錐台分割により、Basic ライトであっても、それなりに綺麗な影を生成できることが分かると思います。

分割数を少なくする程に、分割無しの品質に近づきますが、LiSPSM や USM は分割無しでもそれなりの品質であるため (元より分割無しでの品質向上アルゴリズム)、Basic ライトの場合にのみ大きな影響が表れます。
以下、Basic ライトについての、分割数を変更した場合の比較画像です。
分割 3 + Basic ライト + Basic マップ (2048x2048)
分割 2 + Basic ライト + Basic マップ (2048x2048)
分割 1 + Basic ライト + Basic マップ (2048x2048)
分割 1 は、XNA Shadow Mapping と概ね同等のシャドウ マップ生成です。

以下、Basic ライトについてシャドウ マップ サイズの変化による比較画像です。
分割 3 + Basic ライト + Basic マップ (2048x2048)
分割 3 + Basic ライト + Basic マップ (1024x1024)
分割 3 + Basic ライト + Basic マップ (512x512)
1024x1024 でも、それなりに綺麗かなと僕は感じます。512x512 は流石に厳しいですかね・・・。Basic ライトに加えて VSM を適用すると、更に綺麗な感じにはなりますが、ブラー適用の度合いにより色々と変化するので、比較画像は省略します。なお、VSM を用いる場合、分割数分だけブラーを適用する (負荷が増大する) ことにもなるので、適用すべきか否かについて十分な検討が必要であろうと思われます。例えば、2048x2048 のシャドウ マップに対して VSM のために 3 回のブラーを適用すると、ブラーのカーネル次第ですが、負荷も相当なものになります。

以下、おまけのような物ですが、サンプルでは影の色を C# コード上で変更できるようにしているため、(0, 0.5, 0) に設定した場合の例です。
影への色付け
影を緑色にしたい人は稀だとは思いますが、状況によって影の濃さは異なると思うので、黒をベースにその度合を変えて利用するなども良いかなと感じます。

まぁ、こんな所です。いつまでもシャドウ マッピングに拘っていてはいけないと感じていて、雑に XNA へ移植しています。おかしい点があれば、ご指摘して頂けると幸いです。

2013/04/29

XNA LiSPSM (および VSM)

XNA での LiSPSM (Light Space Perspective Shadow Maps) 実装のサンプルを公開しておきます。
LiSPSMDemo
https://github.com/willcraftia/TestXna/tree/20130429/LiSPSMDemo
ZIP でのダウンロードは以下から (関係ない物も含まれてしまいますが)
https://github.com/willcraftia/TestXna/tree/20130429
XNA Shadow Mapping を原型として LiSPSM の機能を乗せ、それらを切り替えて確認できるようにしてあります。ただし、ライトとしては方向性光源のみを実装し、点光源には対応していません。
なお、ビルドに必要な XNA コンテンツは Git 管理外としているため、別途、XNA 公式サイトより XNA Shadow Mapping をダウンロードし、XNA コンテンツを LiSPSMDemo へコピーしてプロパティを設定する必要があります。
XBOX LIVE indie games - シャドウ シリーズ 1: 基本シャドウ マッピング
http://xbox.create.msdn.com/ja-JP/education/catalog/sample/shadow_mapping_1
LiSPSM 公式サイトにある C++ コード (オリジナル コード) をベースにしていますが、オリジナル コードのままでは問題が幾らかあるため、Ogre の LiSPSM 実装を加えて参考にしています。なお、Ogre では LiSPSMShadowCameraSetup が LiSPSM の実装部分であり、その原型はオリジナル コードです。
Light Space Perspective Shadow Maps
http://www.cg.tuwien.ac.at/research/vr/lispsm/
Ogre
http://www.ogre3d.org/
また、日本語での LiSPSM の解説については Project ASURA を参考にしています。ここでは LiSPSM の仕組みについては述べないため、詳しく知りたい方は Project ASURA の解説を参照すると良いでしょう。
Project ASURA - Light Space Perspective Shadow Maps
http://asura.iaigiri.com/OpenGL/gl59.html
なお、VSM  (Variance Shadow Maps) も合わせて乗せています。
Variance Shadow Maps
http://www.punkuser.net/vsm/
以下、シャドウ マップを VSM とし、LiSPSMLightCamera、FocusedLightCamera、BasicCamera による各ライト カメラでの比較画像です。いずれも、XNA Shadow Mapping で用いられるシャドウ マップ サイズ 2048x2048 です。

LiSPSM + VSM
Focused + VSM
Basic + VSM
LiSPSMLightCamera は、LiSPSM 実装そのものです。FocusedLightCamera は、LiSPSM で用いられる視錐台の歪みに相当する行列を単位行列としたものです。Basic は XNA Shadow Mapping で用いられる基礎的なライト カメラです (実際にはそこから更に不要と判断したコードを除外しています)。

カメラとライトが平行になる状況における補正

カメラとライトが平行に近づくと LiSPSM は大きく品質が劣化しますが、LiSPSMDemo ではそのような場合に n 値に補正を掛け、品質を向上させています。これは、Ogre で実装されている仕組みを参考に、オリジナルの n 算出式の結果に対して適用しています。なお、Ogre では n 算出式が完全自動ではなく、プロパティによる調整を前提に作られているようです (描画するシーンに応じてプロパティを適切に調整する必要があると思います)。

以下、補正 ON と OFF での比較画像です。差異を顕著にするため、VSM ではなく Basic でシャドウ マップを生成しています。
LiSPSM + Basic + 補正 ON
LiSPSM + Basic + 補正 OFF
ここでの補正の仕組みは、カメラとライトの内積の絶対値が、指定の閾値を越える場合に並行であると見做し、並行と見做せる場合に n 値を若干大きくしてしまうという物です。カメラとライトが並行になる場合に発生する品質の劣化は、n が 0 に近づくことで発生するため、0 に近づけさせないようにして解決するという事です。

凸体 B の押し出しに関する問題

方向性光源を用いる場合、凸体 B を構成する際には、表示カメラの視錐台をシーン領域でクリップした後、B の各頂点からライト方向へレイを飛ばし、幾らか B の範囲をライトのある方向へ押し出して領域を拡張する必要があります。
これを行わない場合、投影オブジェクトがカメラの外に出るような状況において、その分だけ影が描画されない問題が発生します。この問題は、例えば、このサンプルにおいては、デュード モデルの影に非常に接近する場合に起こりえます。
オリジナル コードでは、そのようなレイとシーン領域との交点を B へ追加しますが、どうやらレイの始点となる各頂点がシーン領域の縁に存在し、結果として始点が交点となってしまい、交点の意味が無いという状態になってしまいました。もしかすると、凸体 B のクリッピングに誤りがあるのかもしれません。

これに対し、Ogre では、そのようなレイにそって一定の距離 (ライトの遠平面距離) にある点を追加して解決しています。そこで、LiSPSMDemo においても同様の概念で凸体 B を押し出しています。

ただ、実際にはどうなんでしょう?
表示カメラの視錐台をシーン領域でクリップする処理は、シーン領域の一部が視錐台によりクリップされる事も含んでいます。つまり、視錐台の外にある投影オブジェクトは凸体 B の外に出てしまうので、描画範囲から除外されてしまいます。そこで、このような投影オブジェクトを描画範囲に含めるため、凸体 B をライトのある方向へ少し押し出し、最終的なクリッピング領域を広げているのだと思います。ただ、これ自体は、LiSPSM に限らず、一般的にシャドウ マッピングにおいて考えなければならないクリッピング領域の問題であろうかと思います。
最小限必要となる凸体 B の構築を考えた場合、投影オブジェクトで構成される領域を別途管理し、凸体 B へこれを含めるなどの処理を行うべきなのかもしれません。実際、Ogre では投影オブジェクト領域と非投影オブジェクト領域を別途管理し、それらを考慮した領域の結合などを行なっているようです。
ですが、ある範囲に対して投影しうるオブジェクトであるか否かの判定自体が面倒でもあるので、厳密な判定が不要であるならば、一定距離で範囲を広げてしまえば良い気もします。

その他思うこと

Basic でシャドウ マップを作ると、セルフ シャドウが汚いなぁと。VSM でシャドウ マップを作ると、セルフ シャドウは綺麗になるものの、VSM ではモデルと影の関係が変になるんだよなぁと。
LiSPSM + Basic におけるセルフ シャドウ
LiSPSM + VSM におけるセルフ シャドウ
LiSPSM + Basic におけるモデルの足元
LiSPSM + VSM におけるモデルの足元
まぁ、こんな所です。


2013/04/28

LiSPSM にリベンジしていた

数年前、LiSPSM (Light Space Perspective Shadow Maps) の実装を試みたものの、どうにもおかしな振る舞いとなる部分を直せずに利用を断念していましたが、納得していなかったので再挑戦していました。

LiSPSM 公式サイトでは C コードと C++ コードをサンプルとして公開しており、過去の挑戦では C コードを参考にしていましたが、今回は C++ コードを元に実装してみました。実際には、Ogre (オープンソースの 3D グラフィックス エンジン) も参考にしています。Ogre では、LiSPSMShadowCameraSetup クラスが LiSPSM のロジックにあたり、コードの基本はオリジナルと同じです。

で、方向性光源 (directional light) についてのみの実装ですが、何とかまともに動くようになりました。基本はオリジナル コードの模倣ですが、どうもオリジナルのままではカメラを光源の方向へ向けた場合に描画が上手くいかないため、Ogre のコードを真似ました。後は、Ogre では、カメラとライトが概ね平行になる場合に N の算出に補正を掛けていたので、これは良いと思い、形を変えて真似たという所です。

まぁ、自分で納得するか否かの問題で再挑戦しただけであり、恐らく LiSPSM は使わないのですが。僕は PSSM (Parallel Split Shadow Maps) を使う前提としているため、この場合には LiSPSM を用いる必要がそれ程には無いと言いますか。

いずれにせよ、LiSPSM のサンプル コードが少ないことで難儀したので、整理して公開しようと考えています。今の実装は自作 SharpDX ラッパー上の実装であり、サンプル公開として適さないため、XNA コードとして再実装しようかなと。ただ、凸体の構築ロジックではバカスカと新規オブジェクトを生成しているので、これを何とかしてからですかねぇ・・・。

2013/04/01

XNA UI Framework 動画

開発で使用するために作成した UI Framework のデモをニコニコ動画にアップしました。

 

2013/03/28

ベクトルのパック値とレンダ ターゲットでハマる

XNA Particels 3D サンプルと Shadow Mapping サンプルを移植していて、色々とハマりました。

まず、Particels 3D では PackedVector の Short2 を頂点データの一部に利用し、シェーダでは float2 でこれを受け取りますが、同様にした所、どうにも float2 で受け取れませんでした。int2 ならば受け取れます。頂点要素のフォーマット指定に従って、パック値から(バイトの並びから)自動的に float へ展開するものと思っていたのですが、違うのですかね・・・。
パック化の目的は頂点サイズを減らす事にあると思うので、int2 で受け取れるならそれで良いかという事にしてしまいました・・・納得はしていませんが。

続いて、Shadow Mapping はバック バッファ以外のレンダ ターゲットを利用するので、レンダ ターゲット周りの動作確認に良いかと思って移植してみたのですが、光源からの深度を書き込んだレンダ ターゲットがシェーダに渡されない状態にハマっていました。Shadow Mapping サンプルでは左上隅にレンダ ターゲットに書き込まれた深度マップを表示するので、書き込みの成功をこれで確認できるのに、深度マップと合わせてモデルを描画する際に、何故か参照できない(全深度が 0 になっている)状態でした。

結論としては、レンダ ターゲットとして利用しているテクスチャは、レンダ ターゲットとして設定する際には RenderTargetView、シェーダへ渡す際には ShaderResourceView で包んで利用する事になりますが、この両方がアクティブな状態となっている場合、ShaderResourceView で渡している側には 0 埋めされたテクスチャが設定される事が原因でした。MSDN を良く読むと、ID3D11DeviceContext.PSSetShaderResources の Remarks 等に、これを示唆する事が書いてありました。
ShaderResourceView として利用した後に参照を外してやれば良いだけですが、参照の外し忘れで同じ問題にハマるのも怖いので自動解決する方法を模索しましたが、あまり良い方法が思い浮かばないなぁと。
追記:その後、よくよく調べてみると、RenderTargetView を DeviceContext へ設定する際に ShaderResourceView 等の読み取りビューが設定されたスロットが null でリセットされる事が原因でした。素直に書く場合、必要な時に ShaderResourceView を設定するため、仮に null であっても再設定されるコードになるはずですが、僕はラッパークラスで参照をキャッシュするなどしていたため、D3D 内では null であるにも関わらず、ラッパークラスでは null ではないという状態の不整合が発生していたようです。
これらの他に、ハードウェア オクルージョン カリングを使う必要があるので、XNA の OcclusionQuery に相当するクラスを作り、Lens Flare サンプルを移植して試していました。
そろそろ必要な機能が揃い、動作も安定してきましたが、インスタンシングに関する枠組みを作ってみてから、ブロック地形のコードを新たな枠組みの上に乗せてみようかなと思っています。

2013/03/23

XNB モデル データの読み込みと描画まで到達

XNB ファイルを読み込み、自分のモデル クラスへデシリアライズし、描画が可能という所まで来ました。
公式サイトの XNB フォーマットの説明にコード例(C++)も含まれているので、読み込みに関する実装は簡単でしたが、自分が作成した Texture2D クラスのバグと言うか、自分の知識不足のために難儀しました・・・。

ただ、読み込めるデータには制約を設け、例えば、モデルで扱えるエフェクトを BasicEffect に限定したりなどしています。また、今はモデルを読み込みたいだけなので、その他は無視しています。

モデルがデフォルトのまま BasicEffect を用いる場合、BasicEffect へ設定するプロパティが XNB に埋め込まれるだけです。このため、読み込んだプロパティを自作クラスへ設定するだけで済みます。カスタム エフェクトを用いる場合、エフェクトのバイトコード、および、エフェクトに設定するプロパティがディクショナリ形式で埋め込まれます。それらの読み込みは簡単ですが、データの利用には汎用的なエフェクトの枠組みが必要であろうかと思います。XNB はシェーダ モデル 3.0 以下だと思うので、その考慮も大変そうです。

これで、FBX ファイルの読み込みと最適化を XNA コンテンツ プロジェクトに任せてしまい、自分は XNB を利用するだけ、という事が可能になったので、テスト コードやデバッグ コードの記述が随分と楽になるんじゃないかなぁと。

ただ、こうなると、「SpriteFont もコンテンツ プロジェクトで管理して XNB から読み込めばいいんじゃないの?」・・・みたいな。自分で専用コードを実装してしまいましたが、破棄しようかなぁ~と。

2013/03/20

非 XNA プロジェクトから XNA コンテンツ プロジェクトを参照する

Assimp を利用するという事は、参照アセンブリを増やす事であり、ならばそれが XNA のアセンブリでも良いのではと考え始め、試行錯誤していました。X ファイルも FBX ファイルも自分にとって本質的には重要ではないとなると、それらのインポート機能を備えた XNA をそのまま利用する方法を模索してみようという所です。

XNA コンテンツ プロジェクト (.contentproj) を非 XNA プロジェクトからビルド時に参照できれば、後は XNB ファイルを自作クラスへデシリアライズする機能を実装する事で、XNA Content Pipeline の恩恵を得られる・・・はず。コンテンツ プロジェクトは XNA 依存であっても、生成される .xnb はただのバイナリ ファイルであり、実行環境を問わないですからね。

XNA コンテンツ プロジェクトは、XNA がインストールされていれば、Visual Studio で簡単に作成できます。しかし、Visual Studio 上では、非 XNA プロジェクトから参照する術がありません。そこで、どうせ MSBuild でビルドしているのだから .proj ファイルを弄れば良いのでは、と思い弄っていたら上手くいきました。

もしかしたら、もっと簡単にやる方法があるのかもしれませんが、以下、要点を記録として記載しておきます。

1. 参照元プロジェクトで XnaPlatformXnaProfile を定義

参照元 .proj に、<XnaPlatform><XnaProfile> を追加します。例えば、以下のように追加します。
<Project ...>
  <PropertyGroup>
    <Configuration ...>
    ...
    <XnaPlatform>Windows</XnaPlatform>
    <XnaProfile>HiDef</XnaProfile>
  </PropertyGroup>
  ...
</Project>

2. コンテンツ プロジェクトへの参照を追加

参照元 .proj に、参照したい .contentproj<ProjectReference> で定義します。例えば、以下のように追加します。
<Project ...>
  ...
    <ItemGroup>
    ...
    <ProjectReference Include="..\SampleXnbContent\SampleXnbContent.contentproj">
      <Name>SampleXnbContent</Name>
      <XnaReferenceType>Content</XnaReferenceType>
      <Project>{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}</Project>
    </ProjectReference>
    ...
  </ItemGroup>
<Project> には、参照先 .contentproj で定義されている <ProjectGuid> の値をコピーします。

3. コンテンツ用ビルド定義をインポート

参照元 .proj に、<Import> で XNA コンテンツ用定義をインポートします。例えば、以下のように追加します。
<Project ...>
  ...
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.Content.targets" />
  ...
</Project>
$(MSBuildExtensionsPath) は、自分の環境では "C:\Program Files (x86)\MSBuild" です。
ここまでで、参照元プロジェクトのビルドではコンテンツ プロジェクトが同時にビルドされ、参照元プロジェクトの出力先に .xnb ファイルが配置されるかと思います。

4. コンテンツ ルート ディレクトリを定義

ここまででは、参照元プロジェクトの出力先にはコンテンツ プロジェクトの名前がそのままディレクトリとして作られ、その中に .xnb ファイルが出力されます。XNA のデフォルトのように、Content ディレクトリへ .xnb を出力したい場合には、参照先 .contentproj にこれを定義します。
<Project ...>
  <PropertyGroup>
    <ProjectGuid>...</ProjectGuid>
    ...
    <ContentRootDirectory>Content</ContentRootDirectory>
  </PropertyGroup>
</Project>

・・・と、ひとまず出力先に .xnb を含める事が出来たので、後は XNB の内容を解析し、自分のクラスへデシリアライズするだけだなと。

2013/03/19

モデル データを読み込むためのライブラリ: Assimp

XNA 公式サンプルを簡単に移植するには、Model クラスを作り、モデル データを Model へインスタンス化する必要があるなぁ・・・と思い、MonoGame を見ていたら Assimp なる物を呼び出していたので、ダウンロードしてラッパーを作成し、Model クラスの実装を試していました。
Assimp
http://assimp.sourceforge.net/
Assimp 自体は C++ で、これを C# で呼び出すための assimp-net を利用してみました。
assimp-net
https://code.google.com/p/assimp-net/
MonoGame の開発途中の Content Pipeline の FBXImporter を見て Assimp を見つけたのですが、サイトを見る限りでは、Assimp は FBX 非対応なんですよね。実際に FBX ファイルを読み込んでみましたが、インスタンス化は可能な物の、情報は設定されませんでした。X ファイルならば、サイトの機能紹介にあるように読み込めているようです。

で、X で良いのなら FBX も X に変換すれば良いだけですが・・・。過去に FBX と X 間の相互変換を試した事があり、その時の記憶では、どんなツールを落としてきても期待通りに変換できた試しが無いんですよね。それから数年が経過したため、再度、色々と調べてみるのも良い気はしますが・・・。

僕は、自分でモデル データを作る事も、他の人が作ったモデル データを利用することも無く。殆どの場合、僕はコード上でモデル データを自動生成しています。つまり、モデル データのフォーマットに関しては、深く考えるだけ時間の無駄かな、と。

ただし、それ以外の部分で XNA サンプルで試したい事が多いので、強引な対策を採ってみようかなと。XNA 公式サンプルで描画可能なモデル データは、少なくとも XNA 内部で Model インスタンスであるため、XNA で Model インスタンス化した上でデータを抜き出し、自作の JSON データへ出力して読み込む事にしてやろうか、などと考えています。

2013/03/17

SpriteBatch および SpriteFont、ようやく描画に到達

やっとのことで、自作 SpriteFont により文字を描画できる所まで到達しました。故に、記念撮影と日記。


かなり適当なデモ コードによるスクリーン ショットですが、テクスチャ描画、色付け、反転、アウトライン付き文字描画などを試しています。

SpriteBatch および SpriteFont ともに、DirectX Tool Kit (DirectXTK) のソースコードを基本にしています。そして、SpriteFont で用いるフォント データ管理のために、XNA Content Pipeline 風の枠組みも自作していました。
フォント データ:
描画に使用する文字を一枚のスプライト シートに纏めたテクスチャ、および、テクスチャから文字位置を特定するための情報等の全てを纏めたデータ。
DirectXTK では、フォント データを事前に作成するバイナリ データで纏めていますが、これは XNA における XNB の概念かと思います。XNB のファイル形式は、以下で仕様が公開されています。
XBOX LIVE indie games - Compiled (XNB) Content Format:
http://xbox.create.msdn.com/en-us/sample/xnb_format
DirectXTK では、SpriteFont 特化のバイナリ生成アプリケーションを提供していますが、他にも XNB 風に管理したい場合があるだろうと想像し、少し汎用性を持たせるために Content Pipeline の枠組みも自作してみたという所です。
後は、DirectXTK のフォント データの構造が XNA とは異なり、これを XNA に合わせるように調整した感じです。

Content Pipeline の実装では、ひにけに GD で提供されている WPF フォント プロセッサを足がかりに設計を進めていました。
ひにけに GD - 真・簡単(かもしれない)日本語表示:
http://blogs.msdn.com/b/ito/archive/2012/02/19/wpf-font-processor.aspx
上記で紹介されているプロセッサを、ほぼ変更せずに実装できれば、プロセッサとフォント データの生成に関しては概ね正解であろう、という判断です。

XNA 風とは言っても、XNA Content Pipeline には不満が多々あったため、あくまで参考とし、自分が望むように設計していました。好きな所で Content Pipeline の機能を呼び出したい、との理由が大きいですかね。
そもそも、完全に XNA 風とするには Visual Studio や MSBuild との統合が必要であり、これが大変過ぎるので回避一択。

XNA のように高機能ではなく、汎用性もかなり低くなっています。必要となった時に拡張すれば良いかなと。

まぁ、そろそろ花粉がキツくて頭がまともに回らない・・・。

2013/03/16

MonoGame のコードを眺めていた

SpriteFont の実装にあたり、ちょっと XNA Content Pipeline 風の枠組みでも作ってみようか、という事で実装していたらハマり始め、何か参考になるコードは無いだろうかと検索していたら、MonoGame に辿り着きました(と言うか、既に知っていたのに存在を忘れていた・・・)。
MonoGame
http://www.monogame.net/
GitHub: MonoGame
https://github.com/mono/MonoGame
XNA 4.0 のオープンソースかつクロス プラットフォーム対応のプロジェクトだそうです。MonoGame で実装した実ゲーム一覧を見ると、Xbox 360 マーケットプレイスで見かける物がありますね。どれも未プレイですが。

そこで、GutHub から MonoGame のソースコードを落として眺めていました。MonoGame は DirectX 実装に SharpDX を利用しており、Direct3D11 を XNA 4.0 API に合わせてラップしているようです。

Content Pipeline 実装を自分の実装と比べていましたが、そこは似た所で詰まっているなぁと。XNA の API からだけでは、ロジックを推測できない部分が結構あるんですよね。大概は些細な部分であり、互換が目的ではないので代替ロジックで済ますのですが、綺麗な実装は可能ならば模倣したい所です。

ストレートに XNA のソースコードを見たいなぁ・・・。

2013/03/11

SpriteBatch 実装に手こずり中

BasicEffect 風の枠組みの実装はスムーズに完了し、XNA 公式サンプルの Primitives3D を移植し、見た目は上手く動作しているようで、後はさくさくと進められるな!などと思っていたのですが、SpriteBatch でかなり躓いています。

XNA で実装していた時には、SpriteBatch は当たり前の存在とし過ぎていて、内部まで深く考察する事が無かったんですよね。DirectX Tool Kit のソースを見て、なるほどなぁと。

DirectX Tool Kit を参考にひとまず実装したので、サンプル コードとして何が良いかを探している最中です。ちゃんと動くのかなぁ・・・。

2013/03/05

DirectX Tool Kit のソースを覗いてみる

眠れなかったので、「Windows ストアでの DirectX アプリケーション開発ってどうやるんだろう?」と思い、ストアに興味はないのに何となく調べていたのですが、DirectX 11.1 では DirectX Tool Kit (DirectXTK) なるものを利用するというのもあるようですね。
DirectXTK
http://directxtk.codeplex.com/
そこで、上記サイトからソースコードを落として眺めていました。それは、DirectX Math という算術演算ライブラリも知り、これが XNA Math と呼ばれるものでもあったので、「DirectXTK も XNA に関係しているの?」と考えたからです。

そして、この予想があたって良かったかなと。SpriteBatch や BasicEffect 等、馴染み深いクラス名を見ることができます。調べてみると、XNA ビルトイン エフェクトを DirectXTK へ移植したと、開発者が述べていますね。
Shawn Hargreaves Blog: SpriteBatch and BasicEffect for C++ Direct3D 11
http://blogs.msdn.com/b/shawnhar/archive/2012/03/02/spritebatch-and-basiceffect-for-c-direct3d-11.aspx
SharpDX ラッパーにて、XNA BasicEffect 風クラスを D3D11 で作る方法を模索していて、「恐らく、こうするのがベストかなぁ・・・」と思う設計が纏まって実装開始直前だったのですが、DirectXTK BasicEffect の設計と同一だったので安心した所です。なら、この方針で問題が無いんだろう、と。
XNA の StockEffects サンプルにある BasicEffect.fx を見ていた時から違和感があったのですが、そこでは既にマクロとディレクティブを用いてシェーダ モデル 4.0 と 2.0 をコンパイル時に切り替えられるようになっています。コメントにも「DX11 シェーダ モデル 4.0 対象のマクロ」などと書いてもありますし。確か XNA 4.0 の段階でこうなったと記憶しているので、Windows Phone 対応だったんですかね?WP って D3D10 対応?いずれにせよ、元より想定されていたのだなと。
名前の類似性から、「SharpDX Toolkit も実は DirectXTK をベースに?」と予想もしたのですが、こちらの予想は外れたようです。DirectXTK の BasicEffect は、テクニックやパスを用いず、シンプルに ID3D11VertexShader などを利用する構造ですが、SharpDX.Toolkit はエフェクトとしてシェーダ コードを自前で解析した上で、エフェクトとして BasicEffect を実装している構造に見えます。

こうして見ていくと、Windows 8 や WinRT の対応をキッカケに、一度 DirectX を過去の実装(XNA 等)を含めて整理して改めるって事なんですかねぇ・・・。仮にそうであるとすると、ある程度纏まった段階で、再び XNA のような環境を作るであろうと期待して良いのでしょうか・・・。

2013/03/02

SharpDX ラッパーがひとまず稼働

SharpDX のラッパー実装が、SharpDX の MiniCube サンプル アプリケーションの移植まで辿り着き、一応見た目は動いているといった所です。

しかし、まだ頂点シェーダ ステージとピクセル シェーダ ステージの対応のみ、入力処理未対応など、そもそも機能が充実していない事や、見かけ上正常に稼働しているだけでしかない可能性の高さを考えると、更にサンプルを実装しながら修正を加える必要があると感じます。

サンプル アプリケーションとしては、SharpDX のサンプルは簡単な物ばかりであるため、XNA 公式サンプルを試しに移植してみようかと考えています。それにより、実装すべき物が明らかになると思いますし。その前にデバッグ機能を揃えた方が良いのかな・・・。

ある程度落ち着いたら、Minecraft 風に作ったアプリケーションを移植し、動画作成とタグ付けしてのコード公開をあわせて、一段落としないなぁ・・・と。先は長い。

2013/02/26

Effect を捨ててみる

SharpDX ベースの自作ラッパーにて BasicEffect を実装しようとしましたが、違和感から止め、ネットで調べていました。
Effects for Direct3D 11 Update
http://blogs.msdn.com/b/chuckw/archive/2012/10/24/effects-for-direct3d-11-update.aspx
免責事項(disclaimer)で述べている事は、非推奨という事なのでしょう。Windows 8 や RT の Windows ストア アプリケーションでは Effect 11 非対応だそうで。その理由には釈然としない物がありますが、非推奨や廃止となると、技術者が注目しなくなり、情報が減る事が問題ですかね。実際、Direct3D11 の情報を探すと、Effect を用いているサイトが極めて少ないですし。
SharpDX.Direct3D11 の Effect も同様に非推奨のようですが、SharpDX.Toolkit に含まれる Effect フレームワークは、SharpDX.Direct3D11 の Effect とは異なり、Windows ストア アプリケーションでも利用できるように実装されているそうです。これはクラスの依存関係からもそうかなと思います。
そこで、自分にとって Effect が必要であるかを検討しましたが、使わないなら使わないで、それを前提に実装すれば良いだけかな・・・と、言うは易し。

2013/02/20

SharpDX で自分用 DirectX 11 ラッパーを作り始める

SharpDX.Toolkit のソースコードを眺めていると違和感があり、DirectX をより深く知る目的も含めて、ラッパーを自作することにしました。対象は DirectX 11 にしています。
今の所、とても実装が楽しいです。DirectX のインタフェースを知ることで今までの疑問が次々と解決される点が一つの楽しみですが、より簡素なインタフェースへ纏める作業そのものが自分の本能を突き動かすような所があります。
既存コードの修正箇所を減らしたいため、初めは XNA に近づけようとしましたが、それは大きな誤りであると感じ、今は DirectX 11 として利用しやすいか否かという観点で実装しています。
大きな所では、11 ではデバイス、デバイス コンテキスト、スワップ チェーンと、その役割と共に明確に分離されていますが、一方で XNA は 9 であるため、それらが GraphicsDevice として一体化している点などでしょうか。
SharpDX.Toolkit では、11 で分離されたこれらの要素を再び GraphicsDevice として一体化していますが、このために GraphicsDevice が複雑怪奇となっていますし、11 では意味を失っているイベントやメソッドを実装するなどの問題を引き起こしているように見えます。
後は、シェーダ ステージでしょうか。当面、自分は一部のステージしか使わないのですが、既に 11 の文書を頼りに実装しているので、これらは変にラップせずに明確なインタフェースとすべきであろうと考えたりなどしています。

しかし、XNA から応用できる考え方は多々あると感じていて、参考にしながら実装を進めています。4.0 にある RenderTarget と DepthStencilBuffer を纏めてしまう設計などは、3.0 の時と比較して便利だと感じましたし。

当面、デバイスやリソース周りの実装は先が見えているのですが、BasicEffect や SpriteBatch は面倒そうだなぁ・・・と。

で、また脱線し始めたと自分で感じてはいるものの、ラッパー作成は一度は経験した方が良いであろうとも感じ、納得できる所までやろうと思っています。一度自分で経験して理解を深めなければ、他のフレームワークを効率よく扱うこともできないでしょうし。

2013/02/13

SharpDX を触り始める

SharpDX という OSS を触ってみました。
SharpDX
http://sharpdx.org/
SharpDX は C# で DirectX を扱うためのライブラリですが、名前空間 SharpDX.Toolkit には XNA Framework に酷似した枠組みも含まれています。

XNA と比較すると、Game、Graphics、Content アセンブリに相当するクラスがあります。IEffectMatrices などが含まれているので、XNA 4.0 を意識した状態でしょうか。ただし、DirectX 実装の名前空間にあるクラスで十分な物に対してはラッパーは存在しませんし、Content Pipeline の概念などもありません。なお、SharpDX.Toolkit は DirectX 11 対応のみのようです。
追記
後に DirectX Tool Kit (DirectXTK) を知り、名称が似ているので DiectXTK の C# バージョンかとも思ったのですが、API やソースコードを見る限りはそうではないようで。
そこで、過去に作成した XNA アプリケーションの中で簡単なものを選択し、SharpDX.Toolkit を用いて移植してみてます。
追記
SharpDX のラッパー作成を通じて感じていることですが、XNA からの移行として SharpDX を考えることは妥当ではないと思います。僕が DirectX 11 を対象としている事もありますが、SharpDX は 10 以上が主であり(9 対応は後付だそうです)、XNA は 9 対応であり、9 と 10 の差異は大きいと感じます。この差異は、SharpDX.Toolkit においても見受けられます。
一応、SharpDX のフル パッケージには、SharpDX.Toolkit のサンプル アプリケーションも含まれていました。簡単な物ならば DirectX を気にせずに実装できるようです。しかし、DirectX を除いても、フォーム アプリケーションの知識が多少必要でしょうか。

ひとまず、もう少し触ってみようと思います。SharpDX.Toolkit の Game クラスから簡単にフォームへアクセスできるため、Game クラスを主体にしたままエディタを作る事を考えた場合に都合が良いかなと。簡単にボタン コントロールを画面に置いたりできるので、ちょっとしたデバッグ用の UI を作りたい場合にも便利な気がします。

まぁ、「XNA の方が極めて楽だな・・・」と思いながら弄っています。

2013/02/05

天空光

結局、木の生成はスルーし、天空光・・・と言うのが適切か分からないですが、天空光の処理を実装していました。描画の結果としては、以下のような影を落とすための光の処理です。


基礎的なライティングの問題点
基礎的なライティングとして、拡散色 (diffuse)、放射色 (emissive)、反射色 (specular)、環境光色 (ambient) を定め、シェーダ内で指向性光源 (directional light) の方向から最終的な色を決めるという方法があります。
この方法では、面の法線、光の方向、視点方向のみから色を決定します。つまり、光の到達は考慮されず、光が到達しない面であると我々が認識できる場合であっても光で照らします。

通常、これは大きな問題にはならないと思うのですが、洞窟のような地形の描画において期待しない結果をもたらします。洞窟の奥深くへ行く程、光は到達しなくなることを通常は期待しますが、基礎的なライティングでは、問答無用で洞窟を構成する面を照らしてしまいます。

CPU での天空光シミュレーション
そこで、Minecraft のように、ブロックの各位置への光の到達具合をシミュレートし、テクスチャの明るさを変更するという処理を実装していました。

なお、実装の大枠は自分で考えたのではなく、Terasology (Java) を参考にしています。
Terasology
http://blog.movingblocks.net/blockmania/
他にも幾つか Minecraft クローンのオープン ソースを調べたりしましたが、Terasology のコードが最も充実している、かつ、可読性が高いと感じます。
処理の概念は Terasology と大差ないと思いますが、Minecraft や Terasology とは異なり、僕の実装では上下方向についてもチャンクを無限に広げているため、若干、シミュレーションでの判定ロジックが異なります。また、それらとは元より方向性が異なることもあり、シミュレーション結果を得る前にメッシュを構築して描画してしまい、シミュレーション完了でメッシュを再構築するなどしています。
ゲームとして考える場合は、シミュレーション完了を待ってメッシュ構築すべきかと思います。
処理の流れ
前提として、太陽の位置を真上に固定させて考えます。詳しくは知らないですが、Wiki を見る限りでは Minecraft も同じであろうかと思います。太陽の方向を考慮できればベストでしょうが、恐らく、その場合は実用に耐える処理速度を得られない気がします。

大まかな流れとしては、真上からの光の到達具合を判定し、そこから光の拡散を処理するだけです。
このような処理であるため、グリッドに沿った天空光の処理なのかなと思っています。
なお、非同期処理が前提です。ここに限らず、既にほとんどの処理が非同期ですが。

第 1 フェーズ
あるチャンクの内部について、Y 軸についてどこまで光が到達するかを判定します。光レベルは 0 から 15 の値を用い、0 が最も暗い状態、15 が最も明るい状態を示しますが、このフェーズでは光レベル 15 で処理します。
15 は、すなわち 4 ビットです。つまり、byte で 2 つの位置を管理でき、メモリ節約の恩恵を得られます。
第 2 フェーズ
第 1 フェーズで定めた光レベル 15 の全ての位置から、上下前後左右に隣接するブロック位置へ、光レベルを減衰させながら、再帰的に拡散させます。減衰しながらの拡散とは、光レベルを -1 しながら、0 となるまで隣接位置へ光レベルを設定していく処理です。ただし、拡散先の位置により大きな光レベルが設定されている場合は、既により強い光で照らされているため拡散を止めます。

第 3 フェーズ
第 2 フェーズまでで、チャンクの内部で閉じた光レベルの情報が構築されるので、次に互いに隣接するチャンク同士の光の拡散を処理します。これには、あるチャンクについて、隣接チャンクの外周の光レベルを参照して自チャンクの外周の光レベルを更新し、ここから再度、光の拡散を自チャンク内部で行います。これにより、チャンクの光レベルの設定が全て完了するため、メッシュの更新を要求し、メッシュの頂点に光レベルに基づいた陰影情報を書き込むようにします。
この部分は Terasology とは異なる実装にしていると言うか、Terasology のロジックを理解できなかったので、極普通の思考のまま実装しています。もしかすると、演算回数を減らす工夫が Terasology にはあるのかもしれません。

スクリーン ショット
天空光を処理することで、以下のスクリーン ショットのように、洞窟の雰囲気を出せるようになります。

明るくなっている部分は洞窟の入り口であり、そこから奥へ向かうにつれ光が届かなくなり、ブロックは黒くなります。
実際には、環境光遮蔽 (ambient occlustion) を別途シミュレートしているため、ブロック同士で遮蔽する部分は、更に黒くなっています。
以下のスクリーン ショットのように、強引に地形の内部へカメラを置けば、完全に閉じている洞窟などでは、完全に影で覆われてしまう状態であったりします。

とまぁ、こんな事をしていました。ただ、非同期処理とは言え、随分と CPU が苦しそうにしているので、もう少しコードを改善しなければならないと感じています。

2013/02/03

XNA 開発終了だそうで

XNA の開発が 2014/4/1 で終了との記事を見ました。
XNA Today: XNAの開発が2014年4月1日で終了
http://www.xna-today.jpn.org/archives/5359
ここ数ヶ月、XNA の利用に疑問を抱いていたので、終了報告は良いタイミングかもしれないなどと考えている所があります。

自分が XNA を利用し始めた理由は、概ね以下のような感じです。
  • 偶然 XNA の記事を目にした。
  • Java 以外の言語で存分に実装してみたかった。
  • XNA は機能が充実していない (より深く学ぶためのキッカケに適している)。

しかし、最後の「機能が充実していない」という点が、「ゲームを作りたい!」という人には大きなデメリットであっただろうと思います。僕は、これをキッカケに色々とネットで調べ、解釈し、実装するという学習の過程を楽しめていますが、ゲームの完成を目的とする人には、この過程の大半がストレスであると想像します。

まぁ、日本では、PC ゲームも Xbox 360 ゲームも盛んではなく、その時点で厳しかったでしょう。現状、Windows Phone は論外ですし。

当面、XNA で今の実装を続けるのですが、並行して次のプラットフォームを考えています。久しぶりに C++ にしてみる、あるいは、細かい事に頭を使わずに実装できる Java にしてみる、などなど。

2013/01/28

ブロック地形進捗 #2

最大頂点数をとるチャンクを空間全体に敷き詰める前提を立てていましたが、「それは流石にハードルが高すぎる」と考えるに至り、頂点数がそこまで膨大とならないようにノイズを調整し、その他実装を修正していました。

16^3 チャンクで可視範囲を 20 チャンク (20 * 16 = 320 ブロック) としたキャプチャが下図です。

他のオブジェクトの配置を考えると、16 チャンク程度で済ませる気がしないでもありません。

なお、地形の背面に存在する洞窟の状態をキャプチャしたものは下図となります。

視点から見えるチャンクの状態に依存しますが、概ね、描画の負荷が多大な状態です。原因の一つは、描画対象とするチャンクの探索にかかる負荷です。チャンクを含め、シーンに描画するオブジェクトは八分木を用いて管理していますが、満足できる結果ではないと感じています。

これから、地形だけではなく、木を表現するブロックをチャンクへ配置しようと思います。木の配置まで終えたら、節目として動画を上げてみようと思います・・・たぶん。まぁそろそろ、積んだまま放置している Borderlands 2 をやりたいな、と。

2013/01/17

ブロック地形実装進捗

「心が折れそうだ」

煮詰まってきたため、ブログを書いて気持ちを誤魔化すことにしました。納得できるパフォーマンスを出せていないので、まだ動画公開はしませんが、下図が現時点のスクリーン ショットです。

 

僕の GitHub ページでコードは公開されていますが、動画公開まではタグを貼りません。そもそも、自分の環境でもメモリ不足によりアプリケーションが落ちる状態です。

今は、チャンク サイズ 16x16x16 で作成しています。チャンクは、上下左右に int とディスク スペースが許す限り無限に配置できる設計です。
チャンク
立方体ブロックを一塊としてメッシュとする単位。Minecraft では 16x256x16 や 16x128x16 なども用いる模様。
追記
今はチャンク サイズ 32x32x32 としています(チャンクのメッシュは 16x16x16 へ分割した状態)。チャンクの粒度を細かくするとチャンク総数が増えることから、チャンク探索処理に大きな負荷がかかるため、大きなサイズとしました。メッシュはインデックス バッファの制約から 16x16x16 (ushort で収まる範囲) が妥当かと思います。Minecraft 形式の場合ならば、高さ固定から二次元でのチャンク探索となり、比較すると遥かに高速かと思います。
地形は、ノイズを用いて自動生成しています。過去の一般的な地形生成ではノイズをハイトマップ生成に利用しましたが、今回はハイトマップを更に密度へ変換して利用しています。
密度を用いる利点は、密度生成を工夫することで、内部に洞窟を自動生成させたり、ハングしている崖などの、ハイトマップのみでは表現できない地形データを表現できる事。Minecraft でも密度を利用しているとの話。スクリーン ショット上で見える地形の内部には洞窟が存在。
で、満足できていない点ですが、チャンクをあまり多くロードするとメモリ不足に陥る所です (頂点バッファを確保できなくなる)。特に、洞窟を含むチャンクでは頂点数が一気に跳ね上がり、それに応じてロードできるチャンク数が減ります。

今は、可視範囲で 10 チャンク距離 (10 * 16 = 160 ブロック距離)、予備範囲で 12 チャンク距離 (12 * 16 = 192 ブロック距離) をロードしています。やはり、より遠方まで地形を表示したいわけで、せめて可視範囲で 12 チャンク距離程度はロードしたい所です。
Minecraft では 200 ブロック距離までも描画可能との話 (これを知ると、まだまだやれる事があると考えざるを得ません)。
理屈としては、恐らく、チャンク内で交互にブロックが配置 (立方体の角のみ隣接する配置) される構成が、チャンク頂点数を最大とする構成であろうと思います。そこで、この最大頂点数のチャンクのみをロードする前提で考えている所です。
最大頂点数のチャンクは、サイズ 16x16x16 において、頂点数 36864、インデックス数 36864。
チャンクの外部から不可視となる閉塞空間を検出し、閉塞空間に隣接する面を刈り取るなどしてみましたが、最大頂点構成では閉塞空間がなく、あえなく敗れ去った所です。とは言え、閉塞空間を含むチャンクでは大幅に頂点を削減できています。

そこで、今は、カメラとチャンクの位置関係から背面を除去しようとしている所です。チャンクのメッシュは実行中に非同期に更新しているため、カメラとチャンクの位置関係が変化した場合にメッシュ再構築を要求し、背面を刈り取るだけですが、現実装では即座にメッシュ再構築が完了するわけではないため、どうアプローチしようかと悩んでいる所です。

libgdx いじり

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