|
bool PhysicsServerCommandProcessor::processRemoveBodyCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) |
|
{ |
|
bool hasStatus = true; |
|
|
|
SharedMemoryStatus& serverCmd = serverStatusOut; |
|
serverCmd.m_type = CMD_REMOVE_BODY_FAILED; |
|
serverCmd.m_removeObjectArgs.m_numBodies = 0; |
|
serverCmd.m_removeObjectArgs.m_numUserConstraints = 0; |
|
|
|
m_data->m_guiHelper->setVisualizerFlag(COV_ENABLE_SYNC_RENDERING_INTERNAL, 0); |
|
|
|
for (int i = 0; i < clientCmd.m_removeObjectArgs.m_numBodies; i++) |
|
{ |
|
int bodyUniqueId = clientCmd.m_removeObjectArgs.m_bodyUniqueIds[i]; |
|
InternalBodyHandle* bodyHandle = m_data->m_bodyHandles.getHandle(bodyUniqueId); |
|
if (bodyHandle) |
|
{ |
|
#ifndef USE_DISCRETE_DYNAMICS_WORLD |
|
if (bodyHandle->m_multiBody) |
|
{ |
|
serverCmd.m_removeObjectArgs.m_bodyUniqueIds[serverCmd.m_removeObjectArgs.m_numBodies++] = bodyUniqueId; |
|
|
|
if (m_data->m_pickingMultiBodyPoint2Point && m_data->m_pickingMultiBodyPoint2Point->getMultiBodyA() == bodyHandle->m_multiBody) |
|
{ |
|
//memory will be deleted in the code that follows |
|
m_data->m_pickingMultiBodyPoint2Point = 0; |
|
} |
|
|
|
//also remove user constraints... |
|
for (int i = m_data->m_dynamicsWorld->getNumMultiBodyConstraints() - 1; i >= 0; i--) |
|
{ |
|
btMultiBodyConstraint* mbc = m_data->m_dynamicsWorld->getMultiBodyConstraint(i); |
|
if ((mbc->getMultiBodyA() == bodyHandle->m_multiBody) || (mbc->getMultiBodyB() == bodyHandle->m_multiBody)) |
|
{ |
|
m_data->m_dynamicsWorld->removeMultiBodyConstraint(mbc); |
|
|
|
//also remove user constraint and submit it as removed |
|
for (int c = m_data->m_userConstraints.size() - 1; c >= 0; c--) |
|
{ |
|
InteralUserConstraintData* userConstraintPtr = m_data->m_userConstraints.getAtIndex(c); |
|
int userConstraintKey = m_data->m_userConstraints.getKeyAtIndex(c).getUid1(); |
|
|
|
if (userConstraintPtr->m_mbConstraint == mbc) |
|
{ |
|
m_data->m_userConstraints.remove(userConstraintKey); |
|
serverCmd.m_removeObjectArgs.m_userConstraintUniqueIds[serverCmd.m_removeObjectArgs.m_numUserConstraints++] = userConstraintKey; |
|
} |
|
} |
|
|
|
delete mbc; |
|
} |
|
} |
|
|
|
if (bodyHandle->m_multiBody->getBaseCollider()) |
|
{ |
|
if (m_data->m_pluginManager.getRenderInterface()) |
|
{ |
|
m_data->m_pluginManager.getRenderInterface()->removeVisualShape(bodyHandle->m_multiBody->getBaseCollider()->getUserIndex3()); |
|
} |
|
m_data->m_dynamicsWorld->removeCollisionObject(bodyHandle->m_multiBody->getBaseCollider()); |
|
int graphicsIndex = bodyHandle->m_multiBody->getBaseCollider()->getUserIndex(); |
|
m_data->m_guiHelper->removeGraphicsInstance(graphicsIndex); |
|
delete bodyHandle->m_multiBody->getBaseCollider(); |
|
} |
|
for (int link = 0; link < bodyHandle->m_multiBody->getNumLinks(); link++) |
|
{ |
|
btCollisionObject* colObj = bodyHandle->m_multiBody->getLink(link).m_collider; |
|
if (colObj) |
|
{ |
|
if (m_data->m_pluginManager.getRenderInterface()) |
|
{ |
|
m_data->m_pluginManager.getRenderInterface()->removeVisualShape(bodyHandle->m_multiBody->getLink(link).m_collider->getUserIndex3()); |
|
} |
|
m_data->m_dynamicsWorld->removeCollisionObject(bodyHandle->m_multiBody->getLink(link).m_collider); |
|
int graphicsIndex = bodyHandle->m_multiBody->getLink(link).m_collider->getUserIndex(); |
|
m_data->m_guiHelper->removeGraphicsInstance(graphicsIndex); |
|
delete colObj; |
|
} |
|
} |
|
int numCollisionObjects = m_data->m_dynamicsWorld->getNumCollisionObjects(); |
|
m_data->m_dynamicsWorld->removeMultiBody(bodyHandle->m_multiBody); |
|
numCollisionObjects = m_data->m_dynamicsWorld->getNumCollisionObjects(); |
|
|
|
delete bodyHandle->m_multiBody; |
|
bodyHandle->m_multiBody = 0; |
|
serverCmd.m_type = CMD_REMOVE_BODY_COMPLETED; |
|
} |
|
#endif |
|
if (bodyHandle->m_rigidBody) |
|
{ |
|
if (m_data->m_pluginManager.getRenderInterface()) |
|
{ |
|
m_data->m_pluginManager.getRenderInterface()->removeVisualShape(bodyHandle->m_rigidBody->getUserIndex3()); |
|
} |
|
serverCmd.m_removeObjectArgs.m_bodyUniqueIds[serverCmd.m_removeObjectArgs.m_numBodies++] = bodyUniqueId; |
|
|
|
if (m_data->m_pickedConstraint && m_data->m_pickedBody == bodyHandle->m_rigidBody) |
|
{ |
|
m_data->m_pickedConstraint = 0; |
|
m_data->m_pickedBody = 0; |
|
} |
|
|
|
//todo: clear all other remaining data... |
|
m_data->m_dynamicsWorld->removeRigidBody(bodyHandle->m_rigidBody); |
|
int graphicsInstance = bodyHandle->m_rigidBody->getUserIndex2(); |
|
m_data->m_guiHelper->removeGraphicsInstance(graphicsInstance); |
|
delete bodyHandle->m_rigidBody; |
|
bodyHandle->m_rigidBody = 0; |
|
serverCmd.m_type = CMD_REMOVE_BODY_COMPLETED; |
|
} |
Environment
bulletphysics/bullet3masterat63c4d67e337017f9d8b298c900e9aabdb69296e7Description
Removing a maximal-coordinate rigid body does not remove
btTypedConstraintobjects orm_userConstraintsentries that reference it. The multibody branch performs this cleanup, but the rigid-body branch deletes the body after a//todo: clear all other remaining data...comment.Expected behavior:
removeBodyremoves constraints whose endpoint is the removed body, just as the multibody path does.Actual behavior: stepping immediately after removal exits with status 139. If a replacement rigid body is allocated first, the retained fixed constraint silently binds the replacement: a body created at x=5 moves to x=4.5 and its peer moves from x=1 to x=1.5. Removing the constraint before the body is a clean control and leaves both positions unchanged.
Source:
bullet3/examples/SharedMemory/PhysicsServerCommandProcessor.cpp
Lines 12739 to 12848 in 63c4d67
Reproduction package:
rigid-body-removal-constraint-cleanup-poc.zip
Steps to reproduce
poc/README.md.control,dangling, andreusemodes in separate processes.poc/observed-output.txt.