summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerwincoumans <erwin.coumans@gmail.com>2023-02-24 10:54:03 -0800
committerGitHub <noreply@github.com>2023-02-24 10:54:03 -0800
commit0e59474e1cf1fd69e3ca512826cfbe15cd6a9cec (patch)
tree593ed49f85b6478f536cfe9118d1f2e99597f3bc
parentc037d9ba279d74c7e7437a700763892a6ba75760 (diff)
parente323404ac393aeb834a3f8f21549e119c76b67ff (diff)
downloadbullet3-0e59474e1cf1fd69e3ca512826cfbe15cd6a9cec.tar.gz
Merge pull request #4413 from aprilprojecteu/master
re-enable softbody/rigidbody contact report
-rw-r--r--examples/SharedMemory/PhysicsClient.h2
-rw-r--r--examples/SharedMemory/PhysicsClientC_API.cpp39
-rw-r--r--examples/SharedMemory/PhysicsClientC_API.h3
-rw-r--r--examples/SharedMemory/PhysicsClientSharedMemory.cpp28
-rw-r--r--examples/SharedMemory/PhysicsClientSharedMemory.h2
-rw-r--r--examples/SharedMemory/PhysicsDirect.cpp12
-rw-r--r--examples/SharedMemory/PhysicsDirect.h2
-rw-r--r--examples/SharedMemory/PhysicsLoopBack.cpp5
-rw-r--r--examples/SharedMemory/PhysicsLoopBack.h2
-rw-r--r--examples/SharedMemory/PhysicsServerCommandProcessor.cpp188
-rw-r--r--examples/SharedMemory/PhysicsServerCommandProcessor.h1
-rw-r--r--examples/SharedMemory/SharedMemoryCommands.h10
-rw-r--r--examples/SharedMemory/SharedMemoryPublic.h16
-rw-r--r--examples/pybullet/pybullet.c61
-rw-r--r--src/BulletSoftBody/btDeformableContactConstraint.cpp5
-rw-r--r--src/BulletSoftBody/btSoftBody.h10
16 files changed, 339 insertions, 47 deletions
diff --git a/examples/SharedMemory/PhysicsClient.h b/examples/SharedMemory/PhysicsClient.h
index 33c139ef1..8fc863f27 100644
--- a/examples/SharedMemory/PhysicsClient.h
+++ b/examples/SharedMemory/PhysicsClient.h
@@ -67,6 +67,8 @@ public:
virtual void getCachedMeshData(struct b3MeshData* meshData) = 0;
+ virtual void getCachedTetraMeshData(struct b3TetraMeshData* meshData) = 0;
+
virtual void getCachedVREvents(struct b3VREventsData* vrEventsData) = 0;
virtual void getCachedKeyboardEvents(struct b3KeyboardEventsData* keyboardEventsData) = 0;
diff --git a/examples/SharedMemory/PhysicsClientC_API.cpp b/examples/SharedMemory/PhysicsClientC_API.cpp
index ae6015da4..71bdd5c54 100644
--- a/examples/SharedMemory/PhysicsClientC_API.cpp
+++ b/examples/SharedMemory/PhysicsClientC_API.cpp
@@ -1525,6 +1525,24 @@ B3_SHARED_API b3SharedMemoryCommandHandle b3GetMeshDataCommandInit(b3PhysicsClie
return 0;
}
+B3_SHARED_API b3SharedMemoryCommandHandle b3GetTetraMeshDataCommandInit(b3PhysicsClientHandle physClient, int bodyUniqueId)
+{
+ PhysicsClient* cl = (PhysicsClient*)physClient;
+ b3Assert(cl);
+ b3Assert(cl->canSubmitCommand());
+ if (cl)
+ {
+ struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand();
+ b3Assert(command);
+ command->m_type = CMD_REQUEST_TETRA_MESH_DATA;
+ command->m_updateFlags = 0;
+ command->m_resetTetraMeshDataArgs.m_startingVertex = 0;
+ command->m_resetTetraMeshDataArgs.m_bodyUniqueId = bodyUniqueId;
+ return (b3SharedMemoryCommandHandle)command;
+ }
+ return 0;
+}
+
B3_SHARED_API void b3GetMeshDataSetCollisionShapeIndex(b3SharedMemoryCommandHandle commandHandle, int shapeIndex)
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle;
@@ -1549,6 +1567,18 @@ B3_SHARED_API void b3GetMeshDataSetFlags(b3SharedMemoryCommandHandle commandHand
}
}
+B3_SHARED_API void b3GetTetraMeshDataSetFlags(b3SharedMemoryCommandHandle commandHandle, int flags)
+{
+ struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle;
+ b3Assert(command);
+ b3Assert(command->m_type == CMD_REQUEST_TETRA_MESH_DATA);
+ if (command->m_type == CMD_REQUEST_TETRA_MESH_DATA)
+ {
+ command->m_updateFlags = B3_TETRA_MESH_DATA_FLAGS;
+ command->m_requestMeshDataArgs.m_flags = flags;
+ }
+}
+
B3_SHARED_API void b3GetMeshDataSimulationMesh(b3SharedMemoryCommandHandle commandHandle)
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle;
@@ -1574,6 +1604,15 @@ B3_SHARED_API void b3GetMeshData(b3PhysicsClientHandle physClient, struct b3Mesh
}
}
+B3_SHARED_API void b3GetTetraMeshData(b3PhysicsClientHandle physClient, struct b3TetraMeshData* meshData)
+{
+ PhysicsClient* cl = (PhysicsClient*)physClient;
+ if (cl)
+ {
+ cl->getCachedTetraMeshData(meshData);
+ }
+}
+
B3_SHARED_API int b3CreateVisualShapeAddSphere(b3SharedMemoryCommandHandle commandHandle, double radius)
{
return b3CreateCollisionShapeAddSphere(commandHandle, radius);
diff --git a/examples/SharedMemory/PhysicsClientC_API.h b/examples/SharedMemory/PhysicsClientC_API.h
index e73930b58..563272942 100644
--- a/examples/SharedMemory/PhysicsClientC_API.h
+++ b/examples/SharedMemory/PhysicsClientC_API.h
@@ -533,12 +533,15 @@ extern "C"
B3_SHARED_API b3SharedMemoryCommandHandle b3InitRemoveCollisionShapeCommand(b3PhysicsClientHandle physClient, int collisionShapeId);
B3_SHARED_API b3SharedMemoryCommandHandle b3GetMeshDataCommandInit(b3PhysicsClientHandle physClient, int bodyUniqueId, int linkIndex);
+ B3_SHARED_API b3SharedMemoryCommandHandle b3GetTetraMeshDataCommandInit(b3PhysicsClientHandle physClient, int bodyUniqueId);
B3_SHARED_API void b3GetMeshDataSimulationMesh(b3SharedMemoryCommandHandle commandHandle);
B3_SHARED_API void b3MeshDataSimulationMeshVelocity(b3SharedMemoryCommandHandle commandHandle);
B3_SHARED_API void b3GetMeshDataSetCollisionShapeIndex(b3SharedMemoryCommandHandle commandHandle, int shapeIndex);
B3_SHARED_API void b3GetMeshDataSetFlags(b3SharedMemoryCommandHandle commandHandle, int flags);
+ B3_SHARED_API void b3GetTetraMeshDataSetFlags(b3SharedMemoryCommandHandle commandHandle, int flags);
B3_SHARED_API void b3GetMeshData(b3PhysicsClientHandle physClient, struct b3MeshData* meshData);
+ B3_SHARED_API void b3GetTetraMeshData(b3PhysicsClientHandle physClient, struct b3TetraMeshData* meshData);
B3_SHARED_API b3SharedMemoryCommandHandle b3ResetMeshDataCommandInit(b3PhysicsClientHandle physClient, int bodyUniqueId, int num_vertices, const double* vertices);
diff --git a/examples/SharedMemory/PhysicsClientSharedMemory.cpp b/examples/SharedMemory/PhysicsClientSharedMemory.cpp
index 3512fe3ef..1d8d966a7 100644
--- a/examples/SharedMemory/PhysicsClientSharedMemory.cpp
+++ b/examples/SharedMemory/PhysicsClientSharedMemory.cpp
@@ -54,6 +54,7 @@ struct PhysicsClientSharedMemoryInternalData
btAlignedObjectArray<b3CollisionShapeData> m_cachedCollisionShapes;
b3MeshData m_cachedMeshData;
+ b3TetraMeshData m_cachedTetraMeshData;
btAlignedObjectArray<b3MeshVertex> m_cachedVertexPositions;
btAlignedObjectArray<b3VRControllerEvent> m_cachedVREvents;
@@ -1074,6 +1075,24 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus()
b3Warning("Request mesh data failed");
break;
}
+ case CMD_REQUEST_TETRA_MESH_DATA_COMPLETED:
+ {
+ m_data->m_cachedVertexPositions.resize(serverCmd.m_sendMeshDataArgs.m_startingVertex + serverCmd.m_sendMeshDataArgs.m_numVerticesCopied);
+ btVector3* verticesReceived = (btVector3*)m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor;
+ for (int i = 0; i < serverCmd.m_sendMeshDataArgs.m_numVerticesCopied; i++)
+ {
+ m_data->m_cachedVertexPositions[i + serverCmd.m_sendMeshDataArgs.m_startingVertex].x = verticesReceived[i].x();
+ m_data->m_cachedVertexPositions[i + serverCmd.m_sendMeshDataArgs.m_startingVertex].y = verticesReceived[i].y();
+ m_data->m_cachedVertexPositions[i + serverCmd.m_sendMeshDataArgs.m_startingVertex].z = verticesReceived[i].z();
+ m_data->m_cachedVertexPositions[i + serverCmd.m_sendMeshDataArgs.m_startingVertex].w = verticesReceived[i].w();
+ }
+ break;
+ }
+ case CMD_REQUEST_TETRA_MESH_DATA_FAILED:
+ {
+ b3Warning("Request tetra mesh data failed");
+ break;
+ }
case CMD_CALCULATED_INVERSE_DYNAMICS_COMPLETED:
{
break;
@@ -2088,6 +2107,15 @@ void PhysicsClientSharedMemory::getCachedMeshData(struct b3MeshData* meshData)
*meshData = m_data->m_cachedMeshData;
}
+void PhysicsClientSharedMemory::getCachedTetraMeshData(struct b3TetraMeshData* meshData)
+{
+ m_data->m_cachedTetraMeshData.m_numVertices = m_data->m_cachedVertexPositions.size();
+
+ m_data->m_cachedTetraMeshData.m_vertices = m_data->m_cachedTetraMeshData.m_numVertices ? &m_data->m_cachedVertexPositions[0] : 0;
+
+ *meshData = m_data->m_cachedTetraMeshData;
+}
+
const float* PhysicsClientSharedMemory::getDebugLinesFrom() const
{
if (m_data->m_debugLinesFrom.size())
diff --git a/examples/SharedMemory/PhysicsClientSharedMemory.h b/examples/SharedMemory/PhysicsClientSharedMemory.h
index f1a67c525..cf9113c6d 100644
--- a/examples/SharedMemory/PhysicsClientSharedMemory.h
+++ b/examples/SharedMemory/PhysicsClientSharedMemory.h
@@ -80,6 +80,8 @@ public:
virtual void getCachedMeshData(struct b3MeshData* meshData);
+ virtual void getCachedTetraMeshData(struct b3TetraMeshData* meshData);
+
virtual void getCachedVREvents(struct b3VREventsData* vrEventsData);
virtual void getCachedKeyboardEvents(struct b3KeyboardEventsData* keyboardEventsData);
diff --git a/examples/SharedMemory/PhysicsDirect.cpp b/examples/SharedMemory/PhysicsDirect.cpp
index a8aa72a60..f12057ae0 100644
--- a/examples/SharedMemory/PhysicsDirect.cpp
+++ b/examples/SharedMemory/PhysicsDirect.cpp
@@ -67,6 +67,7 @@ struct PhysicsDirectInternalData
btAlignedObjectArray<b3CollisionShapeData> m_cachedCollisionShapes;
b3MeshData m_cachedMeshData;
+ b3TetraMeshData m_cachedTetraMeshData;
btAlignedObjectArray<b3MeshVertex> m_cachedVertexPositions;
btAlignedObjectArray<b3VRControllerEvent> m_cachedVREvents;
@@ -99,6 +100,7 @@ struct PhysicsDirectInternalData
m_timeOutInSeconds(1e30)
{
memset(&m_cachedMeshData.m_numVertices, 0, sizeof(b3MeshData));
+ memset(&m_cachedTetraMeshData.m_numVertices, 0, sizeof(b3TetraMeshData));
memset(&m_command, 0, sizeof(m_command));
memset(&m_serverStatus, 0, sizeof(m_serverStatus));
memset(m_bulletStreamDataServerToClient, 0, sizeof(m_bulletStreamDataServerToClient));
@@ -1691,6 +1693,16 @@ void PhysicsDirect::getCachedMeshData(struct b3MeshData* meshData)
*meshData = m_data->m_cachedMeshData;
}
+void PhysicsDirect::getCachedTetraMeshData(struct b3TetraMeshData* meshData)
+{
+ m_data->m_cachedTetraMeshData.m_numVertices = m_data->m_cachedVertexPositions.size();
+
+ m_data->m_cachedTetraMeshData.m_vertices = m_data->m_cachedTetraMeshData.m_numVertices ? &m_data->m_cachedVertexPositions[0] : 0;
+
+ *meshData = m_data->m_cachedTetraMeshData;
+}
+
+
void PhysicsDirect::getCachedContactPointInformation(struct b3ContactInformation* contactPointData)
{
contactPointData->m_numContactPoints = m_data->m_cachedContactPoints.size();
diff --git a/examples/SharedMemory/PhysicsDirect.h b/examples/SharedMemory/PhysicsDirect.h
index 0d33f8119..441b58e74 100644
--- a/examples/SharedMemory/PhysicsDirect.h
+++ b/examples/SharedMemory/PhysicsDirect.h
@@ -106,6 +106,8 @@ public:
virtual void getCachedMeshData(struct b3MeshData* meshData);
+ virtual void getCachedTetraMeshData(struct b3TetraMeshData* meshData);
+
virtual void getCachedVREvents(struct b3VREventsData* vrEventsData);
virtual void getCachedKeyboardEvents(struct b3KeyboardEventsData* keyboardEventsData);
diff --git a/examples/SharedMemory/PhysicsLoopBack.cpp b/examples/SharedMemory/PhysicsLoopBack.cpp
index 58e4d59c7..427da31e8 100644
--- a/examples/SharedMemory/PhysicsLoopBack.cpp
+++ b/examples/SharedMemory/PhysicsLoopBack.cpp
@@ -183,6 +183,11 @@ void PhysicsLoopBack::getCachedMeshData(struct b3MeshData* meshData)
return m_data->m_physicsClient->getCachedMeshData(meshData);
}
+void PhysicsLoopBack::getCachedTetraMeshData(struct b3TetraMeshData* meshData)
+{
+ return m_data->m_physicsClient->getCachedTetraMeshData(meshData);
+}
+
void PhysicsLoopBack::getCachedContactPointInformation(struct b3ContactInformation* contactPointData)
{
return m_data->m_physicsClient->getCachedContactPointInformation(contactPointData);
diff --git a/examples/SharedMemory/PhysicsLoopBack.h b/examples/SharedMemory/PhysicsLoopBack.h
index 4626aac81..2b6eb87f2 100644
--- a/examples/SharedMemory/PhysicsLoopBack.h
+++ b/examples/SharedMemory/PhysicsLoopBack.h
@@ -78,6 +78,8 @@ public:
virtual void getCachedMeshData(struct b3MeshData* meshData);
+ virtual void getCachedTetraMeshData(struct b3TetraMeshData* meshData);
+
virtual void getCachedVREvents(struct b3VREventsData* vrEventsData);
virtual void getCachedKeyboardEvents(struct b3KeyboardEventsData* keyboardEventsData);
diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp
index 8275451ed..1d691c550 100644
--- a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp
+++ b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp
@@ -2802,7 +2802,7 @@ void PhysicsServerCommandProcessor::createEmptyDynamicsWorld(int flags)
m_data->m_dynamicsWorld->getSolverInfo().m_frictionERP = 0.2; //need to check if there are artifacts with frictionERP
m_data->m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.00001;
m_data->m_dynamicsWorld->getSolverInfo().m_numIterations = 50;
- if (flags & RESET_USE_REDUCED_DEFORMABLE_WORLD)
+ if (flags & RESET_USE_REDUCED_DEFORMABLE_WORLD)
{
m_data->m_dynamicsWorld->getSolverInfo().m_minimumSolverBatchSize = 128;
}
@@ -5677,7 +5677,8 @@ bool PhysicsServerCommandProcessor::processRequestMeshDataCommand(const struct S
separateRenderMesh = (psb->m_renderNodes.size() != 0);
}
bool requestVelocity = clientCmd.m_updateFlags & B3_MESH_DATA_SIMULATION_MESH_VELOCITY;
-
+
+
int numVertices = separateRenderMesh ? psb->m_renderNodes.size() : psb->m_nodes.size();
int maxNumVertices = bufferSizeInBytes / totalBytesPerVertex - 1;
int numVerticesRemaining = numVertices - clientCmd.m_requestMeshDataArgs.m_startingVertex;
@@ -5704,6 +5705,8 @@ bool PhysicsServerCommandProcessor::processRequestMeshDataCommand(const struct S
}
}
}
+
+
sizeInBytes = verticesCopied * sizeof(btVector3);
serverStatusOut.m_type = CMD_REQUEST_MESH_DATA_COMPLETED;
serverStatusOut.m_sendMeshDataArgs.m_numVerticesCopied = verticesCopied;
@@ -5718,6 +5721,51 @@ bool PhysicsServerCommandProcessor::processRequestMeshDataCommand(const struct S
return hasStatus;
}
+bool PhysicsServerCommandProcessor::processRequestTetraMeshDataCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
+{
+ bool hasStatus = true;
+ BT_PROFILE("CMD_REQUEST_TETRA_MESH_DATA");
+ serverStatusOut.m_type = CMD_REQUEST_TETRA_MESH_DATA_FAILED;
+ serverStatusOut.m_numDataStreamBytes = 0;
+ int sizeInBytes = 0;
+
+ InternalBodyHandle* bodyHandle = m_data->m_bodyHandles.getHandle(clientCmd.m_resetTetraMeshDataArgs.m_bodyUniqueId);
+ if (bodyHandle)
+ {
+ int totalBytesPerVertex = sizeof(btVector3);
+ btVector3* verticesOut = (btVector3*)bufferServerToClient;
+ const btCollisionShape* colShape = 0;
+
+ if (bodyHandle->m_softBody)
+ {
+ btSoftBody* psb = bodyHandle->m_softBody;
+
+ int numTetra = psb->m_tetras.size();
+ int maxNumnumVertecies = bufferSizeInBytes / totalBytesPerVertex - 1;
+ int numVerticesRemaining = numTetra * 4;
+ int verticesCopied = btMin(maxNumnumVertecies, numVerticesRemaining);
+ for (int i = 0; i < verticesCopied; i += 4)
+ {
+ const btSoftBody::Tetra& n = psb->m_tetras[i/4];
+ verticesOut[i].setValue(n.m_n[0]->m_x.x(), n.m_n[0]->m_x.y(), n.m_n[0]->m_x.z());
+ verticesOut[i+1].setValue(n.m_n[1]->m_x.x(), n.m_n[1]->m_x.y(), n.m_n[1]->m_x.z());
+ verticesOut[i+2].setValue(n.m_n[2]->m_x.x(), n.m_n[2]->m_x.y(), n.m_n[2]->m_x.z());
+ verticesOut[i+3].setValue(n.m_n[3]->m_x.x(), n.m_n[3]->m_x.y(), n.m_n[3]->m_x.z());
+ }
+
+ sizeInBytes = verticesCopied * sizeof(btVector3);
+ serverStatusOut.m_type = CMD_REQUEST_TETRA_MESH_DATA_COMPLETED;
+ serverStatusOut.m_sendMeshDataArgs.m_numVerticesCopied = verticesCopied;
+ serverStatusOut.m_sendMeshDataArgs.m_startingVertex = clientCmd.m_requestMeshDataArgs.m_startingVertex;
+ serverStatusOut.m_sendMeshDataArgs.m_numVerticesRemaining = numVerticesRemaining - verticesCopied;
+ }
+ }
+
+ serverStatusOut.m_numDataStreamBytes = sizeInBytes;
+
+ return hasStatus;
+}
+
bool PhysicsServerCommandProcessor::processCreateVisualShapeCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
{
bool hasStatus = true;
@@ -8187,7 +8235,7 @@ bool PhysicsServerCommandProcessor::processRequestActualStateCommand(const struc
}
bool RequestFiltered(const struct SharedMemoryCommand& clientCmd, int& linkIndexA, int& linkIndexB, int& objectIndexA, int& objectIndexB, bool& swap){
-
+
if (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter >= 0)
{
if (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter == objectIndexA)
@@ -8232,7 +8280,7 @@ bool RequestFiltered(const struct SharedMemoryCommand& clientCmd, int& linkIndex
{
return true;
}
-
+
return false;
}
@@ -8313,21 +8361,26 @@ bool PhysicsServerCommandProcessor::processRequestDeformableContactpointHelper(c
{
return false;
}
- int numSoftbodyContact = 0;
- for (int i = deformWorld->getSoftBodyArray().size() - 1; i >= 0; i--)
- {
- numSoftbodyContact += deformWorld->getSoftBodyArray()[i]->m_faceRigidContacts.size();
- }
- int num_contact_points = m_data->m_cachedContactPoints.size();
- m_data->m_cachedContactPoints.reserve(num_contact_points + numSoftbodyContact);
for (int i = deformWorld->getSoftBodyArray().size() - 1; i >= 0; i--)
{
btSoftBody* psb = deformWorld->getSoftBodyArray()[i];
+ btAlignedObjectArray<b3ContactPointData> distinctContactPoints;
+ btAlignedObjectArray<btSoftBody::Node*> nodesInContact;
for (int c = 0; c < psb->m_faceRigidContacts.size(); c++)
{
const btSoftBody::DeformableFaceRigidContact* contact = &psb->m_faceRigidContacts[c];
- //convert rigidbody contact
+ // calculate normal and tangent impulse
+ btVector3 impulse = contact->m_cti.m_impulse;
+ btVector3 impulseNormal = impulse.dot(contact->m_cti.m_normal) * contact->m_cti.m_normal;
+ btVector3 impulseTangent = impulse - impulseNormal;
+ // get node in contact
+ int contactNodeIdx = contact->m_bary.maxAxis();
+ btSoftBody::Node* node = contact->m_face->m_n[contactNodeIdx];
+ // check if node is already in the list
+ int idx = nodesInContact.findLinearSearch2(node);
+
+ //apply the filter, if the user provides it
int linkIndexA = -1;
int linkIndexB = -1;
int objectIndexA = psb->getUserIndex2();
@@ -8344,8 +8397,6 @@ bool PhysicsServerCommandProcessor::processRequestDeformableContactpointHelper(c
linkIndexB = mblB->m_link;
objectIndexB = mblB->m_multiBody->getUserIndex2();
}
-
- //apply the filter, if the user provides it
bool swap = false;
if (clientCmd.m_requestContactPointArguments.m_objectAIndexFilter >= 0)
{
@@ -8391,37 +8442,87 @@ bool PhysicsServerCommandProcessor::processRequestDeformableContactpointHelper(c
{
continue;
}
- b3ContactPointData pt;
- pt.m_bodyUniqueIdA = objectIndexA;
- pt.m_bodyUniqueIdB = objectIndexB;
- pt.m_contactDistance = contact->m_cti.m_offset;
- pt.m_contactFlags = 0;
- pt.m_linkIndexA = linkIndexA;
- pt.m_linkIndexB = linkIndexB;
- for (int j = 0; j < 3; j++)
+
+ if (idx < 0)
{
- if (swap)
+ // add new node and contact point
+ nodesInContact.push_back(node);
+ b3ContactPointData pt;
+ pt.m_bodyUniqueIdA = objectIndexA;
+ pt.m_bodyUniqueIdB = objectIndexB;
+ pt.m_contactDistance = -contact->m_cti.m_offset;
+ pt.m_contactFlags = 0;
+ pt.m_linkIndexA = linkIndexA;
+ pt.m_linkIndexB = linkIndexB;
+ for (int j = 0; j < 3; j++)
{
- pt.m_contactNormalOnBInWS[j] = -contact->m_cti.m_normal[j];
- pt.m_positionOnAInWS[j] = contact->m_cti.m_normal[j];
- pt.m_positionOnBInWS[j] = -contact->m_cti.m_normal[j];
+ if (swap)
+ {
+ pt.m_contactNormalOnBInWS[j] = -contact->m_cti.m_normal[j];
+ pt.m_positionOnAInWS[j] = node->m_x[j] - pt.m_contactDistance * pt.m_contactNormalOnBInWS[j]; // not really precise because of margins in btSoftBody.cpp:line 2912
+ // node is force application point, therefore node position is contact point (not contact->m_contactPoint, because not equal to node)
+ pt.m_positionOnBInWS[j] = node->m_x[j];
+ }
+ else
+ {
+ pt.m_contactNormalOnBInWS[j] = contact->m_cti.m_normal[j];
+ // node is force application point, therefore node position is contact point (not contact->m_contactPoint, because not equal to node)
+ pt.m_positionOnAInWS[j] = node->m_x[j];
+ pt.m_positionOnBInWS[j] = node->m_x[j] - pt.m_contactDistance * pt.m_contactNormalOnBInWS[j]; // not really precise because of margins in btSoftBody.cpp:line 2912
+ }
}
- else
+ pt.m_normalForce = (impulseNormal / m_data->m_physicsDeltaTime).norm();
+ pt.m_linearFrictionForce1 = (impulseTangent.dot(contact->t1) * contact->t1 / m_data->m_physicsDeltaTime).norm();
+ pt.m_linearFrictionForce2 = (impulseTangent.dot(contact->t2) * contact->t2 / m_data->m_physicsDeltaTime).norm();
+ for (int j = 0; j < 3; j++)
{
- pt.m_contactNormalOnBInWS[j] = contact->m_cti.m_normal[j];
- pt.m_positionOnAInWS[j] = -contact->m_cti.m_normal[j];
- pt.m_positionOnBInWS[j] = contact->m_cti.m_normal[j];
+ pt.m_linearFrictionDirection1[j] = contact->t1[j];
+ pt.m_linearFrictionDirection2[j] = contact->t2[j];
}
+ distinctContactPoints.push_back(pt);
}
- pt.m_normalForce = 1;
- pt.m_linearFrictionForce1 = 0;
- pt.m_linearFrictionForce2 = 0;
- for (int j = 0; j < 3; j++)
+ else
{
- pt.m_linearFrictionDirection1[j] = 0;
- pt.m_linearFrictionDirection2[j] = 0;
+ // add values to existing contact point
+ b3ContactPointData* pt = &distinctContactPoints[idx];
+ // current normal force of node
+ btVector3 normalForce = btVector3(btScalar(pt->m_contactNormalOnBInWS[0]),
+ btScalar(pt->m_contactNormalOnBInWS[1]),
+ btScalar(pt->m_contactNormalOnBInWS[2])) * pt->m_normalForce;
+ // add normal force of additional node contact
+ btScalar swapFactor = swap ? -1.0 : 1.0;
+ normalForce += swapFactor * contact->m_cti.m_normal * (impulseNormal / m_data->m_physicsDeltaTime).norm();
+ // get magnitude of normal force
+ pt->m_normalForce = normalForce.norm();
+ // get direction of normal force
+ if (!normalForce.fuzzyZero())
+ {
+ // normalize for unit vectors if above numerical threshold
+ normalForce.normalize();
+ for (int j = 0; j < 3; j++)
+ {
+ pt->m_contactNormalOnBInWS[j] = normalForce[j];
+ }
+ }
+
+ // add magnitudes of tangential forces in existing directions
+ btVector3 linearFrictionDirection1 = btVector3(btScalar(pt->m_linearFrictionDirection1[0]),
+ btScalar(pt->m_linearFrictionDirection1[1]),
+ btScalar(pt->m_linearFrictionDirection1[2]));
+ btVector3 linearFrictionDirection2 = btVector3(btScalar(pt->m_linearFrictionDirection2[0]),
+ btScalar(pt->m_linearFrictionDirection2[1]),
+ btScalar(pt->m_linearFrictionDirection2[2]));
+ pt->m_linearFrictionForce1 = (impulseTangent.dot(linearFrictionDirection1) * linearFrictionDirection1 / m_data->m_physicsDeltaTime).norm();
+ pt->m_linearFrictionForce2 = (impulseTangent.dot(linearFrictionDirection2) * linearFrictionDirection2 / m_data->m_physicsDeltaTime).norm();
}
- m_data->m_cachedContactPoints.push_back(pt);
+ }
+
+ int num_contact_points = m_data->m_cachedContactPoints.size() + distinctContactPoints.size();
+ m_data->m_cachedContactPoints.reserve(num_contact_points);
+ // add points to contact points cache
+ for (int p = 0; p < distinctContactPoints.size(); p++)
+ {
+ m_data->m_cachedContactPoints.push_back(distinctContactPoints[p]);
}
}
#endif
@@ -9929,7 +10030,7 @@ bool PhysicsServerCommandProcessor::processReducedDeformable(const UrdfReducedDe
softWorld->addSoftBody(rsb);
}
}
-
+
*bodyUniqueId = m_data->m_bodyHandles.allocHandle();
InternalBodyHandle* bodyHandle = m_data->m_bodyHandles.getHandle(*bodyUniqueId);
bodyHandle->m_softBody = rsb;
@@ -9980,7 +10081,7 @@ bool PhysicsServerCommandProcessor::processReducedDeformable(const UrdfReducedDe
float scaling[4] = { 1,1,1,1 };
int instanceUid = m_data->m_guiHelper->registerGraphicsInstance(shapeUid1, position, orientation, color, scaling);
rsb->setUserIndex(instanceUid);
-
+
if (m_data->m_enableTinyRenderer)
{
int texUid2 = m_data->m_pluginManager.getRenderInterface()->registerTexture(meshData.m_textureImage1, meshData.m_textureWidth, meshData.m_textureHeight);
@@ -10080,7 +10181,7 @@ bool PhysicsServerCommandProcessor::processReducedDeformable(const UrdfReducedDe
}
}
}
-
+
btAlignedObjectArray<btVector3> vertices;
@@ -10093,7 +10194,7 @@ bool PhysicsServerCommandProcessor::processReducedDeformable(const UrdfReducedDe
for (int i = 0; i < rsb->m_faces.size(); i++) // Foreach face
{
-
+
for (int k = 0; k < 3; k++) // Foreach vertex on a face
{
int currentIndex = i * 3 + k;
@@ -15067,6 +15168,11 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
hasStatus = processRequestMeshDataCommand(clientCmd, serverStatusOut, bufferServerToClient, bufferSizeInBytes);
break;
}
+ case CMD_REQUEST_TETRA_MESH_DATA:
+ {
+ hasStatus = processRequestTetraMeshDataCommand(clientCmd, serverStatusOut, bufferServerToClient, bufferSizeInBytes);
+ break;
+ }
case CMD_RESET_MESH_DATA:
{
hasStatus = processResetMeshDataCommand(clientCmd, serverStatusOut, bufferServerToClient, bufferSizeInBytes);
diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.h b/examples/SharedMemory/PhysicsServerCommandProcessor.h
index fb23a1bb9..4035d7d0c 100644
--- a/examples/SharedMemory/PhysicsServerCommandProcessor.h
+++ b/examples/SharedMemory/PhysicsServerCommandProcessor.h
@@ -32,6 +32,7 @@ protected:
bool processCreateCollisionShapeCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
bool processCreateVisualShapeCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
bool processRequestMeshDataCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
+ bool processRequestTetraMeshDataCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
bool processResetMeshDataCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
bool processCustomCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
bool processUserDebugDrawCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
diff --git a/examples/SharedMemory/SharedMemoryCommands.h b/examples/SharedMemory/SharedMemoryCommands.h
index 341c93123..37fc35145 100644
--- a/examples/SharedMemory/SharedMemoryCommands.h
+++ b/examples/SharedMemory/SharedMemoryCommands.h
@@ -1144,6 +1144,13 @@ struct b3RequestMeshDataArgs
int m_flags;
};
+struct b3RequestTetraMeshDataArgs
+{
+ int m_bodyUniqueId;
+ int m_startingVertex;
+ int m_flags;
+};
+
struct b3ResetMeshDataArgs
{
int m_bodyUniqueId;
@@ -1219,8 +1226,9 @@ struct SharedMemoryCommand
struct UserDataRequestArgs m_removeUserDataRequestArgs;
struct b3CollisionFilterArgs m_collisionFilterArgs;
struct b3RequestMeshDataArgs m_requestMeshDataArgs;
+ struct b3RequestTetraMeshDataArgs m_requestTetraMeshDataArgs;
struct b3ResetMeshDataArgs m_resetMeshDataArgs;
-
+ struct b3RequestTetraMeshDataArgs m_resetTetraMeshDataArgs;
};
};
diff --git a/examples/SharedMemory/SharedMemoryPublic.h b/examples/SharedMemory/SharedMemoryPublic.h
index 7541ddb5a..4e3f6d3f3 100644
--- a/examples/SharedMemory/SharedMemoryPublic.h
+++ b/examples/SharedMemory/SharedMemoryPublic.h
@@ -118,6 +118,8 @@ enum EnumSharedMemoryClientCommand
CMD_PERFORM_COLLISION_DETECTION,
CMD_RESET_MESH_DATA,
+
+ CMD_REQUEST_TETRA_MESH_DATA,
//don't go beyond this command!
CMD_MAX_CLIENT_COMMANDS,
};
@@ -244,6 +246,9 @@ enum EnumSharedMemoryServerStatus
CMD_PERFORM_COLLISION_DETECTION_COMPLETED,
CMD_RESET_MESH_DATA_COMPLETED,
CMD_RESET_MESH_DATA_FAILED,
+
+ CMD_REQUEST_TETRA_MESH_DATA_COMPLETED,
+ CMD_REQUEST_TETRA_MESH_DATA_FAILED,
//don't go beyond 'CMD_MAX_SERVER_COMMANDS!
CMD_MAX_SERVER_COMMANDS
};
@@ -481,6 +486,17 @@ struct b3MeshData
struct b3MeshVertex* m_vertices;
};
+enum eTetraMeshDataEnum
+{
+ B3_TETRA_MESH_DATA_FLAGS=2,
+};
+
+struct b3TetraMeshData
+{
+ int m_numVertices;
+ struct b3MeshVertex* m_vertices;
+};
+
struct b3OpenGLVisualizerCameraInfo
{
int m_width;
diff --git a/examples/pybullet/pybullet.c b/examples/pybullet/pybullet.c
index f78f464f9..5a8c2eb03 100644
--- a/examples/pybullet/pybullet.c
+++ b/examples/pybullet/pybullet.c
@@ -9190,6 +9190,64 @@ static PyObject* pybullet_getMeshData(PyObject* self, PyObject* args, PyObject*
}
+static PyObject* pybullet_getTetraMeshData(PyObject* self, PyObject* args, PyObject* keywds)
+{
+ int bodyUniqueId = -1;
+ b3PhysicsClientHandle sm = 0;
+ b3SharedMemoryCommandHandle command;
+ b3SharedMemoryStatusHandle statusHandle;
+ struct b3TetraMeshData meshData;
+ int statusType;
+ int flags = -1;
+
+ int physicsClientId = 0;
+ static char* kwlist[] = {"bodyUniqueId", "flags", "physicsClientId", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii", kwlist, &bodyUniqueId, &flags , &physicsClientId))
+ {
+ return NULL;
+ }
+ sm = getPhysicsClient(physicsClientId);
+ if (sm == 0)
+ {
+ PyErr_SetString(SpamError, "Not connected to physics server.");
+ return NULL;
+ }
+ command = b3GetTetraMeshDataCommandInit(sm, bodyUniqueId);
+ if (flags >= 0)
+ {
+ b3GetTetraMeshDataSetFlags(command, flags);
+ }
+
+ statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command);
+ statusType = b3GetStatusType(statusHandle);
+ if (statusType == CMD_REQUEST_TETRA_MESH_DATA_COMPLETED)
+ {
+ int i;
+ PyObject* pyVertexData;
+ PyObject* pyListMeshData = PyTuple_New(2);
+ b3GetTetraMeshData(sm, &meshData);
+ PyTuple_SetItem(pyListMeshData, 0, PyInt_FromLong(meshData.m_numVertices));
+ pyVertexData = PyTuple_New(meshData.m_numVertices);
+ PyTuple_SetItem(pyListMeshData, 1, pyVertexData);
+
+ for (i = 0; i < meshData.m_numVertices; i++)
+ {
+ PyObject* pyListVertex = PyTuple_New(3);
+ PyTuple_SetItem(pyListVertex, 0, PyFloat_FromDouble(meshData.m_vertices[i].x));
+ PyTuple_SetItem(pyListVertex, 1, PyFloat_FromDouble(meshData.m_vertices[i].y));
+ PyTuple_SetItem(pyListVertex, 2, PyFloat_FromDouble(meshData.m_vertices[i].z));
+ PyTuple_SetItem(pyVertexData, i, pyListVertex);
+ }
+
+ return pyListMeshData;
+ }
+
+ PyErr_SetString(SpamError, "getTetraMeshData failed");
+ return NULL;
+}
+
+
+
static PyObject* pybullet_resetMeshData(PyObject* self, PyObject* args, PyObject* keywds)
{
int bodyUniqueId = -1;
@@ -12644,6 +12702,9 @@ static PyMethodDef SpamMethods[] = {
{"getMeshData", (PyCFunction)pybullet_getMeshData, METH_VARARGS | METH_KEYWORDS,
"Get mesh data. Returns vertices etc from the mesh."},
+ {"getTetraMeshData", (PyCFunction)pybullet_getTetraMeshData, METH_VARARGS | METH_KEYWORDS,
+ "Get mesh data. Returns tetra from the mesh."},
+
{"resetMeshData", (PyCFunction)pybullet_resetMeshData, METH_VARARGS | METH_KEYWORDS,
"Reset mesh data. Only implemented for deformable bodies."},
diff --git a/src/BulletSoftBody/btDeformableContactConstraint.cpp b/src/BulletSoftBody/btDeformableContactConstraint.cpp
index 09398d79a..9c8e72f50 100644
--- a/src/BulletSoftBody/btDeformableContactConstraint.cpp
+++ b/src/BulletSoftBody/btDeformableContactConstraint.cpp
@@ -268,7 +268,7 @@ btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolv
{
dn += m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep;
}
- // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
+ // dn is the normal component of velocity difference. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
btVector3 impulse = m_contact->m_c0 * (vr + m_total_normal_dv * infoGlobal.m_deformable_cfm + ((m_penetration > 0) ? m_penetration / infoGlobal.m_timeStep * cti.m_normal : btVector3(0, 0, 0)));
if (!infoGlobal.m_splitImpulse)
{
@@ -487,6 +487,9 @@ void btDeformableFaceRigidContactConstraint::applyImpulse(const btVector3& impul
btVector3 dv = impulse * contact->m_c2;
btSoftBody::Face* face = contact->m_face;
+ // save applied impulse
+ contact->m_cti.m_impulse = impulse;
+
btVector3& v0 = face->m_n[0]->m_v;
btVector3& v1 = face->m_n[1]->m_v;
btVector3& v2 = face->m_n[2]->m_v;
diff --git a/src/BulletSoftBody/btSoftBody.h b/src/BulletSoftBody/btSoftBody.h
index f91640acb..27705e600 100644
--- a/src/BulletSoftBody/btSoftBody.h
+++ b/src/BulletSoftBody/btSoftBody.h
@@ -223,10 +223,12 @@ public:
/* sCti is Softbody contact info */
struct sCti
{
- const btCollisionObject* m_colObj; /* Rigid body */
- btVector3 m_normal; /* Outward normal */
- btScalar m_offset; /* Offset from origin */
+ const btCollisionObject* m_colObj; /* Rigid body */
+ btVector3 m_normal; /* Outward normal */
+ mutable btVector3 m_impulse; /* Applied impulse */
+ btScalar m_offset; /* Offset from origin */
btVector3 m_bary; /* Barycentric weights for faces */
+ sCti() : m_impulse(0, 0, 0) {}
};
/* sMedium */
@@ -897,7 +899,7 @@ public:
int node1) const;
bool checkLink(const Node* node0,
const Node* node1) const;
- /* Check for existring face */
+ /* Check for existing face */
bool checkFace(int node0,
int node1,
int node2) const;