Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Moving scene view camera from editor script--

Discussion in 'Scripting' started by iceshaft07, Oct 25, 2010.

  1. iceshaft07

    iceshaft07

    Joined:
    Jul 23, 2010
    Posts:
    293
    There are 7 pages of threads somewhat related to this, and I've gone through most of them.

    Most of them say to grab 'Camera.current' and use that-- Well, actually, most people say they *think* that is what Camera.current does.

    However, I have a script in my Editor folder, which otherwise works fine, however Camera.current just gets null reference exceptions.

    My editor script goes somewhat like this:

    Code (csharp):
    1.  
    2. class RobsEditor extends EditorWindow
    3. {
    4.     @MenuItem ("Window/RobsEditor")
    5.     static function Init ()
    6.     {
    7.     var window : RobsEditor = EditorWindow.GetWindow (RobsEditor);
    8.     }
    9.  
    10.     function OnGUI ()
    11.     {
    12.     GUILayout.Label ("Rob's Editor", EditorStyles.boldLabel);
    13.  
    14.     EditorGUILayout.BeginHorizontal();
    15.    
    16.     if (GUILayout.Button("Search"))
    17.     {
    18.                 //This Only prints out the camera in the heirarchy view
    19.         var count : int = Camera.allCameras.Length;
    20.         for (var y : int = 0; y < Camera.allCameras.Length; y++)
    21.         {
    22.             Debug.Log(Camera.allCameras[y].name);
    23.         }
    24.  
    25.                //nothing ever happens
    26.         if (Camera.current != null)
    27.         {
    28.             Camera.current.transform.position.x = 0;
    29.             Camera.current.transform.position.y = 0;
    30.             Camera.current.transform.position.z = -10;
    31.         }
    32.     }
    33.     }
    34. }
    35.  
    Anyone have any ideas?
     
    ciel712 likes this.
  2. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    You should be able to do something like this too.

    Code (csharp):
    1. var sceneCamera:Camera = SceneView.lastActiveSceneView.camera;
    2.  
    3. sceneCamera.transform.position.z = -10;
    Disclaimer: Untested and undocumented, so subject to not work and to change at any point.
     
  3. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    You can also use the following to get the cameras for all open scene views.

    Code (csharp):
    1. var sceneCameras:Camera[] = SceneView.GetAllSceneCameras();
    Disclaimer: Also undocumented/untested, so use at your own risk.
     
    bsq likes this.
  4. iceshaft07

    iceshaft07

    Joined:
    Jul 23, 2010
    Posts:
    293
    Hey--

    That did not work (though, it looks like it would-- ashame that it is undocumented, because I'd love to see what else is in that class).

    It did get into the if statement, but I have no idea what camera changed. Any other suggestions?
     
  5. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    Ah, you're right. The position for the scene view camera is generated every frame. Try editing SceneView.lastActiveSceneView.pivot instead.

    The following code should work.

    Code (csharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class SceneViewCameraTest : ScriptableObject
    5. {
    6.     [MenuItem("Test/Move Scene View Camera")]
    7.     static public void MoveSceneViewCamera()
    8.     {
    9.         Vector3 position = SceneView.lastActiveSceneView.pivot;
    10.         position.z -= 10.0f;
    11.         SceneView.lastActiveSceneView.pivot = position;
    12.         SceneView.lastActiveSceneView.Repaint();
    13.     }
    14. }
    Again, undocumented, so subject to not work/change.
     
    oleg_v, Raseru, rendermouse and 8 others like this.
  6. iceshaft07

    iceshaft07

    Joined:
    Jul 23, 2010
    Posts:
    293
    Hey, I'll give that a shot in a minute-- may I ask where you are getting the undocumented classes?
     
  7. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    Source code :)

    But you can use Reflection to see undocumented class members. Many people use Reflector to do this. Forum search and Google can tell you more.
     
  8. iceshaft07

    iceshaft07

    Joined:
    Jul 23, 2010
    Posts:
    293
    Hey Shawn, that above code worked out-- thanks for that.

    I've read up upon Reflection, and my understanding of it is simply put,

    Code (csharp):
    1.  
    2. if (myClass.HasFunction("Restart"))
    3. {
    4.     myClass.Restart();
    5. }
    6.  
    I'll keep the above product in mind should I want to check it out :)
     
  9. iceshaft07

    iceshaft07

    Joined:
    Jul 23, 2010
    Posts:
    293
    P.S. Any idea how I would get the above software to run on Mac?
     
  10. BarryNorthern

    BarryNorthern

    Joined:
    Dec 5, 2011
    Posts:
    7
    This, of course, would only compile if the class function existed ;) So the function invocation would have to be done at runtime too, some "like": Reflector.invokeFunction(myClass, "Restart");
     
  11. pasoftdev

    pasoftdev

    Joined:
    Jul 30, 2012
    Posts:
    3
    Hello,

    I've found this thread when I was looking for a way to switch view via script,
    I'm writing a script to switch view so I can switch to Top view, Left, Back, Front and so on via shortcut but as it is all undocumented I'm pretty stuck,
    I've managed to move the camera via the code above but I'm clueless on how to rotate it, I've already tried via rotation and via other SceneView.lastActiveSceneView class members. any hint how to do this ?
    by the way it really surprises me there's no hotkeys for doing that!
    at last not on this list
    http://blogs.unity3d.com/2011/08/24/unity-hotkeys-keyboard-shortcuts-in-unity/
     
  12. Archimagus

    Archimagus

    Joined:
    Sep 29, 2012
    Posts:
    21
    I want to do something similar to pasoftdev. Except what I want to do is prevent the camera from rotating. Specifically when the camera is in one of the Iso views (Top, Front, Right, Etc.) When I'm in these modes, I'd really likethe camera to stay locked facing that direction, but I can't seem to find a way to do it. Is this something that could be scripted? Or maybe a feature request? I have tried the "SceneView.lastActiveSceneView.lockRotation" member but to no avail, as well as the rotation member.
     
  13. FireproofWater

    FireproofWater

    Joined:
    Dec 14, 2011
    Posts:
    12
    Last edited: Oct 21, 2012
  14. Zaikman

    Zaikman

    Joined:
    Aug 2, 2011
    Posts:
    17
    I just found out about this tonight while trying to do something similar. I was trying to focus on an object from a top-down view, which I was able to accomplish using this:

    Code (csharp):
    1. sceneView.LookAt(myPosition, Quaternion.Euler(90, 0, 0));
    You can adjust the euler angle values to rotate the camera however you want.
     
    Pholith, oferei and bsq like this.
  15. bsq

    bsq

    Joined:
    Nov 5, 2014
    Posts:
    1
  16. Rodiaz89

    Rodiaz89

    Joined:
    Apr 11, 2014
    Posts:
    136
  17. noemis

    noemis

    Joined:
    Jan 27, 2014
    Posts:
    76
    I found this thread from a script reference from another thread (link).

    The manual script method to align the scene view to an objects saves me time but there is still a small problem like @Hatsuko also noticed: "The position is slightly different." - I'm pretty sure, that this offset comes after using the scroll wheel... because after resetting the view you can use the scroll wheel until it snaps in the exact position, like "Align View to selected" would do. But because scroll wheel is often used in the scene view the time saving is gone, because 1. the rotation must be copied from the selected object to 2. correct the offset with the scroll wheel.

    Now my question to maybe @shawn: how can we reset/write this scene view position offset, which the scroll wheel influences?
     
    Last edited: Sep 4, 2017
  18. zwcloud

    zwcloud

    Joined:
    Mar 15, 2016
    Posts:
    377
    Hi shawn, this changed the position of the pivot, not the position of `SceneView.lastActiveSceneView.camera.transform`. How to set the position of the camera directly?
     
  19. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    Wow, old thread...

    Eh, setting the position directly would not work as you want though. The position is internally set every frame, so your changes would get stomped. The position is set to the following every frame: pivot + rotation * new Vector3(0, 0, -cameraDistance). cameraDistance is derived from size.

    So if you want to move the camera around you'll need to manipulation pivot, rotation, and size properties on the scene view.
     
  20. idbrii

    idbrii

    Joined:
    Aug 18, 2014
    Posts:
    51
    Thanks Shawn!

    This seems to work well:

    Code (CSharp):
    1. public static void TeleportSceneCamera(Vector3 cam_position, Vector3 cam_forward)
    2. {
    3.     // Can't set transform of camera :(
    4.     // It internally updates every frame:
    5.     //      cam.position = pivot + rotation * new Vector3(0, 0, -cameraDistance)
    6.     // Info: https://forum.unity.com/threads/moving-scene-view-camera-from-editor-script.64920/#post-3388397
    7.  
    8.     var scene_view = UnityEditor.SceneView.lastActiveSceneView;
    9.  
    10.     // SceneView.lastActiveSceneView.cameraDistance is private, compute it.
    11.     var offset = scene_view.pivot - scene_view.camera.transform.position;
    12.     var cameraDistance = offset.magnitude;
    13.  
    14.     scene_view.pivot = cam_position + cam_forward * cameraDistance * -1.0f;
    15.     scene_view.rotation = Quaternion.LookRotation(cam_forward);
    16. }
    It's a bit wonky when coming from UI editing (probably doesn't work well when cameraDistance is an extreme value?)

    Edit: there's also an interesting SceneViewCameraFollower script on Unify that uses a different method!
     
    Last edited: Mar 15, 2018
    Ekrem007, ciel712 and Lyrcaxis like this.
  21. idbrii

    idbrii

    Joined:
    Aug 18, 2014
    Posts:
    51
    Found a better method that zooms to an appropriate distance. Also, switching to scene view and using orthographic make it fully automatic!

    Code (CSharp):
    1. public static void TeleportSceneCamera(Vector3 cam_position, Vector3 cam_forward)
    2. {
    3.     UnityEditor.EditorApplication.ExecuteMenuItem("Window/Scene");
    4.  
    5.     // Can't set transform of camera :(
    6.     // It internally updates every frame:
    7.     //      cam.position = pivot + rotation * new Vector3(0, 0, -cameraDistance)
    8.     // Info: https://forum.unity.com/threads/moving-scene-scene_view-camera-from-editor-script.64920/#post-3388397
    9.     // But we can align it to an object! Source: http://answers.unity.com/answers/256969/scene_view.html
    10.     var scene_view = UnityEditor.SceneView.lastActiveSceneView;
    11.     if (scene_view != null)
    12.     {
    13.         scene_view.orthographic = false;
    14.  
    15.         var target = scene_view.camera;
    16.         target.transform.position = cam_position;
    17.         target.transform.rotation = Quaternion.LookRotation(cam_forward);
    18.         scene_view.AlignViewToObject(target.transform);
    19.     }
    20. }
     
    ciel712, Peter77, Tymac and 1 other person like this.
  22. gglobensky

    gglobensky

    Joined:
    May 15, 2017
    Posts:
    2
    You create a problem when editing the target transform directly. I solved it by assigning a tmp Transform = target and applying the modification to it. Then I aligned the unmodified Camera's transform with the tmp Transform. It occurred because I added an offset.
     
  23. mcroswell

    mcroswell

    Joined:
    Jan 6, 2010
    Posts:
    79
    Field of view can be done as well?
     
  24. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    Unfortunately not. SceneView is hardcoded to a FoV of 90.
     
    ciel712, dval and mcroswell like this.
  25. mcroswell

    mcroswell

    Joined:
    Jan 6, 2010
    Posts:
    79
    Thank you for letting me know @shawn - I was banging my head on the problem. It seems you (UT) could add that hook someday.

    Background: I like to use a near-ortho perspective camera in 2D game dev and it would be useful when using an editor script to match the game view. A nice-to-have but not required.

    Thank you for saving me time,

    -Mike
     
  26. Ziflin

    Ziflin

    Joined:
    Mar 12, 2013
    Posts:
    132
    Has anyone found a way to properly specify the camera follow distance from the pivot in the scene view? We're trying to add an editor and some camera control similar to some of the above comments, but there is not a properly exposed way to *set* the camera follow distance. I would expect that the SceneView.LookAt*() methods take a 'distance' value from the pivot instead of the 'size' value they take.

    Trying to calculate this from looking at SceneView.cameraDistance / GetPerspectiveCameraDistance() is about impossible because the values it uses to calculate distance from size are not exposed.

    @shawn Again, is there something that can be added to make this easier?
     
  27. Ziflin

    Ziflin

    Joined:
    Mar 12, 2013
    Posts:
    132
    For anyone wanting to specify the camera *distance* instead of the odd *size* parameter to the LookAt() methods, here is an extension method. Note the distance parameter comes second to avoid conflicts with the *size* overload which comes third.

    The GetSizeFromDistance() method may need to be adjusted if Unity decides to tweak it again at some point, but the source can be found on their GitHub reference thankfully. Ideally Unity would add these overload as they are very useful for those making custom camera controls in the editor.

    Code (CSharp):
    1.     public static class SceneViewExtensions
    2.     {
    3.         // Looks at the pivot point from the specified *distance* and rotation.
    4.         public static void LookAt( this SceneView sceneView, in Vector3 pivot,
    5.             float distance, in Quaternion rotation ) =>
    6.                 sceneView.LookAt( pivot, rotation,
    7.                     GetSizeFromDistance( sceneView, distance ) );
    8.  
    9.         // From SceneView.cs / GetPerspectiveCameraDistance().
    10.         static float GetSizeFromDistance( SceneView sceneView, float distance ) =>
    11.             distance * Mathf.Sin( sceneView.camera.fieldOfView * 0.5f * Mathf.Deg2Rad );
    12.     }
     
  28. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    135
    This worked for me. It seems that SceneView.lastActiveSceneView.Camera .position & .rotation do nothing.

    Code (CSharp):
    1. Vector3 Pivot = Vector3.zero;
    2. Quaternion Rotation = Quaternion.identity;
    3. float Size = 1f;
    4.  
    5. void StoreCamera()
    6. {
    7.     var scene = SceneView.lastActiveSceneView;
    8.     Pivot = scene.pivot;
    9.     Rotation = scene.rotation;
    10.     Size = scene.size;
    11. }
    12. void RestoreCamera()
    13. {  
    14.     var scene = SceneView.lastActiveSceneView;
    15.     scene.pivot = Pivot;
    16.     scene.rotation = Rotation;
    17.     scene.size = Size;
    18.     scene.Repaint();
    19. }
     
    Last edited: Jun 2, 2021
    ciel712 and Tymianek like this.
  29. ciel712

    ciel712

    Joined:
    Dec 3, 2015
    Posts:
    4
    Thanks for this thread y'all, it's still top of Google ranking and helped me a lot trying to figure this out.

    Setting camera transform directly still does not work, and AlignViewToObject works... however it does the aligning over a period of time, instead of setting it immediately.

    Setting the camera's pivot, rotation, and size works wonderfully. Just wanted to elaborate a bit on the math there in the formula and diagram given by this page: https://docs.unity3d.com/ScriptReference/SceneView-size.html

    The formula given is:
    sin(BAC) = BC / AB
    Where:
    BAC = fov / 2 and fov can be obtained from the SceneView.lastActiveSceneView.camera.fieldOfView
    AB is the camera distance value that we are trying to set, so this value is also given
    BC is the "size" we're trying to figure out

    Solving for size gives us:
    size = cameraDistance * sin(fov / 2)
     
    Last edited: Jan 10, 2023
    PrimalCoder and CodeSmile like this.
  30. xeosD

    xeosD

    Joined:
    Apr 6, 2023
    Posts:
    9
    you can now use this approach without having to calculate the distance, as it's an exposed (read only) variable. This makes an almost perfect pixel match from my play mode camera to editor window hotkey (excerpt from my movement controller):

    Code (CSharp):
    1.  if (Input.GetKeyDown(KeyCode.F2))
    2.             {
    3.             SceneView sceneCam = SceneView.lastActiveSceneView;
    4.             sceneCam.rotation = playerCamera.rotation;
    5.             sceneCam.pivot = playerCamera.position + playerCamera.rotation *  new Vector3(0, 0, sceneCam.cameraDistance);
    6.  
    7.             UnityEditor.SceneView.FocusWindowIfItsOpen(typeof(UnityEditor.SceneView));
    8.             }    
     
    Chubzdoomer and ciel712 like this.