- Home /
Calculating BoxCollider bounds and center in runtime
I have a root prefab where I want to add box-collider in runtime based on bounds of child prefabs with letter meshes combined in a word. On the picture I changed size and center manually to match bounds of characters.
This is what I tried:
Bounds bounds = new Bounds(parentObject.transform.position, Vector3.zero);
foreach (MeshFilter meshFilter in parentObject.GetComponentsInChildren<MeshFilter>())
{
bounds.Encapsulate(meshFilter.mesh.bounds);
}
BoxCollider collider = parentObject.AddComponent<BoxCollider>();
collider.center = bounds.center;
collider.size = bounds.size;
I'm getting enormous collider in this case. And it looks like somewhere wrong coordinates conversion.
How can I get size of meshes to calculate correctly offset for the next letter to add (currently I'm using hardcoded constant) ?
How can I calculate center and bounds for box collider in correct coordinate space ?
Answer by Bunny83 · Feb 28, 2017 at 12:09 AM
Mesh.bounds is in local space of the mesh. That means no scaling is applied and no translation. So the location of each character is completely ignored. Are the single character objects scaled or rotated in some way? If the child objects are rotated you can't really use Mesh.bounds. If it is just scaled and translated, you have to scale and translate the bounds you get from your Mesh according to the transform of he child object,
So bounds.size need to be scaled by the childs localscale (You can use Vector3.Scale) and the center need to be offset by the localPosition of the child object.
edit
If the childs are rotated and you need an exact bounds, you may need to iterate through all vertices of each mesh, transform them into the local space of the parent (child-localspace --> worldspace --> parent-localspace) and use encapsulate with all vertex positions.
Child prefabs have default transformation except X position. Scale and rotation applied to Root prefab only.
BoxCollider boxCollider = parentObject.GetComponent<BoxCollider>();
Bounds totalBound = new Bounds(Vector3.zero, Vector3.zero);
$$anonymous$$eshRenderer mf = null;
foreach ($$anonymous$$eshRenderer meshFilter in parentObject.GetComponentsInChildren< $$anonymous$$eshRenderer>())
{
float scale = mf.transform.localScale.x;
Bounds meshBounds = meshFilter.bounds;
totalBound.Encapsulate(new Bounds(meshBounds.center * scale, meshBounds.size * scale));
}
boxCollider.size = totalBound.size;
boxCollider.center = totalBound.center;
To be more precise about prefabs position and scale I've added new screenshot. I tried to use scale but result is the same. Can you show me sample code ??
Well, you forgot to add the position of each object:
Bounds meshBounds = meshFilter.bounds;
meshBounds.size = Vector3.Scale(meshBounds.size, mf.transform.localScale);
meshBounds.center += mf.transform.localPosition;
totalBound.Encapsulate(meshBounds);
For me, subtracting the global position worked:
meshBounds.center -= mf.transform.position;
However, I have didn't need to scale the size in my case, as I know that all of my sub-objects will be of (1,1,1) scale. Also, I have a bit of a different hierarchy, where I might have some empties in-between and stuff like that. And for a hierarchy like that, I feel like local position and scale make little sense, because a parent can be displaced and the child can be at a local position of (0,0,0). In general, using global positions and scales should work for both cases (OP's hierarchy and $$anonymous$$e), so I don't see a point of using locals. I haven't tested that though.
Your answer
Follow this Question
Related Questions
Dynamically creating a box collider for an object with multiple, rotated, and scaled mesh renderers 0 Answers
Mesh collider not working as expected 2 Answers
Rotating/Aligning parents relative to their children 1 Answer
True scale of a visible GameObject with many childs 1 Answer
How Does Unitys PolygonCollider2D calculates its center ?? 1 Answer