スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

透明(アルファブレンド)の表現

XNAに関わらず透明なものを表現するというのはいろいろと面倒なものらしい。
プログラムもゲーム製作も知らなかった私にとってみると「なんで?」と心の底から思ってしまう。
3Dの物体が表示できる時点で想像を超えた世界にいるわけで、透明なものもちゃっちゃとやってくれるものだと思ってしまうのである。

さて早速透明なものを表現することにしよう。

その前に、この記事はアルファチャンネルを知ったばかりの初心者の記事であることを考慮して読んでください。
恐らく間違っている部分も含まれます!!!!

まず必要なのがαチャンネルというものだ。
DDS形式でいうところのA8R8G8B8というやつでRGB情報以外にアルファ情報を持った画像のことである。
アルファチャンネルを持った画像を作るソフトはいろいろあるのでググッってみてください。

アルファチャンネルを使うと0が完全に透明255が完全に不透明と表すことができ、その間の数値では半透明を表せるのである。(透明になるグラデーションなんかが使えますね)
メタセコで透明なMAPを作るとき白と黒で出来たファイルを作ると思うのですがその情報がまさにアルファチャンネル!白や黒や灰色はすべてRGBの値が同じなので一つのチャンネルで間に合うわけです。

さて、このアルファチャンネルを持った画像をXファイルのテクスチャに割り当てましょう。
メタセコなどでPNGやDDSを割り当てたとしても透明MAPを割り当てたわけではないので、透過しているようには見えません。(DDSはプラグインなど設定しないとテクスチャ自身みれません。したいときはsusieという言葉をヒントに!)
これをいつもどおりXNAでモデルを表示させましょう。

そして描写処理の前に
graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
graphics.GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;
graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
と書き込んでください。

終わったら
graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;と戻しておくといいでしょう。


以下おおざっぱな説明
~アルファブレンディング~
・アルファブレンディングとは半透明を表現するために使う設定

//アルファブレンディングによる透明化を有効にする値
graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;

//(ソースピクセル×SourceBlend)と(バックバッファピクセル×DestinationBlend)に適用する算術演算
//Add 加算
//Max 大きい方の値
//Min 小さい方の値
//ReverseSubtract(バックバッファピクセル×DestinationBlend)-(ソースピクセル×SourceBlend)
//Subtract(ソースピクセル×SourceBlend)-(バックバッファピクセル×DestinationBlend)
graphics.GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;

//(ソースピクセル×SourceBlend)と(バックバッファピクセル×DestinationBlend)のBlend方法
//s=ソース値 d=デスティネーション値として説明
//Zero カラーの各成分に (0, 0, 0, 0) を乗算
//One カラーの各成分に (1, 1, 1, 1) を乗算
//SourceColor (Rs, Gs, Bs, As)
//InverseSourceColor (1 - Rs, 1 - Gs, 1 - Bs, 1 - As)
//SourceAlpha (As, As, As, As)
//InverseSourceAlpha (1 - As, 1 - As, 1 - As, 1 - As)
//DestinationAlpha (Ad, Ad, Ad, Ad)
//InverseDestinationAlpha(1 - Ad, 1 - Ad, 1 - Ad, 1 - Ad)
//DestinationColor (Rd, Gd, Bd, Ad)
//InverseDestinationColor(1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad)
//SourceAlphaSaturation (f, f, f, 1) ここで、f = min(A, 1 - Ad)
//BothInverseSourceAlpha (1 - As, 1 - As, 1 - As, 1 - As)ブレンディング係数は (As, As, As, As)
//BlendFactor カラーの各成分に、BlendFactor で設定された定数を乗算
//InverseBlendFactor BlendFactorで設定された定数の反転値を乗算
//BothSourceAlpha このメソッドは廃止された
graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;


//アルファ チャンネルのみのブレンディングには以下を使うらしい
//graphics.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = true;
//graphics.GraphicsDevice.RenderState.AlphaSourceBlend = Blend.One;
//graphics.GraphicsDevice.RenderState.AlphaDestinationBlend = Blend.InverseSourceAlpha;


これで半透明は表現できる。
透明かそうでないかの二択でよい場合がある。
そんなときは、以下。

~アルファテスト~
・アルファテストとは透過するかしないか?の判断テスト。二択である。

//ピクセル単位のアルファ テストを可能にするレンダリング ステート
graphics.GraphicsDevice.RenderState.AlphaTestEnable = true;

//アルファテスト有効時、ピクセルをテストするための基準となるアルファ値 既定値は0
graphics.GraphicsDevice.RenderState.ReferenceAlpha = 1;

//アルファテストのための比較関数 デフォルトは CompareFunction.Always
//Always :テストは常に成功します。
//Equal :新しいピクセル値が、現在のピクセル値未満の場合に、新しいピクセル値を採用
//Greater :新しいピクセル値が、現在のピクセル値を超える場合に、新しいピクセル値を採用
//GreaterEqual:新しいピクセル値が、現在のピクセル値以上の場合に、新しいピクセル値を採用
//Less :新しいピクセル値が、現在のピクセル値未満の場合に、新しいピクセル値を採用
//LessEqual :新しいピクセル値が、現在のピクセル値以下の場合に、新しいピクセル値を採用
//Never :テストは常に失敗します。
//NotEqual :新しいピクセル値が、現在のピクセル値と等しくない場合に、新しいピクセル値を採用
graphics.GraphicsDevice.RenderState.AlphaFunction = CompareFunction.GreaterEqual;


これで完璧。

最初RenderStateを弄るときに「スプライト表現のときだけ?」「これはBasicEffectの時だけ変わるんでしょ?」などと思っていたのだが、カスタムシェーダでもなんなくいけた。
非常に

さてここでようやく透明の大変さがわかってきた。
透明ってことは奥から順に書いていかないと透過している部分がおかしなことになるのである。
その描写順のソートを自前で行わなければならないというのだ。
グーグル先生に頼ってみようと思ったのだがいかんせん情報も少ない。これは困った。
とりあえず流れとしては

不透明なものをざーーーっと描く。
透明なものをざーっと描く。


としたいのだけれども透明かどうか?を調べる方法が見当たらない。仕方ないのでコンテントパイプラインでXMLファイルを読み込む時にそのマテリアルが透明かどうか?のパラメータを渡してやることにした。
これで済むかと思いきや、また壁にぶち当たる。頭クラクラピヨピヨ。
「メッシュをDrawしてやるときに特定のエフェクトは描写しない」という処理を作らないと上記の処理ができないのである。二度描くならそれでもいいのだが重なる描写をするなんてナンセンス。

メタセコでいう素材(マテリアル)ごとにメッシュが生成されてくれていれば簡単なのだが、私の環境では複数のマテリアルとオブジェクトが存在するXファイルを書き出してもメッシュが一つになるようだ。
不透明部分が存在する部分だけ別ファイルにする・・・のもおかしい。
仕方ないのでシェーダで何もしないように設定した。(た、多分軽い)

ここまでの流れをソースにして載せようと思ったが、かなり私の環境に依存しすぎている。これをみて助かる人がいるとも思えなくなってきた(涙)のでやめた。うん、遠い目。


メタセコを弄っていると透明な部分がおかしくなることがある。
これは描写順がおかしいためだ。
オブジェクトの上から描写されていく~というのは感がいい人なら気づいて即修正すると思う。
ここで注意したいのが

メタセコの描写順=エルフレイナの描写順≠XNAの描写順

だということ。
XNAの描写はメタセコのオブジェクトの描写順の真逆から描写されるようだ。
↑と勘違いしていたら実は「メタセコの描写はオブジェクト窓の順だがXNAはメタセコのマテリアルの欄の順で描写される」が正解のようだ。

一応思った描写はできたのだが、透明表現はまだ触れたばかりでこの先おかしな部分もでてくるかもしれない。(私の感がそう思わせる)
アルファブレンド自体、結構重い処理らしいので多用はせず髪の毛などの「使わないと仕方ない部分」だけに留めておきたいものである。





読み返すと「無駄に長い」


ねよっと。

コメントの投稿

非公開コメント

プロフィール

あしゅ

Author:あしゅ
ぷぃぷぃ日常。
いつのまにか雑記ブログに。

カテゴリ
最新記事
検索フォーム
最新コメント
リンク
このブログをリンクに追加する
ブロとも申請フォーム

この人とブロともになる

カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。