- Home /
Get EXACT SkinnedMeshRenderer bounds
I have been trying to do this for a week. I've seen a lot of posts on the subject but none that have solved my problem. I need to get the smallest bounding box for a gameobject that has Skinned Mesh Renderers attached to it. They could have any rotation, scale or local position in the hierarchy. I need a routine that will bake the meshes into temp meshes and get the vertices and find a perfect box that isn't too big. I'm using it to make a special collider that only collides with a raycast from the screen. I have tried everything I could imagine, starting with the obvious solution and that is to just use the renderer's bounds. The last thing I tried was iterating all vertices and finding the min/max for X,Y and Z. This was the closest I've gotten. The size and orientation look pretty good but the center doesn't work for all of my monsters. Even the size can be too big but the position seems to be the biggest issue. How hard can it be to get that little box that Unity already shows in the editor when you pause playback?
Any help would be so greatly appreciated. You don't need to know anything about my game or what I'm doing specifically in order to help. I simply want to pass in a GameObject and get out a bounds object (two vectors) telling me the center and size for all Skinned Meshes within. A bonus would be if I could also include non-skinned meshes (like rigid weapons they may be holding) but I think that will be easier.
Nobody's done this before? I still have no single solution that works for all 3D models, This is making the simple task of targeting monsters a nightmare in my game. I cannot believe a game engine like Unity doesn't have a built in method to give you the real bounds of something.
I figured this out finally. I got it working perfectly. I can always get the exact bounds of any gameobject hierarchy, no matter what twisted mess of rotations and scaling the children have. Seems like this forum is dead though. If anyone is out there and you need the same thing, just ask me. I won't take the time to post anything.
I for one would be very grateful if you were able to post something about your solution. I'm sure it would be useful to others as well. Thanks!
Answer by punk · Aug 31, 2020 at 06:14 PM
Here's they way I got it working, just bear in mind that because the bounds are local just make sure your root bone is pointing up, otherwise the bounds will be at an angle
skinnedMeshRenderer.updateWhenOffscreen = true;
Bounds bounds = new Bounds();
Vector3 center = skinnedMeshRenderer.localBounds.center;
Vector3 extents = skinnedMeshRenderer.localBounds.extents;
bounds.center = center;
bounds.extents = extents;
skinnedMeshRenderer.updateWhenOffscreen = false;
skinnedMeshRenderer.localBounds = bounds;
Answer by DaveL99 · Oct 25, 2019 at 03:34 PM
Here is what I did:
I store a copy of the gameObject's position & rotation, and then set the position to zero and rotation to identity - effectively (temporarily) making local space and world space the same thing.
I then go through all Renderer objects that exist within the gameObject and it's children, and build up the AABB using Bounds.Encapsulate and the Renderer's .bounds property (which returns AA bounds accounting for animations etc. in World-space - but since I've put the object at the origin this is also Local-space).
Finally, I restore the original position & rotation on the gameObject's transform, and then from my "local-space" bounding-box I construct 8 corner vertices and then transform each one into World-space with transform.TransformPoint.
That gives me a non axis-aligned bounding box in world-space, that remains consistent regardless of how the object is rotated in the world etc.
One of the biggest gotchas that people might encounter, is that you can't simply initialise your bounds to zero, or empty. i.e. Don't do this:
boundingBox = new Bounds ();
for (int i = 0; i < renderers.Count; i++)
{
boundingBox.Encapsulate (renderers [i].bounds);
}
Instead you should do this:
boundingBox = renderers [0].bounds;
for (int i = 1; i < renderers.Count; i++)
{
boundingBox.Encapsulate (renderers [i].bounds);
}