From dd8c1f9d3315f35687d512b4816a48176768ff5f Mon Sep 17 00:00:00 2001 From: Kevin Watters Date: Sat, 14 Jan 2017 17:11:51 -0500 Subject: [PATCH] make ExplodeSketchByColor faster by allocating less memory Dramatically reduce the time spent exploding sketches by color by avoiding calling `mesh.colors`, which allocates a new array, for every triangle. Also, updating the progress bar less often gives a nice speed boost as well. --- .../TiltBrush/Scripts/Editor/EditorUtils.cs | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/UnitySDK/Assets/TiltBrush/Scripts/Editor/EditorUtils.cs b/UnitySDK/Assets/TiltBrush/Scripts/Editor/EditorUtils.cs index c6f55743..a51898b8 100644 --- a/UnitySDK/Assets/TiltBrush/Scripts/Editor/EditorUtils.cs +++ b/UnitySDK/Assets/TiltBrush/Scripts/Editor/EditorUtils.cs @@ -31,33 +31,47 @@ public static void ExplodeSketchByColor() { Undo.SetCurrentGroupName("Separate sketch by color"); List newSelection = new List(); bool cancel = false; + + var tri = new int[3] { 0, 0, 0 }; + foreach (var o in Selection.gameObjects) { if (cancel) break; var obj = GameObject.Instantiate(o, o.transform.position, o.transform.rotation) as GameObject; obj.name = o.name + " (Separated)"; Undo.RegisterCreatedObjectUndo(obj, "Separate sketch by color"); newSelection.Add(obj); + int count = 0; foreach (var m in obj.GetComponentsInChildren()) { if (cancel) break; var mesh = m.sharedMesh; + var meshColors = mesh.colors; // Keep a list of triangles for each color (as a vector) we find Dictionary> colors = new Dictionary>(); - for (int i = 0; i < mesh.triangles.Length; i += 3) { - cancel = EditorUtility.DisplayCancelableProgressBar("Separating sketch", "Processing " + mesh.name, (float)i / (float)mesh.triangles.Length); - if (cancel) break; + var triangles = mesh.triangles; + const int PROGRESS_FREQUENCY = 600; + + for (int i = 0; i < triangles.Length; i += 3) { + if (++count > PROGRESS_FREQUENCY) { + count = 0; + cancel = EditorUtility.DisplayCancelableProgressBar("Separating sketch", "Processing " + mesh.name, (float)i / (float)triangles.Length); + if (cancel) break; + } + + tri[0] = triangles[i]; + tri[1] = triangles[i + 1]; + tri[2] = triangles[i + 2]; - var tri = new int[3] { mesh.triangles[i], mesh.triangles[i + 1], mesh.triangles[i + 2] }; // Get the triangle's average color - var color = GetTriangleColorVec(mesh, tri); + var color = GetTriangleColorVec(meshColors, tri); + // Add the triangle to the triangle-by-color list - if (!colors.ContainsKey(color)) - colors.Add(color, new List()); - colors[color].Add(tri[0]); - colors[color].Add(tri[1]); - colors[color].Add(tri[2]); + List trianglesForColor; + if (!colors.TryGetValue(color, out trianglesForColor)) + trianglesForColor = colors[color] = new List(); + trianglesForColor.AddRange(tri); } if (cancel) @@ -65,9 +79,13 @@ public static void ExplodeSketchByColor() { // make a new mesh for each color int colorIndex = 0; + count = 0; foreach (var color in colors.Keys) { - cancel = EditorUtility.DisplayCancelableProgressBar("Separating sketch", "Processing " + mesh.name, (float)colorIndex / (float)colors.Keys.Count); - if (cancel) break; + if (++count > PROGRESS_FREQUENCY) { + count = 0; + cancel = EditorUtility.DisplayCancelableProgressBar("Separating sketch", "Processing " + mesh.name, (float)colorIndex / (float)colors.Keys.Count); + if (cancel) break; + } // Clone the gameobject with the mesh var newObj = GameObject.Instantiate(m.gameObject, m.transform.position, m.transform.rotation) as GameObject; newObj.name = string.Format("{0} {1}", m.name, colorIndex); @@ -95,7 +113,7 @@ public static void ExplodeSketchByColor() { [MenuItem("Tilt Brush/Labs/Separate strokes by brush color", true)] public static bool ExplodeSketchByColorValidate() { - // TODO: validate that selection is a model + // TODO: validate that selection is a model foreach (var o in Selection.gameObjects) { if (o.GetComponent() != null) return true; @@ -108,17 +126,15 @@ public static bool ExplodeSketchByColorValidate() { /// /// Gets the average color of a triangle and returns it as a vector for easier comparison /// - public static Vector3 GetTriangleColorVec(Mesh Mesh, int[] Triangle) { + public static Vector3 GetTriangleColorVec(Color[] meshColors, int[] Triangle) { Vector3 v = new Vector3(); for (int i = 0; i < Triangle.Length; i++) { - var c = Mesh.colors[Triangle[i]]; + var c = meshColors[Triangle[i]]; v.x += c.r; v.y += c.g; v.z += c.b; } - v.x /= Triangle.Length; - v.y /= Triangle.Length; - v.z /= Triangle.Length; + v /= Triangle.Length; return v; } @@ -154,7 +170,7 @@ public static string TiltBrushDirectory { if (string.IsNullOrEmpty (m_TiltBrushDirectory)) Debug.LogErrorFormat ("Could not find the TiltBrush directory. Reimport the Tilt Brush Unity SDK to ensure it's unmodified."); return m_TiltBrushDirectory; - } + } } /// @@ -237,23 +253,23 @@ public static GameObject[] GetFramesFromFolder(Object FolderAsset) { GrabObjectsAtDirectory (sFolderPath, ref frames); // get files in top directory RecursiveSearch (sFolderPath, ref frames); // go through subdirectories - GameObject[] array = frames.ToArray (); + GameObject[] array = frames.ToArray (); System.Array.Sort (array, new AlphanumericComparer ()); return array; } public static void GrabObjectsAtDirectory(string sDir, ref List List) { - foreach (string f in Directory.GetFiles(sDir)) + foreach (string f in Directory.GetFiles(sDir)) { var frame = AssetDatabase.LoadAssetAtPath(f.Substring(Application.dataPath.Length-6)); if (frame != null) List.Add (frame); } } - public static void RecursiveSearch(string sDir, ref List List) + public static void RecursiveSearch(string sDir, ref List List) { - try + try { foreach (string d in Directory.GetDirectories(sDir)) { @@ -261,7 +277,7 @@ public static void RecursiveSearch(string sDir, ref List List) RecursiveSearch(d, ref List); } } - catch (System.Exception excpt) + catch (System.Exception excpt) { Debug.LogError(excpt.Message); }