SuiTechLog

Unity,Arduino,RaspberryPiなど、モノづくり系を気ままに書き残すブログ。

Unityで、頂点カラーを使ってみる


 前回の記事では、頂点カラーのアルファを使いました。今回は、基本に戻って頂点カラーを使って少し遊んでみることにします。

 

 さて、早速頂点カラーを適当にぬりたくった球体を用意しました。

当然ながらUnityのデフォルトシェーダーではただのグレーボールです。

f:id:sui332015:20170201010942p:plain

  

 

頂点カラーを表示してみる!

 その名の通り、mayaや3dsmaxなどのDCCツールで塗った頂点カラーをそのまま表示してみます。

f:id:sui332015:20170201010853p:plain

こちらが完成画像。RGBのカラーが出力されています。

ソースコード 

ソースコードはこちら。


    Shader "Custom/VertexColorSimple" {

	SubShader{
		Tags{ "RenderType" = "Opaque" }

		CGPROGRAM
		#pragma surface surf Lambert

		struct Input {
			fixed4 color : COLOR;
		};

		void surf (Input IN, inout SurfaceOutput o)
		{
			o.Albedo = IN.color;
		}
		ENDCG
	}
	Fallback "Diffuse"
}

 

簡単な解説

#pragma surface surf Lambert

これはsurfという描画関数がありますよ

ライティングは、「組み込みLambert(ディフューズ)ライティングモデル」を使用しますよ

という宣言です。

 

struct Input {
	fixed4 color : COLOR;
};

これは、surt関数に渡す頂点の情報の構造体で、colorを渡します。必要なものだけ渡せばいいので今回はこれだけです。

 

void surf (Input IN, inout SurfaceOutput o)
{
	o.Albedo = IN.color;
}

 これは、surf関数の中身を書きます。第一引数は上で宣言した構造体で、第二引数は出力構造体です。(出力構造体はデフォルトを使用しているのでどこにも宣言していません。)中身の処理は、頂点カラーを出力のアルベド(カラー)に渡しています。

 ここを書き換えることで、もちろんテクスチャカラーなどと混ぜることもできるので、応用してみてください。

 

頂点カラーで、アウトラインの太さを変えてみる

 トゥーンシェーダー等でよく使われるアウトラインを、頂点カラーでいじってみます。

f:id:sui332015:20170201012151p:plain

 さきほどの球体に適用した状態。上記の図で、色のついている部分だけアウトラインが載っていることがお分かりいただけるでしょうか。

 

ソースコード

 Shader "Custom/VertexColorOutline" {

	Properties{
		_LineColor("Line Color", Color) = (0,0,0,1)
		_Outline("Outline Width", float) = 1
	}

	CGINCLUDE
	#include "UnityCG.cginc"
	#pragma target 3.0

	uniform float _Outline;
	uniform float4 _LineColor;
	uniform sampler2D _MainTex;

	//バーテックスシェーダに渡す構造体
	struct appdata {
		fixed4 vertex : POSITION;
		fixed3 normal : NORMAL;
		fixed4 color : COLOR;
	};

	//バーテックスシェーダーから返ってくる戻り値構造体
	struct v2f {
		fixed4 pos : POSITION;
		fixed4 normal : NORMAL;
		fixed4 color : COLOR;
	};

	//アウトライン描画用バーテックスシェーダ
	v2f vert(appdata v) {
		v2f o;
		o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

		fixed3 norm = mul((fixed3x3)UNITY_MATRIX_IT_MV, v.normal);
		fixed2 offset = TransformViewToProjection(norm.xy);

		fixed height = (v.color.r + v.color.g + v.color.b);
		o.pos.xy += offset*_Outline*height;
		o.color = _LineColor;
		return o;
	}

	struct Input {
		fixed4 color : COLOR;
	};

	ENDCG

	SubShader{
		//1パス目
		Name "BaseShader"
		Tags{ "RenderType" = "Opaque" }
		ZWrite On

		CGPROGRAM
		#pragma surface surf Lambert
		void surf(Input IN, inout SurfaceOutput o)
		{
			o.Albedo =(0.5,0.5,0.5);
		}
		ENDCG
		//2パス目
		Pass {
		    Name "OUTLINE"
		    Tags { "LightMode" = "Always" }
			Cull Front
			ZWrite On
		
		    CGPROGRAM
		    #pragma vertex vert
		    #pragma fragment frag
		    half4 frag(v2f i) :COLOR { return i.color; }
		    ENDCG
		}
	}
	Fallback "Diffuse"
}

簡単な解説

 この関数はデフォルトのLambertライティングモデルに、アウトラインを載せたものになります。アウトラインの出し方は、モデルの各頂点を法線方向に少し移動させて、全体的に膨らませたものを表裏、裏返す方法をとっています。(Unityデフォルトのトゥーンシェーダと一緒)。この辺りの詳細は別の機会にするとして、アウトラインの太さは以下で調整しています。

fixed height = (v.color.r + v.color.g + v.color.b);
o.pos.xy += offset*_Outline*height;

頂点カラーのr,g,bの値を足してスカラー値にします。(単純計算のため)

そして、offsetに、アウトラインの太さプロパティをかけ、さらに上記スカラー値をかけます。これによって、頂点カラーに値があるところのみ線が太くなります。

 

まとめると

 頂点カラーは、「カラー」の名がついていますが、特に色に使うと決まっているわけではありません。頂点それぞれに4つの値が持たせられるよ、くらいに考えてください。例えば、4つの値をつかって「3次元ベクトル値」と「1つのスカラー値」として意味を持たせたり(コレがいわゆるRGB+A)、4つの値をそれぞれ「スカラー値」として別々の意味を持たせたり、シェーダー次第でいかようにも使えます。色々と応用がきくので遊んでみてあげてください。

 

蛇足ですが・・・頂点カラーの問題点

なかなか遊べる頂点カラーくんですが、問題もあります。

 

1.塗るのがめんどくさい

 特にポリゴン数が増えてくると、モデラーさんの負担はどんどこ増えます。Mayaや3dsMaxなどのDCCツール内で、ある程度まで自動で塗るツールを用意する、テクスチャやアンビエントオクルージョンから転写するなど、対策は必要です。

 

2.確認しながら作業ができない

 上記のアウトラインの太さを変えるなど特殊な使い方をする場合、Unityでしか画が確認できないのでいちいちUnityへ持っていって見に行かねばなりません。なので、DCCツール内で同じ見た目になるシェーダーを用意しておく必要があります。

 

 単純にそのまま塗らせるとモデラーさんにえらい負担がかかります。なので、その対策は必須となります。ここは、テクニカルアーティストの腕の見せ所ですね。