添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Hi everyone,

I am writing a C# script on Unity 3D. I have two Vector3 that are the same. When I do:

Debug.Log(vect1);
Debug.Log(vect2);

I get the same result (500.0, 150.0, 0.0).

The problem is that when I do:

vect1.Equals(vect2)

I get false! The same happens if I use the == operator

vect1==vect2

P.S. I am sure that they are both Vector3 because when I do vect1.GetType() and vect2.GetType() I always get Vector3.

Try debugging out the Vector using the ToString method with the F8 parameter, like so:

Debug.Log(vect1.ToString("F8"));

This will print the string with 8 points of precision, allowing you to see exactly what the vector is. According to the documentation page though, the == operator should return true even if they’re fairly close.

The Vector’s default ToString method has a very low precision, so it’s easy to not see the difference. Also, the Vector’s == operator doesn’t just do == on each float, instead it checks if the magnitures are within some fixed threshold value, which can easily happen on very large vectors where the precision is low. So in general you shouldn’t use == with vectors unless you know what you’re doing. In most cases you should use Vector3.Distance or similar to check if it’s close enough to your target.

As a general rule, if you’re using == between two Vector3’s, you shouldn’t be. The same applies to floats (or, more accurately, it applies to Vector3 because it applies to floats). Floating point numbers are notoriously slightly inaccurate. The inaccuracies usually don’t matter, UNLESS you’re using the == operator, because 1.0000001 is not 1, and sometimes when using floats, 1f / 2f * 2f can equal 1.00000001.

Anytime you need to do that sort of check, check against distance as @Nitugard suggested.

(If CPU efficiency is key in that situation, you should use (vector1 - vector2).sqrMagnitude - it will give you the square of the distance (which is fine for this comparison), which will be faster than .Distance because .Distance has to compute a square root, which is really slow.)

This came up a couple weeks ago in another thread, and we determined why == and Equals acts differently. Unity actually coded them differently (UGH!). From the UnityEngine dll for Vector3:

    public override bool Equals(object other)
      if (!(other is Vector3))
        return false;
      Vector3 vector3 = (Vector3) other;
      if (this.x.Equals(vector3.x) && this.y.Equals(vector3.y))
        return this.z.Equals(vector3.z);
        return false;
    public static bool operator ==(Vector3 lhs, Vector3 rhs)
      return (double) Vector3.SqrMagnitude(lhs - rhs) < 0.0 / 1.0;

== actually does the SqrMagnitude like everyone is suggesting. But .Equals compares the vectors directly.

Personally, I never use either of these methods, so I never tripped over it myself. Floats are inherently inaccurate, so I’ve never designed anything to need to know if 2 vectors are equal. In my opinion in game design, it’s a weird thing to test for. I might test if 2 vectors are NEAR one another, but never equal.

Except for zero vector, I do see the need to test that. Which is why I have these 2 methods in my VectorUtil:

public static bool NearZeroVector(this Vector3 v)
return MathUtil.FuzzyEqual(v.sqrMagnitude, 0f, MathUtil.EPSILON_SQR);
public static bool NearZeroVector(this Vector2 v)
return MathUtil.FuzzyEqual(v.sqrMagnitude, 0f, MathUtil.EPSILON_SQR);
    /// <summary>
    /// A collection of vector methods. Any statements regarding the clockwise relative directions of a rotation are under the consideration of x-axis is right, and y-axis is up. 
    /// A clockwise rotation would go from y-up to x-right.
    /// </summary>
    public static class VectorUtil
        public static Vector2 NaNVector2 { get { return new Vector2(float.NaN, float.NaN); } }
        public static Vector3 NaNVector3 { get { return new Vector3(float.NaN, float.NaN, float.NaN); } }
        public static Vector2 PosInfVector2 { get { return new Vector2(float.PositiveInfinity, float.PositiveInfinity); } }
        public static Vector3 PosInfVector3 { get { return new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); } }
        public static Vector2 NegInfVector2 { get { return new Vector2(float.NegativeInfinity, float.NegativeInfinity); } }
        public static Vector3 NegInfVector3 { get { return new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); } }

NOTE - I totally suggest explicitly testing the ‘nearness’ with sqrMagnitude as suggested by everyone and just straight up ignore the == and .Equals methods. The fact they don’t act the same, is bad design. Furthermore they don’t act like what the operator implies… == does not imply to me fuzzy equality, it implies equality. I’d write a ‘FuzzyEquals’ method, like in my VectorUtil class again:

        public static bool FuzzyEquals(this Vector2 a, Vector2 b)
            return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
        public static bool FuzzyEquals(this Vector2 a, Vector2 b, float epsilon)
            return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), epsilon);
        public static bool FuzzyEquals(this Vector3 a, Vector3 b)
            return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
        public static bool FuzzyEquals(this Vector3 a, Vector3 b, float epsilon)
            return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), epsilon);
    /// <summary>
    /// A collection of vector methods. Any statements regarding the clockwise relative directions of a rotation are under the consideration of x-axis is right, and y-axis is up. 
    /// A clockwise rotation would go from y-up to x-right.
    /// </summary>
    public static class VectorUtil
        public static Vector2 NaNVector2 { get { return new Vector2(float.NaN, float.NaN); } }
        public static Vector3 NaNVector3 { get { return new Vector3(float.NaN, float.NaN, float.NaN); } }
        public static Vector2 PosInfVector2 { get { return new Vector2(float.PositiveInfinity, float.PositiveInfinity); } }
        public static Vector3 PosInfVector3 { get { return new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); } }
        public static Vector2 NegInfVector2 { get { return new Vector2(float.NegativeInfinity, float.NegativeInfinity); } }
        public static Vector3 NegInfVector3 { get { return new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); } }
              

Hi guys,

I solved the problem by doing a member to member comparison instead of a vector to vector comparison.

int x1=(int)vect1.x;
int y1=(int)vect1.y;
int z1=(int)vect1.z;
int x2=(int)vect2.x;
int y2=(int)vect2.y;
int z2=(int)vect2.z;
Debug.Log((x1==x2)&&(y1==y2)&&(z1==z2));

In this way it’s a simple comparison between integers, so it works.

you’re converting the values to int. That’s a fairly large rounding range. Vectors with as much distance as nearly 2 units in distance from one another will equate as equal.

<0.99f, 0.99f, 0.99f> and <-0.99f, -0.99f, -0.99f> (note those are positive and negative) would be equal.

Also, it’s notably more code than the fuzzyequals options I showed you. Which allows for more control over the rounding size (epsilon). With it you get to decide how close the vectors need to be to be considered equal.

Hi guys,

I solved the problem by doing a member to member comparison instead of a vector to vector comparison.

int x1=(int)vect1.x;
int y1=(int)vect1.y;
int z1=(int)vect1.z;
int x2=(int)vect2.x;
int y2=(int)vect2.y;
int z2=(int)vect2.z;
Debug.Log((x1==x2)&&(y1==y2)&&(z1==z2));

In this way it’s a simple comparison between integers, so it works.

I think the main problem with this is that it will tell you that 2.99999999 and 3 are not equal, which is something that can easily happen with floating point math.

  • return false;
  • Vector3 vector3 = (Vector3) other;
  • if (this.x.Equals(vector3.x) && this.y.Equals(vector3.y))
  • return this.z.Equals(vector3.z);
  • return false;
  • Why is this code written so silly? What’s the point? All of this can be written in a much shorter way, in a single line:

  • public override bool Equals(object other) => other is Vector3 vector3 && x.Equals(vector3.x) && y.Equals(vector3.y) && z.Equals(vector3.z)
  • Don’t necro 4 year threads to complain about unimportant stuff. That method was generated by a decompiler, so it’s going to look ugly. You can find the actual source here, as it’s public these days.
    Also use code tags.

    Iron-Warrior:

    Try debugging out the Vector using the ToString method with the F8 parameter, like so:

    Debug.Log(vect1.ToString("F8"));
    

    This will print the string with 8 points of precision, allowing you to see exactly what the vector is. According to the documentation page though, the == operator should return true even if they’re fairly close.

    You saved my life! tysm

    Since the necro has happened already, might as well share a clean-up / iteration I did on @lordofduct 's code above.

    Using expression bodies for methods and written in a slightly different way, plus a way to avoid situations where a Vector3 is practically zero but not for the purposes of Quaternion.LookRotation where it would result in a Look rotation viewing vector is zero error.

    If the error persists after validating with myVector3.IsValidViewingVector(), shave a few "0"s off of EPSILON_VIEWING_VECTOR

    private const double EPSILON = float.Epsilon;
    private const double EPSILON_SQR = EPSILON * EPSILON;
    private const double EPSILON_VIEWING_VECTOR = 0.000000000000001f;
    public static bool FuzzyEquals0(this float v, double epsilon = EPSILON) => FuzzyEquals(v, 0, epsilon);
    public static bool FuzzyEquals(this float v, float b, double epsilon = EPSILON) => (v - b).Abs() < epsilon;
    public static bool FuzzyEquals(this Vector2 a, Vector2 b, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector2.SqrMagnitude(a - b), epsilon);
    public static bool FuzzyEquals0(this Vector2 a, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector2.SqrMagnitude(a), epsilon);
    public static bool FuzzyEquals(this Vector3 a, Vector3 b, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector3.SqrMagnitude(a - b), epsilon);
    public static bool FuzzyEquals0(this Vector3 a, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector3.SqrMagnitude(a), epsilon);
    /// <summary>
    /// Use to filter out Vector3's that wouldn't cause an issue when used with <see cref="Quaternion.LookRotation(Vector3)"/>
    /// </summary>
    public static bool IsValidViewingVector(this Vector3 a) => !FuzzyEquals0(Vector3.SqrMagnitude(a), EPSILON_VIEWING_VECTOR);