[Unity] 扇状の範囲を可視化したかった

#  扇状の範囲を可視化したかった
![2018y02m21d_024741002.jpg](https://qiita-image-store.s3.amazonaws.com/0/135859/051a0d50-e858-6806-ea37-674e7119dfe7.jpeg)

実行時は見えなくても良いけど、編集中は敵の視野範囲を可視化しておきたいと考え、調べてみる

>【Unity】扇形のギズモを作ってみる
> http://www.urablog.xyz/entry/2017/10/22/183331

なるほど、Gizmoはこういう用途に使えるのか

やりたい事が完成形で見つかってしまったがこのままでは終われないので
Gizmoの仕様確認もかねてこちらのコードを改良してみる

### 機能追加
```c#:FanViwer.cs
using UnityEngine;

namespace Egliss
{
    [DisallowMultipleComponent]
    public class FanViewer : MonoBehaviour
    {
        [SerializeField, Range(0,360.0f)]
        private float _fovX = 90.0f;
        [SerializeField, Range(0, 360.0f)]
        private float _fovY = 90.0f;
        [SerializeField, Range(0,100)]
        private float _distance = 7.0f;
        [SerializeField]
        private Color _color = new Color(1.0f, 0.5f, 0.5f, 0.5f);
        [SerializeField,Range(1,255)]   
        private int _quality = 16;
        [SerializeField]
        private bool _isIgnoreYFan = false;

        public float fovX { get { return _fovX; } }
        public float fovY { get { return _fovY; } }
        public float distance { get { return _distance; } }
        public Color color { get { return _color; } }
        public int quality { get { return _quality; } }
        public bool isIgnoreYFan { get { return _isIgnoreYFan; } }
    }
}
```
![2018y02m21d_031528593.jpg](https://qiita-image-store.s3.amazonaws.com/0/135859/e47bd6bf-8838-11f4-9419-149fdfd096bf.jpeg)

Gizmo側で固定値で設定していたColorやTriangleCountを変更できるように
また、Y方向への範囲は非表示に出来るように

### 最適化

```c#:FanAreaVisualizer.cs
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;

namespace Egliss
{
    public class GizmoExtension
    {
        [DrawGizmo(GizmoType.NonSelected | GizmoType.Selected | GizmoType.InSelectionHierarchy)]
        private static void DrawFan(FanViewer view, GizmoType i_gizmoType)
        {
            //can't draw
            if (view.distance <= 0.0f)
                return;

            DrawFan(view);
        }

        private static void DrawFan(FanViewer view)
        {
            Gizmos.color = view.color;

            Vector3 pos = view.transform.position;
            Quaternion rot = view.transform.rotation;
            Vector3 scale = Vector3.one * view.distance;

            Mesh fanMesh = CreateFanMesh(view.fovX, view.quality);
            Gizmos.DrawMesh(fanMesh, pos, rot, scale);

            if (view.isIgnoreYFan)
                return;

            Mesh fanMesh2 = CreateFanMesh(view.fovY, view.quality);
            Gizmos.DrawMesh(fanMesh2, pos, rot * Quaternion.AngleAxis(90.0f, Vector3.forward), scale);
        }
        private static Mesh CreateFanMesh(float angle, int triangleCount)
        {
            var mesh = new Mesh();

            mesh.vertices = CreateFanVertexBuffer(angle, triangleCount);
            mesh.triangles = CreateFanIndexBuffer(triangleCount);
            mesh.RecalculateNormals();

            return mesh;
        }
        private static int[] CreateFanIndexBuffer(int triangleCount)
        {
            int[] indexBuffer = new int[triangleCount * 6];
            
            for (int L10 = 0; L10 < triangleCount; L10++)
            {
                int index = L10 * 3;
                int index2 = triangleCount * 3 + index;

                //front
                indexBuffer[index + 1] = L10 + 1;
                indexBuffer[index + 2] = L10 + 2;
                //backface
                indexBuffer[index2 + 1] = L10 + 2;
                indexBuffer[index2 + 2] = L10 + 1;
            }
            return indexBuffer;
        }
        private static Vector3[] CreateFanVertexBuffer(float angle, int triangleCount)
        {
            Vector3[] vertexBuffer = new Vector3[triangleCount + 2];

            // startpoint
            vertexBuffer[0] = Vector3.zero;

            float startRad = -angle / 2;
            float angleStep = angle / triangleCount;
            
            for (int L10 = 0; L10 < triangleCount + 1; L10++)
            {
                float nowRad = (startRad + angleStep * L10) * Mathf.Deg2Rad;
                vertexBuffer[L10 + 1] = new Vector3(Mathf.Sin(nowRad), 0.0f, Mathf.Cos(nowRad));
            }
            return vertexBuffer;
        }
    }
}
```

背面描画をインデクスバッファを弄る事で対応
ToArrayしていたListを生配列にしたり、インデクスバッファの0代入を省略したり（C#は配列初期化で規定値0が代入される）

### 引っかかったポイント
・FanViewerにエディタ拡張を適応した際、Gizmoの扇状範囲の更新が行われないタイミングがある
　これは、エディタの入力フィールドからフォーカスが外れるまで更新されないようで
　スライダーを触りながらTabキー連打で範囲が更新されることを確認した
　このため今回はエディタ拡張を行わずRange属性のみ適応した

・Gizmos.DrawMeshにマテリアル等を指定できない
　背面描画を行う際Cull off指定したシェーダのマテリアルを適応できないかと調べたが見つからず
　そのため今回はインデクスバッファを触る事で対応した