Jump to content

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


Recommended Posts

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
Link to comment
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 */ }

 

Link to comment
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.

Link to comment
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. :)

Link to comment
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)
{
...
}

 

 

 

Link to comment
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.

 

Link to comment
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.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...