Search Unity

Check if one Vector is between two others

Discussion in 'Scripting' started by TristanCms, Apr 5, 2017.

  1. TristanCms

    TristanCms

    Joined:
    Mar 17, 2017
    Posts:
    29
    Hi!

    I would like to check if one vector is between two others. Also direction is important in my case.

    If you look at my picture, I would like to check if vector B is between A and C.

     

    Attached Files:

  2. laxbrookes

    laxbrookes

    Joined:
    Jan 9, 2015
    Posts:
    235
    Why not create a collider using the points that you do know? Being A, C and AC. Construct a triangular or cone shaped collider and use...
    Code (CSharp):
    1. if(col.bounds.contains(somePosition)){
    2.     //logic here
    3. }
     
  3. gorbit99

    gorbit99

    Joined:
    Jul 14, 2015
    Posts:
    1,350
    Google before you post
    if (A. <= B.x && B.x <= C.x || C.x <= B.x && B.x <= A.x) {

    }

    One other way would be to check if the unitvectors form a CW or CCW triangle, but this only works if you know the positions of A and C vertices relative to eachother
     
  4. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Neither solution posted yet are particularly good
    You also need to better define what 'between' means

    B is technically 'between' A and C in all 3

    given that the word 'cam' is in your image, is this just checking if some vector lies within the view?
    You can probably get a good result from calculating the dot product with the cameras forward vector

    Or: if B is always exactly half way between A and C, you can calculate that easily enough
     
    lordofduct likes this.
  5. TristanCms

    TristanCms

    Joined:
    Mar 17, 2017
    Posts:
    29
    Ok then I'll be more precise about what I want to do. You see the rectangle on my picture ? That's a world canvas (for VR).The "cam" is my camera.

    Here is what I want to do : I want the canvas to follow the camera when I'm not looking in its direction. But when I'm looking in its direction I dont want it to move. I don't want the x axis to be taken in account. In fact when I look in the direction of the canvas, even if I'm looking above it, I don't want it to move.

    I don't really know how to define my "between". I understand what you mean. I want to check if my camera (vectorB) is looking between the small angle formed by A (cam to left of the canvas) and C (cam to right of the canvas).

    I want to check if the forward of my camera is in the triangle formed by my camera and the to sides of my canvas.
    If the forward of my camera is not in this triangle (B not between A and C) I want to move my canvas to follow the camera. So that the forward of my camera stays, in this triangle.

    Here is what I have for the moment :
    Code (CSharp):
    1.         Vector3 VPlayer = Camera.main.transform.position;
    2.         Vector3 VCursor = _Cursor.transform.position;
    3.         Vector3 VLeft = _LeftPoint.transform.position;
    4.         Vector3 VRight = _RightPoint.transform.position;
    5.  
    6.         Vector3 B = VCursor - VPlayer;
    7.  
    8.         Debug.DrawRay(VPlayer, B, Color.red);
    9.  
    10.         Vector3 A = _LeftPoint.transform.position - VPlayer;
    11.         Vector3 C = _RightPoint.transform.position - VPlayer;
    12.  
    13.         Debug.DrawRay(VPlayer, A * 10, Color.blue);
    14.         Debug.DrawRay(VPlayer, C * 10, Color.green);
    15.  
    16.         if (Vector3.Dot(Vector3.Cross (A, B) , Vector3.Cross (A, C)) >= 0 && Vector3.Dot(Vector3.Cross (C, B) , Vector3.Cross (C, A)) >= 0) {
    17.             Debug.Log ("Inside");
    18.         } else {
    19.             Debug.Log ("Outside");
    20.  
    21.             Vector3 newRotation = new Vector3 (_DownCanvas.transform.eulerAngles.x, Camera.main.transform.eulerAngles.y, _DownCanvas.transform.eulerAngles.z);
    22.             Quaternion _targetRotation = Quaternion.Euler (newRotation);
    23.             _DownCanvas.transform.rotation = Quaternion.RotateTowards (_DownCanvas.transform.rotation, _targetRotation, 200 * Time.deltaTime);
    24.         }
    It takes in account the x axis.. That's not what I want to do. Also, the way my canvas moves is not smooth. Also it may be wrong. I'm not sure about the maths.
     
    Last edited: Apr 5, 2017
  6. gorbit99

    gorbit99

    Joined:
    Jul 14, 2015
    Posts:
    1,350
    If you want to check if it's on screen, then GameObject.GetComponent<Renderer>().isVisible isn't enough?
     
  7. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Try just clamping the rotation of the canvas to the cameras' rotation plus or minus the cameras' horizontal FOV plus the fov size of the canvas
    (Assuming the canvas is rotating around the camera in hierarchy with the pivot at the camera)

    Code (CSharp):
    1.     public Transform cam, canvas, _LeftPoint, _RightPoint, _CenterPoint;
    2.  
    3.     float camX, camY, canvasY, halfFovAngle, leftBuffer, rightBuffer;
    4.  
    5.     void Start () {
    6.         Quaternion initialRot = cam.rotation;
    7.  
    8.         cam.LookAt( _CenterPoint );
    9.         leftBuffer = Vector3.Angle( cam.forward, ( _LeftPoint.position - cam.position ) );
    10.         rightBuffer = Vector3.Angle( cam.forward, ( _RightPoint.position - cam.position ) );
    11.  
    12.         cam.rotation = initialRot;
    13.  
    14.         float radAngle = Camera.main.fieldOfView * Mathf.Deg2Rad;
    15.         float radHFOV = 2 * Mathf.Atan( Mathf.Tan( radAngle / 2 ) * Camera.main.aspect );
    16.         halfFovAngle = ( Mathf.Rad2Deg * radHFOV ) / 2;
    17.     }
    18.  
    19.     void Update () {
    20.         camX -= Input.GetAxisRaw( "Mouse Y" );
    21.         camY += Input.GetAxisRaw( "Mouse X" );
    22.         cam.rotation = Quaternion.Euler( camX, camY, 0 );
    23.  
    24.         canvasY = Mathf.Clamp( canvasY, camY - halfFovAngle - rightBuffer, camY + halfFovAngle + leftBuffer );
    25.         canvas.rotation = Quaternion.Euler( canvas.transform.eulerAngles.x, canvasY, canvas.transform.eulerAngles.z );
    26.     }
    27.  
    28.  
     
    egoquat likes this.
  8. TristanCms

    TristanCms

    Joined:
    Mar 17, 2017
    Posts:
    29
    Thanks ! It works. I had to set halfFovAngle to 0. I don't really understand why and what it is all about. But it works.

    I have another problem now. In this code, you change the rotation of the camera. I would like to change it from another script.

    That's why I tried this :
    camX = cam.rotation.eulerAngles.x;
    camY = cam.rotation.eulerAngles.y;

    Instead of :

    camX -= Input.GetAxisRaw( "Mouse Y" );
    camY += Input.GetAxisRaw( "Mouse X" );

    But since it's in two separated update() that's not "synchronized" the camera and the canvas does not move at the same time.

    I have another problem: When one of my camera axis goes from 0 to 360° or from 360 to 0

    Thanks a lot for you help !
     
  9. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Half Fov Angle is needed to determine how far apart (horizontally) to clamp the left and right edges of the canvas.
    With the value calculated in Start you can see (gif below) that the edges of the canvas clamp to the full size of the camera view, so left and right edge follow the edges of the view.

    When you force the value to zero (half way through gif) it now clamps to the center line of the camera, so theres always some of the canvas overlapping the view.
    If you want some of this overlap, you should instead change the position of the left and right edge - overriding the halfFovAngle will prevent you from modifying the amount of overlap during gameplay (by controling left and right edge position) [if you ever want to]


    For the lag you could try changing it from update to LateUpdate

    For the looping from 0 to 360, you MUST track the modification to the camY variable, not directly access cam.rotation.eulerAngles.y, this is just an unfortunate consequence of the camera angle being managed by quaternions.

    Presumably you are modifiyng the camera rotation in a player script or something, which has its own camY variable, could you access that as public into this script instead?
    playerControl.camY... etc
    Or just move this code into your player script?
     
    lordofduct likes this.
  10. TristanCms

    TristanCms

    Joined:
    Mar 17, 2017
    Posts:
    29
    OK! Thanks a lot! I tried so long to do it. I learned a lot from you. I didn't even know LateUpdate(). In fact, I wanted to use cam.rotation and not camY, because i'm doing it in VR and I use googleVR to control the camera / head rotation. I didn't want to modify the code of GoogleVR that controls the camera rotation. But I understand I'll do it like you said :) Thanks !
     
  11. maxizrin

    maxizrin

    Joined:
    Apr 13, 2015
    Posts:
    20
    Here's a little something I had to write to take advantage of Unity ECS NavMeshQuery.

    Code (CSharp):
    1.  
    2. // Returns greater than one, if vector exceeds right bound, and less than zero if vector exceeds left bound.
    3. private static float VectorDegreesNormalized(Vector3 left, Vector3 right, Vector3 toCheck) {
    4.     var funnelAngle = Vector3.Angle(left, right);
    5.     var checkAngle = Vector3.SignedAngle(left, toCheck, Vector3.Cross(left, right));
    6.     return checkAngle / funnelAngle;
    7. }
    I have yet to test it properly, but it seems to work, a proper path is indeed returned.