プロフィール

Na-7

Author:Na-7
SE(システムエンジニア)として約15年間システム系ソフト会社を勤めあげ、2008年3月退社。現在、ゲーム制作会社設立を目指して活動中。


アクセスカウンター


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


DATE: CATEGORY:スポンサー広告
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
DATE: CATEGORY:三国志軍記開発
近クリップ平面=50
地形モデルのシャドウマップ
シャドウマップを1色8ビットのテクスチャで取得する場合、精度が低いので注意する必要があるようだ。



◎シャドウマップ書き換えテスト

前回のテストで、シャドウマップ(深度テクスチャ)から深度値を取得するのは速度的に無理っぽいことがわかりました。

その後あれこれ考えたのですが、シャドウマップのユニット座標のカラー(深度値)を、ネームプレートの範囲にコピーするのはどうでしょうか?

というわけで、(spriteBatch.Drawを使用して)シャドウマップの書き換えテストをやってみます。

シャドウマップ書き換えテスト

書き換えが反映されて、シャドウマップの一部と、メイン画像の影の形が変わりました。動作的にはOKですが、60→30FPSはちと遅いですね。

細かい計測はしてませんが、追加したコードから察するに、レンダーターゲットとして取得したテクスチャを書き換え前に再描画する(2048×1024)処理がかなり重そうです。

…待てよ?
わざわざシャドウマップを再描画/修正/反映しなくても、深度バッファに直接描画すれば良いのでは?



◎レンダーターゲットの解像度

しかしメインプログラムでやろうとすると、RenderTarget2Dを作成しただけで60→8fpsまで低下しました。
…えっ?まだレンダーターゲット切り替えてないのに、作成しただけで遅くなるものなんですか?

試しにRenderTarget2Dの解像度を変更すると、1024×720以下で60fps、1280×720以上で8fpsになるようです。何かGDCメモリ不足っぽいなぁ…仕方が無いので、当面1024×720とします。(4対3に逆戻り(^^;)

で、一通り実装したつもりですが、動かしてみると…狙い通りになりません。どうやら、シャドウマップの取得に失敗したようです。原理を理解しないままサンプルコードを強引に流用したので、どこかおかしいのでしょう。



◎サンプル解析

というわけで、サンプルを(今度は丁寧に)解析します。まずは、シャドウマップの取得部分を理解しましょう。

…ははぁなるほど。頂点シェーダの

VS_SHADOW_OUTPUT Out;
Out.Position = GetPositionFromLight(vPos);
Out.Depth.x = 1-(Out.Position.z/Out.Position.w);


これで深度を算出して、頂点シェーダでカラー(赤系)に変換してるんですね。

描画時は…なるほど、シャドウマップを参照しながら描画してますね。深度バッファへの直接書き込みはしてません。
…と言うか不可能っぽいですね。まずいなぁ。

サンプルと同じ方式でやろうとしたら、シャドウマップを参照しながらネームプレートを描画するカスタムエフェクトを実装する必要がありますが、ネームプレートには漢字が含まれるので、

・スプライトフォントを描画するカスタムエフェクトを作成する

・スプライトバッチのエフェクトをカスタムエフェクトに切り替える

上記のいずれかを実現する必要があります。不可能とは思いませんが、ハードルがさらに上がっちゃったなぁ…(--;



◎他の方法を検討する

もっと簡単な方法は無いかと改めて考えたのですが、『深度テクスチャからターゲットピクセルのみ集約した中間テクスチャを作成し、そこから色情報(深度値)を取得する』という方法はどうでしょうか?

中間テクスチャの解像度を512×2ぐらいにすれば、そこそこ早く取得できるかも…??



◎シャドウマップの精度

新方式で実用的な速度が出るか試したいのですが、それ以前の問題として、シャドウマップがうまく取得できません。
何が悪いのか?う~ん…。

ここで散々悩まされたのですが、原因はシャドウマップ取得時に渡す斜影変換行列の近/遠クリップ平面にありました。

近クリップ平面=1   近クリップ平面=50

左図:近クリップ平面 = 1.0f、遠クリップ平面=1000.0f
右図:近クリップ平面 = 50.0f、遠クリップ平面=1000.0f

ちなみに、上記画像はシャドウマップ取得前に「白」でクリアしたものです(わかりやすくするため)。通常はシャドウマップ取得前に「黒」でクリアするので、左図は画像全体が真っ黒となり、何も描画されなかったように見えます(混乱しやすい)。

それと、近クリップ平面=1.0f、遠クリップ平面=900.0fとした場合、左図と同様になりました。近/遠クリップ平面間の距離を狭めたのに、右図より悪い結果になった理由は、‘テクスチャ精度が低い(256段階)から’と思われます。興味がある方は、こちらの『③ 深度の精度はNear-Far比で驚くほど落ちる』を参照してください。



◎パフォーマンスチェック

ようやくシャドウマップが取得できました。精度不足の懸念がありますが、とりあえず新案の速度を確認しましょう。

シャドウマップからターゲット座標を集約した中間テクスチャ

(ただの細い線に見えますが)上図は、地形のシャドウマップからターゲット座標のみを集約した中間テクスチャです。画像を拡大してよく見ると、左端から1ピクセル単位で色が変わっているのが確認できます。これは各部隊が描画される位置の地形の深度を表します。

Texture2D.GetData()が激遅なので、シャドウマップから必要な座標の色のみ集約して小さな中間テクスチャを作成し、そちらから色を取得することにより高速化を図ります。

○測定結果
地形モデルのシャドウマップ取得:0.7ms
ピクセル集約&中間テクスチャ作成:2.5ms
中間テクスチャから深度情報取得:6.0ms

むむぅ…深度確認だけで9msは遅すぎですね。

あまり実用的ではなさそうですが、とにかく一度最後まで実装してみましょう。



◎シェーダーインスタンスのW値

その後一通り実装したのですが、深度判定がうまくいきません。どうやら、部隊の深度が正しく取得できていないようです。

ShadowMap_FlagMan01

上図は部隊のシャドウマップです。該当位置に深度値が出力されますが、その値が0~5までしか存在しません(本来は0~255)。今回は近/遠クリップ平面の値を変えてもダメでした。

原因は、HLSL内で深度(Z/W)を計算する際の、W値にありそうです。W値は

float4 val = mul(position, WorldViewProjection);

val.wに格納されるらしいのですが、シェーダーインスタンスの都合により‘ワールド座標変換行列を直接渡すことができない状態’なので、w値を算出する方法がわかりません。

・HLSL内でSRTからワールド座標変換行列を生成する
・他の方法でw値を算出する

上記のどちらかが判明すれば、シェーダーインスタンスでシャドウマップを取得できるようになるのですが、ネットで調べてもわかりませんでした。う~ん…。



◎ベクトルと行列の乗算

仕方がないので、別の方法を考えましょう。XNA側でW値を算出してHLSLに渡すのはどうでしょうか?

…今度は、ベクトルと行列の乗算がわからずに悩みました。HLSLの乗算は数学的な乗算と異なるようなので、こちらのヘルプを読んで試作したのですが…

Vector4とMatrixの乗算(試作)
ShadowMap_FlagMan02

ダメですね。ヘルプの解読を誤った可能性が高そうです。

…というか、もっとわかりやすく書いて欲しいッス(;_;)



◎次回予告

2月になったので、次回は「1月の総括と2月の目標」です。

スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント

シンプルでいいかも

これは技術的な話というよりゲームの内容に立ち入ってしまうので、判断はお任せしますとお断りしておきますが…。

敵部隊を表示するかしないかの判定(一種のヒットチェック)が目的であれば、単純にZX平面のマス目で考えて、自部隊と敵部隊の間に高い山が存在するかどうかをチェックした方が、速度面だけでなく、ゲームシステムの上でもよいのではないでしょうか。

単なる見栄えの問題でカメラのパラメータを変えただけも、敵部隊が表示されたりされなかったり、ゲームのバランスに影響してくるような。

その方が良さそうですね

>目的
今回は、ネームプレートを表示するかしないかの判定が目的でした。例えば、敵1部隊10人のうち3人が見えて7人が山影というのは良いのですが、ネームプレートの「関」が隠れて「羽」だけ見えると困るので。

>カメラのパラメータを変えただけも
「カメラのパラメータ=自部隊の視界」とし、自部隊の位置によって敵の表示人数が変わることを狙っていたので、その点に関してはOKです(高地に陣取ったり敵に近付くと状況把握しやすい)。

>ZX平面のマス目
仰る通り、メリットは他にも沢山ありますね。

マス目方式にする方向で検討させて頂きます。貴重なアドバイスを頂きまして、どうもありがとうございました^^

コメントの投稿


管理者にだけ表示を許可する

トラックバック


この記事にトラックバックする(FC2ブログユーザー)



copyright © ゲーム制作の舞台裏 all rights reserved.Powered by FC2ブログ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。