質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

1回答

5391閲覧

Unity Universal RP における影のみの描画とレイヤーを用いた透過

octa_gongon

総合スコア6

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2020/01/31 10:03

編集2020/01/31 10:06

前提

Unity の Universal RP を用いてARアプリケーションを制作しようとしていて、次の2つの処理を実装したいのですが、シェーダについての理解が追いついておらず、うまくやる方法が見つかりません。知恵をお貸しいただけると幸いです。

実現したいこと

1. 受けた影だけを描画するシェーダ

ARなので、影だけを描画したいのですが、URPに対応したシェーダでのやり方がわかりません。
このページで紹介されているカスタムノードを用いてシャドウのマップを取得することはできており、PBR Graph を用いて影の落ちた平面の影部分を透過することはできるのですが、透過を逆転させると影の落ちている部分と落ちていない部分の区別ができなくなります。(透過してしまった部分は影を受けられないから、という理解で合っているでしょうか…?)
影だけ透過するシェーダ
影だけ透過するシェーダ

2. 透明マント

ハリーポッターの透明マントの要領で、自身が透明かつ自身よりも奥のオブジェクトをすべて透過する処理を実装したいです。このページを参考にいろいろいじってみたところ、一応はできました。(なぜか記事の通りにやっても同じことができなかったのですが、透明マントレイヤーと通常オブジェクトでレイヤーを分けてどちらもDefault Layer Maskから外したうえで、マント→オブジェクトの順でRender Features を用いて追加の描画をしています。ここでマントに透過オブジェクトを用いれば図のように処理できました。)
イメージ説明

しかし、Default Layer Maskから対象を外してしまった時点でオブジェクト同士のシャドウが描画されなくなってしまうのが気に入りません。先ほどの記事のように遮蔽部分の描画色を変えるだけならDefault Layer Maskから外さずにシャドウを維持して行えたのですが、この処理で遮蔽部分のシェーダに透過シェーダを適用すると下にもともとのオブジェクトが描画されているため思ったような表示になりません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

#「受けた影だけを描画するシェーダ」について

下図のように、マスターノードの設定を乗算モードにしてやるというのはどうでしょうか?
ついでに、影の色を調節できた方がいいかと思ってプロパティを用意し、そのRGBは影にスクリーン合成、さらにAに応じて白色を乗せてやり影を薄めるようにしてみました。

図1

マスターノードですが、すみませんが勉強不足につきPBRマスターが内部で何をしているか分からず、余計な色を乗せてしまうかもしれないと不安になりまして、PBRよりも素直な色を描いてくれるだろうと期待してUnlitマスターを使用しました。
ですがこれだとシェーダーグラフのカスタムライティング:Unity 2019 でグラフを拡張する - Unity Technologies Blogのやり方そのままでは正しくShadowAttenを得ることができず、Unity2019.3 URP ShaderGraph Unlit マスターで影を受けるの方法に基づいてライト情報取得ノードのコードを下記のように変更しました。

HLSL

1#if SHADERGRAPH_PREVIEW 2 Direction = half3(0.5, 0.5, 0); 3 Color = 1; 4 DistanceAtten = 1; 5 ShadowAtten = 1; 6#else 7#if SHADOWS_SCREEN 8 half4 clipPos = TransformWorldToHClip(WorldPos); 9 half4 shadowCoord = ComputeScreenPos(clipPos); 10#else 11 half4 shadowCoord = TransformWorldToShadowCoord(WorldPos); 12#endif 13 Light mainLight = GetMainLight(); 14 Direction = mainLight.direction; 15 Color = mainLight.color; 16 DistanceAtten = mainLight.distanceAttenuation; 17 ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData(); 18 half4 shadowParams = GetMainLightShadowParams(); 19 ShadowAtten = SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), TransformWorldToShadowCoord(WorldPos), shadowSamplingData, shadowParams, false); 20#endif

#「透明マント」について
当初はレンダリングパイプラインのカスタマイズで何とかしようと思ったものの、ご質問者さんのおっしゃる影問題をどうにも解決できずあきらめました...もしかするとパイプラインの途中にちょこっと追加処理を挟むだけでは困難で、レンダリングパイプラインを完全に自作してやる必要があるかもしれません。
代替案として、カメラをもう一つ用意して背景だけを描かせ、メインのカメラのレンダリング時にはそれを透明マントの表面に貼り付ける方針を検討してみました。

まずシーン上にあるオブジェクトのうち、透明マントを着たオブジェクト(ご質問者さんの想定における薄紫色のキューブ)と透明マントを通すと見えなくなるオブジェクト(ご質問者さんの想定における不透明キューブ)のレイヤーをともに「InvisibilityCloakEffect」と名前を付けたレイヤーに設定しました。これ以外のレイヤーにあるものは透明マントを通しても見ることができるという想定です(背景オブジェクトなど)。
メインカメラの子としてもう一つカメラを作り(メインカメラを動かした際に追従して動かしたかったため)、下図のようにPriorityを-2、Output Targetを適当なレンダーテクスチャとしました。Culling MaskからはInvisibilityCloakEffectレイヤーを除外しています。
なお、もしおっしゃるように本当に自身よりも奥のオブジェクトをすべて透過する...つまり地面すら貫通して背景が見えるようにしたい場合はレイヤー分けすら不要で、Culling MaskをNothingにしてしまえばいいでしょう(ARとのことですので、背景は実写映像であって地面は不要ということでしょうか)。
Audio Listenerもメインカメラのものがあるので外しました。

図2

メインカメラ側は特に設定はいじっていません。

図3

透明マント用マテリアルは下図のような構成にしました。テクスチャプロパティとして「Albedo」と「Background」、色プロパティとして「Color」を作り、Albedoからサンプリングした色とColorを掛け、RGBにはAを乗算して暗くしてからアルベド色として出力しました。
Backgroundからはスクリーンスペース座標を基に色を取ってきて、アルファに応じて強度を落としてからエミッションに接続しました。

図4

それを使ったマテリアルを作り、Backgroundにはサブカメラのレンダリング先となるレンダーテクスチャをセットしておきます。ColorやAlbedoを調整すると色を乗せることができ、それらのアルファが小さいほど背景色が優位となって透けていきます。

図5

この結果、下図のような見た目になりました。
奥にある青玉、半透明の赤玉、市松模様の床はサブカメラのレンダリング対象になっているので透明マントを通して見えるのに対し、白と灰色のキューブは透明マントによって隠されます。透明マントを着た中央の紫キューブは実際のところ不透明オブジェクトとして扱われていますので、影を落としたり影を受けたりすることが可能です。

図6

透過部分の映像はサブカメラに依存していますので、シーンビューでは背景がずれて表示されてしまう欠点がありますが、ゲームビュー上ではまともに見えるかと思います。この方式の利点としては、透明部分の見え方を透明マントマテリアル側でコントロールしやすいというのが挙げられるかもしれません。たとえばBackgroundテクスチャをサンプリングする際にサンプリング座標を適当に変調させてやれば、プレデターみたいに背景が歪んでかすかに存在を察知できる...みたいな表現もできそうです。

投稿2020/02/03 10:07

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

octa_gongon

2020/02/07 12:32

ありがとうございます…!手元の環境でも再現をすることができました。render texture によるこうした手法は初めて知ったので感動しております 重ねて申し訳ないのですが、例えば影のみのシェーダをCubeに適用すると光が当たっていないはずの側面にも影が出てしまう(Shadow atten が影を受ける向きを考慮していない…?)のですが、これを解決する方法はないでしょうか…
octa_gongon

2020/02/07 13:52

すみません、これに関しては自己解決しました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問