はるのゲーム開発メモ

自分の勉強の成果などをメモ代わりにします

UnityのShader勉強2 基本の形

はじめに

頂点/フラグメントシェーダーを使う際の基本の形をおさらいします。

ぶっちゃけ詳しい説明は他サイトを見たほうがよいです。

参考:

Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた - 凹みTips

基本の形

まずは頂点/フラグメントシェーダーの基本の形です。

Create>Shader>UnlitShaderにてShaderを作成するとこんな感じになります。

Shader "Unlit/TestShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#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 _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed4 col = tex2D(_MainTex, i.uv);
				// apply fog
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}


 

 

 これをマテリアルにあててゲームオブジェクトに与えるとこうなります。

(spriteのみ画像がないと表示されないため白塗りのspriteを適用) 

 

f:id:Haru_android:20171215235725p:plain

 見事に真っ白です。

 

このままではわかりずらいので、コードを書き換えて少なくします。

Shader "Unlit/TestShader"
{
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
			};

			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				return o;
			}
			
			fixed4 frag () : SV_Target
			{
				fixed4 col = fixed4(1,1,1,1);
				return col;
			}
			ENDCG
		}
	}
}

 (見た目は変わらないので割愛)

 

SubShaderやPassの説明は省略します。

重要なのは

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
	float4 vertex : POSITION;
};

struct v2f
{
	float4 vertex : SV_POSITION;
};


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

fixed4 frag() : SV_Target
{
	fixed4 col = fixed4(1,0,0,1);
        return col;
}
ENDCG

の部分です。

 

上下にあるCGPROGRAM~ENDCG内に処理を書きます。

 

そして

#pragma vertex vert
#pragma fragment frag

 この二つが頂点の位置決める関数とピクセルに塗る色を決める関数を指示します。
この場合はvert関数 frag関数を使用すると指示しています。

 

vert関数の説明の前にappdataとv2fを少し考えます。

struct appdata
{
	float4 vertex : POSITION;
};

struct v2f
{
	float4 vertex : SV_POSITION;
};

 

struct appdataにてモデルから頂点やUV、法線などの情報を受け取ります。

モデルなどは三次元情報なのでディスプレイに表示させるために変換します。

struct v2f では変換後の情報を保持します。

 

今回は頂点情報のみを取得しています。

 

POSITIONは頂点情報

SV_POSITIONは変換後の頂点情報です。

 

詳しくは

qiita.com

 

(ちなみに名前は何でもよくて、v2fはvertex To Fragmentの略らしく慣習的にこの名前によくします。appdataをInputに変えたり人それぞれ好みのつけ方をしています。)

 

これらをどう使うかは

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

appdataで受け取った値を、変換してv2fで返します。

 

o.vertex=UnityObjectToClipPos(v.vertex);

 これは変換用の関数です。

 

最後にピクセルに色を塗ります。

fixed4 frag () : SV_Target
{
	fixed4 col = fixed4(1,1,1,1);
	return col;
}

フラグメントでは範囲内のピクセルすべてにこの関数を実行して値を返します。

:〇〇では返した値をどうするかという意味で、ほとんどはSV_Targetを指定します。

これは色を塗ってくれという命令です。

 

fixedとは浮動小数点のデータタイプでc#でいうところのfloatにあたります。

なにもつけなければそのまま値は一つですが、語尾に4がつけば値を4つ持ちます。

他にはfloat、half、fixed,intが使えます。

どれを選ぶかは精度や用途によって使い分け精度が高いほど負荷が高くなります。

高精度 float
中精度 half
低精度 fixed

intは整数で配列のインデックスやカウンターにも使えますが、あまりみかけません。

詳しくは

docs.unity3d.com

 

テクスチャを扱うデータタイプは別記事で書きます。

 

さて、さきほど返していたfixed4(1,1,1,1)ですがrgbaの値です。

すべてが1なので白になります。

これを(1,0,0,1)にすると

f:id:Haru_android:20171216011535p:plain

 

はい、真っ赤になりました。

 

 

おわり

 

今回はここまでにします。

次回は外部からの入力です。