Search Unity

constant object screensize

Discussion in 'Scripting' started by Jean-Fabre, Sep 7, 2007.

  1. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    I having difficulties to find which properties to access in order to efficiently resize gizmo line for example so that they get a constant screensize very much like the manipulation tripod when manipulating objects.

    Thanks,

    Jean
     
  2. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    The easiest case is when the camera is orthographic. Then you don't have to do anything :)

    Now, when the camera is perspective, here's untested javascript conversion from what is used in Unity:
    Code (csharp):
    1.  
    2. // calculate the scaling factor that should be used
    3. // for something at position 'pos'
    4. function CalculateGizmoScale( pos : Vector3 ) : float
    5. {
    6.     var cam = Camera.current;
    7.     var camtr = cam.transform;
    8.     var distance = Vector3.Dot( pos - camtr.position, camtr.forward );
    9.     var width = cam.pixelWidth;
    10.     var height = cam.pixelHeight;
    11.     var denom = Matf.Sqrt( width * width + height * height ) *
    12.         Mathf.Tan( cam.fieldOfView * Mathf.Deg2Rad );
    13.     return Mathf.Max( 0.0001, distance / denom * 100.0 );
    14. }
    15.  
    edit: fixed Camera.current
     
    TakuanDaikon likes this.
  3. forestjohnson

    forestjohnson

    Joined:
    Oct 1, 2005
    Posts:
    1,370
    Transform your position into camera space, then set the z value to a certain constant like 0.5. Then build lines in camera space from that point, and transform it back into world space. For reference on how to do this, read up on the Camera class here: http://unity3d.com/Documentation/ScriptReference/Camera.html

    Edit: Actually aras' idea is probably a lot better. camera.current should be Camera.current though.
     
  4. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    bang on Aras, thanks

    I might however have to build something like you suggest Yoggy because I'd like my gizmo to be visible at all time and not hidden by geometry ( which is another problem than the scaling), I haven't looked at camera rendering strategy to see whether I can draw my gizmo after everything tho, any thoughts on this?


    Jean
     
  5. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Are you drawing those gizmos in the scene view (i.e. like other gizmos), or inside your game?
     
  6. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi Aras,

    I am drawing gizmo in the scene view for now, but it is very likely that I will need such feature in the game view as well since I am building technical applications not games.

    your opinion on both implementation is welcomed!

    Jean
     
  7. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Ok, if you want that in the game view, then you won't be using the Gizmos stuff. That means size calculation should possibly use something else than Camera.current (e.g. pass in the camera you care about; or use Camera.main).

    If you want your things to always display on top of everything, just use a custom shader that uses Overlay rendering queue and does not use depth testing.
     
  8. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Ok, that's doable then.

    I am not good enough just yet to play with shaders, but when it will be needed I'll remember where to look.

    Thanks again,

    Jean
     
  9. Aka_ToolBuddy

    Aka_ToolBuddy

    Joined:
    Feb 25, 2014
    Posts:
    543
    I dug into this subject, and here are my findings:
    I made an optimized version of Unity's HandleUtility.GetHandleSize(), which (Unity's) implementation you can find here: https://github.com/Unity-Technologies/UnityCsReference/blob/2020.1/Editor/Mono/HandleUtility.cs
    Here is my version which I made for my asset Curvy Splines. It does the exact same thing, but is greatly optimized:
    Code (CSharp):
    1.  
    2.         /// <summary>
    3.         /// Much like HandleUtility.GetHandleSize(), but works for gizmos
    4.         /// </summary>
    5.         /// <param name="position"> handle position in world space</param>
    6.         /// <param name="camera"> the camera through which the object is displayed</param>
    7.         /// <param name="cameraCenterWidth"> camera.pixelWidth * 0.5f</param>
    8.         /// <param name="cameraCenterHeight"> camera.pixelHeight * 0.5f</param>
    9.         /// <param name="cameraPosition"> camera.transform.position</param>
    10.         /// <param name="cameraZDirection"> camera.transform.forward</param>
    11.         /// <param name="cameraXDirection"> camera.transform.right</param>
    12. public static float GetHandleSize(Vector3 position, Camera camera, float cameraCenterWidth, float cameraCenterHeight, Vector3 cameraPosition, Vector3 cameraZDirection, Vector3 cameraXDirection)
    13.         {
    14.             //inlined version of Vector3.Dot(positionMinusCameraPosition, cameraZDirection)
    15.             float z = (position.x - cameraPosition.x) * cameraZDirection.x +
    16.                       (position.y - cameraPosition.y) * cameraZDirection.y +
    17.                       (position.z - cameraPosition.z) * cameraZDirection.z;
    18.  
    19.  
    20.             Vector3 b;
    21.             {
    22.                 Vector3 camPosPlusDirB;
    23.                 camPosPlusDirB.x = cameraPosition.x + cameraZDirection.x * z + cameraXDirection.x;
    24.                 camPosPlusDirB.y = cameraPosition.y + cameraZDirection.y * z + cameraXDirection.y;
    25.                 camPosPlusDirB.z = cameraPosition.z + cameraZDirection.z * z + cameraXDirection.z;
    26.                 b = camera.WorldToScreenPoint(camPosPlusDirB, Camera.MonoOrStereoscopicEye.Mono);
    27.             }
    28.  
    29.             float aMinusBX = cameraCenterWidth - b.x;
    30.             float aMinusBY = cameraCenterHeight - b.y;
    31.             return 80f / Mathf.Max((float)Math.Sqrt(aMinusBX * aMinusBX + aMinusBY * aMinusBY), 0.0001f);
    32.         }
    Some explanations and tips for further optimizations:
    1. In my experience you can safely remove the Mathf.Max at the end of the function. It becomes useful only if the camera is ridiculously far from the object. I had to scroll for a minute to make the camera that far.
    2. The function has a lot of redundant parameters that can be deduced from the camera parameter. Feel free to remove them. I kept them because I call this function up to tens of thousands times inside a loop. In those conditions, avoiding calling camera.transform.right at each call makes sense.
    3. If you reaaaally need those extra milliseconds, use this after computing z:
      return z * 0.15f;
      This will give a good enough result. The problem with this method is that the handle size is unsatisfying when transitioning between Perspective and Orthogonal view, and when the scene view window is too narrow to the point that it changes the FOV of the scene view. Because of all the downsides, I am not using this implementation.
    I hope this helps
     
    Last edited: Oct 24, 2020
    PrimalCoder and Oose like this.
  10. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
    You think it will help 13 years later?
     
  11. Aka_ToolBuddy

    Aka_ToolBuddy

    Joined:
    Feb 25, 2014
    Posts:
    543
    If someone had answered with what I wrote until earlier this week, it would have saved me a day of work. So I have hope that this might save someone's else day in the future.
     
    PrimalCoder, OccaSoftware and juan-jo like this.
  12. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
    Fair enough
     
  13. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    Of course it helps throughout the years to update on topics, this is always welcomed.

    Bye,

    Jean