|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using UnityEngine; |
| 5 | +using UnityEditor; |
| 6 | +using ubco.ovilab.HPUI.Interaction; |
| 7 | + |
| 8 | +namespace ubco.ovilab.HPUI.Editor |
| 9 | +{ |
| 10 | + [CanEditMultipleObjects] |
| 11 | + [CustomEditor(typeof(MeshContinuousCollidersManager))] |
| 12 | + public class MeshContinuousCollidersManagerEditor : UnityEditor.Editor |
| 13 | + { |
| 14 | + private MeshContinuousCollidersManager t; |
| 15 | + private bool computedMeshXRes; |
| 16 | + private bool successfullyComputedMeshXRes; |
| 17 | + |
| 18 | + public override void OnInspectorGUI() |
| 19 | + { |
| 20 | + |
| 21 | + serializedObject.Update(); |
| 22 | + |
| 23 | + |
| 24 | + SerializedProperty vertRemapData = serializedObject.FindProperty("vertexRemapData"); |
| 25 | + t = (MeshContinuousCollidersManager)target; |
| 26 | + |
| 27 | + GUIContent buttonContent = new GUIContent("Compute Vertex Remapping", "Run this with the mesh upright outside of play mode"); |
| 28 | + |
| 29 | + if (GUILayout.Button(buttonContent)) |
| 30 | + { |
| 31 | + int[] remapData = RemapVertices(); |
| 32 | + |
| 33 | + // we can compute mesh x resolution |
| 34 | + // by leveraging pythagoras |
| 35 | + // that when the distance between two vertices after remapping |
| 36 | + // is greater than the distance between the previous two pairs |
| 37 | + // we know we're on the next row, so that's our last vertex |
| 38 | + // on the x-axis |
| 39 | + // . |
| 40 | + // | \ here the hypotenuse will always be greater than the x width, even for x = 2 |
| 41 | + // .__. |
| 42 | + // this fails if for some reason mesh x res is 1 |
| 43 | + // or if your differences are lesser than a nanometer |
| 44 | + // or if your mesh is not a rectangular grid |
| 45 | + // at which point, you're on your own |
| 46 | + |
| 47 | + Mesh tempMesh = new Mesh(); |
| 48 | + t.Mesh.BakeMesh(tempMesh); |
| 49 | + for (int i = 1; i < remapData.Length - 1; i++) |
| 50 | + { |
| 51 | + Vector3 prevVertex = tempMesh.vertices[remapData[i - 1]]; |
| 52 | + Vector3 currVertex = tempMesh.vertices[remapData[i]]; |
| 53 | + Vector3 nextVertex = tempMesh.vertices[remapData[i + 1]]; |
| 54 | + float prevToCurrDist = Vector3.Distance(prevVertex, currVertex); |
| 55 | + float currToNextDist = Vector3.Distance(currVertex, nextVertex); |
| 56 | + if (Mathf.Abs(prevToCurrDist - currToNextDist)>0.0000001f) |
| 57 | + { |
| 58 | + t.MeshXResolution = i + 1; |
| 59 | + successfullyComputedMeshXRes = true; |
| 60 | + break; |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + computedMeshXRes = true; |
| 65 | + |
| 66 | + vertRemapData.arraySize = remapData.Length; |
| 67 | + |
| 68 | + for (int i = 0; i < remapData.Length; i++) |
| 69 | + { |
| 70 | + vertRemapData.GetArrayElementAtIndex(i).intValue = remapData[i]; |
| 71 | + } |
| 72 | + |
| 73 | + } |
| 74 | + |
| 75 | + serializedObject.ApplyModifiedProperties(); |
| 76 | + |
| 77 | + if(computedMeshXRes) |
| 78 | + { |
| 79 | + if (successfullyComputedMeshXRes) |
| 80 | + { |
| 81 | + string message = $"Computed Mesh X Resolution as {t.MeshXResolution}"; |
| 82 | + EditorGUILayout.HelpBox(message, MessageType.Info); |
| 83 | + } |
| 84 | + else |
| 85 | + { |
| 86 | + string message = "Failed to compute Mesh X Resolution! Please Set Manually!"; |
| 87 | + EditorGUILayout.HelpBox(message, MessageType.Error); |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + DrawDefaultInspector(); |
| 92 | + } |
| 93 | + |
| 94 | + private int[] RemapVertices() |
| 95 | + { |
| 96 | + SkinnedMeshRenderer targetMesh = t.Mesh; |
| 97 | + Mesh tempMesh = new Mesh(); |
| 98 | + if(targetMesh==null) |
| 99 | + { |
| 100 | + Debug.LogError("Please assign mesh first!"); |
| 101 | + } |
| 102 | + targetMesh.BakeMesh(tempMesh, true); |
| 103 | + return GetRectifiedIndices(tempMesh, serializedObject.FindProperty("flipOrderForRecompute").boolValue); |
| 104 | + } |
| 105 | + |
| 106 | + private int[] GetRectifiedIndices(Mesh mesh, bool flipOrder) |
| 107 | + { |
| 108 | + int vertexCount = mesh.vertexCount; |
| 109 | + Vector3[] vertices = mesh.vertices; |
| 110 | + int[] correctedIndices = new int[vertexCount]; |
| 111 | + List<(Vector3 vertex, int index)> indexedVertices = new List<(Vector3 vertex, int index)>(vertexCount); |
| 112 | + for (int i = 0; i < vertexCount; i++) |
| 113 | + { |
| 114 | + indexedVertices.Add((vertices[i], i)); |
| 115 | + } |
| 116 | + indexedVertices.Sort((a, b) => |
| 117 | + { |
| 118 | + if (Math.Abs(a.vertex.y - b.vertex.y) > 0.00001) |
| 119 | + return a.vertex.y.CompareTo(b.vertex.y); |
| 120 | + return b.vertex.x.CompareTo(a.vertex.x); |
| 121 | + }); |
| 122 | + |
| 123 | + for (int i = 0; i < vertexCount; i++) |
| 124 | + { |
| 125 | + correctedIndices[i] = indexedVertices[i].index; |
| 126 | + } |
| 127 | + int[] remapData = flipOrder ? correctedIndices.Reverse().ToArray() : correctedIndices; |
| 128 | + return remapData; |
| 129 | + } |
| 130 | + } |
| 131 | +} |
0 commit comments