はるのゲーム開発メモ

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

UnityのShader勉強3 外部からの入力

 

今回は外部から値を入力してみます。

モデルごとに色を変えたり、頂点のずらす量、使用するテクスチャなどを与えることができます。

値を入力するにはProperties{}を使います。

前回のコードに加えてみます。

Shader "Unlit/TestShader"
{
	Properties{
      //ここに外部から何を入れるか決める
	}
	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
		}
	}
}

 

入力する値は

Properties{
	_Texture("Texture",2D)="white"{}
	_Float("float",float) = 1
	_Color("Color",Color) = (1,1,1,1)
	_Range("Range",Range(0,10))=0.5
	_Vector("ector",Vector)=(0,0,0,0)
}

このように書きます。

テクスチャの種類は2DのほかにCube,3Dとあるのですがまだ使っていないので省略します。

これをマテリアルから見てみると

f:id:Haru_android:20171216014344p:plain

こんな感じになりました。

それぞれの意味については特に説明もいらないと思います。

 

書きかたにはとても癖があり

例えば

_Float("float",float)=1

の場合

_Float 変数名
"float" インスペクター上の名前
float
=1 入力する初期値

となります。

非常にややこしいです。

 

ちなみにCGPROGRAM~ENDCG外では;はつけません。

こういうところがわかりずらいです。

 

さて入力できたのですがこのままでは使えません。

まずは使えるようにします。

Shader "Unlit/TestShader"
{
	Properties{
		_Texture("Texture",2D)="white"{}
		_Float("float",float) = 1
		_Color("Color",Color) = (1,1,1,1)
		_Range("Range",Range(0,10))=0.5
		_Vector("ector",Vector)=(0,0,0,0)
	}
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			sampler2D _Texture;
			fixed _Float;
			fixed4 _Color;
			fixed _Range;
			fixed4 _Vector;
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内に上記のように記述します。

uniform修飾子をつけるとかいてあるブログもありましたが、公式をみると必須ではないようです。

記述方法は

Propertiesで宣言した変数名と同じ変数で新たに宣言します。

 

テクスチャの場合はsampler2D

_Float,、_Rangeは値が一つなのでfixedなど

_Color、_Vectorは値が四つあるのでfixed4などと記述しましょう

 

これで外部から入力した値を使用することができるようになりました。

 

今回は入力した色でモデルを塗ってみます。

frag関数の

fixed4 col=(1,0,0,1);

fixed4 col=_Color;

 

と書き換えてみます。

f:id:Haru_android:20171216020715p:plain

無事に入力した色でモデルを塗ることができました。

 

続いて、すこし頂点もずらしてみます。

 

まずは変換前の頂点をずらしてみます。

vert関数を

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); return o;

v2f o;
float4 ver = v.vertex;
ver.x += _Range;
o.vertex = UnityObjectToClipPos(ver);
return o;

と書き換えてみます。

f:id:Haru_android:20171216022336p:plain

 

ずれましたね。

UnityChanが逆に動いているのはもともと後ろを向いているのを反転させているからです。(目と髪の一部はちがう動きをしていますが、不明です。別パーツだから元の向きがちがうのかな?でもEditor上ではちゃんと動いてるのに...)

またCanvasのImageはずれません。

 

次に変換後にずらしてみます。

ためしに_Rangeではなく_Vectorでずらしてみます。

vert関数を

v2f o;
float4 ver = v.vertex;
o.vertex = UnityObjectToClipPos(ver);
o.vertex += _Vector; return o;

と書き換えてみます。

f:id:Haru_android:20171216023623p:plain

真上から見た写真です。

わかりずらいですが、カメラをどこから向けてもカメラに対した向きに動きます。

 

xで左右に、yで上下に、zで前後、wでカメラに近づいたり離れたり。

これは実際にやって見て気づいたのですが、

y軸のみ加算で下へモデルは動き、Imageは上に動きました。

 

調べたのですが、よくわかりませんでした。

Unityの座標の扱い方の問題でしょうか?

 

まぁ上にずらしたい!とかあんまりないので無視します。

必要になったら調べます。

 

 

頂点をずらすのは、実用的な話で言えば法線方向に膨らませてアウトラインに使えます。

 

おわり

今回は外部から受け取った値を実際に使ってみました。

頂点を任意の位置にずらす際はもっと勉強が必要そうです。

 

次回はテクスチャを貼り付けてみます。

 

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

 

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

 

 

おわり

 

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

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

 

 

 

 

 

 

 

 

 

 

UnityのShader勉強1 はじめに

 

挨拶

こんにちは

初心者ゲーム開発者のはるです

 

2ヶ月近くUnityのShaderを勉強しているのですが、学んだ内容を忘れて毎回検索するのも辛くなってきたので、一度おさらいのために書き出そうと思います。

Unityのシェーダーには

・サーフェイスシェーダー

・頂点/フラグメントシェーダー

・固定関数シェーダー

がありますが、僕が勉強しているのは二つ目の頂点/フラグメントシェーダーが主になります。

サーフェイスシェーダーも便利なのですが、ちゃんと理解するには頂点/フラグメントシェーダーだなということでこちらを進めていきます。

 

 

ほぼ自分用のメモなのでもし読む際は自己責任にてお願いします。

間違っていたりしたら教えてくださると助かります。

 

 

バージョン:Unity2017.1.1f1

 

勉強の進め方

基本的には色々なブログをめぐったり、公式を読んだり、Unityちゃんを読み解いたりしています。

 

また、デフォルトで入っているShaderなどは公式からダウンロードできますので必ず手に入れておきましょう。

unity3d.com

 

終わりに

次回から早速いろいろ書いていきます。