- Home /
Gross "Almost zero" Vector components when adjusting to local space and custom handles
Hey gang,
I am drawing some handles to display a Vector3 relative to a GameObject, think of moving a child object and how it's position in the inspector is relative to the parent.
The handles I am drawing manipulate the elements in a Vector3 array that the object has. These vectors need to be relative to the object and display as such (again think of moving a child object and how its own inspector displays the position as relative to the parent) and I specifically don't want to have it reference a bunch of empty child game objects (personal challenge for me to up my game as a programmer).
What I am using is a combination of InverseTransformPoint and TransformPoint to place the handles in the scene but keep the value as a relative position. I feed the position into the Handle.PositionHandle using TransformPoint so it is drawn relative to the object in question, then that is wrapped in an InverseTransformPoint to get it back to a form that is relative to the parent.
NOTE: "b" is a reference to a class that stores the vector I want the handles for as well as other information (its name starts with a "b" so that is what I am using in code, I wanted to explain that in case you were expecting a 'v' for some standard vector) and "t" is just the transform of the object that these vectors are relative to.
b.position = t.InverseTransformPoint(Handles.PositionHandle(t.TransformPoint(b.position), t.rotation));
So this ALMOST works, the problem is that when I start rotating the main object, and the vector 3 is then moved relative to it, its XYZ components in the Inspector change by ludicrously small amounts that are essentially zero (I even see a few decimal places with an e in the mix).
I just want it to be as nice and clean as if I had a child object, none of this decimal kerfuffle. The following image should help.
Answer by Bonfire-Boy · Nov 26, 2019 at 05:10 PM
I really don't like the idea of changing the data as per steve_thud's answer.
An alternative would be to write your own inspector for the Transform class and do the rounding only on display. One could/should add the option to switch to showing the precise values, and only enable editing when those are being shown.
Creating a new inspector for Transform can be really useful. My current project, for instance, has one which shows World as well as Local position/rotation values, and has drag/drop targets enabling me to copy the position of a game object or other asset (I'm using lots of scriptable objects that define objects' positions).
Oh cool, great idea! I will try it out!
But while we're talking, was my method for calculating the local position the "right" way? I can't help but feel that even with the floating point rounding errors steve-thud mentioned, there has got to be a way for me to do it and I'm just lacking the know-how.
I'm not sure what you mean. The only problem with those numbers is in your perception of them. That's not to belittle the issue - it is handy if zeros stand out as such. But it's also important to understand that floating point "errors" are things that you have to live with rather than try to make go away.
Hey, fair enough. Just ruling out the possibility that I was doing sub-optimally.
Thanks again :)
Actually your issue is that you do not actually check if there actually was a change due to the handle but you always convert the position to worldspace and back each time and replace the original value regardless. You should do:
EditorGUI.BeginChangeCheck();
Vector3 newPos = Handles.PositionHandle(t.TransformPoint(b.position), t.rotation);
if (EditorGUI.EndChangeCheck())
{
b.position = t.InverseTransformPoint(newPos);
}
I made those changes but I still get the same rounding issue. But in general, I should do it this way in the future?
Additionally this message appears in the inspector:
"Should not be capturing when there is a hotcontrol"
Answer by steve-thud · Nov 26, 2019 at 02:24 PM
These small changes in position are caused by floating point rounding errors. Unity is doing its best to calculate the position of the object, but due to computing limitations its going to be a little off by an insignificant amount, as you are seeing here.
If you're really committed to having fewer decimal points show up in the inspector, and you're already setting the position through code, then you can try this:
int numberOfDecimalPoints = 2;
Vector3 newPosition = t.InverseTransformPoint(Handles.PositionHandle(t.TransformPoint(b.position), t.rotation));
newPosition.x = System.Math.Round(newPosition.x, numberOfDecimalPoints);
newPosition.y = System.Math.Round(newPosition.y, numberOfDecimalPoints);
newPosition.z = System.Math.Round(newPosition.z, numberOfDecimalPoints);
b.position = newPosition;
For the short term, this is what I am going to do (certainly this will be the solution for some other stuff I am working on) but I might go with making the custom inspector, but still thanks for the answer!