Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

2018y02m21d_024741002.jpg

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

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

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

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

機能追加

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

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

最適化

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指定したシェーダのマテリアルを適応できないかと調べたが見つからず
 そのため今回はインデクスバッファを触る事で対応した

Egliss
drecom-inc
Drecom with entertainment として発明を産み続け、人々の期待を超えるサービスを提供することを目的とした会社です。
https://www.drecom.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away