前回ギズモの描画方法を学びました。
今回は自分でメッシュを作ってそのメッシュをギズモとして描画することに挑戦します。
この記事にはUnity2017.2.0f3を使用しています。
下準備
さて、前回のギズモの表示の仕方を参考にして作っていきましょう。
www.urablog.xyz
まずコンポーネントを作成します。
RangeObject.cs
using UnityEngine; public class RangeObject : MonoBehaviour { [SerializeField, Range( 0.0f, 360.0f ) ] private float m_widthAngle = 0.0f; [SerializeField, Range( 0.0f, 360.0f ) ] private float m_heightAngle = 0.0f; [SerializeField, Range( 0.0f, 15.0f )] private float m_length = 0.0f; public float WidthAngle { get{ return m_widthAngle; } } public float HeightAngle { get{ return m_heightAngle; } } public float Length { get{ return m_length; } } } // class RangeObject
このコンポーネントの情報をギズモとしてシーンビューに表示させるようにしましょう。
ギズモ描画用のスクリプトをEditorフォルダに作ります。
RangeObjectGizmosEditor.cs
using UnityEngine; using UnityEditor; using System.Collections.Generic; public static class RangeObjectGizmosEditor { [DrawGizmo( GizmoType.NonSelected | GizmoType.Selected )] private static void DrawPointGizmos( RangeObject i_object, GizmoType i_gizmoType ) { } } // class RangeObjectGizmosEditor
今回目指しているものはWidthAngle
とHeightAngle
の角度の大きさの扇形のギズモが作りたいです。
無いかな、そんなギズモを描画する関数は。
https://docs.unity3d.com/ScriptReference/Gizmos.htmldocs.unity3d.com
無いですね。
仕方ない、作りましょうか。
メッシュ作成
こんな感じに作ればいいはずです。
角度とポリゴン数を指定出来るようにしておきましょう。
RangeObjectGizmosEditor.cs
private static Mesh CreatFunMesh( float i_angle, int i_triangleCount ) { var mesh = new Mesh(); mesh.vertices = /* 何らかの方法で頂点の配列を作る */null; mesh.triangles = /* 何らかの方法でポリゴンインデックス配列を作る */null; mesh.RecalculateNormals(); return mesh; }
まずは頂点の配列を作りましょう。
頂点の位置を指定するには、サイン値とコサイン値を使って計算しましょう。
一応、引数が変な場合の対応も入れておいてっと。
RangeObjectGizmosEditor.cs
private static Vector3[] CreateFanVertices( float i_angle, int i_triangleCount ) { if( i_angle <= 0.0f ) { throw new System.ArgumentException( string.Format( "角度がおかしい! i_angle={0}", i_angle ) ); } if( i_triangleCount <= 0 ) { throw new System.ArgumentException( string.Format( "数がおかしい! i_triangleCount={0}", i_triangleCount ) ); } i_angle = Mathf.Min( i_angle, 360.0f ); var vertices = new List<Vector3>( i_triangleCount + 2 ); // 始点 vertices.Add( Vector3.zero ); // Mathf.Sin()とMathf.Cos()で使用するのは角度ではなくラジアンなので変換しておく。 float radian = i_angle * Mathf.Deg2Rad; float startRad = -radian / 2; float incRad = radian / i_triangleCount; for( int i = 0; i < i_triangleCount + 1; ++i ) { float currentRad = startRad + ( incRad * i ); Vector3 vertex = new Vector3( Mathf.Sin( currentRad ), 0.0f, Mathf.Cos( currentRad ) ); vertices.Add( vertex ); } return vertices.ToArray(); }
あとは三角形の頂点順に頂点インデックス配列を作りましょう。
RangeObjectGizmosEditor.cs
private static Mesh CreateFanMesh( float i_angle, int i_triangleCount ) { var mesh = new Mesh(); var vertices = CreateFanVertices( i_angle, i_triangleCount ); var triangleIndexes = new List<int>( i_triangleCount * 3 ); for( int i = 0; i < i_triangleCount; ++i ) { triangleIndexes.Add( 0 ); triangleIndexes.Add( i + 1 ); triangleIndexes.Add( i + 2 ); } mesh.vertices = vertices; mesh.triangles = triangleIndexes.ToArray(); mesh.RecalculateNormals(); return mesh; }
これでメッシュが作れたと思いますよ。たぶん。
ギズモ描画
先ほど作ったメッシュをGizmos.DrawMesh()
を使ってこのメッシュを描画しましょう。
RangeObjectGizmosEditor.cs
private static readonly int TRIANGLE_COUNT = 12; private static readonly Color MESH_COLOR = new Color( 1.0f, 1.0f, 0.0f, 0.7f ); [DrawGizmo( GizmoType.NonSelected | GizmoType.Selected )] private static void DrawPointGizmos( RangeObject i_object, GizmoType i_gizmoType ) { if( i_object.Length <= 0.0f ) { return; } Gizmos.color = MESH_COLOR; Transform transform = i_object.transform; Vector3 pos = transform.position + Vector3.up * 0.01f; // 0.01fは地面と高さだと見づらいので調整用。 Quaternion rot = transform.rotation; Vector3 scale = Vector3.one * i_object.Length; Mesh fanMesh = CreateFanMesh( i_object.WidthAngle, TRIANGLE_COUNT ); Gizmos.DrawMesh( fanMesh, pos, rot, scale ); }
出来ましたー。
これでWidthAngle
は対応できたのでHeightAngle
も対応しましょう。
同じようにメッシュを作って、回転させてしまえば大丈夫なはずです。
RangeObjectGizmosEditor.cs
[DrawGizmo( GizmoType.NonSelected | GizmoType.Selected )] private static void DrawPointGizmos( RangeObject i_object, GizmoType i_gizmoType ) { if( i_object.Length <= 0.0f ) { return; } Gizmos.color = MESH_COLOR; Transform transform = i_object.transform; Vector3 pos = transform.position + Vector3.up * 0.01f; // 0.01fは地面と高さだと見づらいので調整用。 Quaternion rot = transform.rotation; Vector3 scale = Vector3.one * i_object.Length; if( i_object.HeightAngle > 0.0f ) { Mesh fanMesh = CreateFanMesh( i_object.HeightAngle, TRIANGLE_COUNT ); Gizmos.DrawMesh( fanMesh, pos, rot * Quaternion.AngleAxis( 90.0f, Vector3.forward ), scale ); } if( i_object.WidthAngle > 0.0f ) { Mesh fanMesh = CreateFanMesh( i_object.WidthAngle, TRIANGLE_COUNT ); Gizmos.DrawMesh( fanMesh, pos, rot, scale ); } }
うまくいったかのように見えましたが、反対から見ると表示されていませんね。
回転させてもう一回描画するようにしましょう。
RangeObjectGizmosEditor.cs
[DrawGizmo( GizmoType.NonSelected | GizmoType.Selected )] private static void DrawPointGizmos( RangeObject i_object, GizmoType i_gizmoType ) { if( i_object.Length <= 0.0f ) { return; } Gizmos.color = MESH_COLOR; Transform transform = i_object.transform; Vector3 pos = transform.position + Vector3.up * 0.01f; // 0.01fは地面と高さだと見づらいので調整用。 Quaternion rot = transform.rotation; Vector3 scale = Vector3.one * i_object.Length; if( i_object.HeightAngle > 0.0f ) { Mesh fanMesh = CreateFanMesh( i_object.HeightAngle, TRIANGLE_COUNT ); Gizmos.DrawMesh( fanMesh, pos, rot * Quaternion.AngleAxis( 90.0f, Vector3.forward ), scale ); Gizmos.DrawMesh( fanMesh, pos, rot * Quaternion.AngleAxis( 270.0f, Vector3.forward ), scale ); } if( i_object.WidthAngle > 0.0f ) { Mesh fanMesh = CreateFanMesh( i_object.WidthAngle, TRIANGLE_COUNT ); Gizmos.DrawMesh( fanMesh, pos, rot, scale ); Gizmos.DrawMesh( fanMesh, pos, rot * Quaternion.AngleAxis( 180.0f, Vector3.forward ), scale ); } }
出来ましたね。
この調子でギズモをいろいろ作っていって、作業の効率化を目指します。