Browse Source

Soft body bug fixes (#898)

* A scaled compound shape with a center of mass of non zero would not apply the correct transform to its sub shapes
* A soft body without any edges would hang the solver

Fixes #895
Jorrit Rouwe 1 year ago
parent
commit
ede3071ebd

+ 2 - 0
Docs/ReleaseNotes.md

@@ -35,6 +35,8 @@ For breaking API changes see [this document](https://github.com/jrouwe/JoltPhysi
 * Fixed unit tests failing when compiling for 32-bit Linux. The compiler defaults to using x87 instructions in this case which does not work well with the collision detection pipeline. Now defaulting to the SSE instructions.
 * Fixed unit tests failing when compiling for 32-bit Linux. The compiler defaults to using x87 instructions in this case which does not work well with the collision detection pipeline. Now defaulting to the SSE instructions.
 * Fixed assert and improved interaction between a fast moving rigid body of quality LinearCast and a soft body.
 * Fixed assert and improved interaction between a fast moving rigid body of quality LinearCast and a soft body.
 * When creating a MeshShape with triangles that have near identical positions it was possible that the degenerate check decided that a triangle was not degenerate while the triangle in fact would be degenerate after vertex quantization. The simulation would crash when colliding with this triangle.
 * When creating a MeshShape with triangles that have near identical positions it was possible that the degenerate check decided that a triangle was not degenerate while the triangle in fact would be degenerate after vertex quantization. The simulation would crash when colliding with this triangle.
+* A scaled compound shape with a center of mass of non zero would not apply the correct transform to its sub shapes when colliding with a soft body
+* A soft body without any edges would hang the solver
 
 
 ## v4.0.2
 ## v4.0.2
 
 

+ 4 - 1
Jolt/Physics/Collision/Shape/CompoundShape.cpp

@@ -249,7 +249,10 @@ void CompoundShape::DrawGetSupportingFace(DebugRenderer *inRenderer, RMat44Arg i
 void CompoundShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const
 void CompoundShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const
 {
 {
 	for (const SubShape &shape : mSubShapes)
 	for (const SubShape &shape : mSubShapes)
-		shape.mShape->CollideSoftBodyVertices(inCenterOfMassTransform * Mat44::sRotationTranslation(shape.GetRotation(), shape.GetPositionCOM()), shape.TransformScale(inScale), ioVertices, inNumVertices, inDeltaTime, inDisplacementDueToGravity, inCollidingShapeIndex);
+	{
+		Mat44 transform = shape.GetLocalTransformNoScale(inScale);
+		shape.mShape->CollideSoftBodyVertices(inCenterOfMassTransform * transform, shape.TransformScale(inScale), ioVertices, inNumVertices, inDeltaTime, inDisplacementDueToGravity, inCollidingShapeIndex);
+	}
 }
 }
 
 
 void CompoundShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const
 void CompoundShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const

+ 46 - 42
Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp

@@ -565,60 +565,64 @@ SoftBodyMotionProperties::EStatus SoftBodyMotionProperties::ParallelApplyEdgeCon
 	JPH_ASSERT(num_groups > 0, "SoftBodySharedSettings::Optimize should have been called!");
 	JPH_ASSERT(num_groups > 0, "SoftBodySharedSettings::Optimize should have been called!");
 	uint32 edge_group, edge_start_idx;
 	uint32 edge_group, edge_start_idx;
 	SoftBodyUpdateContext::sGetEdgeGroupAndStartIdx(ioContext.mNextEdgeConstraint.load(memory_order_relaxed), edge_group, edge_start_idx);
 	SoftBodyUpdateContext::sGetEdgeGroupAndStartIdx(ioContext.mNextEdgeConstraint.load(memory_order_relaxed), edge_group, edge_start_idx);
-	if (edge_group < num_groups && edge_start_idx < mSettings->GetEdgeGroupSize(edge_group))
+	if (edge_group < num_groups)
 	{
 	{
-		// Fetch the next batch of edges to process
-		uint64 next_edge_batch = ioContext.mNextEdgeConstraint.fetch_add(SoftBodyUpdateContext::cEdgeConstraintBatch, memory_order_acquire);
-		SoftBodyUpdateContext::sGetEdgeGroupAndStartIdx(next_edge_batch, edge_group, edge_start_idx);
-		if (edge_group < num_groups)
+		uint edge_group_size = mSettings->GetEdgeGroupSize(edge_group);
+		if (edge_start_idx < edge_group_size || edge_group_size == 0)
 		{
 		{
-			bool non_parallel_group = edge_group == num_groups - 1; // Last group is the non-parallel group and goes as a whole
-			uint edge_group_size = mSettings->GetEdgeGroupSize(edge_group);
-			if (non_parallel_group? edge_start_idx == 0 : edge_start_idx < edge_group_size)
+			// Fetch the next batch of edges to process
+			uint64 next_edge_batch = ioContext.mNextEdgeConstraint.fetch_add(SoftBodyUpdateContext::cEdgeConstraintBatch, memory_order_acquire);
+			SoftBodyUpdateContext::sGetEdgeGroupAndStartIdx(next_edge_batch, edge_group, edge_start_idx);
+			if (edge_group < num_groups)
 			{
 			{
-				// Process edges
-				uint num_edges_to_process = non_parallel_group? edge_group_size : min(SoftBodyUpdateContext::cEdgeConstraintBatch, edge_group_size - edge_start_idx);
-				if (edge_group > 0)
-					edge_start_idx += mSettings->mEdgeGroupEndIndices[edge_group - 1];
-				ApplyEdgeConstraints(ioContext, edge_start_idx, edge_start_idx + num_edges_to_process);
-
-				// Test if we're at the end of this group
-				uint edge_constraints_processed = ioContext.mNumEdgeConstraintsProcessed.fetch_add(num_edges_to_process, memory_order_relaxed) + num_edges_to_process;
-				if (edge_constraints_processed >= edge_group_size)
+				bool non_parallel_group = edge_group == num_groups - 1; // Last group is the non-parallel group and goes as a whole
+				edge_group_size = mSettings->GetEdgeGroupSize(edge_group);
+				if (non_parallel_group? edge_start_idx == 0 : edge_start_idx < edge_group_size)
 				{
 				{
-					// Non parallel group is the last group (which is also the only group that can be empty)
-					if (non_parallel_group || mSettings->GetEdgeGroupSize(edge_group + 1) == 0)
+					// Process edges
+					uint num_edges_to_process = non_parallel_group? edge_group_size : min(SoftBodyUpdateContext::cEdgeConstraintBatch, edge_group_size - edge_start_idx);
+					if (edge_group > 0)
+						edge_start_idx += mSettings->mEdgeGroupEndIndices[edge_group - 1];
+					ApplyEdgeConstraints(ioContext, edge_start_idx, edge_start_idx + num_edges_to_process);
+
+					// Test if we're at the end of this group
+					uint edge_constraints_processed = ioContext.mNumEdgeConstraintsProcessed.fetch_add(num_edges_to_process, memory_order_relaxed) + num_edges_to_process;
+					if (edge_constraints_processed >= edge_group_size)
 					{
 					{
-						// Finish the iteration
-						ApplyCollisionConstraintsAndUpdateVelocities(ioContext);
-
-						uint iteration = ioContext.mNextIteration.fetch_add(1, memory_order_relaxed);
-						if (iteration < mNumIterations)
+						// Non parallel group is the last group (which is also the only group that can be empty)
+						if (non_parallel_group || mSettings->GetEdgeGroupSize(edge_group + 1) == 0)
 						{
 						{
-							// Start a new iteration
-							StartNextIteration(ioContext);
-
-							// Reset next edge to process
-							ioContext.mNumEdgeConstraintsProcessed.store(0, memory_order_relaxed);
-							ioContext.mNextEdgeConstraint.store(0, memory_order_release);
+							// Finish the iteration
+							ApplyCollisionConstraintsAndUpdateVelocities(ioContext);
+
+							uint iteration = ioContext.mNextIteration.fetch_add(1, memory_order_relaxed);
+							if (iteration < mNumIterations)
+							{
+								// Start a new iteration
+								StartNextIteration(ioContext);
+
+								// Reset next edge to process
+								ioContext.mNumEdgeConstraintsProcessed.store(0, memory_order_relaxed);
+								ioContext.mNextEdgeConstraint.store(0, memory_order_release);
+							}
+							else
+							{
+								// On final iteration we update the state
+								UpdateSoftBodyState(ioContext, inPhysicsSettings);
+
+								ioContext.mState.store(SoftBodyUpdateContext::EState::Done, memory_order_release);
+								return EStatus::Done;
+							}
 						}
 						}
 						else
 						else
 						{
 						{
-							// On final iteration we update the state
-							UpdateSoftBodyState(ioContext, inPhysicsSettings);
-
-							ioContext.mState.store(SoftBodyUpdateContext::EState::Done, memory_order_release);
-							return EStatus::Done;
+							// Next group
+							ioContext.mNumEdgeConstraintsProcessed.store(0, memory_order_relaxed);
+							ioContext.mNextEdgeConstraint.store(SoftBodyUpdateContext::sGetEdgeGroupStart(edge_group + 1), memory_order_release);
 						}
 						}
 					}
 					}
-					else
-					{
-						// Next group
-						ioContext.mNumEdgeConstraintsProcessed.store(0, memory_order_relaxed);
-						ioContext.mNextEdgeConstraint.store(SoftBodyUpdateContext::sGetEdgeGroupStart(edge_group + 1), memory_order_release);
-					}
+					return EStatus::DidWork;
 				}
 				}
-				return EStatus::DidWork;
 			}
 			}
 		}
 		}
 	}
 	}