もんしょの巣穴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

[UE4] HTC Viveでプレイヤーの顔の位置を取得する方法

個人的な覚書。

HTC Vive(に限らないと思うのですが)、プレイヤーの顔の位置、つまりヘッドセットの位置を取得したい場合があるはずです。
キャラがこっちを向くとか、敵がこちらを攻撃してくるとか。

UE4にはHMD関連の命令として [Get Orientation and Position] という命令があります。
これで取得できるPositionを使えばいいんだよね?と思っていたらそうじゃなかった。
どうの座標が正確に何なのかはわからないのですが、どうも焦点位置っぽい。

ではどうすればいいのかというとこういう感じにノードを組む。

ue409.jpg

これで正常にプレイヤーの顔の位置めがけて弾丸を発射してくれましたとさ。
やったね!
  1. 2016/05/08(日) 18:34:24|
  2. UE4
  3. | トラックバック:0
  4. | コメント:1

[UE4] 昔懐かしいレンズフレア

少し前にある方々と飲んだ時のこと、VRにおけるポストプロセスはなんとかならないだろうか、という話題が出ました。

VRでは、主に速度的な問題で、全画面処理を複数回行わなければならないポストプロセスはコストが高くなります。
その上立体視なので、左右で画面の描画状態が異なり、派手なポストプロセスほど誤魔化しきれない問題を発生させます。

しかし、主に映像業界の人からすると、ポストプロセスはできるだけ使いたくなるわけです。
派手でかっこいい映像を作ろうと思えば思うほどポストプロセスは重要になります。
エフェクトやモーションももちろん重要ですが、よりかっこよく!と求めていくとポスプロに進まざるを得ません。

ポスプロの速度的なコストは、最悪恐ろしいレベルのハイスペックPCを用意すればなんとかなるかもしれません。
しかし、立体視との相性問題はかなり手強い技術的問題です。

特に飲み会で話題になっていたのはDOFとレンズフレアでした。
この2つはランタイムコストもさることながら、立体視との相性が疑問視されるポスプロです。

DOFについてはエンジニア(自分含む)は比較的肯定的でした。
DOFによって視線誘導がしやすいのではないか、というのが理由でした。

しかしこれに関しては反対意見もありますので、何ら問題がない、とは言えないでしょう。
下手をすると視線誘導が露骨すぎて酔う原因になるかもしれません。

もう一つのレンズフレアは特にUE4では難しいです。
UE4のレンズフレアはやはり描画された画面情報から生成するわけですが、強い光源が左右の画面で同じように出るとは限りません。
つまり、レンズフレアを生成する光源が右目用画面のみに描画されるという状態では、右目画面にはレンズフレアが発生し、左目画面には発生しないという状態になります。
これはもちろんよろしくない状態で、しかも解決が難しい問題になってしまいます。

そこで白羽の矢が立ったのが昔ながらのスプライトを利用したレンズフレアです。
太陽や点光源くらいにしか使えませんが、演出として使うには必要十分でもあります。

さて、ここで問題。
立体視で昔ながらのスプライト式レンズフレアはどのように見えるのが正しいのか?
レンズフレアはレンズ内部での光の再反射によって発生するのでレンズ面(スクリーン面とほぼ同じ?)に張り付いて見えるのが正しい?
しかし、人間の目は左右で場所が違っているので、光の再反射の仕方も変わるはず。左では見えるけど右は見えない、もしくはその逆だっておかしくないのでは?
これらは本来の正しさよりも、人間が自然に見えるのは何か?という感覚的な問題になってくるような気がします。

これはある作品で実装したことがあるのですが、リファレンスとした作品は2作品あります。

1つはPC版バイオハザード5です。
あまり知られていないかもしれませんが、PC版バイオハザード5は立体視に対応していました。
そしてレンズフレアはスクリーン面に張り付いている形、つまり視差なしの状態ですべてのフレアが描画されていたのです。
これを見て思ったのは…開発者の方には大変申し訳無いのですが、これはひどいw でした。

バイオハザード5の立体視はスクリーン面をガラス窓として、その奥でゲームシーンが進行するジオラマのような立体視の使い方でした。
もしかしたらシーンによっては飛び出しも利用していたかもしれませんが、自分が確認した短い時間では確認できませんでした。
つまり、ガラス窓を通して動くジオラマを見ていたら、そのガラス窓にぺたりとレンズフレアっぽい光の輪がいくつも張り付いていたわけです。
残念ながら見たことがある人でなければこの感覚は正確にわからないと思いますが、ある程度想像できるのではないでしょうか?

もう1つの作品は、これは見たことがある人も多いと思われますが、映画トランスフォーマー/ダークサイド・ムーンです。
この作品は当時増えてきていた立体視作品の中でも特に出来が良かったと思います。
レンズフレアやグレアなどの表現もそれまでの作品と比べて非常に多く使われていて、前述の作品を作成している最中に大変参考になった作品です。
実際にレンズフレアが使われているのは予告編でも見られます。

https://www.youtube.com/watch?v=rRIf17ntga0

もちろん、立体視で見なければどうなっているのかわかりませんが。

この作品を立体視で見たのは劇場でのみ1回だけですが、その時にこの手のポスプロは極力チェックするようにしてました。
…まあ、途中から映画が面白くてそちらにばかり集中してしまいましたがw
運が良かったのはレンズフレアがかなり早いうちに出てきてくれたことです。
少なくとも自分が見た限り、レンズフレアには奥行きがありました。
光源からどんどんこちらに向かってきていると感じられたわけです。
自分はそう感じた、というだけで現実にはそうではなかったかもしれませんが、少なくともバイオハザード5のようなものではありませんでした。

申し訳ありませんが、以前関わった作品でどう実装したかについてここでは書けません。
とりあえず言えることは、今回の実装方法とは別、ということだけですね。
着想自体はトランスフォーマーで間違いないです、はい。

今回UE4での実装では、通常は2Dスクリーン上に貼り付けるフレアスプライトを今回は3D空間上に、奥から手前に配置されるようにしてみました。
処理的にも軽いので、VRでも使用できるかもしれません。
残念ながらVRHMDを持っていないので確認できていませんが、どなたか確認していただけると助かります。

とまあ前置きが長くなりましたが、続きからで実装を提示します。


[[UE4] 昔懐かしいレンズフレア]の続きを読む
  1. 2016/01/24(日) 02:05:37|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

[UE4] Customノード3分ハッキング

UE4 Advent Calendar その2、12日目の割り込み記事です。
代わりに書くボタンが出来ていたので、予定のものとは全く異なる記事ですが割り込ませていただきました。
元担当者の方、問題があるようならコメンとなりTwitterなりで呼びかけていただけると助かります。

10月のUnreal Fest後の飲み会にて、ギルティギアなどでお馴染みのアークシステムワークス家弓さんからマテリアルエディタの [Custom] ノードについて面白い話を教えてもらいました。
試してみたところ実際にうまくいき、そのことをTwitterで呟いたら家弓さんが簡単にまとめてくださいました。



プログラマであればこの情報だけで色々とできるようになるかと思いますが、[Custom] ノードはこの方法を使ったちょっと特殊な手法なんかもありますので、ここでまとめておこうと思います。
なお、最新のUE4.11 Preview1にて動作を確認しています。
今後のアップデートで使用できなくなったり、使用できるけどやり方変えないとダメという場合もあるかもしれませんのでご注意ください。

元々、Epic Games的には、[Custom] ノードはノードベースで作成するには面倒だけどコードで書いたらすごく簡単、といったものを簡単に実装できるように用意したものではないかと思います。

わかりやすい例を挙げるならベクトルの要素のスウィズルですね。
スウィズルは主にシェーダで用いられますが、要素の入れ替え処理です。
使い道はともかくとして、例えばfloat3のカラーの値があったとして、これのrgb値をgbrの順番に入れ替えたい、という場合です。
これをマテリアルノードで表現するとこうなります。

ue392.jpg

[Texture Sample] ノードの場合は [Component Mask] を使う必要は本来ないのですが、定数でも同じように処理できるようにするために使用しています。
この程度のノードの組み方は別に難しくはありませんが、同じような処理が散見されるようになってしまうと可読性が悪くなってしまいます。
この組み方がマテリアルエディタのいたるところで使用されている、という状況を想像するだけで処理を追いたくなくなるんじゃないでしょうか?

では、これを [Custom] ノードで表現すると、このようになります。

ue393.jpg

結果は同じですが、マテリアルノードは[Custom]1つだけです。
処理もたったの1行で、極めて簡単です。
ベクトル要素のスウィズル機能は現在のプログラマブルシェーダを組み込んでいるハードであればこのように簡単に実装できるのですが、ノードで表現するとどうしても冗長になってしまいますね。

このように冗長なノードを簡単にまとめられるという利点が [Custom] ノードには存在しますが、いくつか弱点が存在しています。
プログラムコードを書かなければならないためシェーダプログラムに対する知識が必要だという点が1つ、プラットフォームごとにコンパイルが通るコードを書かなければいけないという点が1つ、そしてなにより、マテリアル関数として作成されている関数を呼び出すことが出来ないという点です。

1つ目の問題は、まあ [Custom] ノード使う人はシェーダコードの書けるプログラマかTAくらいでしょうからそれほど問題にならないでしょう。

2つ目の問題も当たり障りのない処理を書く分には処理系に依存することはほぼありません。四則演算やlerp, powといった、どのプラットフォームにも存在する命令だけを使っておけば問題になりません。

3つ目の問題は現状では対応できません。が、やはり使いたいと思うことはあるのではないかと思います。
実は今回の [Custom] ノードの家弓メソッド(適当に命名w)を使うと、この問題にも限定的ではありますが対応できるのです。

というわけで、続きからで家弓メソッドの詳細と、様々な使い方について書いていこうと思います。
ただ、先に注意しておくと、この手法はハック的な手法であるため、いつか使用できなくなる可能性もあります。
家弓さんの話ではUE3の頃から使えた手法らしいのでそんなに簡単に潰されることはないとは思いますが、使用の際には十分注意してください。

[[UE4] Customノード3分ハッキング]の続きを読む
  1. 2015/12/23(水) 12:01:42|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

[UE4] GBufferを拡張せずに異方性スペキュラをやってみる

前回前々回のAdvent Calendar用記事ではGBufferを拡張してワールド空間タンジェントを保存、異方性スペキュラを実装とやっていました。
しかし、GBuffer拡張時にも書いたように、GBufferが増えることによってGBuffer書き込み時の処理速度に影響を与えるという問題が浮上してきます。

昔のハードウェアはGPUの計算能力が低かったため、色々なものをテクスチャに保存してルックアップテーブルとして参照するということをやっていました。その方が速かったわけです。
しかし現代のハードウェアは計算能力が大変高くなったため、ルックアップテーブルを利用することで遅くなる事例も出ています。
GBufferにしても同様で、GBufferを増やして書き込み、読み出しを行うより、今あるGBufferに圧縮して書き込み、読みだしてデコードする方が高速な場合も存在します。
もちろん、実装方法や条件によっても変化はすると思いますが、GBufferを増やさなくて済むならそれに越したことはないはずです。
某ハードの場合だと特に、GBufferを増やしたらESRAMに載らなくなりました、なんてことになりかねませんからね!

というわけで、前回まではGBufferを増やして高品質な異方性スペキュラをやる方法を提示したわけですが、今回はGBufferを増やさずに対応する方法を提示していきます。
ついでにマテリアル入力を増やして、タンジェントと異方性の度合いをマテリアルエディタで計算、設定ができるようにします。

今回もまたソースコード量が多目です。
一部のコードは前回と被りますので、そちらも参照していただければと思います。

[[UE4] GBufferを拡張せずに異方性スペキュラをやってみる]の続きを読む
  1. 2015/12/13(日) 14:05:25|
  2. UE4
  3. | トラックバック:1
  4. | コメント:0
前のページ 次のページ

プロフィール

monsho

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

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

カテゴリー

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

RSSフィード

リンク

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

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