見出し画像

動画と連動するライトをつくる

Clusterワールド製作者向けのワールドギミック解説記事です。

こちらのワールドで使用した色変更ギミックのつくり方の解説記事になります。シェーダーコードを含む解説のため、中級者向けの内容になります。

仕組み

1. カメラで色を取得→RenderTextureに保存
2. RenderTextureをシェーダーパラメータとして指定→モデルに色を反映

ざっくりとこのような仕組みになってます。

カラーピッカー作成

 Cluster内のオブジェクトから色を取得するカラーピッカーの作成方法を解説します。

ここで作成するカラーピッカーのサンプルはこちらからダウンロードできます。

1. 持ち手作成
「Hierachyウィンドウ」上で右クリック→「Create」→「3D Object」→「Cube」を作成し、名前を「ColorPicker」にします。

画像1

図のようにScaleをX:0.01, Y:0.01, Z:0.25に設定します。
プレイヤーとコライダーの干渉を避けるため、「Box Collider」の「IsTrigger」をONにします。(削除でもOK)
また、掴めるように「Inspectorウィンドウ」の「Add Component」ボタンを押し、「Grabbable Item」を追加します。
手を放しても床に落とさないようにするため、Rigidbodyの「Is Kinematic」をON、「Use Gravity」をOFFにします。

2. ピッカー部分作成

画像2

図のように「ColorPicker」直下に再度「Cube」を作成し、名前を「Picker」とします。
ScaleをX:0.25, Y:0.25、PositionをZ:1に設定します。
こちらも「Box Collider」の「IsTrigger」をONにします。(削除でもOK)

レンダーテクスチャ作成

カメラで取得した色を保存するレンダーテクスチャを作成します。

「Projectウィンドウ」で右クリック→「Create」→「Render Texture」
名前は「CameraColorTex」にします。
先程作成したテクスチャを選択します。単一の色を保存できれば良いのでサイズを1x1、FilterModeをPointにします。

RenderTextureサイズ

カメラを作成

色を取得するカメラをカラーピッカーに設置します。

「ColorPicker」を右クリック→「Create」→「Cemera」を新規作成して、名前を「PickerCamera」にします。

画像4

「PickerCamera」を選択し、図のようにPositionをZ:0.5に設定します。
Cameraの「ClearFlags」を「Solid Color」、「Background」を黒 RGB(0,0,0)に設定します。これで何も映っていない領域が黒で初期化されます。
さらに、「Projection」を「Orthographic」に変更、Sizeを0.001、Near:0.01、Far:0.25に設定します。これでPickerに交差した部分だけカメラに写るようになります。
最後に、TargetTextureに「CameraColorTex」を設定します。AudioListnerも不要なので削除します。

これでカメラからRenderTextureに色を取得、保存する機構ができました。

オブジェクトに色を反映させる

RenderTextureに保存した色をオブジェクトに反映させるためにはマテリアルのTextureにRenderTextureを指定します。

StandardシェーダーなどはTextureの指定ができますが、対応するシェーダーがない場合は新規作成するか、既存シェーダーを改造する必要があります。

シェーダーを新規作成する

まずは対応するシェーダーを新規作成してみましょう。(作成が不要な方は読み飛ばしてかまいません。)

「Projectウィンドウ」で右クリック→「Create」→「Shader」→「Unlit Shader」を新規作成して、名前を「ColorChangeShader」にします。

Shader "Unlit/ColorChangeShader"
{
   Properties
   {
       _ColorTex("ColorTex", 2D) = "white" {}
   }
   SubShader
   {
       Tags { "RenderType"="Opaque" }
       LOD 100

       Pass
       {
           CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
           #pragma multi_compile_fog

           #include "UnityCG.cginc"

           struct appdata
           {
               float4 vertex : POSITION;
               float2 uv : TEXCOORD0;
           };

           struct v2f
           {
               float2 uv : TEXCOORD0;
               UNITY_FOG_COORDS(1)
               float4 vertex : SV_POSITION;
           };

           sampler2D _ColorTex;

           v2f vert (appdata v)
           {
               v2f o;
               o.vertex = UnityObjectToClipPos(v.vertex);
               o.uv = v.uv;
               UNITY_TRANSFER_FOG(o,o.vertex);
               return o;
           }

           fixed4 frag(v2f i) : SV_Target
           {
               fixed4 col = tex2D(_ColorTex, 0.5);
               UNITY_APPLY_FOG(i.fogCoord, col);
               return col;
           }
           ENDCG
       }
   }
}

シェーダーの内容としては_ColorTexパラメータにテクスチャを受け取って、そのテクスチャの色をモデルの色として出力しているだけです。

実際にUnity上で確認するためにマテリアルを作成します。
「Projectウィンドウ」で右クリック→「Create」→「Material」でマテリアルを新規追加して、名前を「ColorChangeMaterial」にします。
「ColorChangeShader」を「ColorChangeMaterial」にドラッグ&ドロップしてシェーダーをマテリアルに設定します。
「ColorChangeMaterial」のInspectorからColorTexに「CmaeraColorTexを設定します。

画像5

マテリアルが作成できたらテストしてみましょう。

Materialを新規作成して名前を「RedMaterial」にします。MaterialのAdlbedoカラーを赤色 RGB(255,0,0)に設定します。
Cubeを作成して名前を「RedCube」にして、「RedMaterial」を設定します。色おw反映させるオブジェクトとして同様にCubeを作成して名前を「ColorChangeCube」にします。
「ColorChangeCube」に「ColorChangeMaterial」を設定します。

Scene上で「ColorPicker」を選択して移動し、ピッカー部分を「RedCube」に刺します。

画像6

動画のように色が変われば成功です。

既存シェーダーを改造する

シェーダーがTextureの指定に対応していない場合、改造する必要があります。

改造したいシェーダーを開き、以下の編集を加えます。

1. テクスチャパラメータ追加
2. 色をテクスチャから取得した色に変える

これだけではなんのこっちゃという感じなので具体的な方法を説明します。

1. テクスチャパラメータ追加

    Properties
  	{
  		// ...
  		_ColorTex("ColorTex", 2D) = "white" {}
  		// ...
  	}

Propertiesに「_ColorTex」パラメータを追加してカメラ画像のテクスチャを指定可能にします。テクスチャが無設定の場合は白色(white)になります。

Propertiesに定義しただけではシェーダー内から参照できないのでPassブロックに「_ColorTex」の変数定義を忘れずに追加します。

    Pass
	{
  	    // ...
		sampler2D _ColorTex;
        // ...
	}

※フラグメントシェーダー(fixed4 frag(v2f i){...})より手前に定義します。

2. テクスチャの色を適用する

最後にフラグメントシェーダー内の色を書き換えます。

        fixed4 frag(v2f i) : SV_Target
		{
  		    // ...
			fixed4 col = tex2D(_ColorTex, 0.5);
     		// ...
		}

returnしている色を返す直前に「_ColorTex」の色を適用します。

シェーダーごとの個別対応

LiveHouse:Clastをつくるにあたって既存シェーダーに手を入れたので、その知見を載せます。

ビームライトシェーダー (https://booth.pm/ja/items/1637978
「BeamLightBooth」シェーダーを開きます。
Propertiesブロック、Passブロックにに上記の「_ColorTex」の定義を追加します。
174行目の「_Color」を「tex2D(_ColorTex, 0.5)」に置き換えます。

VoxkeVolumetricLight (https://voxelkei.booth.pm/items/2098480)
「VoxkeVolumeLight_v4」シェーダーを開きます。
Propertiesブロック、Passブロックにに上記の「_ColorTex」の定義を追加します。
143行目の「_Color」を「tex2D(_ColorTex, 0.5)」に置き換えます。
※こちらはLiverHouse:Clastでは使用してませんが試したときのやり方です。

動画と連動する

やり方は凄い簡単で手元にスクリーンを設置して、カラーピッカーで色を取得するだけです。

設置方法
「Ctrl+D」で「StandardMainScreen」を複製して操作しやすい位置に置きます。スクリーンの色を取得できる位置にカラーピッカーを適当に配置します。

ちらつき問題
LiveHouse:Clastでは、そのままだと色変化が激しすぎるので画質を落とし、補完された画像から色を取得するようにしています。
やり方としてはスクリーンにカメラを設置して、画質を下げたRenderTextureに画像を一旦保存してます。
画質を下げたRenderTextureを表示するモデルを手元に置いてそこからカラーピッカーで色を取得しています。

ライトの点滅
こちらはスクロールする白黒画像を使用することで点滅を実現しています。
色とは別にカラーピッカーとRenderTextureを用意してシェーダー内で以下のように合成しています。

tex2D(_ColorTex, 0.5).rgb * tex2D(_PowerTex, 0.5).rgb;

カラーピッカーの複製
カラーピッカーを複数作る場合はRenderTextureを分ける必要があります。RenderTextureはカメラ毎に別のものを設定する必要があります。

色を自由に変える
LiverHouse:Clastでは手元にこのような形で画像を並べることで好きな色に変更できるようになってます。

画像7

色の入力用パネルはこちらで配布しています。

画像8

あとがき

いかがだったでしょうか、実はこのシステムはVRChatでもよく見る連動システムをCluster上で実装したものです。

やろうと思えばパーティクルの色や表示のON/OFFなども変えることができます。

トリガーギミックが入れば演出のON/OFF、カメラの動きなどもっと制御できるものが増えるので、表現の幅もさらに広がるのかなと思います。

配布ファイルリンク

ColorPickerSample
ColorPanel


いいなと思ったら応援しよう!