うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】Scene View に 選択してないオブジェクトの Collider を表示する

あらまし

Unity で Collider を設定している際に選択しているオブジェクトの Collider しか表示されない

f:id:hacchi_man:20200125003159p:plain

今回はすべて Mesh が見えているが Mesh が無くても Collider をセットすることもあり
個人的には下図のように見えてほしい

f:id:hacchi_man:20200125003255p:plain

そのため、選択していないオブジェクトの Collider を表示する拡張を作成した

実装

DrawGizmoAttribute を用いて特定のコライダーの場合 Gizmo を利用して SceneView に描画する

非選択かつ表示されているオブジェクトのコライダーを表示するので
DrawGizmoAttribute の引数は GizmoType.NonSelected になる

理想としては private static void DrawCollider(Collider collider, GizmoType type) を定義して
Collider のタイプを判定して処理をしたかったが 継承したクラスの場合呼び出されなかったので
各 Colliderごとにメソッドを作成している

Gizmo

Gizmo で利用できるのは以下である

  • DrawCube 中心とサイズを持つキューブを描画します
  • DrawFrustum 位置と回転のために設定されている Gizmos.matrix を使用してカメラの錐台を描画します
  • DrawGUITexture シーンにテクスチャを描画します
  • DrawIcon シーンビューにアイコンを描画します
  • DrawLine from から to に向かってラインを描画します
  • DrawMesh メッシュを描画します
  • DrawRay from から from + direction に向けてレイを描画します
  • DrawSphere center と radius から球体を描画します
  • DrawWireCube center と size からキューブを描画します
  • DrawWireMesh ワイヤフレームメッシュを描画します
  • DrawWireSphere center と radius からワイヤーフレームの球体を描画します

これらには CapsuleCollider を描画する処理が無いので Handles を利用しておこなう

また CompositeCollider2D は Mesh の取得方法が分からなかったでの、今回はスキップする

実装結果

下図のように選択していない Collider でも表示することができた

f:id:hacchi_man:20200125014019p:plain

コード

using UnityEditor;
using UnityEngine;

public static class EditorColliderDrawer
{
    private static readonly Color Color = new Color(0, 0.5f, 0.5f, 1f);
    
    [DrawGizmo(GizmoType.NotInSelectionHierarchy)]
    private static void DrawBoxCollider2D(BoxCollider2D collider, GizmoType type)
    {
        Gizmos.color = Color;
        Gizmos.DrawLine(collider.bounds.min, new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.min.z));
        Gizmos.DrawLine(collider.bounds.min, new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.min.z));
        Gizmos.DrawLine(collider.bounds.max, new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.max.z));
        Gizmos.DrawLine(collider.bounds.max, new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.min.z));
    }
    
    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawCircleCollider2D(CircleCollider2D collider, GizmoType type)
    {
        Handles.color = Color;
        Handles.DrawWireArc(collider.bounds.center, Vector3.forward, Vector3.up * collider.radius, 360f, collider.radius);
    }
    
    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawCapsuleCollider2D(CapsuleCollider2D collider, GizmoType type)
    {
        Handles.color = Color;
        var sideHeight = (collider.size.y - collider.size.x) / 2f;
        var circleHeight = (collider.size.x - collider.size.y) / 2f; 
        if (sideHeight < 0f)
            sideHeight = 0f;
        if (circleHeight > 0f)
            circleHeight = 0f;
        
        var top = collider.bounds.center;
        top.y -= circleHeight;
        Handles.DrawWireArc(top, Vector3.forward, Vector3.right * collider.size.x / 2f, 180f, collider.size.x / 2f);
        
        var bottom = collider.bounds.center;
        bottom.y += circleHeight;
        Handles.DrawWireArc(bottom, Vector3.forward, Vector3.left * collider.size.x / 2f, 180f, collider.size.x / 2f);
        

        var leftTop = collider.bounds.center;
        var leftBottom = collider.bounds.center;
        
        leftTop.x += collider.size.x / 2f;
        leftTop.y += sideHeight;
        
        leftBottom.x += collider.size.x / 2f;
        leftBottom.y -= sideHeight;
        Handles.DrawLine(leftTop, leftBottom);
        
        var rightTop = collider.bounds.center;
        var rightBottom = collider.bounds.center;
        
        rightTop.x -= collider.size.x / 2f;
        rightTop.y += sideHeight;
        
        rightBottom.x -= collider.size.x / 2f;
        rightBottom.y -= sideHeight;
        Handles.DrawLine(rightTop, rightBottom);
    }
    
    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawPolygonCollider2D(PolygonCollider2D collider, GizmoType type)
    {
        Gizmos.color = Color;
        for (var i = 0; i < collider.pathCount; i++)
        {
            var paths = collider.GetPath(i);
            for (var j = 0; j < paths.Length; j++)
            {
                var next = j + 1 % paths.Length;
                if (next >= paths.Length)
                    next = 0;
                Gizmos.DrawLine(paths[j], paths[next]);
            }
        }
    }
    
    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawMeshCollider(MeshCollider collider, GizmoType type)
    {
        if (collider.sharedMesh == null)
            return;

        Gizmos.color = Color;
        Gizmos.DrawWireMesh(collider.sharedMesh, collider.transform.position, collider.transform.rotation);
    }
    
    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawSphereCollider(SphereCollider collider, GizmoType type)
    {
        Gizmos.color = Color;
        Gizmos.DrawWireSphere(collider.center + collider.transform.position, collider.radius);
    }

    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawBoxCollider(BoxCollider collider, GizmoType type)
    {
        Gizmos.color = Color;
        Gizmos.DrawLine(collider.bounds.min, new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.min.z));
        Gizmos.DrawLine(collider.bounds.min, new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.min.z));
        Gizmos.DrawLine(collider.bounds.min, new Vector3(collider.bounds.min.x, collider.bounds.min.y, collider.bounds.max.z));
        Gizmos.DrawLine(collider.bounds.max, new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.max.z));
        Gizmos.DrawLine(collider.bounds.max, new Vector3(collider.bounds.max.x, collider.bounds.max.y, collider.bounds.min.z));
        Gizmos.DrawLine(collider.bounds.max, new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.max.z));
        Gizmos.DrawLine(
            new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.min.z),
            new Vector3(collider.bounds.max.x, collider.bounds.max.y, collider.bounds.min.z)
        );
        Gizmos.DrawLine(
            new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.min.z),
            new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.max.z)
        );
        Gizmos.DrawLine(
            new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.min.z),
            new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.max.z)
        );
        Gizmos.DrawLine(
            new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.min.z),
            new Vector3(collider.bounds.max.x, collider.bounds.max.y, collider.bounds.min.z)
        );
        Gizmos.DrawLine(
            new Vector3(collider.bounds.min.x, collider.bounds.min.y, collider.bounds.max.z),
            new Vector3(collider.bounds.max.x, collider.bounds.min.y, collider.bounds.max.z)
        );
        Gizmos.DrawLine(
            new Vector3(collider.bounds.min.x, collider.bounds.min.y, collider.bounds.max.z),
            new Vector3(collider.bounds.min.x, collider.bounds.max.y, collider.bounds.max.z)
        );
    }

    [DrawGizmo(GizmoType.NonSelected)]
    private static void DrawCapsuleCollider(CapsuleCollider collider, GizmoType type)
    {
        var top = collider.center;
        var bottom = collider.center;
        top.y += collider.height / 2f - collider.radius;
        bottom.y -= collider.height / 2f - collider.radius;
        top += collider.transform.position;
        bottom += collider.transform.position;

        Handles.color = Color;
        var forward = bottom - top;
        var rot = Quaternion.LookRotation(forward);
        var pointOffset = collider.radius / 2f;
        var length = forward.magnitude;
        var center2 = new Vector3(0f, 0, length);
        var angleMatrix = Matrix4x4.TRS(top, rot, Handles.matrix.lossyScale);
        using (new Handles.DrawingScope(angleMatrix))
        {
            Handles.DrawWireDisc(Vector3.zero, Vector3.forward, collider.radius);
            Handles.DrawWireArc(Vector3.zero, Vector3.up, Vector3.left * pointOffset, -180f, collider.radius);
            Handles.DrawWireArc(Vector3.zero, Vector3.left, Vector3.down * pointOffset, -180f, collider.radius);
            Handles.DrawWireDisc(center2, Vector3.forward, collider.radius);
            Handles.DrawWireArc(center2, Vector3.up, Vector3.right * pointOffset, -180f, collider.radius);
            Handles.DrawWireArc(center2, Vector3.left, Vector3.up * pointOffset, -180f, collider.radius);
            DrawLine(collider.radius, 0f, length);
            DrawLine(-collider.radius, 0f, length);
            DrawLine(0f, collider.radius, length);
            DrawLine(0f, -collider.radius, length);
        }
    }

    private static void DrawLine(float arg1, float arg2, float forward)
    {
        Handles.DrawLine(new Vector3(arg1, arg2, 0f), new Vector3(arg1, arg2, forward));
    }
}