Animated Mesh Collision (2)

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Animated Mesh Collision (2)

Post by doggan »

Hey Norbo - I see there is already a thread in this forum with the same title, but I'd like to get into a bit more detail with you. I originally made this post @ Gamedev, but surprisingly, I have had 0 responses. Hopefully you (or someone else here) can provide some feedback.

---------------------------------

I am wondering how the bow/arrow collision is done in Shadow of the Colossus with an animated mesh. In the game, you are able to shoot arrows at the colossi. If the arrow hits a furry part of the enemy, it will stick, and stay in the skin even as the enemy moves around (just like you would imagine). If you hit a protected area of the enemy, the arrow bounces off.

In my current prototype implementation, I am using various bounding volumes, which are placed at the bones of the animated mesh. This kind of works, but it is not terribly accurate and there are some definite visual errors associated with this approach. Also, I am unable to differentiate between 'protected areas' and 'soft areas' unless I specifically place a bone at each of these locations.

I would think that Shadow of the Colossus is doing some type of per-triangle raycast test (probably after an initial bounding volume pass).. but then again, it is PS2, so this may be too expensive.

---------------------------------

How would you approach this within the Bepu framework? Thanks!
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

There's a few options:

1) Transforming a DetectorVolume to the right spot
DetectorVolumes are arbitrary triangulated volumes which can both be queried actively or be used as an event system that throws events when objects move through different intersection states. If you wanted to use queries, you could detect the initial collision event with the character body and then ask the related DetectorVolumes if the projectile was contained. Alternatively, you could catch the events thrown by the character’s DetectorVolumes to see if the projectile is currently in an intersecting state.

The detector volume’s TriangleMesh can have its worldMatrix set to the bone’s world transformation multiplied by the sticky patch’s local transformation each frame to get the correct location relative to the character.

2) Transforming an entity with isDetector = true to the right spot
Detector entities can be used to define convex areas (or arbitrary volumes with a compound body) that other entities will hit (but not undergo collision response with) and throw events. That way, when an arrow/projectile enters/exits the detector entity, you can catch the event. If the arrow impacts the skin while still in the state of being contained by a detector entity, you can say that the projectile should stick.

Similar to the above, you’ll also need to translate and rotate the entity to the right location relative to the nearest bone so that it appears to be in the right spot. Instead of setting a matrix, you’d need to do it through position and orientation.

3) Putting tags (Entity.tag field) on subbodies of a CompoundBody
This option requires a highly triangulated (or otherwise segmented) CompoundBody which isn't ideal. Basically, it would allow you to detect if the impacted subbody was ‘sticky’ or not and then decide what to do from there. This is probably not the best option due to its dependency on the segmentation of a compoundbody to determine stickiness.


I think my preferred solution would be #1 due to its relatively high flexibility and robustness. You can also perform raycasts against DetectorVolumes if you need to. Note that the static TriangleMesh.getVerticesAndIndicesFromModel is quite a bit more robust now so you should be able to at least use it for quick DetectorVolume testing.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

I just did some testing, and unfortunately it appears there may be some issues with the event-based approach with DetectorVolumes when changing the worldMatrix repeatedly. The query-based approach should still be OK, but I'll do some more looking into it.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

False alarm!

I forgot about the fact that I redesigned the way a worldMatrix is applied. It no longer automatically refits; now, after applying a new transformation, either triangleMesh.hierarchy.refit() or triangleMesh.hiearchy.reconstructHierarchy() should be called depending on the severity of the transformation. In almost all cases, calling refit suffices.

This is mentioned in the documentation of the worldMatrix property. You'd think I would have remembered or read that, given that I wrote it.
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Re: Animated Mesh Collision (2)

Post by doggan »

Interesting ideas. The suggested approach is basically simulating a skinned mesh with intelligently placed rigid body meshes. Due to vertex blending and deformation, I fear that there will be some issues near joints and areas where vertices are affected by multiple bones. It might be acceptable though. I'm also toying with some software based skinning ideas. Hmm..
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Re: Animated Mesh Collision (2)

Post by doggan »

Additional question for you Norbo :) -

If I manually change the vertex positions of an existing TriangleMesh hierarchy, will refit() suffice? This is more than simply changing the world matrix of the mesh - I'd like to perform actual deformation. If so, what is the cost of refit? Is it something that could be called on a per-frame basis?

I'm thinking that for the simulation I am envisioning, I may need to manage my own list of deforming Triangles, and manage my own spacial hierarchy.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

Refit should work fine. In some extreme transformation cases, calling reconstructHierarchy instead may be useful to improve later query speed, but it is unlikely that simple animation transforms could ever produce such a bad configuration. It has a relatively low cost; in fact, the new DynamicBinaryHierarchy broadphase does a similar operation over a tree spanning every entity in the world every frame.
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Re: Animated Mesh Collision (2)

Post by doggan »

Are there any possible optimizations for TriangleBoundingVolumeHierarchy.refit() to get better performance, especially on the 360? i.e. changing the margins, or something else along those lines?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

The cost will be essentially the same under any tuning circumstance since its cost is directly related to the tree structure. It recomputes the bounding box of the leaf nodes based on triangle positions and works its way up, merging bounding boxes to form parent bounding boxes until it reaches the root. Are you encountering a performance issue with it, and if so, how detailed are the meshes in question (triangle count wise)?
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Re: Animated Mesh Collision (2)

Post by doggan »

It is called when a user performs a certain event, right before a raycast needs to be performed. It creates a noticeable hiccup. I will try some other options and look into time-slicing it.

I'm testing with a 13k triangle mesh, and a 2k triangle mesh. Our final collision mesh will probably be somewhere in the middle, but this will depend on what the artists can get it down to.

Both tests run perfectly on a PC build. Any chance there is an underlying floating point issue?

From your tests, what sort of data size would you expect this to run on?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

13k would definitely be pushing it; the xbox in particular will run a significant bit slower regardless. A few optimizations to the process could be made, but the speed wouldn't improve in the worst case usage. The alternative is multithreading it (usually a bit unwieldy for this kind of traversal) or otherwise timeslicing it as you mentioned.

Are these meshes representative of the whole character, or are they the detection patches?
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Re: Animated Mesh Collision (2)

Post by doggan »

It's the entire character.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

Have you attempted a strategy where simple detector volume meshes are per-vertex transformed into a proper blended location near the character? The character would then have an alternate approximate representation as well as the normal graphics.

Is your current plan actually using a StaticTriangleGroup for 'mesh perfect' collision, or is it something else?
doggan
Posts: 20
Joined: Fri Jan 09, 2009 9:26 pm

Re: Animated Mesh Collision (2)

Post by doggan »

I ended up implementing a solution that deconstructs my mesh, creates bounding volumes, re-arranges verts and indices, and dynamically creates small 'partial' TriangleMeshes of < 2k polygons each. I can then do pruning w/ bounding volumes, and call refit() only when necessary on these small mesh chunks. Works perfectly on the 360. :)

As a side note/question: I am manually managing these bounding volumes I create, and performing my raycasts on them individually (i.e. not through the physics space). In order to use these entities, though, it seems I have to add them to the physics space, and set isAlwaysActive = true. If I don't add the entity to the physics space, setting the properties of the entity (position, etc) will have no effect. So, is there any way to use Bepu entities w/o adding them to the space?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Animated Mesh Collision (2)

Post by Norbo »

I think what you are encountering is the buffered states. State properties which do not have the 'internal' prefix are buffered for thread safety and are only written/updated when the entity is updated by the space. The 'internal' prefixed properties, however, are not thread safe and so can be used to directly and immediately read/modify properties.
Post Reply