Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Determine point on upper right side of horizon of sphere

Discussion in 'Scripting' started by WilyC, Dec 21, 2019.

  1. WilyC

    WilyC

    Joined:
    Aug 21, 2019
    Posts:
    7
    I am trying to get the location of a point that would be on the upper right side of a sphere's horizon from the perspective of a given camera.

    For example, this code works correctly for objects roughly in the middle of the field of view:

    Code (CSharp):
    1.    
    2. private Vector3 GetEdgePoint(Camera camera, Vector3 possition, float diameter){
    3.         var shift =   (diameter/2) / SQRT_TWO;
    4.         var edgePoint = possition + (camera.transform.up.normalized * shift) + (camera.transform.right.normalized * shift);
    5.  
    6.         return edgePoint;
    7.     }
    8.  

    I understand why this doesn't work for objects near the edge of the field of view - the 'direction' of the camera's transform is still directly ahead so I can't use it to determine the plane on which to shift my point.

    I suspect I could solve the problem by making an empty GameObject, copying in the position and rotation of the camera, performing a LookAt to the target and then using the direction of that GameObject as the normal for my cross section plane for the sphere. The thing is, that kinda seems like a hack and I feel there must be a better way to do it. It would happen for a number of onscreen targets each frame so I'm looking to keep it pretty efficient (which I may already not be doing - I'm fully amateur at this).

    Any suggestions?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,385
    Why create a GO and copy the information?

    Just do the math that is like doing all that.

    Quaternion.LookRotation is effetively like LookAt, you just need to calculate the direciton:
    https://docs.unity3d.com/ScriptReference/Quaternion.LookRotation.html

    The direction would be (targetPosition - cameraPosition).

    So:
    Code (csharp):
    1. var q = Quaternion.LookRotation(targetPosition - cameraPosition);
    (I guess in your code cameraPosition would be possition)

    As for getting the 'up' and 'right', you can see from the source code it's really just the rotation * Vector3.up, or Vector3.right:
    https://github.com/Unity-Technologi...form/ScriptBindings/Transform.bindings.cs#L51
    Code (csharp):
    1. public Vector3 up { get { return rotation * Vector3.up; } set { rotation = Quaternion.FromToRotation(Vector3.up, value); } }
    (note you also don't need to normalize those, they're already unit vectors)

    And since we calculated the rotation that would be looking at the target position as 'q', our up and right would be:
    Code (csharp):
    1. var up = q * Vector3.up;
    2. var right = q * Vector3.right;
    Now you have your values for your formula.
     
  3. WilyC

    WilyC

    Joined:
    Aug 21, 2019
    Posts:
    7

    Thanks for the reply, but this doesn't work when I switch my camera to view the objects top down. The point seems to assume it was from the perspective of a side camera even when the camera is above (my camera can observe its target from any point in a surrounding sphere).

    If I implement my edge point as follows (where 'phantomTransform' is a from a placeholder GameObject), it all works fine - so I'd love to be able to implement the equivalent of this but using the math directly as you suggest:

    Code (CSharp):
    1.     private Vector3 GetEdgePointPhantom(Camera camera, Vector3 possition, float diameter){
    2.         var shift =   (diameter/2) / SQRT_TWO;
    3.      
    4.         phantomTransform.position = camera.transform.position;
    5.  
    6.         phantomTransform.LookAt(possition, camera.transform.up);
    7.  
    8.         var edgePoint = possition + (phantomTransform.up.normalized * shift) + (phantomTransform.right.normalized * shift);
    9.  
    10.         return edgePoint;
    11.     }
     
  4. WilyC

    WilyC

    Joined:
    Aug 21, 2019
    Posts:
    7
    OK - this seems to work. Just added the camera's up to the LookRotation. Thanks for your help!


    Code (CSharp):
    1.     private Vector3 GetEdgePoint(Camera camera, Vector3 possition, float diameter){
    2.         var shift =   (diameter/2) / SQRT_TWO;
    3.  
    4.         var q = Quaternion.LookRotation(possition - camera.transform.position, camera.transform.up);
    5.  
    6.         var up = q * Vector3.up;
    7.         var right = q * Vector3.right;
    8.  
    9.         var edgePoint = possition + (up * shift) + (right * shift);
    10.  
    11.         return edgePoint;
    12.     }