Skip to content

Instantly share code, notes, and snippets.

@FaffyWaffles
Last active June 1, 2022 16:32
Show Gist options
  • Save FaffyWaffles/e7724e4ea863e8f8cd78837909b29384 to your computer and use it in GitHub Desktop.
Save FaffyWaffles/e7724e4ea863e8f8cd78837909b29384 to your computer and use it in GitHub Desktop.
Odin Bug Report
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Sirenix.OdinInspector;
public class MeshDebug : SerializedMonoBehaviour
{
private GameObject target;
private MeshFilter meshFilter;
public enum DrawType { Both, Face, Vertex, Neither };
public DrawType drawType;
public enum LabelDrawType { Vertex, Shared };
public LabelDrawType labelDrawType;
public enum RayType { Ray, Arrow };
public bool drawNormals = true;
[ShowIfGroup("drawNormals")]
[FoldoutGroup("drawNormals/Normals", expanded: true)]
[Range(.001f, .01f)] public float gizmoSize = .005f;
[FoldoutGroup("drawNormals/Normals", expanded: true)]
[Range(.001f, .075f)] public float length = .0275f;
[FoldoutGroup("drawNormals/Normals", expanded: true)]
public RayType rayType;
[FoldoutGroup("drawNormals/Normals", expanded: true)]
public Color faceColor = Color.green;
[FoldoutGroup("drawNormals/Normals", expanded: true)]
public Color vertexColor = Color.red;
public bool drawLabels;
[ShowIfGroup("drawLabels")]
[FoldoutGroup("drawLabels/Labels", expanded: true)]
[Range(-.05f, .05f)]
public float labelOffsetNormal = 0f;
[FoldoutGroup("drawLabels/Labels", expanded: true)]
[Range(-.01f, .01f)]
public float labelOffsetX, labelOffsetY, labelOffsetZ = 0f;
public bool drawUVs;
public bool drawWireframe = true;
public bool drawEdges;
public int findIndex = -1;
public Color findColor = Color.yellow;
private Mesh mesh;
public Vector3[] vertices;
public int[] triangles;
public Vector3[] normals;
public Vector2[] uvs;
public Color[] gizmoColor;
private bool init = false;
private void Awake()
{
Initialize();
DistinctRandomColors(vertices.Length, out gizmoColor, UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 1f, 1f));
init = true;
}
private void OnDrawGizmosSelected()
{
if (init)
{
DrawNormals();
if (drawEdges)
DrawEdges();
EditorUtility.SetSelectedWireframeHidden(GetComponent<Renderer>(), !drawWireframe);
}
}
private void Initialize()
{
if (target == null)
target = this.gameObject;
if (meshFilter == null)
{
meshFilter = GetComponent<MeshFilter>();
if (meshFilter == null)
Debug.LogError("MeshFilter Required");
}
mesh = meshFilter.sharedMesh;
vertices = mesh.vertices;
triangles = mesh.triangles;
normals = mesh.normals;
uvs = mesh.uv;
FindSharedVerts();
}
private void DrawNormals()
{
switch (drawType)
{
case DrawType.Both:
DrawFaceNormals();
DrawVertexNormals();
break;
case DrawType.Face:
DrawFaceNormals();
break;
case DrawType.Vertex:
DrawVertexNormals();
break;
}
}
//[LabelText("$submeshCount")]
//[InfoBox("@\"Submesh Count= \" + submeshCount.ToString()", InfoMessageType.None)]
public int submeshCount;
public void DrawFaceNormals()
{
for (int i = 0; i < triangles.Length; i += 3)
{
Vector3 center = FindCenter(i).Item1;
Vector3 dir = FindCenter(i).Item2;
if (drawNormals)
Draw(center, dir, faceColor);
if (drawLabels)
DrawLabels(center, dir, (i / 3).ToString());
}
submeshCount = mesh.subMeshCount;
if (WaffleWare.WLists.CheckIndex(findIndex * 3, 0, (triangles.Length / 3) - 1))
{
Vector3 center = FindCenter(findIndex * 3).Item1;
Vector3 dir = FindCenter(findIndex * 3).Item2;
DrawFound(center, dir, findColor);
}
}
public bool vertexGroups;
public void DrawVertexNormals()
{
if (labelDrawType == LabelDrawType.Vertex)
{
for (int i = 0; i < vertices.Length; i++)
{
Vector3 tPoint = transform.TransformPoint(vertices[i]);
Vector3 tVector = transform.TransformVector(normals[i]);
if (drawNormals)
if (vertexGroups)
Draw(tPoint, tVector, gizmoColor[i]);
else
Draw(tPoint, tVector, vertexColor);
if (drawLabels)
DrawLabels(tPoint, tVector, i.ToString());
if (drawUVs)
{
Vector2 uv = uvs[triangles[i]];
DrawLabels(tPoint, tVector, uv.ToString());
}
}
}
else if (labelDrawType == LabelDrawType.Shared)
{
for (int i = 0; i < sharedVerts.Count; i++)
{
Vector3 tPoint = transform.TransformPoint(sharedVerts[i].vertex);
//Vector3 tVector = transform.TransformVector(normals[sharedVerts[i].sharedIndices[0]]);
Vector3 tVector = transform.TransformVector(sharedVerts[i].normalAverage);
if (drawNormals)
if (vertexGroups)
Draw(tPoint, tVector, gizmoColor[i]);
else
Draw(tPoint, tVector, vertexColor);
if (drawLabels)
DrawLabels(tPoint, tVector, i.ToString());
if (drawUVs)
{
Vector2 uv = uvs[triangles[i]];
DrawLabels(tPoint, tVector, uv.ToString());
}
}
}
if (WaffleWare.WLists.CheckIndex(findIndex * 3, 0, vertices.Length))
{
Vector3 iPoint = transform.TransformPoint(vertices[findIndex * 3]);
Vector3 iVector = transform.TransformVector(normals[findIndex * 3]);
if (WaffleWare.WLists.CheckIndex(findIndex * 3, 0, vertices.Length))
DrawFound(iPoint, iVector, findColor);
}
}
public void Draw(Vector3 from, Vector3 direction, Color color)
{
from = target.transform.TransformPoint(from);
Vector3 v = from + (direction * .1f);
//if (!Physics.Linecast(Camera.current.transform.position, v))
if ((DepthCulling(v) && depthCulling) || !depthCulling)
{
Gizmos.color = color;
Gizmos.DrawSphere(from, gizmoSize);
if (rayType == RayType.Ray)
Gizmos.DrawRay(from, direction * length);
else if (rayType == RayType.Arrow)
{
Handles.color = color;
Handles.ArrowHandleCap(0, from, Quaternion.LookRotation(direction), length, EventType.Repaint);
}
}
//if (Camera.current.transform.InverseTransformDirection(direction).z < 0f)
//{
//Gizmos.color = color;
// Gizmos.DrawSphere(from, .005f);
// Gizmos.DrawRay(from, direction * .1f);
//}
}
public void DrawFound(Vector3 from, Vector3 direction, Color color)
{
//if (Camera.current.transform.InverseTransformDirection(direction).z < 0f)
//{
Gizmos.color = color;
Gizmos.DrawSphere(from, .01f);
Gizmos.DrawRay(from, direction * 1f);
//}
}
public bool depthCulling;
public void DrawLabels(Vector3 from, Vector3 direction, string label)
{
from = target.transform.TransformPoint(from);
Vector3 labelOffset = new Vector3(labelOffsetX, labelOffsetY, labelOffsetZ);
Vector3 v = from + (direction * labelOffsetNormal) + labelOffset;
if (drawNormals)
v += (direction * length);
//if (!Physics.Linecast(Camera.current.transform.position, v))
// Handles.Label(v, label);
if ((DepthCulling(v) && depthCulling) || !depthCulling)
Handles.Label(v, label);
//if (((DepthCulling(target.transform.TransformPoint(v))) && (depthCulling)) || ((!depthCulling)))
// Handles.Label(v, label);
//if (Camera.current.transform.InverseTransformDirection(direction).z < 0f)
//{
// Vector3 v = from + (direction * .1f);
// Handles.Label(v, label);
//}
}
public void DrawEdges()
{
foreach (var item in edgeDict)
{
Edge e = item.Value;
if (!e.shared)
Debug.DrawLine(e.vertexX, e.vertexY, Color.red);
}
}
public (Vector3, Vector3) FindCenter(int i)
{
Vector3 v0 = transform.TransformPoint(vertices[triangles[i]]);
Vector3 v1 = transform.TransformPoint(vertices[triangles[i + 1]]);
Vector3 v2 = transform.TransformPoint(vertices[triangles[i + 2]]);
Vector3 center = (v0 + v1 + v2) / 3;
Vector3 dir = Vector3.Cross(v1 - v0, v2 - v0);
dir /= dir.magnitude;
return (center, dir);
}
private bool DepthCulling(Vector3 v) ///needs to be mesh collider
{
if (Physics.Linecast(Camera.current.transform.position, v))
return false;
return true;
}
[Range(.0001f, .001f)] public float buffer = .0001f;
private bool done = false;
[HideReferenceObjectPicker]
public class Vert
{
[HorizontalGroup("Split", Width = 75)]
[ListDrawerSettings(Expanded = true)]
public List<int> sharedIndices;
[HideInInspector]
public Vector3 vertex;
//[HideInInspector]
public Vector3 normalAverage;
//[HideInInspector]
public List<Vector3> vertNormals = new List<Vector3>();
[VerticalGroup("Split/Right")]
[BoxGroup("Split/Right/Vertex"), LabelWidth(15)]
public float x, y, z;
public Vert(List<int> sharedIndices, Vector3 vertex)
{
this.sharedIndices = sharedIndices;
this.vertex = vertex;
this.x = vertex.x;
this.y = vertex.y;
this.z = vertex.z;
}
}
[HideReferenceObjectPicker]
[ListDrawerSettings(ShowIndexLabels = true, NumberOfItemsPerPage = 10)]
public List<Vert> sharedVerts = new List<Vert>();
public Dictionary<int, int> vertDict = new Dictionary<int, int>();
public Dictionary<HashSet<int>, Edge> edgeDict = new Dictionary<HashSet<int>, Edge>(HashSet<int>.CreateSetComparer());
[HideReferenceObjectPicker]
public class Edge
{
public Vector2Int edgeIndices;
public Vector3 vertexX;
public Vector3 vertexY;
public bool shared;
public Edge(Vector2Int edgeIndices, Vector3 vertexX, Vector3 vertexY)
{
this.edgeIndices = edgeIndices;
this.vertexX = vertexX;
this.vertexY = vertexY;
}
}
public List<Vector2Int> edgeIndices = new List<Vector2Int>();
public void FindSharedVerts()
{
sharedVerts = new List<Vert>();
vertDict = new Dictionary<int, int>();
edgeDict = new Dictionary<HashSet<int>, Edge>(HashSet<int>.CreateSetComparer());
edgeIndices = new List<Vector2Int>();
HashSet<int> hashedIndices = new HashSet<int>();
for (int i = 0; i < vertices.Length; i++)
{
Vert v = new Vert(new List<int>(), vertices[i]);
if (!hashedIndices.Contains(i))
{
for (int j = 0; j < vertices.Length; j++)
{
if (!hashedIndices.Contains(j))
{
if (Mathf.Abs((vertices[i] - vertices[j]).sqrMagnitude) < (buffer * buffer))
{
hashedIndices.Add(j);
v.sharedIndices.Add(j);
v.vertNormals.Add(normals[j]);
}
}
}
hashedIndices.Add(i);
sharedVerts.Add(v);
}
}
int sharedVertCount = sharedVerts.Count;
for (int i = 0; i < sharedVertCount; i++)
{
sharedVerts[i].normalAverage = Centroid(sharedVerts[i].vertNormals);
foreach (int vertIndex in sharedVerts[i].sharedIndices)
vertDict.Add(vertIndex, i);
}
FindSharedEdges();
}
public void FindSharedEdges()
{
edgeDict = new Dictionary<HashSet<int>, Edge>(HashSet<int>.CreateSetComparer());
for (int i = 0; i <= (triangles.Length / 3) - 1; i++)
{
int i0 = triangles[i * 3 + 0];
int i1 = triangles[i * 3 + 1];
int i2 = triangles[i * 3 + 2];
int t0 = vertDict[i0];
int t1 = vertDict[i1];
int t2 = vertDict[i2];
AddEdge(t0, t1);
AddEdge(t1, t2);
AddEdge(t2, t0);
}
foreach (var item in edgeDict)
{
Edge e = item.Value;
if (!e.shared)
{
edgeIndices.Add(new Vector2Int(e.edgeIndices.x, e.edgeIndices.y));
edgeIndices.Add(new Vector2Int(e.edgeIndices.y, e.edgeIndices.x));
}
}
done = true;
}
void AddEdge(int x, int y)
{
HashSet<int> edgeHash = new HashSet<int>();
edgeHash.Add(x);
edgeHash.Add(y);
if (!edgeDict.ContainsKey(edgeHash))
{
Vector2Int v2 = new Vector2Int(x, y);
Vector3 v3X = sharedVerts[x].vertex;
Vector3 v3Y = sharedVerts[y].vertex;
edgeDict.Add(edgeHash, new Edge(v2, v3X, v3Y));
//edgeIndices.Add(new Vector2Int(x, y));
}
else
edgeDict[edgeHash].shared = true;
}
void DistinctRandomColors(int colorCount, out Color[] colors, Color initColor)
{
colors = new Color[colorCount];
//Color initColor = UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 1f, 1f);
colors[0] = initColor;
float hue, saturation, value;
Color.RGBToHSV(initColor, out hue, out saturation, out value);
float normalizedHue = Mathf.Clamp01(hue);
for (int i = 1; i < colorCount; i++)
{
float angle = (((360 * colorCount) - (360 * i)) / colorCount);
float normalized = (angle / 360) + normalizedHue;
Color newColor = Color.HSVToRGB(normalized % 1, saturation, value);
colors[i] = newColor;
}
}
Vector3 Centroid(List<Vector3> vertNormals)
{
Vector3 vSum = new Vector3();
foreach (Vector3 v in vertNormals)
vSum += v;
return (vSum) / vertNormals.Count;
}
}
@FaffyWaffles
Copy link
Author

image

@FaffyWaffles
Copy link
Author

This script has been confirmed to be able to reproduce the error by isolating it in a new scene

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment