- Home /
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
Answer by alpineboarder · Mar 12, 2019 at 12:33 AM
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. :)
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[i] = vertices[ boundaryPath[i].v1 ];
}
List<Vector2> newColliderVertices = new List<Vector2>();
for(int i=0; i < yourVectors.Length; i++)
{
newColliderVertices.Add(new Vector2(yourVectors[i].x, yourVectors[i].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<Edge> GetEdges(int[] aIndices)
{
List<Edge> result = new List<Edge>();
for (int i = 0; i < aIndices.Length; i += 3)
{
int v1 = aIndices[i];
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<Edge> FindBoundary(this List<Edge> aEdges)
{
List<Edge> result = new List<Edge>(aEdges);
for (int i = result.Count-1; i > 0; i--)
{
for (int n = i - 1; n >= 0; n--)
{
if (result[i].v1 == result[n].v2 && result[i].v2 == result[n].v1)
{
// shared edge so remove both
result.RemoveAt(i);
result.RemoveAt(n);
i--;
break;
}
}
}
return result;
}
public static List<Edge> SortEdges(this List<Edge> aEdges)
{
List<Edge> result = new List<Edge>(aEdges);
for (int i = 0; i < result.Count-2; i++)
{
Edge E = result[i];
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;
}
}
Worked Perfectly for me, thank you. Probably saved me about 5 hours of manually aligning polygon colliers.
$$anonymous$$eep in $$anonymous$$d that this only works properly if your 3d meshes either have no depth changes at the silhouette or you're using an orthographic camera, so no perspective. However if an orthographic camera is used, it's kinda wasteful to use 3d meshes in the first place.
I'm working with unity's ProBuilder and I was wondering if the script is possible to create an outline for shapes like this. For easier shapes it works perfectly!! (Btw the view in the screenshots won't be the game view)
][1]
i have tried to use this and although it does generate a polygon collider, it only seems to do so from the bottom of the mesh, instead of from the angle of the camera, do you know of any way to fix this?
I don't know if we're dealing with the exact same problem but this is what worked for me:
When using probuilder only try to use the extrude function. For some reason when I try to add loopcuts to my mesh it messes with how the polygon collider gets created. (even though the topology is the exact same with both methods.)
So for now I just don't use loopcuts when I make things with probuilder. (Although I must say it's quite annoying to do it that way xd)
I am not using probuilder, but the issue seems to be that it is using every edge instead of only the outer ones, and it doesn't change the colliders based on rotation, so its always generating them as if they had no rotation, although I get that 2d colliders don't work on rotated objects anyway.
Your answer
Follow this Question
Related Questions
Make a Good Collider on Blender import? 2 Answers
Cant fix my collider problem on an object, help me up :) 1 Answer
Unity 3D mesh collider collision detection 0 Answers
Mesh collider wont collide smoothly 0 Answers
Error downloading Unity 2 Answers