Jump to content
  • Advertisement
Sign in to follow this  
Pilpel

Software skinning for a precise AABB

This topic is 972 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've implemented frustum culling and it works great for static meshes, but skeletal animated meshes might go outside of the pre-calculated aabb (or sphere), and still get culled.

 

So the best solution I could think of is to go through all the animation sets when the model is loaded, and calculate the maximum aabb that can possibly be. 

I already do skinning in the glsl vertex shader, but software skinning sounds harder to implement.

The implementation stages I have in my head are these:

When loading a model:

1. Load all meshes. (don't dump vertices and vertex weights that are stored on the cpu yet)

2. Load all animation sets.

3. Go through all animation sets, calculate bone transforms for every key frame, and transform all the meshes' vertices.

For each key frame, calculate the entire model's AABB, and merge it with the previous AABB.

 

This should take my much time to implement, so I wanted to ask here if it sounds okay and if there's anything I'm missing.

Share this post


Link to post
Share on other sites
Advertisement
Unity solves this problem by letting the user manually set the bounding box for the skinned mesh. Perhaps before trying to make an automated solution, you could simply do that.

Share this post


Link to post
Share on other sites

That sounds like a lot of extra effort for a solution. Why check on a per bone BB. Ask yourself if that much accuracy is necessary? Perhaps a single OOBB/AABB will suffice to cover the whole animated object? A lot less cycles are wasted when checking only a single BB instead of an unknown n amount, sacrificing resolution for performance.

Share this post


Link to post
Share on other sites

Have you considered an OBB for each bone which after you transform you create an AABB from?  Both for each bone and for the whole object?  I think thats right.

Share this post


Link to post
Share on other sites
Have you considered an OBB for each bone which after you transform you create an AABB from?  Both for each bone and for the whole object?  I think thats right.

This is the common way used in all big animation system, it's computed at export time.

The second option if you know the animation list is to compute the AABB of each animation, find the bigger AABB for all animations.

The last option as said before is to set manually a bounding box.

On the second and last option you can also compute the AABB big enough to handle all rotations to avoid to transform it with the rotation of the object.

Edited by Alundra

Share this post


Link to post
Share on other sites

The AABB of the bind pose should be conservative enough to use for culling, unless the object being skinned have subobjects ( ex. tentacles ), that my extend beyond the bind pose when animated. The approach you propose would work, but you could take it a step further and probably do that at export time ( if you are using a custom format. )

Share this post


Link to post
Share on other sites

For the OBB, the export time option works good, for other option since you can retarget any animation to one skeleton, you can't know exactly what animation list will be played.

Share this post


Link to post
Share on other sites
All the listed options are incredibly slow for having many instances in real time running at the same time (except the ones that suggest baking the AABB data).
 
The best solution that is good enough for 99% of cases is to save the AABBs at different frame intervals (granted, you need to do software skinning first) store them (e.g. in the mesh file), and then linearly interpolate between those AABBs.
 
Btw sw skinning takes no sh@t time to implement, here:
 
//Parameters
const Matrix4x4 * __restrict poseMatrix;
uint8_t const  * __restrict vertexData;
size_t posStride;
size_t blendIndexStride;
size_t blendWeightStride;
size_t numVertices;
size_t bytesPerVertex;
int numWeightsPerVertex;

Vector3 max( -std::numeric_limits<float>::max() );
Vector3 min(  std::numeric_limits<float>::min() );

for( size_t i=0; i<numVertices; ++i )
{
	const Vector3 __restrict  *vPos = reinterpret_cast<const Vector3 __restrict  *>( vertexData + posStride );
	const uint8_t __restrict  *blendIndex = reinterpret_cast<const uint8_t __restrict  *>( vertexData + blendIndexStride );
	const float __restrict  *blendWeight = reinterpret_cast<const float __restrict  *>( vertexData + blendWeightStride );
	
	for( int j=0; j<numWeightsPerVertex; ++j )
	{
		const Vector3 translatedPos = poseMatrix[blendIndex[j]] * vPos;
		
		max.x = std::max( max.x, translatedPos.x );
		max.y = std::max( max.y, translatedPos.y );
		max.z = std::max( max.z, translatedPos.z );
		min.x = std::min( min.x, translatedPos.x );
		min.y = std::min( min.y, translatedPos.y );
		min.z = std::min( min.z, translatedPos.z );
	}
	vertexData += bytesPerVertex;
}
There. I wrote it in under 5 minutes. Now you have no excuse.
poseMatrix is the matrix you would normally pass to the vertex shader but without the world space component (so that the operation is done in local space). Edited by Matias Goldberg

Share this post


Link to post
Share on other sites


The best solution that is good enough for 99% of cases is to save the AABBs at different frame intervals (granted, you need to do software skinning first) store them (e.g. in the mesh file), and then linearly interpolate between those AABBs.

 

I wouldn't do that, just go for a static AABB as mentioned before.

What you can do is simply rotate your model in bind pose in some loop or so, and find the maximum AABB, this works pretty well.

 

Storing AABB's and interpolating them is really overkill, and you need to pass it around your blend trees and handle all the blending and logic in there as well then to get the right AABB. It isn't really worth it I think. Then you could also just build the bounds from the transformed obb's at the end. I doubt that is much slower than this with large blend trees involved. 

Share this post


Link to post
Share on other sites

I agree with Buckshag. Interpolation seems a bit overkill.

 

@Matias Thanks for the code snippet. Is poseMatrix the Bones[] array I pass to the vertex shader per frame?

Btw, what's up with all those __restricts and reinterpret casts? :P

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!