Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice
  2. We've opened up a space to discuss, share feedback, and showcase everything related to the Unity Shader Graph! Come show us what you've made.
    Dismiss Notice

Writing an Editor Window that mimics the Scene View

Discussion in 'Extensions & OnGUI' started by gilley033, Jan 15, 2019.

  1. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    I am writing an editor extension (let's call it EE1) that involves the manipulation of a pattern. The pattern's data is stored in a scriptable object and represented by game objects in the scene view, however, since the data is stored as a scriptable object, I don't actually need to save any data to a scene object. The pattern is just a 2D or 3D array of cells, with some cells being active, and others inactive.

    Currently I just open up a new scene, load the pattern, and the user can then manipulate/change the pattern. The scene is closed once pattern editing is finished.

    The issue is, I have another editor extension (also which utilizes the scene view, let's call it EE2) that uses the pattern, and it would be beneficial to allow both these editor extensions to run at once, as adjusting the pattern to fit the users needs would be easier if they could have EE2 open. Otherwise, to edit the pattern using EE1, I have to close the EE2 scene.

    If the pattern were just two dimensional, I could build EE1 using an Editor Window, however the pattern can be three dimensional, which is why it is easier to use game objects to represent it and also make use of the rotatable camera.

    So, what I really need, is a sort of dummy scene view that allows me to load game objects into it, but doesn't actually utilize a scene asset. This dummy scene view would also need to be usable while an actual scene view is also open, in the same way you can open an editor window while a scene is open.

    Does anyone have any experience with this?
     
  2. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Is there any reason you can't have both of them in the same scene?
     
  3. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    It would be basically impossible to do the pattern editing while the second editing process is underway. Sort of difficult to explain, but I did consider that possibility and it is not feasible. Thanks for the suggestion though!
     
  4. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    161
    I had an idea for an editor which was something similar, however I never implemented it. What I planned on doing was changing the culling mask on the scene view camera.

    So in editor 1: it could see objects on
    layer A

    and
    editor 2: could not see objects on
    layer A


    possibly you could do something similar?
     
  5. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Hmm, I suppose that should be possible, since each scene view should utilize its own camera. I will play around with this and see what I can come up with. Thanks for the suggestion!
     
  6. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    You could still do that without culling masks. The scene is a large place. Just put the components far away from each other.
     
  7. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Yes, but since the scene in question could basically contain anything (i.e., when the 'editor' is launched, I'd just load it into whatever scene was currently open), calculating a "safe" place where no other objects appear may be ridiculously hard, if not impossible.

    Or am I missing something?
     
  8. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Would it be possible to provide some more context (screenshots, etc.) as to what you're working with? Might make it possible to give more specific advice.
     
  9. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
  10. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Firstly, you can certainly calculate a 'safe' space for the editor by checking the AABBs of all the renderers in the scene. Not that I would recommend doing that, but it isn't impossible.

    Second, check out this API: https://docs.unity3d.com/ScriptReference/SceneManagement.EditorSceneManager.NewPreviewScene.html

    Make your gameobjects and add it to that scene. You can create a camera for the scene, and then render it with https://docs.unity3d.com/ScriptReference/Handles.DrawCamera.html into an EditorWindow.
     
  11. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    PreviewScene looks like it has some potential. I'll look into it. Thanks!
     
  12. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    161
    if you look into the preview scene, you might want to look at my post here:
    https://forum.unity.com/threads/modify-gameobject-in-previewgui.556792/#post-3699133
    where I have ripped out the source of previewgui

    ~The reason for this is, because the object is instantiated when you add it to the preview scene, you lose reference to it. the above code solves that~
     
    Last edited: Jan 21, 2019
  13. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    The PreviewScene method is not the same as the OnPreviewGUI method. Using a PreviewScene does not cause you to lose the reference to gameobjects you add to it.
     
    BinaryCats likes this.
  14. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    161
    ah okay, my bad
     
  15. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Is doing it with Handles.DrawCamera the only way? I would like the user to make use of some of the functionality that is built into the normal Scene View, such as changing the camera view and dragging the scene camera around. It seems like I would need to re-engineer such functionality doing things this way. Am I wrong?

    And also, how would I go about creating a camera for this preview scene?
     
    Last edited: Jan 23, 2019
  16. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Yep. It's not overly difficult though.

    You create a camera same way you'd create a camera through code for any other purpose. Create a new GameObject and add a Camera component.
     
  17. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Okay, thank you!
     
  18. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Sorry, I must ask for more help, as it seems you are the only one with knowledge of this stuff (if you can point me to instructional material I will be glad to figure all this out on my own).

    In any case, I have created a Preview Scene, added a camera to it (I used EditorSceneManager.MoveGameObjectToScene to make sure it is in the preview scene), and am using Handles.DrawCamera, but it seems to be drawing the camera of whatever scene I have open rather than the one I created for the Preview Scene. Also, I cannot get the camera render to cover the entire editor window. I also tried using Handles.SetCamera first.

    Handles.SetCamera(sceneCamera);
    Handles.DrawCamera(new Rect(0, 0, position.width, position.height), sceneCamera);

    Where position is the EditorWindow.position rect. I am using 0, 0 after looking at the SceneView class on GitHub. sceneCamera is 100% a reference to the camera created procedurally and moved to the PreviewScene.

    I am not sure what I am doing wrong.
     
  19. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Can you post the entirety of the EditorWindow code as it stands, as well as a screenshot of what you're seeing? It doesn't make any sense for it to be drawing a different camera than you pass it.
     
  20. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Sure.

    The Preview Scene, Editor Window, and game objects are all created via a button press in the inspector of my pattern scriptable object, through a call to this static method:

    Code (CSharp):
    1.  
    2. static LoadingPatternEditor OpenEditingWindow()
    3. {
    4.     var scene = EditorSceneManager.NewPreviewScene();
    5.     scene.name = "DLK_Loading_Pattern_Editor";
    6.     workingEditor = EditorWindow.GetWindow<LoadingPatternEditor>();
    7.     workingEditor.position = new Rect(Screen.width / 2 + 300, 400, 600, 300);
    8.     var root = new GameObject("DLK_Loading_Pattern_Editor_Root");
    9.     root.transform.position = new Vector3(.5f, .5f, .5f);
    10.     EditorSceneManager.MoveGameObjectToScene(root, scene);
    11.     var camGO = new GameObject("Camera");
    12.     Camera cam = camGO.AddComponent<Camera>();
    13.     camGO.transform.position = new Vector3(.5f, .5f, .5f);
    14.     EditorSceneManager.MoveGameObjectToScene(camGO, scene);
    15.            
    16.     workingEditor.OnEditorLoaded(scene, cam, root);
    17.     //workingEditor.PreviousSceneSetup = currentScenes;
    18.     return workingEditor;
    19. }
    20.  
    The scene, camera, and root game object (which just serves as a parent for game objects used as visual cues for the pattern in the scene) are all passed to the Editor Window via the OnEditorLoaded call.

    The OnGUI method of the EditorWindow looks like this:
    Code (CSharp):
    1. private void OnGUI()
    2. {
    3.     if (!editorScene.IsValid() || !editorScene.isLoaded)
    4.     {
    5.         OnEditorUnLoaded();
    6.         return;
    7.     }
    8.  
    9.     isInTopDownOrtho = sceneCamera.orthographic && sceneCamera.transform.rotation == downView;
    10.  
    11.     if (patternRepositoryCurrentlyBeingEdited == null)
    12.         AccountForNewRepository();
    13.  
    14.     patternRepositoryCurrentlyBeingEdited.Update();
    15.  
    16.     //GUI.Box(rect, GUIContent.none);
    17.     GUISkin skin = GUI.skin;
    18.     GUI.skin = style;
    19.  
    20.     DrawGUI();
    21.     if (currentPattern != null)
    22.         currentPattern.DrawEditor();
    23.  
    24.     SceneView.RepaintAll();
    25.     GUI.skin = skin;
    26.  
    27.     patternRepositoryCurrentlyBeingEdited.ApplyModifiedProperties();
    28. }
    The DrawGUI method is what contains the actual camera rendering.
    Code (CSharp):
    1. void DrawGUI()
    2. {
    3.     GetStyles();
    4.  
    5.     Handles.SetCamera(sceneCamera);
    6.     Handles.DrawCamera(new Rect(0, 0, position.width, position.height), sceneCamera);
    7.     Handles.BeginGUI();
    8.     EditorGUILayout.BeginVertical("BackgroundWindow");
    9.  
    10.     EditorGUILayout.BeginHorizontal(horizontalStyle);
    11.     LabelField("Show Full Menu");
    12.     showMenuProp.boolValue = EditorGUILayout.Toggle(showMenuProp.boolValue, toggleStyle, toggleWidth, toggleHeight);
    13.     EditorGUILayout.EndHorizontal();
    14.  
    15.     if (showMenuProp.boolValue)
    16.         DrawFullMenu();
    17.     else
    18.         DrawHiddenMenu();
    19. }
    There is a lot more code. I can post it all if you don't think it would be helpful, but I am hopeful that whatever I am doing wrong is apparent in the code posted above. Posting the entire code would provide a lot to sift through.

    Thanks for the help!
     
  21. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Forgot the screen shot. Note if I stretch the EditorWindow vertically the camera render also does not completely fill it in that axis, even though the DrawCamera call is using the current postion rect of the window which should be its full size.
    EditorWindow.png

    Update: Resizing the Game Window changes the size of the render in my Editor Window, so for some reason it is using The Game View size instead of my Editor Windows size. In fact it just seems to be rendering the Game View instead of the camera I have added to my preview scene.
     
    Last edited: Jan 24, 2019
  22. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Another update. I got the camera to take up the whole EditorWindow by setting its hide flags to HideAndDontSave. However, this camera is still not displaying the PreviewScene, so I am left to believe that MoveGameObjectToScene is not working correctly.
     
  23. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    The Handles.BeginGUI call should be unnecessary, since you're already in a GUI context in OnGUI.

    Are you sure that it is actually drawing the game view camera and not just that the game view and editor view cameras are in the same position/rotation?

    I will attempt to make a test editor and troubleshoot this myself, because I don't see anything obviously wrong with your code.
     
  24. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Hey, thank you but I think I figured it out. The issue was that the camera I created via code was still displaying the open scene rather than the preview scene. I just had to set camera.scene to the preview scene. I still have some stuff to work out but it seems to be working!

    Also, you are right about Handles.BeginGUI. This is just leftover from the way I had been doing it before (without an editor).

    Thank you so much for the help. It's people like you that make this community great. I am going to try and exhaust all options the next time an issue comes up before posting, lol.
     
  25. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    It could be some interplay with some other part of my code, but it looks like when using Handles.DrawCamera, you do have to include the Handles.BeginGUI. Not sure why, but without it everything gets messed up.
     
  26. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Yep, I was just about to post that I got it working with these parameters:

    Code (CSharp):
    1.         previewScene = EditorSceneManager.NewPreviewScene();
    2.  
    3.         var camObj = new GameObject( "Camera" );
    4.         cam = camObj.AddComponent<Camera>();
    5.         cam.transform.position = new Vector3( 0, 0, -10 );
    6.         cam.hideFlags = HideFlags.HideAndDontSave;
    7.         cam.scene = previewScene;
    8.         cam.enabled = false;
    9.         SceneManager.MoveGameObjectToScene( camObj, previewScene );
    Also, I just tripped across the undocumented class PreviewRenderUtility. Check it out, it will probably save you a lot of trouble:

    Code (CSharp):
    1. PreviewRenderUtility renderUtils;
    2.  
    3. private void OnEnable () {
    4.     renderUtils = new PreviewRenderUtility();
    5.     renderUtils.AddSingleGO( GameObject.CreatePrimitive( PrimitiveType.Cube ) );
    6.     renderUtils.camera.transform.position = new Vector3( 0, 0, -10 );
    7. }
    8.  
    9. private void OnDisable () {
    10.     renderUtils.Cleanup();
    11. }
    12.  
    13. public void OnGUI () {
    14.     var pos = position;
    15.     pos.x = 0;
    16.     pos.y = 0;
    17.     renderUtils.BeginPreview( pos, EditorStyles.helpBox );
    18.     renderUtils.Render();
    19.     renderUtils.EndAndDrawPreview( pos );
    20. }
     
  27. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Cool, I will take a look at it. This would be used instead of the PreviewScene, correct?

    Your code still helped, I was not disabling the camera and it was causing the preview camera to be rendered in the Game View. So thanks again!
     
  28. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    584
    Yep, this is a wrapper around a PreviewScene. Takes care of the camera, and has its own lights as well.
     
  29. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    161
    ahhhh yes PreviewRenderUtility this is what was ringing a bell when I linked my previous reply
     
  30. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Well, I have everything displaying nicely in the window now. Thanks so much for your help!!

    Now I just need to figure out how to recreate the scene view movement controls, i.e., panning, camera rotation, and all that jazz. I am trying to decipher the SceneViewMotion class to get some clues, but if anyone has a tutorial or some other aid to give please feel free to share!!
     
  31. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Bumping this thread once again.

    I was previously making extensive use of the Handles class to draw some manipulable controls in the Scene View, however Handles is really meant to be used with the Scene View. With that said, I found that I can draw the handles in my custom editor by using the Handles.SetCamera method (and using the camera from the PreviewRenderUtility).

    This works, but only when the editor window is a certain size. Anything smaller and the handles do not show up in the correct spot.

    Positioning is wrong
    Incorrect.png
    Positioning is right Correct.png
     
  32. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    So this problem appears to be due to the aspect ratio of the preview camera not being updated when the windows width is changed. You will notice in the Scene View that the camera aspect (or maybe it's field of view?) changes when the window is resized both horizontally (width) or vertically (height). However, with the preview utility, it is only adjusted when the window is resized vertically. This seems like a bug.
     
  33. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    161
    iirc its because PRU is intended to work as a square? the previewed object needs to be constrained in the viewport.

    So if you grow the width of the preview window past 1:1 (width:height) it cant zoom in the object anymore, because its constrained by the height. likewise for height.

    Have you tried making your preview window width shorter than the height of the window, then adjusting the height?

    This was over a year ago, I worked on a PRU so my memory is very foggy sorry
     
    gilley033 likes this.
  34. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    717
    Thank you for the suggestions/advice. I tested making the window's width smaller than the height and then adjusting the height. It does not affect anything. The aspect changes properly when the height is adjusted. Adjusting the width simply has no effect on the aspect, regardless of whether the width is smaller/larger/the same as the height.

    Thanks again. If you recall anything else I would be delighted to try any other suggestions you might have!
     
    BinaryCats likes this.
  35. ecurtz

    ecurtz

    Joined:
    May 13, 2009
    Posts:
    601
    I actually just submitted this as a bug yesterday. I didn't realize it was limited to the PreviewRenderUtility. I believe Handles malfunction when the camera aspect goes below 1.0.

    I'm doing something very similar and my current scheme is just to duplicate SceneViewMotion and take out some of the stuff I don't need, but that's definitely a hack. Eager to hear if anyone has a better plan.

    EDIT: Bug was reproduced and accepted (Case 1134881) so hopefully this will get fixed at some point.
     
    Last edited: Mar 15, 2019