UnityのDefaultの機能と、外部Webサービスを使って、エモいShaderを書く-その1-


#この記事の趣旨
この記事はリソースを作れないプログラマの人が
UnityのDefaultの素材をつかって、いい感じの素材を生み出したい。
そのためのShaderを使っていい感じにエモい素材を作成していった際のものです。


#以下の人におすすめ
・シェーダーは書けるけど、モデルを作るのは向いてない。
・エモいタイトル画面とかのいい感じの素材が欲しい

#記事を読む前に

このシェーダー、すでにおわかりの人がいるかもしれませんが、カプセルが、望んでいる動作と違います。
理由として現状考えている理由が、最初の頂点シェーダー部分で、比較対象用に頂点座標を色々いじくりまわしてピクセルシェーダー側に流していますが、
※以下のコード

```
//頂点の位置を調整するためのもの　0.5は頂点の色の違い -0.5は上の頂点を見たいため。
o.line_info = float2(v.vertex.y + 0.5 , v.vertex.y - 0.5);
```

この0.5がたまたまCubeや、Sphereに対して、行った際に、その座標の範囲が、このコードの部分といい感じに
なったと推測しています。（間違っているかもしれません。）
なので、その部分を修正する必要があるのかなと今の所考えています。



#今回の作成物
今回作成したのは、CubeなどのDefault素材に対して、線状のものを、上方向へ流していくシェーダー

###完成の品がこちら
![lineshader.gif](https://qiita-image-store.s3.amazonaws.com/0/101366/d732a6e0-0c9b-32cf-16ea-fd971ecdcab9.gif)

なんかいい感じ！




以下シェーダソース全文

``` sample.shader

Shader "Unlit/LineShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_Line("BorderLine",Range(0,5)) = 1
		_DRange("DisplayRange",Range(0.0,1.0)) = 0.2
		_PowRange("Pow",Range(0,20)) = 10
	}
	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;
				//線分の情報
				float2 line_info:TEXCOORD1;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _Line;
			float _DRange;
			//べき乗の回数
			int _PowRange;


			v2f vert (appdata v)
			{
				v2f o;


				//頂点の位置を調整するためのもの　0.5は頂点の色の違い -0.5は上の頂点を見たいため。
				o.line_info = float2(v.vertex.y + 0.5 , v.vertex.y - 0.5);
				//o.line_info = float2(v.vertex.x, v.vertex.y);
				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);

				//調整されたLineの高さ 0-1.0の範囲で納める
				float _adjustedLine = fmod(_Line ,1.0);
				
				//ラインの一致している部分
				//頂点の値の一致する部分
				float _lineHmatch1 = step(i.line_info.x, _adjustedLine);
				//足された側の一致したところ
				float _lineHmatch2 = step(i.line_info.y,_adjustedLine);

				//描画を行う範囲
				float _range1 =  step(_adjustedLine - i.line_info.x, _DRange);
				float _range2 =  step(_adjustedLine - i.line_info.y,_DRange);
	

				//距離による色の減衰  描画をあくまでも↑が白くしたいので１から引く　範囲を明確にしたいのでべき乗で調整
				float _distance1 = 1 - distance(i.line_info.x, _adjustedLine);
				_distance1 = pow(_distance1 , _PowRange);

				float _distance2 = 1 - distance(i.line_info.y, _adjustedLine);
				_distance2 = pow(_distance2, _PowRange);


				float _ans1 = _lineHmatch1 * _range1 *_distance1;
				float _ans2 = _lineHmatch2 * _range2 *_distance2;

				return max(_ans1, _ans2);

			}
			ENDCG
		}
	}
}


```


#説明

※推測による部分も多く存在しています。


###頂点の移動
まず、以下のコード

```
//頂点の位置を調整するためのもの　0.5は頂点の色の違い -0.5は上の頂点を見たいため。
o.line_info = float2(v.vertex.y + 0.5 , v.vertex.y - 0.5);
```

この部分は、頂点座標の位置を、調整しやすい値に加工している部分です。
今回の、シェーダーでは、以下の図のように、合計2か所の色を塗る箇所が出てきます。


そのため、下の部分の線の描画の部分と、上の部分の描画の線の部分の位置を描画するか否かの判断をしないといけません。

これを実現するために、下の部分の底上げをして0－1の判断がしやすいように
上の部分を底下げをして、下の部分と同じ位置に判断を行えるようにしています。
図でいうならば以下です。




###ラインの位置の判断

```

//調整されたLineの高さ 0-1.0の範囲で納める
float _adjustedLine = fmod(_Line ,1.0);			

//ラインの一致している部分
//頂点の値の一致する部分
float _lineHmatch1 = step(i.line_info.x, _adjustedLine);

//足された側の一致したところ
float _lineHmatch2 = step(i.line_info.y,_adjustedLine);
```

まず、0－1の範囲内で判断をするために、設定しているプロパティの値を調整しています。
※たぶんカプセルの例のように、0－1の範囲を超えたモデルの場合は、おそらく、この範囲の調整から必要になります。

この判断は、あくまでも、指定した範囲より下かどうかを判定するためのものです。
そのため、＿Lineの値が1の時は、これだけをカラーとして返した場合は、全面が白になります。


###描画の範囲を限定する。

```
//描画を行う範囲
float _range1 =  step(_adjustedLine - i.line_info.x, _DRange);
float _range2 =  step(_adjustedLine - i.line_info.y,_DRange);
```
このコードは、あくまで、線分から、指定した範囲が、描画するように指定します。
stepの処理が以下です。
https://msdn.microsoft.com/ja-jp/library/ee418379(v=vs.85).aspx

線分位置-頂点座標の範囲が、指定した範囲なら、描画する。
この線分位置-頂点座標　という計算を行っているのは、＋－での判断を行うためです。
これをdistanceでやった場合、線分＜頂点位置になった場合でも、色が出てしまうため、それを防ぐために引き算で求めています。



###距離減衰

```

float _distance1 = 1 - distance(i.line_info.x, _adjustedLine);
_distance1 = pow(_distance1 , _PowRange);


```

1から引いているのは、距離が近いほど、白く出すため。
powで、べき乗しているのは、色のグラデーションのかかり方の調整用です。
値が大きいほど、短い距離でいい感じに、白＞黒のグラデーションがかかり今回のようなデモ映像になります。