Proper way to support holes with the hkpTriSampledHeightFieldBvTreeShape class

Proper way to support holes with the hkpTriSampledHeightFieldBvTreeShape class


I need to support holes in my heightfield data. The Havok documentation alludes to using the hkpTriSampledHeightFieldBvTreeShape class in such cases, which is what I've started to do (i.e. instantiating a hkpTriSampledHeightFieldBvTreeShape around a hkpTriSampledHeightfieldCollection around a hkpSampledHeightFieldShape). I need my heightfield holes to be respected by both character proxies moving around on the terrain, and by ray and shape casts executed against the Havok world (aabbPhantoms, etc).

I think I've been able to make character proxies respect the hole data by overriding "hkpTriSampledHeightFieldBvTreeShape::queryAabb(const hkAabb& aabb, hkArray& hits)", such that I allow the hkpTriSampledHeightFieldBvTreeShape's version of this method to execute, and then prune hits from the returned hkArray if those hits overlap my hole data.

However, I'm not sure what approach to take to make sure that ray and shape casts also behave properly. I thought that if I installed my own custom filter into the Havok world, I could override hkpCollisionFilter::isCollisionEnabled(const hkpShapeRayCastInput& aInput, const hkpShape& bShape ... ) to return false if the shape was a heightfield and the shapeKey overlapped my hole data. However, that particular isCollisionEnabled method never seems to be called. I also thought to try overriding hkpTriSampledHeightFieldBvTreeShape::castRayImpl to somehow set the m_rayShapeCollectionFilter in the hkpShapeRayCastInput, but again, my collectionFilter's isCollisionEnabled method does not seem to get called.

In short, looking for a little guidance on where/how I can filter out per-triangle hits for my TriSampled heightfield, and would also like to know if there's a cleaner approach than what I did to make character proxies respect my heightfield hole data.

Thanks for reading, any help much appreciated.

6 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

To append to my earlier post, I'm realizing that the "isCollisionEnabled" methods I mentioned above are probably called only when parsing the individual shapes in a shapeCollection (listShape, ec), and not when parsing the individual triangles that comprise a single shape.

An alternate approach would be to make my inherited version of hkpTriSampledHeightFieldBvTreeShape::castRayImpl create a hkpRayHitCollector on the stack, call hkpTriSampledHeightFieldBvTreeShape::castRayWithCollector, and then flip through the collector results, manually keeping track of the closest result whose "extraInfo" field (for a heightfield, the (x,z) pair) does not overlap my hole data. I feel like I'm ignoring something obvious about how triSampled heightfields are supposed to be used, but I'm having trouble understanding if some more elegant callback is available to me.

As before, any info appreciated, thanks.

Hi Rahul,

You're definitely on the right track. But I think instead of changing the collision filter itself, you'd want to override hkpShapeContainer::getCollisionFilterInfo your heightfield shape, to return a filterInfo that collides with nothing for the "hole" triangles.

I tried this myself a year or two ago, and the collision filtering and queryAabb approaches were the two that I came up with. I'll see if I can resurrect my old demo sometime soon. My gut feeling is that the queryAabb one will perform a bit better, since it will prune subshapes out earlier in the collision pipeline than filtering will.

You're also correct that neither of these will probably work for raycasting. The function that does the actual heightfield raycasting, hkpSampledHeightFieldShape::castRayInternal, has no concept of shape keys - it doesn't deal with any of the shape collection interface; all it knows about is a bunch of height values.

I know a few weeks ago, you were talking about implementing your own versions of hkpTriSampledHeightfieldBvTree/Collection for doing the diamond tesselation. Did you get those working? It is possible to add support for this to your classes?


Hey Chris,

Just wanted to finally follow up on this; I did end up rolling my own heightfield traversal algorithm for raycasting, to solve both the diamond tessellation and hole requirements for raycating against heightfields. I'm integrating it by overriding the castRayImpl and CastRayWithCollector methods of the hkpTriSampledHeightFieldBvTreeShape class. Seems to get me what I need.

Thanks for the advice,


Hi Rahul,

Glad you got it working. Out of curiosity, what's the performance difference between your raycasting implementation and ours?


Hey Chris,

The performance of my stuff does degrade to maybe 4-5x slower for a long raycast that (at a very rough estimate) spans the length of one of my heightfields, where the heightfield is a square grid with 129 heightposts to an edge. At a guess, I'm probably doing some excessive floating-point math that I could maybe trim down.

In practice, most of our raycasts will be relatively short, and so the difference is smaller, maybe a .01-.02 ms difference for a ray that spans ~20 quads. And of course there is the extra work to query hole and triangle flip data on a per-quad basis.

Thanks, -RG

Leave a Comment

Please sign in to add a comment. Not a member? Join today