// Editor script that displays the number and UV coordinates of each individual vertex making up a triangle within a mesh // To install, place in the Assets folder of a Unity project // Open via Window > Show Vertex Info // Author: Luke Gane // Last updated: 2015-02-07 using UnityEditor; using UnityEngine; public class ShowVertexNumber : EditorWindow { Mesh curMesh; MeshFilter curMeshFilter; SkinnedMeshRenderer curSMR; bool meshAvailable = false; int curFace = 0, numFaces = 0, newFace = 0; GUIStyle centredStyle = null; Vector3 p1, p2, p3; [MenuItem("Window/Show Vertex Info")] public static void ShowWindow(){ EditorWindow.GetWindow(typeof(ShowVertexNumber)); // Show existing window instance; if one doesn't exist, it is created } void OnEnable(){ // See http://answers.unity3d.com/questions/58018/drawing-to-the-scene-from-an-editorwindow.html if (SceneView.onSceneGUIDelegate != this.RenderStuff){ // This appears to be a sufficient check SceneView.onSceneGUIDelegate += this.RenderStuff; } OnSelectionChange(); } void OnDestroy(){ SceneView.onSceneGUIDelegate -= this.RenderStuff; } void OnSelectionChange(){ bool noMesh = true; if (Selection.activeGameObject){ curMeshFilter = Selection.activeGameObject.GetComponentInChildren(); if (curMeshFilter){ curMesh = curMeshFilter.sharedMesh; meshAvailable = true; numFaces = curMesh.triangles.Length/3; noMesh = false; } else{ curSMR = Selection.activeGameObject.GetComponentInChildren(); if (curSMR){ curMesh = curSMR.sharedMesh; meshAvailable = true; numFaces = curMesh.triangles.Length/3; noMesh = false; } } } if (noMesh){ meshAvailable = false; numFaces = 0; } curFace = 0; newFace = curFace; Repaint(); } void OnInspectorUpdate(){ Repaint(); } void OnGUI(){ if (meshAvailable){ EditorGUILayout.LabelField("Number of faces: ", numFaces.ToString()); EditorGUILayout.LabelField("Current face index: ", curFace.ToString()); newFace = EditorGUILayout.IntField("Jump to face index: ", curFace); if (newFace != curFace){ if (newFace >= 0 && newFace < numFaces){ curFace = newFace; } } EditorGUILayout.BeginHorizontal(); if (GUILayout.Button ("Prev Face")){ curFace = (curFace-1) % numFaces; if (curFace < 0){ curFace = curFace + numFaces; } } if (GUILayout.Button ("Next Face")){ curFace = (curFace+1) % numFaces; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Index of red vertex: ", curMesh.triangles[curFace*3].ToString()); EditorGUILayout.LabelField("Index of green vertex: ", curMesh.triangles[curFace*3 + 1].ToString()); EditorGUILayout.LabelField("Index of blue vertex: ", curMesh.triangles[curFace*3 + 2].ToString()); EditorGUILayout.Space(); EditorGUILayout.LabelField("UV coords red vertex: ", "(" + curMesh.uv[curMesh.triangles[curFace*3]].x.ToString() + ", " + curMesh.uv[curMesh.triangles[curFace*3]].y.ToString() + ")"); EditorGUILayout.LabelField("UV coords green vertex: ", "(" + curMesh.uv[curMesh.triangles[curFace*3 + 1]].x.ToString() + ", " + curMesh.uv[curMesh.triangles[curFace*3 + 1]].y.ToString() + ")"); EditorGUILayout.LabelField("UV coords blue vertex: ", "(" + curMesh.uv[curMesh.triangles[curFace*3 + 2]].x.ToString() + ", " + curMesh.uv[curMesh.triangles[curFace*3 + 2]].y.ToString() + ")"); } else{ EditorGUILayout.LabelField("Current selection contains no mesh."); } } // Analogous to OnSceneGUI message handler of the Editor class void RenderStuff(SceneView sceneView){ if (meshAvailable){ int index1 = curMesh.triangles[curFace*3]; int index2 = curMesh.triangles[curFace*3 + 1]; int index3 = curMesh.triangles[curFace*3 + 2]; if (curMeshFilter){ p1 = curMeshFilter.transform.TransformPoint(curMesh.vertices[index1]); p2 = curMeshFilter.transform.TransformPoint(curMesh.vertices[index2]); p3 = curMeshFilter.transform.TransformPoint(curMesh.vertices[index3]); } else if (curSMR){ p1 = curSMR.transform.TransformPoint(curMesh.vertices[index1]); p2 = curSMR.transform.TransformPoint(curMesh.vertices[index2]); p3 = curSMR.transform.TransformPoint(curMesh.vertices[index3]); } Handles.color = Color.red; Handles.DotCap(0, p1, Quaternion.identity, 0.25f*HandleUtility.GetHandleSize(p1)); Handles.color = Color.green; Handles.DotCap(0, p2, Quaternion.identity, 0.25f*HandleUtility.GetHandleSize(p2)); Handles.color = Color.blue; Handles.DotCap(0, p3, Quaternion.identity, 0.25f*HandleUtility.GetHandleSize(p3)); Handles.color = Color.yellow; Handles.DrawDottedLine(p1, p2, 5f); Handles.DrawDottedLine(p2, p3, 5f); Handles.DrawDottedLine(p3, p1, 5f); if (centredStyle == null){ centredStyle = new GUIStyle(GUI.skin.label); centredStyle.normal.textColor = Color.black; centredStyle.fixedWidth = 40; // If you regularly inspect meshes with more than 999 vertices you may wish to increase this value centredStyle.fixedHeight = 20; centredStyle.alignment = TextAnchor.MiddleCenter; centredStyle.normal.background = Texture2D.whiteTexture; // For reference, whiteTexture is 4x4 (not particularly relevant here) centredStyle.fontSize = 12; centredStyle.clipping = TextClipping.Overflow; } Handles.Label(p1, index1.ToString(), centredStyle); Handles.Label(p2, index2.ToString(), centredStyle); Handles.Label(p3, index3.ToString(), centredStyle); sceneView.Repaint(); } } }