【unity】モバイルならビルの窓の反射って加算でよくね??

と思って調べてみると、ガラス表現を割としっかり屈折など計算しているものは見かけるが、加算でやっている方は見かけなかった。(調べ方が足りなかっただけかも知れないが)
ということで

ビルの反射を加算で表現してみよう

思い立ったらすぐ行動。まず用意するものはこちら。
1. ビルのモデル

画像1

まあこんなもんでいいでしょう。モバイル用にしてはポリゴン割きすぎだが今はそんなこと気にしない。隣の側面も同じものを回転させて並べればいいと思ったので割愛して1面のみ作成。
2. テクスチャA

画像2

こちらもさくっと作成。解像度は1024pxと高めだがそれも今は気にしない。
3. テクスチャB

画像3

これに至ってはフリー素材の一部を切り取って暗く加工しただけである。(本番ではしっかり作ろう)
4. シェーダー

Shader "Custom/NewUnlitShader"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_SubTex("SubTexture", 2D) = "white" {}
	}
		SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
				float2 uv2 : TEXCOORD1;
			};

			sampler2D _MainTex;
			sampler2D _SubTex;
			float4 _MainTex_ST;
			float4 _SubTex_ST;

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

			fixed4 frag(v2f i) : SV_Target
			{
				fixed4 colA = tex2D(_MainTex, i.uv);
				fixed4 colB = tex2D(_SubTex, i.uv2);
				fixed4 col = colA + colB;

				return col;
			}
			ENDCG
		}
	}
}

Unlitシェーダーからさらにいらないものを省いた超シンプル設計。
加算もcolA + colBでやるだけのものすごくシンプルなもの。一応タイリングはテクスチャごとに設定できるようにした。

そして表示した結果がこちら

画像4



まあまあええ感じやん?


テクスチャのタイリングを分けているから結構タイリングがバレにくいし個人的にはそこそこ満足。
ここにもうひと手間加えてみよう。


カメラの位置に応じてテクスチャをオフセット

このシェーダー、お手軽でいいのだが今の段階では当然反射している光が動くことがなく、カメラを動かすと不自然な感じになる。そこで思いついた。
カメラ位置に応じてオフセットしよう
カメラのx,z座標をテクスチャオフセットxに、y座標をオフセットyにそれぞれ流し込めば、それっぽく見えるんじゃないか?

てことで書き加えたのがこちら。

float CamPos = float((_WorldSpaceCameraPos.x * -1) + _WorldSpaceCameraPos.z);
float2 scroll = float2(CamPos, (_WorldSpaceCameraPos.y) * -1) / 4;

たったこれだけ。
説明は後でするとして一回見て頂こう。

画像5

GIFでは分かりにくいが、白っぽい部分に注視してみるとテクスチャが動いているのが分かる。
上の計算式は各々お好みで調整してもらえればと思うが、私のお好みがこの結果だ。まずカメラのx,z座標は単純に足してみただけだが、見た感じ違和感はなかったのでこれで問題ないと判断した。xには-1をかけてあるが、これはオブジェクトの配置方法によって変わるかと思われる。私の場合は反対だと感じたためマイナスをかけている。yについても同様にスクロール方向が逆に感じた為マイナスをかけた。
最後にスクロールスピードが速く感じた為4で割っている。これもUVの展開方法やオブジェクトのサイズによって変わるだろう。自分のシーン上での適切な数値を入力してほしい。

ちなみにサブテクスチャのほうを、テクスチャの割り当てがない場合白を表示する設定にしてしまっていたため、加算しても影響が出ないよう黒に変更した。

_SubTex("SubTexture", 2D) = "white" {}
                               ↓
_SubTex("SubTexture", 2D) = "black" {}



コード全文

Shader "Custom/NewUnlitShader"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_SubTex("SubTexture", 2D) = "black" {}
	}
		SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
				float2 uv2 : TEXCOORD1;
			};

			sampler2D _MainTex;
			sampler2D _SubTex;
			float4 _MainTex_ST;
			float4 _SubTex_ST;

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

			fixed4 frag(v2f i) : SV_Target
			{
				float CamPos = float((_WorldSpaceCameraPos.x * -1) + _WorldSpaceCameraPos.z);
				float2 scroll = float2(CamPos, (_WorldSpaceCameraPos.y) * -1) / 4;
				
				fixed4 colA = tex2D(_MainTex, i.uv);
				fixed4 colB = tex2D(_SubTex, i.uv2 + scroll);
				fixed4 col = colA + colB;

				return col;
			}
			ENDCG
		}
	}
}

気になった方は是非試してみてくれ。
それでは!



余談【加算の仕組み】

知らない方のために画像の加算や乗算の仕組みについて追記しておこう。
加算乗算とは、早い話が学校で習う「光の三原色、色の三原色」というやつだ。

画像6

出典:https://iro-color.com/episode/three-primary-colors.html
左が足した結果。右が掛けた結果になる。
掛け算は通常増えるものなのになんで暗くなるの?と疑問を持つ方も少なくないはず。ここではその部分まで踏み込んでいこう。

まず加算から。

色はRGBで表示されるのはきっとみんな知っているだろう。Rはレッド、Gはグリーン、Bがブルーだ。デジタルの世界ではこれらそれぞれを0~255の256段階で表示している。上記画像で言えば、赤い部分がR=255, G=0, B=0という具合。
加算は、この数字を至って単純に足しているだけなのである。例えば黄色の部分は、赤い円がR=255, G=0, B=0、緑の円がR=0, G=255, B=0なので、双方が足されてR=255, B=255, B=0という結果で黄色くなっている。ちなみに255を超えた場合は255で止まるようになっている為、どんなに沢山の画像を加算合成しても、R=255, G=255, B=255までにしかならない
この数式でいくと、白が全て255ということになるため、上記にあった「白を加算合成してはいけない」というのは、合成結果が真っ白になってしまうからである。

次に乗算を見ていこう。

乗算は、加算と同様に考えると255×255などという場合も出てきてしまい、全く意味をなさない。なので乗算では、この0~255という数字を一度0~1に自動で置き換えている。この場合、白はR=1, G=1, B=1となる。
するとどうだろう、例えばR=100, G=120, B=150という色があったとして、白を掛け算してもR=100, G=120, B=150のままである。先ほどの三原色の例でいくと、
ピンクがR=255, G=0, B=255
黄色がR=255, G=255, B=0
水色がR=0, G=255, B=255 なので、
ピンクと黄色が合成されたエリアは
R=1×1=1
G=0×1=0
B=1×0=0
となり、R=255のみの赤が表示される、というわけだ。


現実世界では、光の三原色は自然光を、色の三原色は絵の具を例えたりするが、実はこういった関係性が成り立っているのである。

この記事が気に入ったらサポートをしてみませんか?