Search Unity

[SOLVED] How to force update in edit mode.

Discussion in 'Scripting' started by keenanwoodall, Sep 26, 2018.

  1. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598

    As you can see, the mesh updates extremely slowly in edit mode but it is much smoother in play mode. Is there something I can do to force it to update at a higher rate in edit mode.

    Here's the code, the important part (the code for the handles) is at the bottom in DrawBoundsHandles() the rest is just drawing inspector fields.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. namespace Deform
    5. {
    6.     [CustomEditor (typeof (TwistDeformer))]
    7.     public class TwistDeformerEditor : Editor
    8.     {
    9.         private const float HANDLE_SIZE = 0.05f;
    10.  
    11.         public override void OnInspectorGUI ()
    12.         {
    13.             base.OnInspectorGUI ();
    14.  
    15.             var twist = target as TwistDeformer;
    16.  
    17.             EditorGUI.BeginChangeCheck ();
    18.             var newAngle = EditorGUILayout.FloatField (new GUIContent ("Angle"), twist.Angle);
    19.             if (EditorGUI.EndChangeCheck ())
    20.             {
    21.                 Undo.RecordObject (twist, "Changed Angle");
    22.                 twist.Angle = newAngle;
    23.             }
    24.  
    25.             EditorGUI.BeginChangeCheck ();
    26.             var newStrength = EditorGUILayout.FloatField (new GUIContent ("Strength"), twist.Strength);
    27.             if (EditorGUI.EndChangeCheck ())
    28.             {
    29.                 Undo.RecordObject (twist, "Changed Strength");
    30.                 twist.Strength = newStrength;
    31.             }
    32.  
    33.             EditorGUI.BeginChangeCheck ();
    34.             var newMode = (DeformerMode)EditorGUILayout.EnumPopup (new GUIContent ("Mode"), twist.Mode);
    35.             if (EditorGUI.EndChangeCheck ())
    36.             {
    37.                 Undo.RecordObject (twist, "Changed Mode");
    38.                 twist.Mode = newMode;
    39.             }
    40.  
    41.             EditorGUI.BeginChangeCheck ();
    42.             var newTop = EditorGUILayout.FloatField (new GUIContent ("Top"), twist.Top);
    43.             if (EditorGUI.EndChangeCheck ())
    44.             {
    45.                 Undo.RecordObject (twist, "Changed Top");
    46.                 twist.Top = newTop;
    47.             }
    48.  
    49.             EditorGUI.BeginChangeCheck ();
    50.             var newBottom = EditorGUILayout.FloatField (new GUIContent ("Bottom"), twist.Bottom);
    51.             if (EditorGUI.EndChangeCheck ())
    52.             {
    53.                 Undo.RecordObject (twist, "Changed Bottom");
    54.                 twist.Bottom = newBottom;
    55.             }
    56.  
    57.             EditorGUI.BeginChangeCheck ();
    58.             var newAxis = (Transform)EditorGUILayout.ObjectField (new GUIContent ("Axis"), twist.Axis, typeof (Transform), true);
    59.             if (EditorGUI.EndChangeCheck ())
    60.             {
    61.                 Undo.RecordObject (twist, "Changed Axis");
    62.                 twist.Axis = newAxis;
    63.             }
    64.         }
    65.  
    66.         private void OnSceneGUI ()
    67.         {
    68.             var twist = target as TwistDeformer;
    69.             if (twist == null)
    70.                 return;
    71.  
    72.             DrawBoundsHandles (twist);
    73.         }
    74.  
    75.         private void DrawBoundsHandles (TwistDeformer twist)
    76.         {
    77.             Handles.color = new Color (1f, 0.5f, 0f);
    78.  
    79.             var direction = twist.Axis.forward;
    80.             var topWorldPosition = twist.transform.position + direction * twist.Top;
    81.             var botWorldPosition = twist.transform.position + direction * twist.Bottom;
    82.  
    83.             Handles.DrawLine (topWorldPosition, botWorldPosition);
    84.  
    85.             var topSize = HandleUtility.GetHandleSize (topWorldPosition) * HANDLE_SIZE;
    86.             var botSize = HandleUtility.GetHandleSize (botWorldPosition) * HANDLE_SIZE;
    87.  
    88.             EditorGUI.BeginChangeCheck ();
    89.             var newTopWorld = Handles.Slider (topWorldPosition, direction, topSize, Handles.DotHandleCap, 0f);
    90.             var newTop = twist.Axis.InverseTransformPoint (newTopWorld - twist.transform.position).z;
    91.             if (EditorGUI.EndChangeCheck ())
    92.             {
    93.                 Undo.RecordObject (twist, "Changed Top");
    94.                 twist.Top = newTop;
    95.             }
    96.  
    97.             EditorGUI.BeginChangeCheck ();
    98.             var newBotWorld = Handles.Slider (botWorldPosition, -direction, botSize, Handles.DotHandleCap, 0f);
    99.             var newBot = twist.Axis.InverseTransformPoint (newBotWorld - twist.transform.position).z;
    100.             if (EditorGUI.EndChangeCheck ())
    101.             {
    102.                 Undo.RecordObject (twist, "Changed Bottom");
    103.                 twist.Bottom = newBot;
    104.             }
    105.         }
    106.     }
    107. }
    [edit] For what it's worth, the mesh deformation is started in Update and finished in LateUpdate using the job system. The handles are changing the 'top' and 'bottom' fields of the TwistDeformer. Those fields are exposed in the inspector as well. When you change the values in the inspector in edit mode the mesh updates smoothly; just like in play mode. It has something to do with changes to the handles not telling unity to update objects similarly to changes to the inspector.

    [solved] doesn't make too much sense, but call Repaint() at the end of OnInspectorGUI() and changes to handles in OnSceneGUI will refresh objects with [ExecuteInEditMode] smoothly.
     
    Last edited: Sep 27, 2018
  2. atkins79

    atkins79

    Joined:
    Jun 22, 2018
    Posts:
    4
  3. Can-Baycay

    Can-Baycay

    Joined:
    Dec 14, 2010
    Posts:
    27
    In a similar problem which I wanted to trigger Update() calls without an extra editor script, I've used QueuePlayerLoopUpdate and RepaintAll inside OnDrawGizmos in a script marked with [ExecuteAlways]. That made Unity call the Update method continuously and frequently.

    Code (CSharp):
    1. [ExecuteAlways]
    2. public class NeverEndingUpdateCallsInEditor : MonoBehaviour
    3. {
    4.    void Update()
    5.    {
    6.       // Your thing goes here...
    7.      Debug.Log("Yeehaw!");
    8.    }
    9.  
    10.    void OnDrawGizmos()
    11.    {
    12.       // Your gizmo drawing thing goes here if required...
    13.  
    14. #if UNITY_EDITOR
    15.       // Ensure continuous Update calls.
    16.       if (!Application.isPlaying)
    17.       {
    18.          UnityEditor.EditorApplication.QueuePlayerLoopUpdate();
    19.          UnityEditor.SceneView.RepaintAll();
    20.       }
    21. #endif
    22.    }
    23. }
    Note that OnDrawGizmos method is only called by Unity when gizmo drawing is enabled for that object, which can be a cool feature depending on why the Update calls are needed. If you want the Update to be called when not drawing gizmos, you may use EditorApplication.delayCall += EditorApplication.QueuePlayerLoopUpdate inside Update. Though this way, the frequency of Update calls will depend on Unity's delayCall processing frequency, which is not that high. That would also be a cool feature where Update is called frequently when gizmos are enabled and not that frequently when gizmos are disabled.
     
  4. SergeantBiscuits

    SergeantBiscuits

    Joined:
    Jul 22, 2012
    Posts:
    17
    This is great. Thank you!
     
  5. Anisoropos

    Anisoropos

    Joined:
    Jul 30, 2012
    Posts:
    102
    Thanks you so much for sharing - this is a very clean solution. Great material as an option for a base class for Editor Utilities I think.
     
  6. CodeFriendlyArt

    CodeFriendlyArt

    Joined:
    Jun 3, 2016
    Posts:
    10
    Wow, this is pure gold! Thanks for sharing!
     
  7. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    Though triggering SceneView.RepaintAll() constantly is an option, it's not one that I would recommend. You will be doing a lot of unnecessary and constant scene repainting even when nothing is changing. Below I outline a couple of options that don't require a throwaway object and will utilize Repaints with more economy in mind.

    The most ideal option is to call SceneView.RepaintAll when you detect that something has changed -- in OP's case, you would repaint inside the EditorChangeCheck (or have one encompassing change check around the whole thing).

    Alternatively, if you want to have the SceneView constantly repaint while your tool is active, you can place your RepaintAll inside your Editor class in the OnSceneGUI callback:

    Code (CSharp):
    1. void OnSceneGUI () {
    2.   if( Event.current.type == EventType.Repaint ) {
    3.     SceneView.RepaintAll();
    4.   }
    5. }
    This will constantly repaint while your editor is active, but will stop when it's inactive.

    Using
    QueuePlayerUpdateLoop
    is generally not necessary for Editor scripts unless you're dealing with a class marked as
    [ExecuteInEditMode]
    or
    [ExecuteAlways]
    .
     
    Last edited: Aug 19, 2021
    Tyrant7 and curiouspers like this.
  8. ShangAlf

    ShangAlf

    Joined:
    Aug 6, 2014
    Posts:
    8
    +1000 thanks for the hack .. searched for days what could trigger this real time editor update :)
     
  9. Gustorvo

    Gustorvo

    Joined:
    Oct 26, 2017
    Posts:
    32
    Code (CSharp):
    1.  
    2. public static Vector3 ToInspectorEulerVector(this Quaternion q)
    3.         {
    4.             return new Vector3(WrapAngle(q.eulerAngles.x), WrapAngle(q.eulerAngles.y), WrapAngle(q.eulerAngles.z));
    5.             float WrapAngle(float angle)
    6.             {
    7.                 angle %= 360;
    8.                 return angle > 180 ? angle - 360 : angle;              
    9.             }
    10.         }
    11.  
     
  10. kiet57441

    kiet57441

    Joined:
    Mar 21, 2020
    Posts:
    3
    i have a better idea
    public override bool RequiresConstantRepaint()
    {
    return true;
    }
     
  11. odoluca

    odoluca

    Joined:
    Nov 5, 2014
    Posts:
    28
    Thank you so much!
     
  12. Entretoize

    Entretoize

    Joined:
    Feb 27, 2015
    Posts:
    59
    None of these methods works for me can you explain how you do ? And give the full code ?