[Unity] アウトライン Outline - 詳細篇　モデル拡大法

# モデル拡大法
[概念篇](http://qiita.com/kerrot/items/c5cc75fffd6cac6b602d)で書いた方法：
モデルの点を法線の方向に沿って移動し、マテリアルは単色にして、背面描画すること。

これをShaderで実現するには：（Outline部分Only）

```
Pass{
	//背面描画する
	Cull Front

	CGPROGRAM
	#include "UnityCG.cginc"			
	#pragma vertex vert
	#pragma fragment frag

	float4 _OutlineColor;
	float _Outline;

	struct Input
	{
		float4 vertex : POSITION;
		float3 normal : NORMAL;
	};

	struct Output
	{
		float4 pos : SV_POSITION;
		fixed4 color : TEXCOORD0;
	};

	fixed4 frag(Output o) : SV_Target
	{
		return o.color;
	}

	Output vert(Input i)
	{
		Output o;
		//モデルの点を法線の方向に沿って移動する
		i.vertex.xyz += normalize(i.normal) * _Outline;
		o.pos = UnityObjectToClipPos(i.vertex);
		//単色にする
		o.color = _OutlineColor;
		return o;
	}

	ENDCG
}
```

以上のShaderを使った物：
![image](https://qiita-image-store.s3.amazonaws.com/0/124698/145254ce-2e85-f735-35db-47d1a58f72cc.png)

# 問題点と解決方法
[概念篇](http://qiita.com/kerrot/items/c5cc75fffd6cac6b602d)でも書いたようにキューブの場合は問題がある。その理由は：
![image](https://qiita-image-store.s3.amazonaws.com/0/124698/0d333c71-766b-03fe-5556-f77e09d0b56c.png)
赤い頂点は複数の三角と関わり、それぞれの法線は違う。だから、法線の方向に沿って移動したら、三角たちが離れてしまう。では、同じ法線にすればいい：
![image](https://qiita-image-store.s3.amazonaws.com/0/124698/e3da9a56-63e4-4a13-b60c-b4d6629ac756.png)
こうして、全ての頂点の法線を変えて、移動する時は問題が起こらない。

```
 public static void MeshNormalAverage(Mesh mesh)
    {
        Dictionary<Vector3, List<int>> map = new Dictionary<Vector3, List<int>>();

        #region build the map of vertex and triangles' relation
        for (int v = 0; v < mesh.vertexCount; ++v)
        {
            if (!map.ContainsKey(mesh.vertices[v]))
            {
                map.Add(mesh.vertices[v], new List<int>());
            }

            map[mesh.vertices[v]].Add(v);
        }
        #endregion

        Vector3[] normals = mesh.normals;
        Vector3 normal;

        #region the same vertex use the same normal(average)
        foreach (var p in map)
        {
            normal = Vector3.zero;

            foreach (var n in p.Value)
            {
                normal += mesh.normals[n];
            }

            normal /= p.Value.Count;

            foreach (var n in p.Value)
            {
                normals[n] = normal;
            }
        }
        #endregion

        mesh.normals = normals;
    }
```
でも法線を変えるとライティングも変わる。だから、Outlineのモデルだけ法線を変え、元のモデルは変わらない。Outlineのためにモデルをクローンする:
[Copy components at runtime](http://answers.unity3d.com/questions/530178/how-to-get-a-component-from-an-object-and-add-it-t.html)
クローンするのはMeshRendererとMeshFilter、或いはSkinnedMeshRenderer。Meshをクローンする時ちょっと注意：

```
Mesh tmpMesh = (Mesh)Instantiate(GetComponent<MeshFilter>().sharedMesh);
outlineObj.GetComponent<MeshFilter>().sharedMesh = tmpMesh;
```

# 成果
![image](https://qiita-image-store.s3.amazonaws.com/0/124698/04363f20-d25e-a260-acef-be106e783b0a.png)
基本は問題ないが、深度にはやはりまだ問題がある：
![image](https://qiita-image-store.s3.amazonaws.com/0/124698/8f1eb18b-45c2-c42f-ae90-f767e3ec3bba.png)

実際のキャラクターも試そう：
![image](https://qiita-image-store.s3.amazonaws.com/0/124698/1592d471-c31f-b07d-03e9-aa960af62d80.png)
左はUnityエディターのOutline、右は自分のもの。左の方が正しいと思うが、右の方も悪くない。

深度に関してはまだ研究する必要がある。とりあえず、ここまでの結果：
[Github：Unity Outline](https://github.com/kerrot/UnityOutline)