
ShaderGraphを使ったClusterスクリーンの特殊表現
挨拶
こんにちは。Clusterでクラブ用ワールドの作成とクラブイベントを運営しているWakkyと申します。
本記事は Cluster Creator #2 Advent Calendar 2023 の8日目として投稿いたします。普段記事を書く習慣がないため拙い文章ですがご容赦ください。
テーマ
Clusterのワールドの必須アイテムであるメインスクリーンですが。普通の使い方をするとBaseColorのテクスチャとして画像や映像が出力されます。これに少し手を加えてEmissionMapとして出力する方法を紹介いたします。
イメージは下の動画を見ていただくと早いと思います。
主にShaderGraphを使って作成していきます
こういう演出の解説って需要ありますかね?
— Wakky (@W_akky) December 4, 2023
僕のワールド #BlueLounge で使ってる手法なんですが、クラスタースクリーンの共有映像を投影映像風にしています。割と簡単なんですがあまりやってる人を見ないので。。
需要ありそうならアドベントカレンダーに書こうかと思ってます。#cluster pic.twitter.com/hqgWNGCjpA
前提事項
Unityの導入およびClusterCreaterKitが導入済みのものとして話を進めます
アセットの準備
オブジェクトとマテリアルの設定
Scene上にスクリーンを表示するオブジェクトを準備します。簡単のためにQuadを使います。
※Materialも新規作成して追加してください。名前を「ScreenMat」としました作成したQuadにAddComponentからStandardMainScreenViewを追加してください
ShaderGraphの導入、適用
PackageManagerからShaderGraphをインストールします
新規シェーダーを作成します
Projectウィンドウ上で右クリック⇒Create⇒ShaderGraph⇒BuiltIn⇒LitShader Graph を選択。今回Shader名を「CustomScreenShader」としました。
※LitShaderとは:光の影響を受ける(物理ベース)シェーダーのことMaterialのShader設定を「Shader Graphs/CustomScreenShader」に指定します
テクスチャセットの準備
効果を分かりやすくするためにPBRテクスチャを利用します。今回は以下のフリーテクスチャを利用しました
https://ambientcg.com/view?id=Tiles093
準備が終わったらInspectorが下図のような状態になっています

各テクスチャのノード作成
作成したShaderGraphをクリックするとノード編集ウィンドウが開きます。まずはPBRテクスチャを適用するためのノードを組んでいきます。
LitShader Graphでは画像のようなノードがあらかじめ用意されています。この中のFragmentノードが色情報を最終的に出力するノードです。ここに各種テクスチャノードを接続していきます。

BaseColorノードの作成
BaseColorテクスチャを設定するためのノードを作成します
スペースキーを押してCreateNodeウインドゥから「Sample Texture 2D」を追加
同様に「Texture 2D Asset」を追加してSample Texture 2DのTextureに接続
Sample Texture 2DのRGBA(4)をFragmentノードのBaseColorに接続

BaseColorノードのプロパティ化
Inspector上で操作できるように必要なノードをプロパティ化していきます
Texture 2D Assetを右クリック⇒Convert to ⇒ Property
左のPropertyリストに追加されるので、名前をColorTexに変更します

Normalノードの作成
BaseColorノードと同様の手順でNormalノードを作成します。FragmentノードのNormalに繋ぐ部分以外は同じ手順です。

Roughnessノードの作成
RoughnesMapを適用するためのノードを組みます。LitShader GraphではSmoothnessで定義されていますので色情報を反転させる必要があります。
BaseColorノードと同様の手順で Sample Texture 2D と Texture 2D Asset を接続
One Minusノードを作成してRGBA(4)アウトプットとSmoothnessインプットの間に接続

使用するテクスチャセットが非金属なので、今回Metallicノードの作成は省略します
ClusterScreenを適用する
ここからがこの記事の本題です。ClusterScreenが反映されるノードを作成していきます
スクリーン用ノードの作成
下図のようなノードを組みます。そろそろ操作に慣れたと思いますので細かい操作説明は省略します。

今までのノードとの違いはSample Texture 2DのUVに接続してる部分です。ここにはテクスチャの配置(TilingやOffset)の情報が渡されています。部の図のTexture 2D AssetとVector 4に適切な設定をすることでメインスクリーンとして使用することができるようになります。
スクリーン用ノードのプロパティ設定
Texture 2D AssetとVector 4をプロパティ化します。名前の設定は任意で大丈夫です

プロパティ化したTextur 2D Assetを選択して、GraphInspectorのNodeSettingのReferenceを「_MainTex」に書き換えます。メインスクリーンはこの設定を入れたテクスチャに画像や映像を反映します。
※何も投影していないときに発光しないようにModeの部分をBlackに設定しておきます。

プロパティ化したVector4を選択して、GraphInspectorのNodeSettingのReferenceを「_MainTex_ST」に書き換えます。こうすることでメインスクリーンのUV情報がこの4次元ベクトルに反映されます。
Vector4の各パラメーターは以下の情報をUVに渡します
x:横方向の縮尺
y:縦方向の縮尺
z:横方向のポジション
w:縦方向のポジション
※スクリーン投影するとこの4つのパラメーターがメインスクリーンの指定値に上書きされます

Maskノードの作成
スクリーンの枠外の部分が光らないようにEmissionにMask処理をするテクスチャのノードを組みます。

使用するMaskテクスチャには以下のような画像が必要になります。
・白い部分のアスペクト比が16:9の正方形の白黒画像
面倒臭い場合は下の画像をそのまま使ってください。

MaskとスクリーンのノードをBlendする
スクリーンのノードとMaskのノードをBlendノードでMixします。BlendModeはMultipleにしてください。
さらにスクリーンの色の強さを調整できるようにMultiplyノードに繋ぎます。さらにB側のインプットにSliderノードを接続してプロパティ化します。
最後にMultiplyノードのOutをFragmentノードのEmissionに繋ぎます。

最終的なプロパティの状態

マテリアルに各種テクスチャを設定する
QuadのInspectorを開いて以下のようにダウンロードした各種テクスチャとMaskテクスチャを適用します。ScreenTexには何も入れません。

動作確認
Unity上で再生して、サンプル画像を投影してみましょう
・Cluster⇒Preview⇒ControlWindow⇒サンプル画像を投影
以下のような後ろが透けたようなスクリーンになれば成功です。
※Strengthの値をいい感じに調整してください。

ワールドアップロードをして映像を写した動画が冒頭のXの投稿になります。
応用:構造体の一部に埋め込む
実用性を求める場合、ビルや壁などの一部にScreenを埋め込む処理が必要になります。
サンプルモデルのUV設定
Blender等のモデリングソフトで簡単な壁のモデルを作成します。形とテクスチャはなんでもいいです。今回は以下のような壁を作成しました。

このモデルの図のオレンジの選択した位置にスクリーンが投影されるようにします(下図)。選択箇所のメッシュはClusterScreenのアスペクト比(16:9)に調整してください。

BaseColor、Normal、Roughness用のUV(1枚目)に加えて、ScreenとMask用のUV(2枚目)を作成します。
2枚目のUVではスクリーンを移したい部分をマスクテクスチャの白い部分に合わせて、スクリーンを写さない部分のメッシュは縮小してマスクの黒い部分に配置します


Unityで対応UVを指定する
Unityにモデルをインポートして作成済みのCustomScreenShaderを適用します。
スクリーン用ノードとMask用ノードの各UVを2枚目のUVとして指定します。※赤枠部分をUV0→UV1に変更

Sceneを再生してClusterのサンプル画像が図の様に表示されれば完成です。

余談
ノードの組み方次第でいろんな効果を演出できます。自分の作成ワールドであるBlueLoungeにも設置しています。
下の動画では背面の壁がEmissionに、前面のDJブース側がNormalMapに共有映像を投影しています。
#BlueLounge のスクリーンを改修した。だいぶNormalMapが強調して映るようになったと思う。 pic.twitter.com/VSsiNjumSV
— Wakky (@W_akky) August 18, 2023
ワールドのリンクはこちら