Generate 2D polygon collider from 3D mesh

My game use 2d physic, but 3D graphics. The unity editor automatically generates a collider polygon using the sprite of the desired shape. If for example on a sprite a circle is drawn on a transparent background, then the generated collider polygon will be round. When the 2D scene mode is fixed, if you click on the 3d mesh model - it is outlined in orange (as can be seen in the screenshot), I want to make the polygon a collider polygon of the same shape as if it was a sprite. Tell me, please, how can I do this except to manually sketch the collider polygon? I need to algorithm working on at least simple examples as in the screenshot 113561-снимок-экрана-2018-03-23-в-181557.png

I was looking for this exact solution myself (All that dragging around polygon points was driving me insane).

Here’s an editor script I wrote that will match any PolygonCollider2D to the MeshFilter on a GameObject.

Just plop it into an Editor folder, highlight the GameObject, and click Update Polygon Colliders up in the Tools menu, or Ctrl/Cmd+T

Seems to work well with ProBuilder and in Prefab Edit Mode. I’m sure this can be greatly improved upon, feel free!

GIANT credit goes to @Bunny83 for their EdgeHelper class! Wouldn’t work nearly as well without it. :slight_smile:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using UnityEditor.SceneManagement;
using System.Linq;

public static class SetPolygonCollider3D
{
    [MenuItem("Tools/Update Polygon Colliders %t", false, -1)]
    static void UpdatePolygonColliders()
    {
        Transform transform = Selection.activeTransform;
        if(transform == null)
        {
            Debug.LogWarning("No valid GameObject selected!");
            return;
        }

        EditorSceneManager.MarkSceneDirty(transform.gameObject.scene);

        MeshFilter[] meshFilters = transform.GetComponentsInChildren<MeshFilter>();
        
        foreach(MeshFilter meshFilter in meshFilters)
        {
            if(meshFilter.GetComponent<PolygonCollider2D>() != null)
            {
                UpdatePolygonCollider2D(meshFilter);
            }
        }
    }

    static void UpdatePolygonCollider2D(MeshFilter meshFilter)
    {
        if(meshFilter.sharedMesh == null)
        {
            Debug.LogWarning(meshFilter.gameObject.name + " has no Mesh set on its MeshFilter component!");
            return;
        }

        PolygonCollider2D polygonCollider2D = meshFilter.GetComponent<PolygonCollider2D>();
        polygonCollider2D.pathCount = 1;

        List<Vector3> vertices =  new List<Vector3>();
        meshFilter.sharedMesh.GetVertices(vertices);

        var boundaryPath = EdgeHelpers.GetEdges(meshFilter.sharedMesh.triangles).FindBoundary().SortEdges();

        Vector3[] yourVectors = new Vector3[boundaryPath.Count];
        for(int i = 0; i < boundaryPath.Count; i++)
        {
            yourVectors _= vertices[ boundaryPath*.v1 ];*_

}
List newColliderVertices = new List();

for(int i=0; i < yourVectors.Length; i++)
{
newColliderVertices.Add(new Vector2(yourVectors_.x, yourVectors*.y));
}*_

Vector2[] newPoints = newColliderVertices.Distinct().ToArray();

EditorUtility.SetDirty(polygonCollider2D);

polygonCollider2D.SetPath(0, newPoints);
Debug.Log(meshFilter.gameObject.name + " PolygonCollider2D updated.");
}
}

public static class EdgeHelpers
{
public struct Edge
{
public int v1;
public int v2;
public int triangleIndex;
public Edge(int aV1, int aV2, int aIndex)
{
v1 = aV1;
v2 = aV2;
triangleIndex = aIndex;
}
}

public static List GetEdges(int[] aIndices)
{
List result = new List();
for (int i = 0; i < aIndices.Length; i += 3)
{
int v1 = aIndices*;*
int v2 = aIndices[i + 1];
int v3 = aIndices[i + 2];
result.Add(new Edge(v1, v2, i));
result.Add(new Edge(v2, v3, i));
result.Add(new Edge(v3, v1, i));
}
return result;
}

public static List FindBoundary(this List aEdges)
{
List result = new List(aEdges);
for (int i = result.Count-1; i > 0; i–)
{
for (int n = i - 1; n >= 0; n–)
{
if (result_.v1 == result[n].v2 && result*.v2 == result[n].v1)
{
// shared edge so remove both*

result.RemoveAt(i);
result.RemoveAt(n);
i–;
break;
}
}
}
return result;
}
public static List SortEdges(this List aEdges)
{
List result = new List(aEdges);
for (int i = 0; i < result.Count-2; i++)
{
Edge E = result*;*
for(int n = i+1; n < result.Count; n++)
{
Edge a = result[n];
if (E.v2 == a.v1)
{
// in this case they are already in order so just continoue with the next one
if (n == i+1)
break;
// if we found a match, swap them with the next one after “i”
result[n] = result[i + 1];
result[i + 1] = a;
break;
}
}
}
return result;
}
}_