[SOLVED] Ragdolls and bounding boxes

Problems building or running the engine, queries about how to use features etc.
Post Reply
User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

[SOLVED] Ragdolls and bounding boxes

Post 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)]
Last edited by lunkhound on Sat Nov 09, 2013 9:28 pm, edited 1 time in total.

User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1889
Joined: Sun Mar 08, 2009 5:25 am
x 104

Re: Ragdolls and bounding boxes

Post 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.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: Ragdolls and bounding boxes

Post 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.

User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1889
Joined: Sun Mar 08, 2009 5:25 am
x 104

Re: Ragdolls and bounding boxes

Post 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.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: Ragdolls and bounding boxes

Post 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.
Attachments
skelbbox.patch
skeleton based bounding boxes
(5.5 KiB) Downloaded 51 times

User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1889
Joined: Sun Mar 08, 2009 5:25 am
x 104

Re: Ragdolls and bounding boxes

Post by mkultra333 »

I never use Ogre's inbuilt shadows so I forgot that could be an issue for others.
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.


User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: Ragdolls and bounding boxes

Post 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.

User avatar
c6burns
Beholder
Posts: 1511
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 134

Re: Ragdolls and bounding boxes

Post 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.

Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Ragdolls and bounding boxes

Post 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:

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: Ragdolls and bounding boxes

Post 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
Last edited by lunkhound on Thu Jan 30, 2014 1:26 am, edited 2 times in total.

shenjoku
Gremlin
Posts: 193
Joined: Sat Aug 06, 2011 11:02 pm
x 4

Re: [SOLVED] Ragdolls and bounding boxes

Post 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.
Last edited by shenjoku on Fri Aug 01, 2014 12:55 am, edited 1 time in total.

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: [SOLVED] Ragdolls and bounding boxes

Post 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.

shenjoku
Gremlin
Posts: 193
Joined: Sat Aug 06, 2011 11:02 pm
x 4

Re: [SOLVED] Ragdolls and bounding boxes

Post by shenjoku »

Sweet, that works perfectly. Thanks :)

shenjoku
Gremlin
Posts: 193
Joined: Sat Aug 06, 2011 11:02 pm
x 4

Re: [SOLVED] Ragdolls and bounding boxes

Post 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.

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: [SOLVED] Ragdolls and bounding boxes

Post 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'.

shenjoku
Gremlin
Posts: 193
Joined: Sat Aug 06, 2011 11:02 pm
x 4

Re: [SOLVED] Ragdolls and bounding boxes

Post by shenjoku »

I see. That's good to know, thanks :)

SufferinPup
Greenskin
Posts: 119
Joined: Tue Mar 02, 2010 11:09 pm
x 2

Re: [SOLVED] Ragdolls and bounding boxes

Post 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.

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: [SOLVED] Ragdolls and bounding boxes

Post 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.

SufferinPup
Greenskin
Posts: 119
Joined: Tue Mar 02, 2010 11:09 pm
x 2

Re: [SOLVED] Ragdolls and bounding boxes

Post 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.

User avatar
lunkhound
Gremlin
Posts: 169
Joined: Sun Apr 29, 2012 1:03 am
Location: Santa Monica, California
x 17

Re: [SOLVED] Ragdolls and bounding boxes

Post 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).

Post Reply