開発中のメイン画面ビルボードの城とネームプレートが実装され、ゲーム画面らしくなってきた。ネームプレートは城の前後関係を考慮して重ね合わされ、以前より読みやすくなった。
◎城モデルの画像取得今回は城モデルの画像取得/表示です。
まず、画像取得プログラムを改修して、ACLモデル以外に通常モデルのスクリーンショットも取得できるようにしました。他にも、画像出力前に既存ファイルを一旦削除するとか、各種パラメータを一箇所にまとめるとか、細かい改修を併せて実施しました。
城モデルは城門の数によって5種類あるので、全ての画像を取得すると32×5=160枚になります。城門4つの城を使い回すことにする場合、90度分の画像で足りるので、たった8枚に減らせます。
パフォーマンス的にはその方が良さそうな気がしますが、調整は後で行うこととして、とりあえず160枚取得しました。
◎城データの読み込み城を配置する前に、城データ(名称や座標を記述したテキストデータ)を読み込む必要があります。
データ読み込み機能は漢字表示機能と連動したものを過去に実装済ですが、漢字表示機能はひにけにXNAの改造版です。XNA3.1化に伴い、ひにけに版がアップデートされたので、こちらもアップデートすべきでしょうか?
ちょっと悩みましたが、既存プログラムが複雑なので今回は単純にコンバートしたプロジェクトを取り込みました。
とりあえず今は動けばいいや(笑)
しかし単純コンバート版を組み込んで実行すると「ファイルが無い」とエラーになりました。テキストファイルはC#で読み込むため、「出力ディレクトリにコピー」を「常にコピーする」に設定しておかないと、デバッグフォルダにファイルが存在せず、エラーになってしまうのです。
漢字表示機能に関係してるのかと思って原因調査に手間取りましたが、結局以前決めた仕様を忘れていたことが原因でした(爆)
◎城とネームプレートの表示データ読み込み機能、漢字表示機能などを再実装し、城の位置の高さを取得して配置しました。

高さはちゃんと取得できてますね。しかし静止画だとわかりませんが、スクロールするとカクカクします。アニメしないモデルだと目立つなぁ…。

ネームプレートを表示しました。城の位置は大体合ってるようですね。
しかし困ったことに、SpriteSortMode.Immediateを設定すると、スプライトバッチのDrawString()やEnd()でエラーになってしまい、他のソートモードを指定すると、非透過状態となってしまいます。
これは以前から悩んでいた問題ですが、どうしても原因がわからないのでスプライトを避けてました。しかしいよいよ実害が出てきたことですし、何としても解決しないといけません。
◎スプライトバッチ開始オプションヘルプを参照すると、
Immediate モードでは、グラフィック デバイス設定の衝突を発生させることなく存在させられるのは、1 つのアクティブな SpriteBatch インスタンスのみです。とあります。グラフィックデバイスやスプライトバッチのインスタンスが複数混在してるのではないかとか、コンテントマネージャをオーバーライドしたことが影響してないかとか、いろいろ調べたのですが、結局はスプライトバッチ開始オプションの問題でした。
改修前:
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);改修後:
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.BackToFront, SaveStateMode.None);SpriteSortModeの中ではImmediateが一番早そうですが、この場合SaveStateMode.SaveStateとしないと、3Dモデルの描画が乱れるという不都合がありました。しかし今はビルボード方式により3Dモデルが単純化されたので、この問題は発生しません。
改修後の組み合わせにすると、無事に透過処理が行われ、負荷も若干軽減された気がします。
◎ネームプレートの透明度城やネームプレートが無事に表示されると、いろいろ気になる点が出てきます。
まずはネームプレートと文字の原点を左上から中心に変更し、上下と左右のサイズ比率や表示位置を調整しやすくしました。但し、表示位置は城の傾きやカメラ位置に連動して調整する必要があるので、城の傾きを修正してから最終調整します。
次に、ネームプレートが重なるとゴチャゴチャして読めないという問題がありますが、よく考えたら、背景が半透明では重なると読めなくて当然です。文字の左右を半透明とし、文字位置の背景は不透明としました。

これで幾分マシになったようですが、まだまだ読み辛いです。よく見ると、後方の城名が前方のネームプレートの手前に描かれ、文字と文字が重なっています。
これはつまり、カメラ視点で城の前後関係を把握して、後方の文字の手前に前方のネームプレートを配置(または描画)する必要があるってことですね。
◎城の前後関係カメラと各城の距離を1つ1つ計算し、それらをソートして順序を把握しようとすると、面倒な上に遅くなりそうです。XNAでサクッとできないものでしょうか?そもそも城モデルはXNAが前後位置を把握して描画してるわけだから、そこから情報を取得できても良さそうな気がします。
そこで深度バッファを確認すると、これはレンダリングされた各ピクセルの深度を記録したものでした。ピクセル単位の情報では役に立ちません。やはり自前でやらなきゃダメか。
やむなく自前での実装を検討します。カメラと各城の位置関係により距離は取得できるので、問題はソートです。
…でも待てよ?距離を0〜1の範囲に縮小して深度を指定すれば、自前ソートは不要?
float layerDepth = Vector3.Distance(モデル位置, カメラ位置) / 最大距離(=マップの対角線);※spriteBatch.Draw()の引数に上記layerDepthをセットする

無事ソートできたようです。こんなに簡単に出来るとは思いませんでした(^^;
ちなみに、左図は文字背景完全不透明バージョンです。
見た目がちょっとアレなので、透明度2段階バージョンとしました(右図)。
◎次回予告画像を取得して表示するだけと思っていたのですが、実際にやってみると課題問題が予想以上にありました。まぁ、深度指定のコツとか収穫もあったので良しとしましょう。
次回は城表示関連の残課題に対応します。
城の傾きの修正が難しくて試行錯誤中。
テーマ : ゲーム製作 関連 - ジャンル : ゲーム
コメントの投稿