Search Unity

Simple crosshairs in sceneview, why does it sometimes not update?

Discussion in 'Immediate Mode GUI (IMGUI)' started by imaginaryhuman, Sep 19, 2016.

  1. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Code (CSharp):
    1.     public void UseCrosshairs(){
    2.         //Draw crosshairs in the scene view
    3.         if (GeneralUseCrosshairs == true){
    4.             //Only draw if crosshairs are switched on
    5.             Vector2 Mouse = Event.current.mousePosition;
    6.             Handles.color = Color.gray;
    7.             Camera cam = SceneView.lastActiveSceneView.camera;
    8.             Handles.DrawLine(SceneToWorld(new Vector2(Mouse.x,0)),cam.ScreenPointToRay(new Vector2(Mouse.x,cam.pixelHeight-1)).origin);
    9.             Handles.DrawLine(SceneToWorld(new Vector2(0,cam.pixelHeight-Mouse.y)),cam.ScreenPointToRay(new Vector2(cam.pixelWidth-1,cam.pixelHeight-Mouse.y)).origin);
    10.         }
    11.     }
    I have a simple bit of code in a custom inspector to draw crosshairs in the sceneview. It generally works. I have a SceneView.RepaintAll() elsewhere so it updates every frame. Normally fine.

    However, when I roll the mousewheel which zooms the scene view, SOMETIMES it will continue drawing every frame, and sometimes not. I can zoom in, maybe the crosshairs disappear and never show at all at that zoom level, I zoom back out again to where they were showing and now they don't show where they used to, I zoom in again and now suddenly they're showing. Like, what is going on here? I'm not trapping the mousewheel events so its doing the normal unity zoom functionality there, but why would different camera scales cause the crosshairs to sometimes show and sometimes not show, even when returning to the same zoom level where they were once working? Its totally bizarre.

    Debug.Log on the camera proves the camera is always found and never goes missing, so it's not that.
     
  2. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    This happens somewhat more strangely if I flip to a 3d camera... if I draw a solid disc as well, sometimes the disc stays drawing but the crosshairs go away, or they go partly away.. I wonder if this has to do with floating point accuracy issues? Doesn't make much sense because at the 'same zoom' (or what should be) sometimes the lines show, sometimes they don't... unless maybe there's a tiny fractional error produced by like 'add this much to the scale', resulting in a slight error, then 'subtract that much from the scale' a 2nd time it end up with a different float result because it couldn't represent the scale perfectly? So then why at some scales does this mess up and not at others?
     
  3. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Strange thing is, drawing a large disc in the scene view also makes the entire disc disappear (along with the crosshairs) at certain camera scales. And again, completely inconsistent as to which scales cause this. The entire disc disappears along with the crosshairs. From what I can tell, all the numbers coming out of the math etc are exactly normal and within range.
     
  4. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    This version using camera.ScreenToWorldPoint() instead to convert the coordinates, works perfectly at all camera scales with nothing disappearing ever.

    Code (CSharp):
    1.     public void UseCrosshairs(){
    2.         //Draw crosshairs in the scene view
    3.         if (GeneralUseCrosshairs == true){
    4.             //Only draw if crosshairs are switched on
    5.             Vector2 Mouse = Event.current.mousePosition;
    6.             Handles.color = Color.gray;
    7.             Camera cam = SceneView.lastActiveSceneView.camera;
    8.             Handles.DrawLine(cam.ScreenToWorldPoint(new Vector3(Mouse.x,0,1)), cam.ScreenToWorldPoint(new Vector3(Mouse.x,cam.pixelHeight-1,1)));
    9.             Handles.DrawLine(cam.ScreenToWorldPoint(new Vector3(0,cam.pixelHeight-Mouse.y,1)), cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth-1,cam.pixelHeight-Mouse.y,1)));
    10.         }
    11.     }
    The entire problem is in camera.ScreenPointToRay() - which works most of the time but some of the time is absolutely broken. I'm presuming objects disappear because the world coords it provides are sometimes garbage. Or at least, the .origin parameter is sometimes broken/faulty or is doing something funky. Totally unreliable (Unity 5.4).

    Bug? Or just bad physics behavior (if it uses a raycast?) ... I have zero colliders in my scene.
     
  5. SarfaraazAlladin

    SarfaraazAlladin

    Joined:
    Dec 20, 2013
    Posts:
    280
    Because ScreenPointToRay ignores the z value, it might be that the line you draw is being made at the near, or far clip plane of the camera. ScreenToWorldPoint uses the z value of your vector3 to determine how far in front of the camera the position should be, so the lines you draw using it are probably at a more comfortable draw distance from the editor camera's clip planes.
     
  6. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    But when then does it provide a .origin property, which pretty much fluctuates randomly, not in any way tied to the scale factor? Why at the same zoom, does it sometimes give a ray origin that makes sense in its X,Y coordinates, and at other times totally nonsense? It's not the Z coord I even want, it's the XY position in worldspace. Sometimes it's valid, sometimes it's totally nuts.
     
  7. SarfaraazAlladin

    SarfaraazAlladin

    Joined:
    Dec 20, 2013
    Posts:
    280
    I'm sorry if I'm misunderstanding you, but are you sure that the x y position is off target? If the handles are just flickering, it seems most likely to me that the z position is where your trouble is. Also, you should look into HandleUtility.GetHandleSize to make sure the size of your handles is consistent, regardless of their distance to the camera.

    https://docs.unity3d.com/ScriptReference/HandleUtility.GetHandleSize.html
     
  8. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Yah its not that and its nothing to do with handle size. The handles aren't flickering either.

    It's like this:

    1) zoom to a given scale, the handles show fine

    2) zoom to some other scale, the handles maybe show fine

    3) zoom back to the exact same scale as in (1) and the handles do not show

    4) zoom to the scale in (2) and maybe the handles show, maybe they don't

    While at any given scale factor, and without changing the scale, whether or not the handles show remains consistent until the scale is changed... once changed, it is completely random as to whether that scale factor will show the handles or not. So if e.g. the scale factor is at exactly 1.0, lets say the handles show fine. Now we zoom to 1.4, maybe the handles show fine. We go back to 1.0 where the handles were showing fine and now they're not showing. We go back to 1.4 and maybe they're showing still, back to 1.0 and oh look, they're showing again.

    There is no connection between whether they show and what the scale factor is, other than that it's completely inconsistent. I don't know if its xy that's off but using '.origin' simply gives inconsistent data. Or at least, using this command does, which is why I switched to a different method.
     
  9. Deleted User

    Deleted User

    Guest

    Scrolling with the mouse wheel as well as Alt + RMB will move the camera, change its near and far clipping plane and also change the distance between the camera and the pivot/orbit point. Specifically, zooming out will increase the near and far clipping plane distances, while zooming in while decrease them.

    Orthographic cameras are affected by this the same way perspective cameras are. Even though theoretically they need not have a world position at all, they still do, and anything outside their cuboid frustum will not be visible. This is very irritating to have to deal with in the editor, and I assume is the cause of the problem you are having. I suggest writing a script to place these cameras in such a manner that it won't become a problem "anytime soon".

    Here is what I use:
    Code (csharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4.  
    5. public class OrthographicFixScript {
    6.  
    7.     [MenuItem("Tools/Fix Cameras %#c")]
    8.     public static void FixCameras() {
    9.  
    10.         // Some point near whatever you want the cameras to focus on,
    11.         // i.e. change their positions so that the centers of their frustums
    12.         // are at the same depth as this point.
    13.         // Here I just use the world space origin because that's mostly good enough.
    14.         Vector3 pointOfInterest = Vector3.zero;
    15.  
    16.         ArrayList sceneViews = SceneView.sceneViews;
    17.         int len = sceneViews.Count;
    18.         int touchedCams = 0;
    19.         for (int i = 0; i < len; i++) {
    20.             SceneView sv = (SceneView)sceneViews [i];
    21.             if (sv != null) {
    22.                 Camera c = sv.camera;
    23.                 if (c != null) {
    24.                     if (c.orthographic) {
    25.                         float near = c.nearClipPlane;
    26.                         float far = c.farClipPlane;
    27.                         float visibleDepth = far - near;
    28.                         float centerDepth = near + visibleDepth * 0.5f;
    29.                         Plane planeOfInterest = new Plane (c.transform.forward, pointOfInterest);
    30.  
    31.                         Ray viewRay = new Ray (c.transform.position, c.transform.forward);
    32.                         float distance;
    33.                         planeOfInterest.Raycast (viewRay, out distance);
    34.  
    35.                         Vector3 centerPlaneViewPoint = c.transform.position + c.transform.forward * distance;
    36.                         Vector3 newPos = centerPlaneViewPoint - centerDepth * c.transform.forward;
    37.  
    38.                         sv.LookAtDirect (newPos, c.transform.rotation);
    39.                         touchedCams++;
    40.                     }
    41.                 }
    42.             }
    43.         }
    44.         if (touchedCams > 0) {
    45.             Debug.Log ("Readjusted " + touchedCams + " camera" + (touchedCams == 1 ? "" : "s") + ".");
    46.             SceneView.RepaintAll ();
    47.         }
    48.     }
    49. }
    50.  
     
    Last edited by a moderator: Oct 30, 2016