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

arithmetic problem

Discussion in 'Scripting' started by TomPo, Jun 4, 2019.

  1. TomPo

    TomPo

    Joined:
    Nov 30, 2013
    Posts:
    86
    Hi

    What I want to achieve is to find a point on the trace line from the camera to mousepos where height from the ground will be constant.

    The shortcut is:
    Code (CSharp):
    1. Vector3 pos = new Vector3(hit.point.x, height, hit.point.z);
    but then transform is not matching mouse pos.

    Simple Lerp will also not work because of changing distance and camera movement/rotation.

    What I have so far...
    From a mathematical point of view, it should work but doesn't :D as my C (hypotenuse) values go crazy.

    Code (CSharp):
    1.     public LayerMask Floor;
    2.     public Transform Dummy;
    3.     private Transform Cam;
    4.     private Vector3 Pos;
    5.  
    6.     private void Start() {
    7.         Cam = Camera.main.transform;
    8.     }
    9.  
    10.     void Update() {
    11.         Tracing();
    12.         Dummy.position = Pos;
    13.     }
    14.  
    15.     private void Tracing() {
    16.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    17.         if (Physics.Raycast(ray, out RaycastHit hit, float.MaxValue, Floor)) {
    18.  
    19.             Vector3 dir = Cam.position - hit.point;
    20.             float angleBeta = Vector3.Angle(dir,Vector3.down) -90; //angle raydir and floor
    21.             float b = 0.5f; // cathetus - const height
    22.             float a = b / Mathf.Tan(angleBeta); // second cathetus
    23.             float c = Mathf.Sqrt((a * a) + (b * b)); //hypotenuse
    24.             Pos = Vector3.MoveTowards(hit.point, Cam.position, c);
    25.  
    26.         }
    27.     }
    28.  
    So I have to questions:
    1 - where is the mistake? Should I take somewhere cam rotation into the calculations?
    2 - is there some easier way to achieve this?
     
    Last edited: Jun 4, 2019
  2. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    If I'm following you, I think I can see what you're trying to do- at first blush, this is really just a right-triangle problem, correct?
    Code (csharp):
    1.   |\
    2. A | \ C
    3.   |__\
    4.     B
    If B is the ground, C is the hypotenuse / raycast from the camera, and A is the distance from the ground you'd like. BC is where the raycast makes contact with the ground, so what you really want seems to be AB's exact position relative to that point.

    I can't really help you with the vector math here, trig isn't really my area to begin with, and you'd have to apply the camera's rotation to the resulting positions and such too, so I'd just be "winging it" experimenting for an hour to figure it out. What I can say is that, purely from a logical standpoint, the result is going to be flawed. If the ground is perfectly flat, you can raycast against a plane at a given height instead and cut all of the work here. If the ground isn't flat though, then the point AB that you get from this calculation isn't going to be an exact distance from the ground under it, because B isn't necessarily straight.

    To put it another way, if the ground were perfectly parallel with the raycast angle from the camera for some distance, there may be a ton of results along that path that satisfy the distance-to-ground you want, or if the floor suddenly falls away, such as a balcony, there may be zero.

    So my suggestion, given that a perfect answer doesn't seem possible, is to actually stop trying to manually calculate it and do two raycasts- the first to determine the point of contact for a ray from the camera to the mouse position intersecting the floor, then set a plane's position to that point + some given height value, and then raycast again to see where you make contact with the plane. If you need the point on the ground below that, do a third raycast from the plane intersection point down to intersect with the floor/terrain again.

    If this isn't the type of calculation that you need to do every frame, and just on click, then one raycast or several isn't going to make much difference, so long as you're not generating much garbage. You may want to look into the NonAlloc methods if you haven't already.
     
  3. TomPo

    TomPo

    Joined:
    Nov 30, 2013
    Posts:
    86
    HI
    I'm raycasting from camera to the floor with mouse position
    Now I want that dummy (just some box for now) will be under the mouse point BUT const height from the ground.
    So I'm trying to calculate the distance I have to move this dummy closer to the camera so it still will be under the mouse point but at given height over the ground.
    The Ground is not moving it's just a plane.
    The Easiest way to achieve this is just to add this height to hit.point but then dummy position is not matching pointer position.

    So on your great triangle image :) we have:
    A - given height
    Angle between BC - raycast angle
    and we need to calculate C - so the distance dummy has to be moved closer to camer to be at height A
    B = A / Tan(angle)
    c2 = A2 * B2 -> c= sqrt(A*A + B*B)

    But somehow it's going bad :D


    " If the ground is perfectly flat, you can raycast against a plane at a given height instead and cut all of the work here."
    Sounds like a good idea - I think... I hope...
    How to manage this?

    Another easy way is to put some boxcollider matching floor size but with proper height and raycasting agaist this collider and not the floor - cheating ;)

    But I'm pretty sure this can be done via arithmetics calculations ;)
     
    Last edited: Jun 4, 2019
  4. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    The link gives an example- a Plane is its own object type, not a BoxCollider that requires a GameObject in the scene. It's a small mathematical construct representing a two-dimensional plane in three-dimensional space. You can use Plane.Raycast and calculate the intersection point of a ray with that construct in like two lines of code, as per the documentation for Plane.Raycast, and it's supposedly incredibly cheap to perform- I'm not even sure it uses the physics system at all, but just math as you're trying to do.

    And yes, it can be done manually I'm sure, but there's no need to reinvent the wheel if there's a tool that can give you the same result with little or no effort. =)

    An example of a plane that might do what you want could be:
    Code (csharp):
    1. mPlane = new Plane(Vector3.up, new Vector3(0f, floorHeight + heightOffset, 0f));
    ... where floorHeight is the Y position of the floor, and the offset is the distance above the floor where you want the plane to be placed. The Vector3.up says that you want the plane to face in the upward (+Y) direction. You can then Plane.Raycast with your ray from the camera- just do exactly as in the Plane.Raycast documentation example to get the position where it intersects with ray.GetPoint(enter).

    Code (csharp):
    1. mPlane = new Plane(Vector3.up, new Vector3(0f, floorHeight + heightOffset, 0f));
    2. if (Input.GetMouseButton(0))
    3. {
    4.     Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    5.     float enter = 0.0f;
    6.  
    7.     if (mPlane.Raycast(ray, out enter))
    8.         Vector3 hitPoint = ray.GetPoint(enter);
    9. }
     
    Last edited: Jun 4, 2019