プロフィール

Na-7

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


アクセスカウンター


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


DATE: CATEGORY:スポンサー広告
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
DATE: CATEGORY:XNA修得
ステンシルシャドウ公式サンプル01
シャドウのサンプルプログラム
ステンシルバッファやアルファブレンディングを利用してステンシルシャドウを描画する公式サンプルプログラム。筆者PCで実行すると上図の画面になったが、他の環境では異なる可能性がある。



◎レンダーステート

前回コメントでyohさんからアドバイスを頂いたので、今回は予定を変更して、レンダーステートを勉強します。さて、レンダーステートの何を勉強すれば良いのでしょうか?

まず半透明処理ですが、スプライトバッチ、BasicEffect(実体はHLSL)、ACLやSoftimageのライブラリ、カスタムエフェクト等を併用するとうまくいかないことがあります。これまでは、ろくな知識もなく試行錯誤だけで強引に突破してきました。

3Dテストプログラムのラストシーンでは、ACLとスプライトバッチ併用で半透明を実装するために何十通りもの組み合わせを半日かけて試しましたw

しかしこれは効率が悪い上に、組み合わせが変わると通用しないので、次のステップに繋がりません。まずXNAの半透明処理をきちんと理解した上で、他の機能がどのように影響するのか把握する必要がありますね。

また、レンダーステートに関しては、他にも知らない機能やプロパティが沢山あります。XNAの全ての描画は各プロパティの設定に影響を受けるので、レンダーステートの機能やプロパティは一通り知っておく必要がありそうです。



◎現状確認プログラム

まず、レンダーステートがどのように変化するのか確認するプログラムを作りながら、どんなプロパティがあるのかグループ分けしながら確認しました。

レンダーステート出力プログラム(デバッグ用)

ちなみに、私の理解度はこんな感じです。

○よく知らない機能
・カラーバッファーチャンネル関連
・ステンシル/ステンシルテスト関連
・カリング モード
・シザー テスト
・ポイントサイズ関連
・完全テクスチャ マッピング

○機能概要は知っているが、使いこなせないもの
・アルファ関連
・深度バイアス/深度バッファ関連
・マルチサンプリング関連

○ある程度使いこなせそうなもの
・塗りつぶしモード
・フォグ関連
・テクスチャラッピング関連

よく知らない機能について、機能概要を把握することから始めましょう。



◎ステンシルバッファ

よく知らない機能の中で、わりと頻繁に御目にかかるのはステンシルバッファです。ネットを探ると、こちらの記事がわかりやすかったので実際に試してみました。

ステンシルテスト01

ステンシルバッファ非公式サンプル解析メモ

ステンシルバッファは、描画領域を設定可能とする機能のようですね。全体の流れはある程度理解しましたが、疑問点もあります。



◎公式サンプル

しばらくパラメータをいじったりしましたが、それだけではよくわからなかったので、こちらの公式サンプルも解析することにしました。

ステンシルシャドウ公式サンプル01

このサンプルでは、ステンシルモードのアダプタチェックなどもやってます。ちなみに、
SurfaceFormat.Depth15Stencil1
SurfaceFormat.Depth24Stencil4

上記フォーマットはXbox360でサポートされないようです。ちょっと意外。

ソース内の各コードはさほど難しくないのですが、Quadクラスの実体が何なのか、いまいちよくわかりません。行単位で細かく解析すると時間がかかるので、他のサンプルを探すことにしました。



◎非公式サンプル

こちらに良さげなサンプルがありました。

公式サンプルをスマートに改修した感じです。コメントは当然日本語。HPの解説記事も図入りでわかりやすかったので、他の記事も見てみたいです^^

ステンシルシャドウ非公式サンプル01

あれ?影は表示されますが、地面が表示されませんね?
ひょっとして、公式サンプルも地面が表示されなかった??

こちらのテクスチャークワッドの公式サンプルを実行したら、何も表示されませんでした。ガーン!!

メインPCのオンボードGPUはイレギュラーなシロモノですが、まさか平面描画の公式サンプルがNGとは!(>_<)



◎ステンシル無しシャドゥ

ステンシル機能を無効化したらどうなるか試してみました。

ステンシルシャドウ非公式サンプル02

この画面を見て、ステンシルバッファの使用目的がようやくピンときました。影領域への描画を一回とする(均一化する)ためだったのですね。



◎回路は1つ

最初に挙げたように、XNAでアルファブレンディングを実装する手段は複数あります。どれか1つの手段で実装すれば単純で問題無いのですが、複数組み合わせた場合に「何がどう影響するのかよくわからん!」と悩んでました。しかし今回サンプルコードを解析する過程で、ようやく基本的なことに気が付きました。

・レンダリング用の回路(=半透明を処理する回路)は
 GPUに1つだけ
 →どの手法も同じ回路を使用している
 →ある手法で回路の一部を操作すると、
  他の手法に対してもそのまま影響が残る

各手法のコードはそれぞれ別次元のような感覚で認識していたのですが、全部同じ次元で処理される(描画される)のですね。

yohさんが『面倒でも毎フレーム、シェーダに参照される全てのステートを自力で設定するのが確実です。』とコメントされた真意を改めて認識しました。



◎サンプル解析まとめ

ステンシルシャドウの公式/非公式サンプルは、3つのテクニックで影を実装しています。

・Matrix.CreateShadow()を利用して、影を斜めにしている

・ステンシルバッファを利用して、影の濃さを均一化している

・アルファブレンディングを利用して、影を半透明化している

だいぶわかってきたと思うので、演習に入りましょう。



◎演習

前回(初期化目的で)挿入したspriteBatchを削除し、レンダーステート設定で初期化するようにしました。

半透明処理を改善した

境界線が目立たなくなって、殆ど気付かないレベルになりました。ここまではOKです。


次に、ステンシルシャドウの実装を考えたのですが、その半透明処理にはHLSLのさらなる改修が必要なので、とりあえず後廻し。一応ステンシルのコードは組み込みましたが、半透明が未実装なので確認できません。

で、影を斜めにする部分ですが、投影行列の値は正常(確認済)なのに、全然斜めにならなくて悩みまくりです(ーー;

行列を渡す所までは正しいはずだから、ライブラリやシェーダの中身が問題?でもオブジェクト全体にワールド座標行列は反映されてるんだよなぁ…。ひょっとして、ボーン増加改修でスケールが非サポートなのが敗因?でもオブジェクト全体のスケールは有効だし、スケール以外の変化も見られない。う~ん…。



◎次回予告

ステンシルシャドウをいきなりSoftimageライブラリに実装するのは無謀だったかもしれません。先にノーマルモデルやACLで演習した方が良さそうです。

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

スポンサーサイト

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

コメント

ちょっとだけ。「回路は1つ」というところですが、より正確に言うとじつはGPUには複数の頂点シェーダと複数のピクセルシェーダが組み込まれていて、頂点またはピクセル単位でエフェクトプログラムを並列実行しています(GPUのスペック表にはそれぞれ何基搭載されているか書いている)。他にもいくつかの回路は複数存在するのではないかと。

ただレンダステートそのものについては、そちらの仰られているようにZEnableならZEnableを表す“フラグ”が一つだけあると見なしてよいと思います。

なるほど。実際の回路は、私のイメージより複雑だったんですね。

それで1つ質問させて頂きたいのですが、XNAからグラフィックデバイスに対する命令はマルチスレッドで受け渡されるのでしょうか?

そこがシングルスレッドであれば、回路の実体が1つでも複数でも気にする必要は無さそうですが、マルチスレッドであれば、XNAやHLSLのコードを組む上で注意点がありそうな気がしたので…。

いえ、私も事前のボーン計算などはマルチスレッドにしていますがXNA内でのメソッドコール部分はシングルスレッドです。XNAの内部でどうなっているかは不明ですが、DirectXのサンプルプログラムなどでも呼び出し部はマルチスレッドにしているものは見当たらないので、恐らく同じでしょう。

と言うより、「回路自体はじつは複数あるが、それはハードウェアやデバイスドライバ、DirectXがラップしているのでゲームプログラマは考えなくてよい」という設計思想のようです。なので「実際はもっと複雑だけれど、プログラムを組む時は(今回のブログにあるように)大まかに1つのものとして見なしてよい」と思います。

ただ、それでもシェーダが複数存在することを知っている方が理解しやすいケースがありまして、例えば「レンダリング中に、別の頂点やピクセルの演算結果を参照することはできない」というのがあります。隣りのピクセルに何が描かれているかは(そのピクセルが既に描画を終えているかどうか分からないので)取得することができないのです。なので隣りのピクセルを参照したい場合(ぼかし効果など)、いったん別のレンダターゲットに描く必要がある、というわけです。

ありがとうございました!

なるほど…わかりやすい解説を頂きまして、どうもありがとうございました。

お陰様で、とても良い勉強になりました!^^

コメントの投稿


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

トラックバック


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



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