- Home /
Pivot vs center
I've seen a lot of posts similar to this but nothing so far that answers the question. You know when you have a prefab of a group of objects highlighted? There is an Editor button at the top left that toggles between "Center" and "Pivot". Highlight a prefab and switch to "R" for rotation. Keep clicking the Center/Pivot button. Obviously, Unity knows the difference between these two points because you can see the rotator sphere tool shift between the two points (if you object's pivot isn't center).
My question is, HOW do I get this offset? I want to throw my prefab into an empty GameObject and then give the single child an offset to counteract this difference. Thus far, I have been eyeballing this shift and changing the X and Z until there was no shift. I want to do this in code. My way is tedious! Please help :)
Answer by Adam-Mechtley · Sep 18, 2017 at 08:34 PM
I don't know how complicated your prefab is, but the actual code used to collect the bounds that gets used for Tools.handlePosition is quite a bit more complex, totally arbitrary, and subject to change.
Today, as of 2017.1/2, it will first include the collider's bounds. It will then check if the object has a renderer and, if so, add its bounds. If there is no renderer, it will add the bounds of the MeshFilter if there is one. If there is neither a renderer nor mesh filterer, then it moves on to check a variety of component types (Light, which has its own bounds calculation; ReflectionProbe, RectTransform, and then ultimately just its Transform's position).
The only actual way to get the delta you want programmatically is something like:
Tools.pivotMode = PivotMode.Center;
var center = Tools.handlePosition;
Tools.pivotMode = PivotMode.Pivot;
var delta = center - Tools.handlePosition;
Answer by Bunny83 · Sep 18, 2017 at 08:23 PM
Do you really want the exact same result as Unity gives you? Unity does calculate the bounding volume of all objects selected. This is only based on the worldspace bounds of all Renderers and all Colliders on those objects.
So this should give you the same worldspace position as Unity when you select "center".:
public static Vector3 CalculateCenter(params Transform[] aObjects)
{
Bounds b = new Bounds();
foreach(var o in aObjects)
{
var renderers = o.GetComponentsInChildren<Renderer>();
foreach(var r in renderers)
{
if (b.size == Vector3.zero)
b = r.bounds;
else
b.Encapsulate(r.bounds);
}
var colliders = o.GetComponentsInChildren<Collider>();
foreach (var c in colliders)
{
if (b.size == Vector3.zero)
b = c.bounds;
else
b.Encapsulate(c.bounds);
}
}
return b.center;
}
Note that this method searches through the whole hierarchy downwards. So if you have a parent object, just pass the parent:
Vector3 center = CalculateCenter(parent);
Thank you for your response!
I did do something similar before I posted this. I made a function that traverses only the renderers (not colliders) and I ended up with the same thing as your function returns for a particular prefab I have: (9.1f, 0, -4.1f)
In manually finding the difference between the pivot and center, I end up with something different: (-8.8f, 0, 8.2f).
I can't figure out why. But only if I shift X back by -8.8f and Z by 8.2f will I get the pivot to be right on top of the center, despite these results of using encapsulate recursively.
Any ideas ?
Well you must be doing something wrong. Either you initialize the Bounds with the world origin (note my if statement in the loops) or you do something wrong in your offsetting. See this image
The handle is the center handle and the 3 white lines are drawn inside OnDrawGizmos around the center position i calculated with my method. They are for sure identical.
How do you do the offsetting? The easiest way is to create the empty gameobject, positioning it at the calculated center and after that you add your object(s) as childs. When you use transform.parent = p;
or transform.SetParent(p, true);
the objects will keep their absolute position.
You can get my test script from my dropbox if you want to try it yourself. (direct download)
Thanks for the comprehensive solution! Once the center is calculated, is this used via assigning it to an objects child.positions, the parent itself? Fiddling with the results trying to deter$$anonymous$$e how to correctly use the center. Could you clarify, @Bunny83?