おもちゃラボ

Unityで遊びを作ってます

【Unityシェーダ入門】テクスチャをブレンドして自然な地形を表示する

例えば草と土、土とレンガ、など複数のテクスチャをうまい感じにブレンドすることで、自然な見た目の地形表現ができるようになります。Photoshopで作成しても良いのですが、リアルタイムに変化させたい場合や、ステージを見ながら調整したい場合はシェーダを使うと便利です。

f:id:nn_hokuson:20161027070404p:plain

テクスチャをブレンドする方針

テクスチャをブレンドする場合、テクスチャ1とテクスチャ2をどのような割合でブレンドするかの指標となる画像(マスク画像)がもう一枚必要になります。通常このマスク画像は白黒の画像を用意します。

f:id:nn_hokuson:20161027065913p:plain

マスク画像が白に近い場合はテクスチャ1を強めで、マスク画像が黒色に近い場合はテクスチャ2の色を強めで出します。これを数式にすると次のようになります。

color = Texture1 * p + Texture2 * (1-p)

ここでpはマスク画像の明度(0.0〜1.0)です。pが0の場合にはテクスチャ1の画像に、pが1の場合はテクスチャ2の画像になります。

このマスク画像自体はPhotoshopなどで簡単に作成できます。Photoshopを起動し、適当にファイルを作成した上で、メニューバーから「フィルタ」→「描画」→「雲模様」を選択します。「フィルタ」→「ぼかし」→「ガウスフィルタ」で少しぼかした方がブレンドした結果は綺麗になります。

f:id:nn_hokuson:20161027183247p:plain

ステージを作成する

ステージとなるPlaneをシーンビューに追加しましょう。ヒエラルキービューから「Create」→「3D Object」→「Plane」を選択してください。

次に、いま作成したパネルにマテリアルとシェーダを設定します。プロジェクトビューで右クリックから「Create」→「Shader」→「Standard Surface Shader」を選択しblendという名前で保存します。続いてblendシェーダを選択した状態で、右クリックから「Create」→「Material」を選択し、groundという名前で保存します。

最後に作成したgroundのマテリアルをPanelドラッグ&ドロップし、シェーダを「Custom/blend」に変更します。シェーダの詳しい作成方法と設定方法は下の記事で紹介していますので参照して下さい。

nn-hokuson.hatenablog.com

シェーダを作成する

次にマスク画像をもとに2枚のテクスチャをブレンドするシェーダを作成しましょう。

Shader "Custom/sample" {
	Properties {
		_MainTex ("Main Texture", 2D) = "white" {}
		_SubTex ("Sub Texture", 2D) = "white" {}
		_MaskTex ("Mask Texture", 2D) = "white" {}	
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows
		#pragma target 3.0

		sampler2D _MainTex;
		sampler2D _SubTex;
		sampler2D _MaskTex;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutputStandard o) {
			fixed4 c1 = tex2D (_MainTex, IN.uv_MainTex);
			fixed4 c2 = tex2D (_SubTex,  IN.uv_MainTex);
			fixed4 p  = tex2D (_MaskTex, IN.uv_MainTex);
			o.Albedo = lerp(c1, c2, p);			
		}
		ENDCG
	}
	FallBack "Diffuse"
}

このシェーダでは、ブレンドする2枚のテクスチャ、マスク画像をインスペクタから操作できるように、Properiesにこれらの変数を記述しています。

サーフェイスシェーダではテクスチャのuv座標を使うため、Input構造体にuv_MainTexを宣言しています。surfメソッドでは上記の数式を使って2枚のテクスチャをブレンドしています。

テクスチャ1の色をc1に、テクスチャ2の色をc2に代入しています。ブレンドの割合を示すpはマスク画像が黒ければ0.0、白ければ1.0にしたいので、マスク画像をグレースケールに変換した上でpに代入しています。グレースケール変換はこちらの記事で紹介しています。

nn-hokuson.hatenablog.com

最後に2枚のテクスチャをpを使ってブレンドしています。lerpは上記の計算をするためのメソッドです。第一引数と第二引数の影響度をpで指定します。c1とc2はそれぞれr・g・bの要素を持つため、実際には下記のような計算になります。シェーダは、こういう処理が簡単にかけるので助かります。

color.r = c1.r * p + c2.r * (1-p);
color.g = c1.g * p + c2.g * (1-p);
color.b = c1.b * p + c2.b * (1-p);

Propertiesブロックで指定した変数にブレンドしたいテクスチャをセットします。プロジェクトビューからインスペクタにブレンドするテクスチャとマスク画像をドラッグ&ドロップします。

f:id:nn_hokuson:20161027184734p:plain

結果

2枚のテクスチャをブレンドして地形を表示した結果は次のようになります。

f:id:nn_hokuson:20161027070904g:plain

私の書いたUnity5の教科書もお願いします!