Scaling btBvhTriangleMeshShape

Post Reply
reltham
Posts: 66
Joined: Fri Oct 12, 2007 6:28 pm
Location: San Diego

Scaling btBvhTriangleMeshShape

Post by reltham »

Right now when you set the scale of a btBvhTriangleMeshShape it rebuilds the bvh from scratch.

Here's my issue. I have a world with many trees that are the same model just instanced around the world and with different scales. As it stands each one has it's own btBvhTriangleMeshShape in order to work correctly, because you can't do scaling in the Object transform or at the object level. I would like to share the shape amonst all of the trees (thus sharing the bvh) and just have the scale be instanced as it is with rendering.

Can someone explain why we can't have scale in the btCollisionObject transform?

Alternatively is there some way that the bvh can be shared between objects of different scales? Could the scale be handled differently such that the bvh doesn't get rebuilt?

Also, as a note, the current implenetation of setLocalScaling on btBvhTriangleMeshShape will cause a potential memory leak in the case when the bvh is not owned by the shape (aka deserialized into it). It just allocates a new bvh that will never get cleaned up. It would be nice if there was a way to use deserializing and have the shape own the bvh (take ownership via gifting).
User avatar
Erwin Coumans
Site Admin
Posts: 4232
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scaling btBvhTriangleMeshShape

Post by Erwin Coumans »

It is possible to re-use btBvhTriangleMeshShape of different scaling among several collision objects/rigid bodies. To do this, use one btTriangleIndexVertexArray and use this single instance for several btBvhTriangleMeshShape, each with a different local scaling. The mesh information will be re-used, but the BVH data will be re-created for each btBvhTriangleMeshShape. How many different scaling factors (for the trees) do you have?
reltham wrote: Can someone explain why we can't have scale in the btCollisionObject transform?
Scaling is not a rigid transformation but a deformation, so we chose not to include scaling in the rigid body world transform (there are tons of complications). Instead, most of the collision shapes support local scaling and instancing, so they can be shared.
Alternatively is there some way that the bvh can be shared between objects of different scales? Could the scale be handled differently such that the bvh doesn't get rebuilt?
Sharing a single bvh between triangle meshes of different scaling is already on the todo list, see this issue. We are looking into it, but feel free to make a contribution if you need it urgently.
Also, as a note, the current implenetation of setLocalScaling on btBvhTriangleMeshShape will cause a potential memory leak in the case when the bvh is not owned by the shape (aka deserialized into it). It just allocates a new bvh that will never get cleaned up. It would be nice if there was a way to use deserializing and have the shape own the bvh (take ownership via gifting).
Bullet has a strict rule that who creates memory is responsible to delete it, so we try to avoid 'gifting' and reference counting for now.

Thanks for the feedback,
Erwin
reltham
Posts: 66
Joined: Fri Oct 12, 2007 6:28 pm
Location: San Diego

Re: Scaling btBvhTriangleMeshShape

Post by reltham »

Thanks for the quick reply.

Just to clarify that last point, the current implementation of setLocalScaling() on btBvhTriangleMeshShape will leak memory if the bvh is not owned by the shape. It allocates a new bvh, but does not change the ownsBvh flag, so the new allocation is never freed. If I understand your desire here, it would be correct to have the scale function set the ownsBvh flag when it allocates the new one. I think it should probably also be documented that calling the scale function on the shape when it doesn't own the bvh is going to cause it to stop using the bvh you created it with and instead use a newly allocated/created one.

I just noticed that if you use the deserialize functionality, then there is no way to set the scale on the shape to what it should be to match the bvh you just deserialized into it. The normal setLocalScaling() will build a new bvh.

I will attempt to address the above two things and provide a update/patch.

I don't think I would be able to make the appropriate changes required for the issue of sharing bvh's among shapes of differing scale. I think it would take me a while to even figure out what needs to be done. Hopefully it ends up being done sometime before we ship, so I can take advantage of the memory savings.

Roy
reltham
Posts: 66
Joined: Fri Oct 12, 2007 6:28 pm
Location: San Diego

Re: Scaling btBvhTriangleMeshShape

Post by reltham »

Below are the changed functions in btBvhTriangleMeshShape that I am planning to submit to you. Is this an acceptable way to do it?
If so, then I will submit the changed cpp/h files to the google code issue tracker.

Code: Select all

// if the scale is changed and the bvh was not previosly owned, then this functions will create a new bvh and change to owning it.
// the unowned bvh is left for the owner to deal with.
void	btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling)
{
	if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON)
	{
		btTriangleMeshShape::setLocalScaling(scaling);
		if (m_ownsBvh)
		{
			m_bvh->~btOptimizedBvh();
			btAlignedFree(m_bvh);
		}
		///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work
		void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16);
		m_bvh = new(mem) btOptimizedBvh();
		//rebuild the bvh...
		m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax);
		m_ownsBvh = true;
	}
}

void	btBvhTriangleMeshShape::setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& scaling)
{
	btAssert(!m_bvh);
	btAssert(!m_ownsBvh);

	m_bvh = bvh;
	m_ownsBvh = false;
	// update the scaling without rebuilding the bvh
	if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON)
	{
		btTriangleMeshShape::setLocalScaling(scaling);
	}
}
reltham
Posts: 66
Joined: Fri Oct 12, 2007 6:28 pm
Location: San Diego

Re: Scaling btBvhTriangleMeshShape

Post by reltham »

Should I submit this change as is? Or do you have another preferred way?
kali
Posts: 1
Joined: Thu Jul 31, 2008 3:52 pm

Re: Scaling btBvhTriangleMeshShape

Post by kali »

I tried sharing a btTriangleIndexVertexArray by different btBvhTriangleMeshShape on the latest release, bullet 2.69. But changing the scaling on one of them changes the scaling on every btBvhTriangleMeshShape with the same btTriangleIndexVertexArray.

The code does support this behaviour, calling setLocalScaling on btBvhTriangleMeshShape calls setLocalScaling on it's base btTriangleMeshShape, which calls setScaling on m_meshInterface, which is exactly the shared btTriangleIndexVertexArray, so scaling is applied to all shapes sharing it.

You can however share mesh data by sharing the btIndexedMesh in btTriangleIndexVertexArray. Either by manually constructing one or more btIndexedMesh objects or extracting them from a btTriangleIndexVertexArray and creating multiple btTriangleIndexVertexArray by calling addIndexedMesh on it. If I understand correctly.
User avatar
Erwin Coumans
Site Admin
Posts: 4232
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scaling btBvhTriangleMeshShape

Post by Erwin Coumans »

reltham wrote: Below are the changed functions in btBvhTriangleMeshShape that I am planning to submit to you. Is this an acceptable way to do it?
In general it is recommended to use the googlecode issue tracker for patches. That way the patch is less likely to get lost/unnoticed. But for this occasion, the patch will be applied, thanks for the contribution.
kali wrote:You can however share mesh data by sharing the btIndexedMesh in btTriangleIndexVertexArray. Either by manually constructing one or more btIndexedMesh objects or extracting them from a btTriangleIndexVertexArray and creating multiple btTriangleIndexVertexArray by calling addIndexedMesh on it. If I understand correctly.
Indeed, you are right: each scaling needs its own btStridingMeshInterface-derived class (for example btTriangleIndexVertexArray) and btBvhTriangleMeshShape, because the scaling is stored at the btStridingMeshInterface level.

Thanks for the feedback,
Erwin
reltham
Posts: 66
Joined: Fri Oct 12, 2007 6:28 pm
Location: San Diego

Re: Scaling btBvhTriangleMeshShape

Post by reltham »

Not to be annoying, but I am curious when it's planned to make it so that the bvh data can be shared?

I am at the point in my project where I need to prebuild bvh data and store it in the level/object data. Currently I am forced to create a seperate bvh data for each object instance. This is not only wasteful of memory, but it's problematic when an artists updates an objects collision mesh because now they have to re-export the entire level instead of just that one object.

I tried looking into doing the change myself, but I am not really sure where to start. It seems like the main issue is scaling. It needs to somehow apply scaling without needing the bvh to be redone. I'm guessing this is either going to slow down things or require a significant change to how it works... but I could be wrong.

Roy
User avatar
Erwin Coumans
Site Admin
Posts: 4232
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scaling btBvhTriangleMeshShape

Post by Erwin Coumans »

reltham wrote:but I am curious when it's planned to make it so that the bvh data can be shared?
We add it for the Bullet 2.71 release. Right now, we are focussing on getting 2.70 released.
I am at the point in my project where I need to prebuild bvh data and store it in the level/object data. Currently I am forced to create a seperate bvh data for each object instance. This is not only wasteful of memory, but it's problematic when an artists updates an objects collision mesh because now they have to re-export the entire level instead of just that one object.

I tried looking into doing the change myself, but I am not really sure where to start. It seems like the main issue is scaling. It needs to somehow apply scaling without needing the bvh to be redone. I'm guessing this is either going to slow down things or require a significant change to how it works... but I could be wrong.
It is not trivial indeed. The basic idea is to create the BVH from the unscaled mesh, and perform BVH queries in 'unscaled' space. This means applying the inverse scaling to the query object.

Hope this helps,
Erwin
reltham
Posts: 66
Joined: Fri Oct 12, 2007 6:28 pm
Location: San Diego

Re: Scaling btBvhTriangleMeshShape

Post by reltham »

That is good news that it'll be in 2.71, thanks!

I can make things work for now with it the way it is, and then convert over when this feature is in and save a bunch of memory.

Roy
User avatar
jarno
Posts: 57
Joined: Tue Mar 16, 2010 1:42 am

Re: Scaling btBvhTriangleMeshShape

Post by jarno »

Resurrecting an old thread, because I just got bitten by the same scaling problem.

It appears that the problem with setting a local scale for a bt[Bvh]TriangleMeshShape still affects the scaling of the (possibly shared) mesh interface. So somewhere along the line the intended bugfix didn't make it in.

---JvdL---
User avatar
Erwin Coumans
Site Admin
Posts: 4232
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scaling btBvhTriangleMeshShape

Post by Erwin Coumans »

The btScaledBvhTriangleMeshShape is made for this purpose. Please let us know if this doesn't work for you.

Thanks,
Erwin
User avatar
jarno
Posts: 57
Joined: Tue Mar 16, 2010 1:42 am

Re: Scaling btBvhTriangleMeshShape

Post by jarno »

Oh man, I can't believe I missed that collision shape type. Yup, works as advertised. Dank U!

---JvdL---
Post Reply