World Shifting

Romain Daize
Posts: 15
Joined: Tue Jan 06, 2009 10:04 am

World Shifting

Post by Romain Daize »

Hello,

It could be very nice to add a Shift feature into the Bullet world, so this one would shift bodies silently, contact points & entire broadphase in one call without moving bodies one by one (which would remove/add non needed overlaps during shifting). I have started an implementation which shift the broadphase directly and returns discretized shifted value (as the broadphase is quantified, it does not support all shift values), contact points are shifted too. But the raycast broadphase accelerator is missing as shifting this one seems to be more complicated. Tell me if you need this peace of code so then you can add it in a future release (and correct it if needed). Perhaps I missed to update some data.

Thanks.
Romain Daize
Posts: 15
Joined: Tue Jan 06, 2009 10:04 am

Re: World Shifting

Post by Romain Daize »

ShiftWorld feature can be added to a future release ?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: World Shifting

Post by Erwin Coumans »

We welcome contributions, please keep them concise (don't change thousands lines of code).

Cheers,
Erwin
Mark J
Posts: 2
Joined: Tue Jan 05, 2010 3:23 pm

Re: World Shifting

Post by Mark J »

World Shifting is exactly the problem I've been trying to solve! Romain Daize, is there any chance I could see your solution? Is it already merged into a trunk somewhere?

Thanks!
Romain Daize
Posts: 15
Joined: Tue Jan 06, 2009 10:04 am

Re: World Shifting

Post by Romain Daize »

Hi guys,

For now I just implemented btAxisSweep3 broadphase, tell me if you have any question or if you disagree with this. I tried to add some checks in some places to ensure coherency. Maybe there is still some bugs (just by reading the code), tell me if this is the case.

Code: Select all

template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::ShiftAllObjects(btVector3 const& a_rf3ShiftDistance, btVector3& a_rf3RealShiftDistance)
{
	// Quantize the shift distance
	BP_FP_INT_TYPE i3DistanceQuant[3];
	int i3signs[3];

	QuantizeShiftDistance(i3DistanceQuant, i3signs, a_rf3ShiftDistance);

	// Compute real shift distance
	a_rf3RealShiftDistance.setValue(
		i3signs[0] > 0 ? (btScalar)(i3DistanceQuant[0]) / (m_quantize.getX()) : -(btScalar)(i3DistanceQuant[0]) / (m_quantize.getX()) ,
		i3signs[1] > 0 ? (btScalar)(i3DistanceQuant[1]) / (m_quantize.getY()) : -(btScalar)(i3DistanceQuant[1]) / (m_quantize.getY()) ,
		i3signs[2] > 0 ? (btScalar)(i3DistanceQuant[2]) / (m_quantize.getZ()) : -(btScalar)(i3DistanceQuant[2]) / (m_quantize.getZ()));

	
	// Iterate over edges, first and last edges are reserved for the sentinel and will not being shifted
	for (BP_FP_INT_TYPE axis=0; axis<3; axis++)
	{
		Edge* pCurEdge = m_pEdges[axis] + 1;
		for (BP_FP_INT_TYPE i=1; i<m_numHandles*2+1; i++)
		{	
			// Update current edge position
			BP_FP_INT_TYPE& rPos = pCurEdge->m_pos;

			// Add some checks
			#ifdef BT_DEBUG 
				btScalar fInitRealPos = (btScalar)rPos / m_quantize.m_floats[axis];
				BP_FP_INT_TYPE bEdgeType = pCurEdge->IsMax();
				btAssert(bEdgeType == 0 || bEdgeType == 1);
			#endif // BT_DEBUG

			if(i3signs[axis] < 0)
			{
				// Make sure edge won't go out of broadphase
				btAssert((rPos & m_bpHandleMask) >= i3DistanceQuant[axis]);
				btAssert((rPos & m_bpHandleMask) >= i3DistanceQuant[axis]);
				rPos = rPos - i3DistanceQuant[axis];
			}
			else
			{
				// Make sure proxy won't go out of broadphase				
				btAssert(m_handleSentinel - (rPos & m_bpHandleMask) > i3DistanceQuant[axis]);
				btAssert(m_handleSentinel - (rPos & m_bpHandleMask) > i3DistanceQuant[axis]);
				rPos = rPos + i3DistanceQuant[axis];
			}	

			btAssert(pCurEdge->IsMax() == bEdgeType);

			// Check update is valid
			#ifdef BT_DEBUG 
				btScalar fCurRealPos = (btScalar)rPos / m_quantize.m_floats[axis];
				btScalar fDist = fabsf((fInitRealPos + a_rf3RealShiftDistance.m_floats[axis]) - fCurRealPos);
				btAssert(fDist < 1e-4f);
			#endif // BT_DEBUG


			// Update handle if we finished updating all its edges
			if((pCurEdge->IsMax() == 1) && (axis == 2))
			{
				Handle* pCurHandle = getHandle(pCurEdge->m_handle);
				pCurHandle->m_aabbMin += a_rf3RealShiftDistance;
				pCurHandle->m_aabbMax += a_rf3RealShiftDistance;
			}

			// Switch to next edge
			pCurEdge++;
		}
	}
}

template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::QuantizeShiftDistance(BP_FP_INT_TYPE* a_i3Out, int* a_i3Signs, btVector3 const& a_rf3ShiftDistance) const
{
	btVector3 v = a_rf3ShiftDistance.absolute() * m_quantize;
	btAssert(v[0] >= 0.f && v[0] < m_handleSentinel);
	btAssert(v[1] >= 0.f && v[1] < m_handleSentinel);
	btAssert(v[2] >= 0.f && v[2] < m_handleSentinel);
	a_i3Out[0]=(BP_FP_INT_TYPE)v[0] & m_bpHandleMask;
	a_i3Out[1]=(BP_FP_INT_TYPE)v[1] & m_bpHandleMask;
	a_i3Out[2]=(BP_FP_INT_TYPE)v[2] & m_bpHandleMask;

	for (int i=0; i<3; i++)
	{
		a_i3Signs[i] = (a_rf3ShiftDistance[i] < 0.f) ? -1 : 1;
	}
}
Moreover you will have to shift contact points :

Code: Select all

	int iManifoldsCount = m_pCollisionDispatcherBT->getNumManifolds();
	for(int iManifold = 0; iManifold < iManifoldsCount, iManifold++)
	{
		btPersistentManifold* pManifold = m_pCollisionDispatcherBT->getManifoldByIndexInternal(iManifold);
		btAssert(pManifold != NULL);
		int iContactCount = pManifold->getNumContacts();
		for(int iContact = 0; iContact < iContactCount; iContact++)
		{
			btManifoldPoint& rContactPoint = pManifold->getContactPoint(iContact);
			rContactPoint.m_positionWorldOnA = rContactPoint.m_positionWorldOnA + f3ShiftValue;
			rContactPoint.m_positionWorldOnB = rContactPoint.m_positionWorldOnB + f3ShiftValue;
		}
	}
Tell me if I'm missing something, constraints should not need any shift (all data are in local space), but maybe I'm wrong with this.
For now I didn't add anything into Bullet source code, is there some documentation for doing this properly ? Any convention ?
I have tested this code many times and it seems to work well, for now...

Don't forget that the raycast broadphase accelerator is missing as shifting this one seems to be more complicated (I really need some help for this), so you will have to disable this feature from the broadphase: when instantiating your btAxisSweep3 broadphase, simply setup disableRaycastAccelerator to TRUE.
Mark J
Posts: 2
Joined: Tue Jan 05, 2010 3:23 pm

Re: World Shifting

Post by Mark J »

Thank Romain,

I've tried using your code to shift, but for me it doesn't appear to change bodies' positions. When I use try to use it, the only thing that happens is my bodies' collisions seem to stop.

Do I also need to manually set the position transform for all of my bodies?

Any ideas?
Romain Daize
Posts: 15
Joined: Tue Jan 06, 2009 10:04 am

Re: World Shifting

Post by Romain Daize »

Here we simply shift broadphase and contact points, but you need to shift bodies too, translate your rigid body by the real shift distance computed by ShiftAllObjects method : void btRigidBody::translate(const btVector3& v). You need to translate all others objects if any (characters, phantoms etc...)