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
Generate 2D polygon collider from 3D mesh
Asked Answered
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 @Hid 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 _ = vertices[boundaryPath *.v1];
}
List<Vector2> newColliderVertices = new List<Vector2>();
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<Edge> GetEdges(int[] aIndices)
{
List<Edge> result = new List<Edge>();
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<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_.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<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 *;
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;
}
}
© 2022 - 2024 — McMap. All rights reserved.
Worked Perfectly for me, thank you. Probably saved me about 5 hours of manually aligning polygon colliers.
– AdustI'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) @Hid or @Boundless ][1]
– Raveauxi 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?
– MisdoubtHey, it seems like the script thingy only got half of the script and the other half is just plain text, which makes it really hard to just ctrl+v it into unity, and adds a few characters that aren't supposed to be there. I'm still a beginner in unity so i don't know how to debug it, especially since it's my first time using editor scripts. could you pls help? thanks in advance
– Cottbus