Fengist

[SOLVED] When 1 <> 1 Ya gotta love Unity.

Recommended Posts

Posted (edited)

So, I'm trying to detect when a thrustTransform has been rotated.

        public override void OnStart(StartState state)
        {
           myEngine = part.Modules.OfType<ModuleEngines>().FirstOrDefault();
           mytransform = part.FindModelTransform(myEngine.thrustVectorTransformName);
           startForward = this.vessel.transform.forward - mytransform.forward;
        }

Seems logical to me.  I compare the vessel forward to the thrustTransform forward and get a vector.

Then, in fixedUpdate I compare them again to see if it's pointing a different direction

            float newdirection = 1.0f;
            Vector3 forward = this.vessel.transform.forward - mytransform.forward;
            Debug.Log("Forward: " + forward.normalized + " StartForward: " + startForward.normalized);
            if (startForward.normalized != forward.normalized)
            {
                newdirection = -1;
            }
            Debug.Log("New Direction: " + newdirection + " Last Direction: " + lastdirection);

and here's the log output

[LOG 09:40:19.550] Forward: (0.2, 0.1, -1.0) StartForward: (0.2, 0.1, -1.0)
[LOG 09:40:19.550] New Direction: 1 Last Direction: 1
[LOG 09:40:19.569] [UIMasterController]: ShowUI
[LOG 09:40:19.577] Forward: (0.2, 0.1, -1.0) StartForward: (0.2, 0.1, -1.0)
[LOG 09:40:19.577] New Direction: -1 Last Direction: 1

As soon as the UIMasterController loads ShowUI... my two vectors no longer equal each other even though the values are identical.

Whut?????

(0.2, 0.1, -1.0) <> (0.2, 0.1, -1.0)!!!

Yea, that is correct.

Tried Vector3.Equals and (0.2, 0.1, -1.0) still <> (0.2, 0.1, -1.0)

*edit

And then I found this post: https://forum.unity.com/threads/comparing-two-identical-vector3-returns-false.327128/

Which clearly describes the fact that vectors will almost never = another vector.

Since I only need to know if the vector was rotated 180 degrees I went with this solution

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));

which worked.

Edited by Fengist
  • Like 1

Share this post


Link to post
Share on other sites
28 minutes ago, Fengist said:

Since I only need to know if the vector was rotated 180 degrees I went with this solution


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));

which worked.

That will probably still glitch out occasionally when one of the components is close to an integer. I believe the usual solution to comparing floating point numbers (a very common difficulty regardless of Unity) is to subtract them and compare the absolute value of their difference to some small constant, for example:

const double epsilon = 0.005;

if (Math.Abs(x1 - x2) < epsilon) { /* do stuff */ }

 

Share this post


Link to post
Share on other sites
Just now, HebaruSan said:

That will probably still glitch out occasionally when one of the components is close to an integer. I believe the usual solution to comparing floating point numbers (a very common difficulty regardless of Unity) is to subtract them and compare the absolute value of their difference to some small constant, for example:


const double epsilon = 0.005;

if (Math.Abs(x1 - x2) < epsilon) { /* do stuff */ }

 

Ya, I saw that solution as well.

        public static bool FuzzyEquals(this Vector2 a, Vector2 b)
        {
            return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
        }

but what I'm trying to detect will be either 0 or 180 out so rounding should be fine.  The complaint I have is when I output the debug.log and it shows me (0.3, 0.5, -0.8)... well, I expect that to  be EQUAL to (0.3, 0.5, -0.8) and not to hide a gob of floating points in there.

Share this post


Link to post
Share on other sites
4 minutes ago, Fengist said:

but what I'm trying to detect will be either 0 or 180 out so rounding should be fine.

Hmm, doesn't look like that's the case from the code you posted. You're comparing the x, y, and z components of two vectors, which can be any floating point values, not just 0 or 180. And if vect1.x is (for example) 1.0001 while vect2.x is 0.99998, you'll have the same problem again.

4 minutes ago, Fengist said:

The complaint I have is when I output the debug.log and it shows me (0.3, 0.5, -0.8)... well, I expect that to  be EQUAL to (0.3, 0.5, -0.8) and not to hide a gob of floating points in there.

Oh. Well, it's not. :)

Share this post


Link to post
Share on other sites
18 hours ago, Fengist said:

Since I only need to know if the vector was rotated 180 degrees I went with this solution


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));

which worked.

But now you're converting floats to integers, and then comparing those.  Depending on how exact you want to be, this is wrong by almost any definition I can think of

What's interesting is that according to Unity, vector3 comparisons using the == IS using an "approximate" method, see here:

https://docs.unity3d.com/ScriptReference/Vector3-operator_eq.html

Regarding the output, I suspect that if you replaced the internal output code with outputting the individual values yourself, you might see the differences.

I'd use code something like the following:

Vector3 v1, v2;
...

if ( (Math.Abs(v1.x - v2.x) < 0.01) && (Math.Abs(v1.y - v2.y) < 0.01) && (Math.Abs(v1.z - v2.z) < 0.01) )
{
...
}
                                                                                                       
or

if (Math.Abs(v1.magnitude - v2.magnitude) < 0.01)
{
...
}

 

 

 

Share this post


Link to post
Share on other sites
6 minutes ago, linuxgurugamer said:

if (Math.Abs(v1.magnitude - v2.magnitude) < 0.01) { ... }

You probably mean

(v1 - v2).magnitude < 0.01

:P

Share this post


Link to post
Share on other sites
37 minutes ago, peteletroll said:

You probably mean

(v1 - v2).magnitude < 0.01

:P

Probably, I typed that in, wasn't tested at all

Share this post


Link to post
Share on other sites

From what I read when comparing Vectors in Unity  == is an approximation.  I was using != which, as I understand it is not an approximation which makes no logical sense.  And you are correct @linuxgurugamer.  If I printed out vector.x it gave me the full value of x.

I finally ended up ripping out vectors and used quaternian local rotations and a quaternian.dot to compare them.  For whatever reason, quaternian != quaternian works but vector != vector doesn't.  I originally tried the local rotation thinking that was the solution but I guess my code was bad and it kept giving inconsistent results.

I still protest the fact that when I tell Unity to show me the value of a variable that it shows me a rounded approximation instead.  If I visually inspect the contents of 2 variables and they LOOK equal then they should be equal.  I know of no other examples in all the programming languages I know of where that type of illogic exists.

 

Share this post


Link to post
Share on other sites
2 minutes ago, peteletroll said:

@Fengist, floating point numbers are always approximate, and floating point vectors are too. You may want to read something about them here: https://en.m.wikipedia.org/wiki/Floating-point_arithmetic

I've been writing code for well over 30 years.  I'm well aware of what floating points are.  Again, when I ask a language to show me a variable... show me the variable, not some ballpark guesstimate.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now