Page 1 of 1

[SOLVED] Ragdolls and bounding boxes

Posted: Sun Nov 03, 2013 9:15 am
by lunkhound
So I guess Ogre doesn't update the bounding box of an entity when the bones are animated. I found some threads discussing this issue:

http://www.ogre3d.org/forums/viewtopic.php?t=10497
http://www.ogre3d.org/forums/viewtopic.php?p=261048
http://www.ogre3d.org/forums/viewtopic.php?f=1&t=77106

In the project I'm working on, I have a character that, when killed, goes into a "ragdoll" mode where physics controls the motions of the bones, and the bones can travel far away from the scene node. When this happens, the bounding box gets left behind and the character isn't culled properly. None of the threads I've seen so far have presented a workable solution.

I can't compute the bounding box myself and use Mesh::_setBounds() because the mesh may be shared between different characters (all of which need different bounding boxes). And there is no mechanism to override the bounding box at the Entity level.
I could adjust the scene node position to follow the bones, but that still isn't going to fit the ragdoll properly, and especially not if the ragdoll splits into separately moving parts.
I don't want to just hugely oversize the bounding boxes and hurt performance....

Is there something I'm missing here? How do other projects deal with ragdolls bounding boxes?

[edit: marking this "solved" since my pull request was approved (still not merged yet though)]

Re: Ragdolls and bounding boxes

Posted: Sun Nov 03, 2013 10:17 am
by mkultra333
I use hugely oversized bounding boxes.

I do the same as you, ragdolls that can break apart. I found Ogre bounding box culling generally messed things up for me in all kinds of ways, in all kinds of situations. Not faulting Ogre, just that its ways didn't fit in with my needs as far as culling went. So I always use oversized bounding boxes and instead use a manual zone-portal system plus manual frustum checks for most my culling.

Re: Ragdolls and bounding boxes

Posted: Mon Nov 04, 2013 11:34 pm
by lunkhound
Thanks for the info. It would seem that if I want reasonable bounding boxes on these guys my best option is to modify Ogre.

Re: Ragdolls and bounding boxes

Posted: Tue Nov 05, 2013 5:00 am
by mkultra333
One thing you might try, which is similar to what I do. I'm assuming that even when broken apart, your ragdoll is just one mesh, one entity.

By default, set the bounding box to be super huge or infinite. Then each frame, create an independent bounding box big enough to encase every piece of the broken up skeleton. Do a frustum check on that box, if it isn't in the scene then disconnect the skeleton's node from the scene so it doesn't draw. Of course, if the box is visible, connect it back.

It's unlikely that the actual drawing of the triangles has much of an impact, the main real cost of drawing something not visible is the batch for the entity/mesh. So whether only an arm is on screen or the entire broken up skeleton, the cost is probably about the same. So you won't get any benefit from culling piece by piece, rather it's really an all-or-nothing performance hit if you have to draw any part at all.

Re: Ragdolls and bounding boxes

Posted: Tue Nov 05, 2013 7:30 am
by lunkhound
The workaround you are suggesting, how does it work with shadow cameras? You can't really do per-camera culling if you are detaching from the scene node.
I really think that culling should just work. Culling is clearly something that a graphics engine should be able to do without these crazy workarounds.

Anyway, I've got it working pretty well with my patched Ogre, the bounding boxes are a bit oversized, but not too bad. See the attachment for my patch.

To use it, just do:

Code: Select all

    entity->setUpdateBoundingBoxFromSkeleton( true );
    entity->getMesh()->_setBoundingSphereRadius( 0.2 );  // set inflation amount
You have to enable it for each entity separately to get the new behavior. The second line is optional but the bounding boxes will be a bit too big.

Re: Ragdolls and bounding boxes

Posted: Tue Nov 05, 2013 9:47 am
by mkultra333
I never use Ogre's inbuilt shadows so I forgot that could be an issue for others.

Re: Ragdolls and bounding boxes

Posted: Tue Nov 05, 2013 11:11 pm
by Transporter
This is an expected behavior, see https://ogre3d.atlassian.net/browse/OGRE-192

Re: Ragdolls and bounding boxes

Posted: Wed Nov 06, 2013 2:34 am
by lunkhound
Transporter wrote:This is an expected behavior, see https://ogre3d.atlassian.net/browse/OGRE-192
David Rogers wrote:Animations don't update the bounding box of a node because bones have no bounding info, we'd need to perform software transforms of every vertex every frame to recalculate the bounding volume. And if shader based skinning is involved then there is certainly no way to predict what the bounding box should be.
I really don't get this. You certainly don't need to perform software transforms of every vertex every frame to compute a reasonable-fitting bounding box. If you want an exact-fitting bounding box then sure, but there's really no need for that. All you need to compute a "good enough" bounding box is the position of the skinning bones. Compute the bounding box of those, then inflate the result by some per-mesh precomputed distance that ensures all vertices will be enclosed no matter what. The result isn't an optimal-fitting box, but so what? It's basically free to compute--Ogre is already traversing all the bones every frame to generate the skinning matrices.

Re: Ragdolls and bounding boxes

Posted: Wed Nov 06, 2013 2:47 am
by c6burns
I think your solution is fine in theory (have not looked at the code). As I understand the use-case is that multiple nodes are using the same mesh, but require different bounding boxes based on manually controlled bones being driven by physics. Yes, the existing behaviour of ogre is expected and thus not a bug, and that was never being disputed in this thread. I think that JIRA issue is not exactly relevant because this isn't a discussion of a bug, but a proposition of a new feature.

Re: Ragdolls and bounding boxes

Posted: Wed Nov 06, 2013 8:34 am
by Transporter
lunkhound wrote:I really don't get this. You certainly don't need to perform software transforms of every vertex every frame to compute a reasonable-fitting bounding box. If you want an exact-fitting bounding box then sure, but there's really no need for that. All you need to compute a "good enough" bounding box is the position of the skinning bones. Compute the bounding box of those, then inflate the result by some per-mesh precomputed distance that ensures all vertices will be enclosed no matter what. The result isn't an optimal-fitting box, but so what? It's basically free to compute--Ogre is already traversing all the bones every frame to generate the skinning matrices.
Feel free to reopen the bug ticket and submit your solution. :wink:

Re: Ragdolls and bounding boxes

Posted: Wed Nov 06, 2013 10:15 pm
by lunkhound
I put the code up on my repo here:

[edit: dead link removed]

(and issued a pull request)

[edit: the code has been merged into the default branch]
https://bitbucket.org/sinbad/ogre/pull- ... boxes/diff

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Wed Jan 29, 2014 8:00 pm
by shenjoku
Is this code still available somewhere? The link to the pull request is dead.

EDIT: Never mind. I found the merged pull request here.

EDIT2: Is there a way to inflate the bounding box being calculated by some amount? Earlier you mention something about inflating when setting the bounding sphere radius but no matter what value I set that to it doesn't seem to affect the bounding box calculated from the skeleton.

This feature is almost exactly what we need except that it's still difficult to select things, so being able to inflate the bounds slightly would make it perfect.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Wed Jan 29, 2014 10:28 pm
by lunkhound
Yes it got merged into the default branch and I had to create a different pull request than the one I linked to. I'll edit the old message.
At first I used the bounding sphere radius on the mesh for this purpose, but later I changed it to have a dedicated value rather than reusing a value meant for something else. To set the value, call Mesh::_setBoneBoundingRadius( ... ). And there is a getter function too.

You can also call Mesh::_computeBoneBoundingRadius() to compute a value that should be all but guarantteed to fully enclose the mesh. It gets automatically called by Entity::setUpdateBoundingBoxFromSkeleton( ... ) when you first enable this feature.

A few things to keep in mind:
- Meshes are shared between Entities, so if you have multiple Entities using the same mesh, and each time you create an entity you bump up the boneBoundingRadius you could end up increasing it more than intended
- do not call _computeBoneBoundingRadius() on a mesh that isn't loaded yet. If you have threading enabled, meshes may get loaded asynchronously in a separate thread.
- _computeBoneBoundingRadius() won't do anything if the boneBoundingRadius is already set to some nonzero value

What you are looking to do should be totally doable, you just need to be a bit careful if threading is enabled.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Wed Jan 29, 2014 11:13 pm
by shenjoku
Sweet, that works perfectly. Thanks :)

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Fri Jan 31, 2014 3:59 am
by shenjoku
I hate to double post but this a related question that needs to be answered and I don't know how else to bump the topic.

What exactly is the default branch? Does that mean it is part of every Ogre version? If I checkout just the v1-9 branch would it be part of it? Since we're going to be upgrading to 1.9 soon it would be good to know if we have to manually patch it.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Fri Jan 31, 2014 5:20 am
by lunkhound
The default branch is just a branch named "default" and it is where development is happening for the next version of Ogre. At the time of this writing, the default branch is where 1.10 is being developed. My change didn't make it into 1.9, the devs were only taking bug fixes for 1.9 and my change was considered a new feature so it went into 1.10 (aka 'default').

It shouldn't be any trouble to backport the changes to 1.9 though. I originally made the changes to the 1.9 branch and then had to 'hg graft' them over to 'default'.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Fri Jan 31, 2014 5:28 am
by shenjoku
I see. That's good to know, thanks :)

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Mon Feb 24, 2014 7:06 pm
by SufferinPup
I've been battling this issue in ogre for a long time, thank you SO MUCH for this submission. I'll be merging it into our code shortly.

I do have one issue with it though - is it necessary to do the computation in getBoundingBox? It seems this would only be necessary once per frame, or maybe at a point just after animations are applied (if it can happen more than once per frame). We write our code assuming getBoundingBox does minimal processing, so it might be called hundreds of times per frame.

Thanks again, and this is a very worthy addition to the main ogre feature set.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Tue Feb 25, 2014 1:17 am
by lunkhound
SufferinPup, good question.

Given the interface of MovingObject (from which Entity is derived) for bounding boxes, getBoundingBox is, unfortunately, the most sensible place for that calculation. Note that there are 2 functions for bounding boxes:

Code: Select all

const AxisAlignedBox& Entity::getBoundingBox() const;               // calculate and return LOCAL coordinates bounding box
const AxisAlignedBox& Entity::getWorldBoundingBox(bool derive) const;   // optionally calculate (if derive==true) and return WORLD coordinates bounding box
Both of these functions are recursive(!) for entities with attached objects! Although getWorldBoundingBox does not recurse if you pass in 'false'. This is an EPIC fail in API design, IMO.
Not the least of which is the fact that we've got one recursive function, getWorldBoundingBox, calling another recursive function (getBoundingBox) recursively! :shock:
That's right, getWorldBoundingBox is recursive-squared! The number of calls to getBoundingBox is O(N^2) in the number of decendant-attached objects or something like that.

This is what the calling sequence between those functions looks like for a single entity 'A' with no attached children:

Code: Select all

  A->Entity::getWorldBoundingBox( true )
     visit children -- none
     A->MovingObject::getWorldBoundingBox( true )
        A->Entity::getBoundingBox()
           A->Entity::getChildObjectsBoundingBox() -- no children
           A->Entity::mFullBoundingBox updated
        aabb.transformAffine(...)
        A->MovingObject::mWorldAABB updated
        return aabb
And then for a single entity 'A' with single child entity 'B':

Code: Select all

  A->Entity::getWorldBoundingBox( true )
     visit children -- B
     B->Entity::getWorldBoundingBox( true )
        B->MovingObject::getWorldBoundingBox( true )
           B->Entity::getBoundingBox()
              B->Entity::getChildObjectsBoundingBox() -- no children
              B->Entity::mFullBoundingBox updated
           aabb.transformAffine(...)
           B->MovingObject::mWorldAABB updated
           return aabb -> discarded
     A->MovingObject::getWorldBoundingBox( true )
        A->Entity::getBoundingBox()
           A->Entity::getChildObjectsBoundingBox() -- B
              B->Entity::getBoundingBox()
                 B->Entity::getChildObjectsBoundingBox() -- none
                 B->Entity::mFullBoundingBox updated (again!)
              aabb.transformAffine(...)
           A->Entity::mFullBoundingBox updated
        aabb.transformAffine(...)
        A->MovingObject::mWorldAABB updated
        return aabb
Note that B's local bbox is uselessly updated twice. And it only gets worse the more attached entities there are...

My advice would be:

If performance matters, don't call getBoundingBox. In the Ogre core, that function is only called once per object per frame (except for the useless multiple updates due to the recursive-squared calling pattern).
If you need the local space bounding box of entities, add a new method that just returns Entity::mFullBoundingBox without updating it.

If you need the world space bounding box, calling getWorldBoundingBox is fine as long as you don't pass in 'true'.

Also be careful with the number of attached entities you use, there are some parts of Ogre that won't scale well with many attached entities.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Tue Feb 25, 2014 4:18 am
by SufferinPup
Wow that's super interesting and a bit eye opening, I never really traced the full path of getBoundingBox, it looked innocuous enough (it is only something like 4 lines of code before this change!). I think I'll just add a getLocalBoundingBox function that just returns mFullBoundingBox, which should be updated enough as long as Ogre itself is calling getBoundingBox at least once per frame. I only ever need the local bounding box anyway.

I know Ogre 2.0 is a major redesign, hopefully this sort of thing will be taken into consideration. Back when Ogre was new calculating the bounding box per frame was a bad idea, but it is very common practice now, and I'd even go so far as to say an expected part of any 3d engine.

Re: [SOLVED] Ragdolls and bounding boxes

Posted: Tue Feb 25, 2014 9:19 pm
by lunkhound
I'm also hoping that this sort of thing has been cleaned up in 2.0. I think one of the reasons for the API being like that is due to the lazy-evaluation design of 1.x. With 2.0 dropping lazy-eval, I'm hoping that leads to API improvements (as well as performance improvements).