もんしょの巣穴blog

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

[UE4] Weighted Blended OITの実装

今回はWeighted Blended OITと呼ばれる技術をUE4のエンジンコードを改造して実装する話です。
エンジンコード改造となりますので文字多めです。

・OIT(Order Independent Transparency)とは?
OITとはOrder Independent Transparencyの略です。
順序に依存しない半透明、というような意味ですが、ほぼそのままの意味です。

知っての通り、半透明を描画する際には描画順序が重要になります。
大抵のシステムではメッシュ単位などでZソートを行い、画面の奥のメッシュから順番に描画していきます。
この手法はほとんどどんなシーンでも有効に働きますが、一部のシーンではうまくいきません。

わかりやすいのは半透明メッシュが入れ子構造になっている場合です。
半透明のグラスの中にやはり半透明のウィスキーが入っている、という場合、正しい描画順序はグラスの奥→ウィスキー→グラスの手前となります。
しかしメッシュ単位での描画となるとウィスキー→グラス、もしくはウィスキー入りグラス1回で描画、という事にもなります。
後者はどうしようもないとして、前者はグラスの奥側を正しく描画できないので、グラスの奥は描画しないなどの措置がとられるのではないかと思います。

ゲーム中のちょっとした小物くらいならそれでもいいかもしれません。
しかし、昨今のゲームは大変映像が綺麗になっていて、カットシーンなどでも高解像度です。
また、ゲームエンジンを利用した建築ビジュアライゼーションなども需要が出てきています。
このような状況で半透明の順番を正しく考えなければならない、そういうデザインを心がけなければならないというが難しくなってきているのは否定できません。

OITを実装しているゲームはほとんどないのが現状ですが、非常に高い優先度とはいえないまでもあったら欲しい機能と考えられているのではないでしょうか?

・Weighted Blended OITとは?
OITの実装としてはLinkListを利用したものが最も有名なのではないかと思います。
手前味噌ですが、私も以前実装したサンプルをアップしています。

DirectXの話 第110回

この手法は新生トゥームレイダーでララ・クロフトの髪の毛の表現で使用されていましたが、やはり速度面で苦労していたようです。
正確に表現しようとするとこの手法は正確な半透明の順番を守ることが出来ます。また、トゥームレイダーでは順番を完全に正確に守らずに高速化を図っていたと記憶しています。

ある程度のスケーラビリティを持っていると言っても重いものは重い。
実装も比較的面倒ですし、このサンプルを作成した段階ではRadeonのドライバのバグで正常に描画されないこともありましたしね…

今回紹介するWeighted Blended OITは比較的軽く、実装も容易です。

Weighted Blended OITのペーパー

しかしかなり大胆に近似している手法であるため、正確な半透明表現はできませんし、使用の際には注意が必要です。

概要を簡単に説明してしまうと、半透明が重なった際に、その色が最終的な映像にどの程度影響を及ぼすかを重み付けして最後に正規化するという手法です。
と言ってもわかりにくいと思いますので、実例で解説します。

不透明メッシュ描画完了時、フレームバッファにはCsというカラーが描かれていたとします。
ここに(C1, A1)という半透明カラーが描画されたとしましょう。なお、Cはカラー、Aはアルファです。
それよりも手前に今度は(C2, A2)という半透明カラーが描画されます。
最終結果Cfは以下のような計算になります。

Cf = C2 * A2 + (C1 * A1 + Cs * (1-A1)) * (1 - A2) = C2 * A2 + C1 * A1 * (1 - A2) + Cs * (1 - A1) * (1 - A2)

アルファ値は0.0~1.0で、アルファ値同士の乗算(A1 * (1-A2)(1 - A1) * (1 - A2))は1.0を超えることはありません。
アルファ値に着目すると、最終結果により強い影響を与えるのはアルファの乗算結果が大きいカラーということになります。
つまり、A2が大きければC2の影響が大きくなり、A1が大きければC1の影響が大きくなります。
両方小さければCsの影響が大きくなります。

今度はA1 = 0.5A2 = 0.5とした場合の結果を計算してみましょう。

Cf = 0.5 * C2 + 0.25 * C1 + 0.25 * Cs

アルファ値が固定の場合、最後に描画されたC2の影響が大きくなります。
より一般的に考えると、深度が手前の半透明カラーの方が影響を与えやすいということです。

つまり、アルファ値が大きければ大きくなる、深度が近ければ大きくなる、という感じの関数 w(a, z) を作成し、これによって各半透明カラーの影響度を求める、というのがこの技術です。

弱点としてはあくまでも各カラー単体でのブレンドウェイトしか求められないため、前後関係などを正確に表現できるというわけではない点です。
そのため、画像処理ソフトで求められたブレンドの結果はこの技術で再現することはほぼ不可能です。
また、ウェイト関数によってはカメラの移動に対して結果が安定しません。
安定させようとすると今度は小さな距離の差がほとんど無視される結果になります。
入れ子構造の半透明ではまともな結果が得られないでしょう。

と、このように制約も大きな技術ではありますが、限定的な使用方法なら用途もあるんじゃないでしょうか?
…あるかなぁ?

それはともかく、続きからでソースコードの改変を行っていきます。

[[UE4] Weighted Blended OITの実装]の続きを読む
スポンサーサイト
  1. 2016/06/11(土) 12:42:57|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

プロフィール

Author:monsho
ゲームプログラマ?

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

カテゴリー

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

RSSフィード

リンク

このブログをリンクに追加する

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