Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question How to check if a Vector3 is in a rectangle (which is defined by two Vector3's)?

Discussion in 'Scripting' started by FUTURE_SL, May 27, 2024.

  1. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9

    We have:
    Vector3 A - lower near left point
    Vector3 B - highest far right point
    We need to check if an arbitrary Vector3 C is in this rectangle
     
  2. Maeslezo

    Maeslezo

    Joined:
    Jun 16, 2015
    Posts:
    351
    Bunny83 likes this.
  3. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9
  4. Maeslezo

    Maeslezo

    Joined:
    Jun 16, 2015
    Posts:
    351
    Weird, it should.

    Please post the case with specific values when it is not working and we can take a look
     
    Bunny83 likes this.
  5. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9
    I'm writing a plugin for a game where the map rotates all the time and rooms change places. I'm working with local coordinates relative to the room and turning them into global coordinates. Could this be the cause of the problem?
    Code (CSharp):
    1. Room room = Exiled.API.Features.Room.Get(Room);
    2. Bounds bounds = new Bounds();
    3. bounds.SetMinMax(API.GetRelativePosition(Min, room), API.GetRelativePosition(Max, room));
     
  6. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9

    Code (CSharp):
    1. Room room = Exiled.API.Features.Room.Get(Room);
    2.  
    3. Log.Info($"Room: {room.Type}");
    4. Log.Info($"Min local coordinates: {Min}");
    5. Log.Info($"Max local coordinates: {Max}");
    6.  
    7. Bounds bounds = new Bounds();
    8. Vector3 min = API.GetRelativePosition(Min, room);
    9. Vector3 max = API.GetRelativePosition(Max, room);
    10.  
    11. Log.Info($"Min global coordinates: {min}");
    12. Log.Info($"Max global coordinates: {max}");
    13.  
    14. bounds.SetMinMax(min, max);
     
  7. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9

    Code (CSharp):
    1. Room room = Exiled.API.Features.Room.Get(Room);
    2.  
    3. Log.Info($"Room: {room.Type}");
    4. Log.Info($"Min local coordinates: {Min}");
    5. Log.Info($"Max local coordinates: {Max}");
    6.  
    7. Bounds bounds = new Bounds();
    8. Vector3 min = API.GetRelativePosition(Min, room);
    9. Vector3 max = API.GetRelativePosition(Max, room);
    10.  
    11. Primitive primitive = Primitive.Create(min);
    12. primitive.Color = Color.yellow; // Create cube with yellow color
    13. Primitive.Create(max); // Create cube with white color
    14.  
    15. Log.Info($"Min global coordinates: {min}");
    16. Log.Info($"Max global coordinates: {max}");
    17.  
    18. bounds.SetMinMax(min, max);
     
  8. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9
    Log.Info(bounds.SqrDistance(player.Position));


    When it doesn't work it's logs when staying at this rectangle: ~3.260395 and other (not 0)
    When it works: 0
     
  9. Maeslezo

    Maeslezo

    Joined:
    Jun 16, 2015
    Posts:
    351
    Bounds doesn't have rotation, so it's better that A,B, and C are in local coordinates
     
    Bunny83 likes this.
  10. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9
    Code (CSharp):
    1. Bounds bounds = new Bounds();
    2. bounds.SetMinMax(Min, Max);
    3. ...
    4. Log.Info(bounds.Contains(room.transform.InverseTransformPoint(player.Position));
    Doesn't works :/
     
  11. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9
    Bounds: Center: (-1.77, 2.31, -0.04), Extents: (1.69, 1.81, -1.68)
    Player position at local room: (-2.47, 0.96, -0.01)
     
  12. Maeslezo

    Maeslezo

    Joined:
    Jun 16, 2015
    Posts:
    351
    I don't know what exactly your problem is.

    You can play around with this toy example to see how bounds and contains work
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BoundsTest : MonoBehaviour
    6. {
    7.     public Transform a;
    8.     public Transform b;
    9.     public Transform c;
    10.  
    11.     public Color inside = Color.green;
    12.     public Color outside = Color.red;
    13.     public bool wired = true;
    14.  
    15.     public Bounds bounds;
    16.  
    17.     public bool isInside;
    18.  
    19.     private void Update()
    20.     {
    21.         Vector3 localMin = transform.InverseTransformPoint(a.position);
    22.         Vector3 localMax = transform.InverseTransformPoint(b.position);
    23.         bounds.SetMinMax(localMin, localMax);
    24.  
    25.         Vector3 localPosition = transform.InverseTransformPoint(c.position);
    26.         isInside = bounds.Contains(localPosition);
    27.     }
    28.  
    29.     private void OnDrawGizmos()
    30.     {
    31.         Matrix4x4 cacheMatrix = Gizmos.matrix;
    32.         Gizmos.matrix = transform.localToWorldMatrix;
    33.  
    34.         Gizmos.color = isInside ? inside : outside;
    35.         if (wired)
    36.         {
    37.             Gizmos.DrawWireCube(bounds.center, bounds.size);
    38.         }
    39.         else
    40.         {
    41.             Gizmos.DrawCube(bounds.center, bounds.size);
    42.         }
    43.  
    44.         Gizmos.matrix = cacheMatrix;
    45.     }
    46. }
    47.  
    bounds.gif
     
  13. FUTURE_SL

    FUTURE_SL

    Joined:
    Jan 23, 2024
    Posts:
    9

    I've drawn the bounds now. Very strange, but they look the same in all cases (right and wrong)
     
  14. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,194
    Well, I do :) The extent of the bounds must NOT be negative. The result would be a negative volume. The bounds is centered around the center point and the extents defines half the size of the volume.

    As we can see in the min / max coordinates, the max coordinate has a smaller z position than the min coordinate. Not sure where you got your two points from, but if you're not sure which parts are "min" and which are "max", you could do either

    Code (CSharp):
    1. Vector3 min = Vector3.Min(A, B);
    2. Vector3 max =Vector3.Max(A,B);
    which ensures that your min vector is actually the minimum in all 3 axis and max is actually max. Or you could do something like this:

    Code (CSharp):
    1. Bounds bounds = new Bounds(A, Vector3.zero);
    2. bounds.Encapsulate(B);
    This does essentially the same as the first solution. At least internally.
     
    Ryiah and Maeslezo like this.
  15. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,697
    Why not just use trigger colliders? :confused:
     
  16. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,559
    There are some situations where polling a condition is more convenient or less fiddly than setting up an event-oriented mechanism to track the condition. Bounds.Contains is polling, OnTriggerEnter is an event. OnTriggerEnter has a lot of cases where it's not reliable, since it is dealing with state in both Unity-world and PhysX-world. For example, enter a trigger collider, change parents [stand on moving platform, etc.], and never get the OnTriggerExit.
     
  17. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,697
    Oops! I could have sworn you could poll rectangle colliders, but no. I think what I was actually thinking of is OverlapBox.
    https://docs.unity3d.com/ScriptReference/Physics.OverlapBox.html

    The advantage here is that you could supply the orientation and Unity will do all of the fiddly rotatey stuff.
     
  18. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,559
    You can do (myCollider.ClosestPoint(v3) == v3) and hope that matrix roundoff error is within the sloppy == tolerance. Sometimes I dream about being given a month on the Unity team just to add a lot more orthogonal API consistency to the physics classes, and a Collider.ContainsPoint() would be high on the list.
     
  19. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,947
    One cute way to do this for an arbitrary rectangular prism is to check the point against all 6 of your rectangular prism's planes with https://docs.unity3d.com/ScriptReference/Plane.GetSide.html .

    If the point is on the positive side (or negative side, depending on how you construct the planes in your code) of all 6 planes, it is inside the prism.