Jump to content
  • Advertisement
Sign in to follow this  
Journey

Problem with low granularity collision detection and response in cloth simulation

This topic is 3648 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

well, I have some spheres that are attached to vertices in a piece of cloth. Sort of a low granularity collision detection and response mechanism. The spheres keep the cloth from penetrating itself. So far I have calculated linear impulse in the collision response not accounting for friction. As a result, after calculating spring forces in the cloth, I calculate collisions between the spheres, which in turn modify the velocity when they collide If I run the simulation with the spheres unattached, the simultion runs fine, I can push spheres against each other, though when I attach them to the cloth, I get an ugly "bouncing effect" when I try to push the spheres together, and it bounces constantly and "explodes" due to having to deal with both linear impulse from collision and the spring damper forces, even though the springs are dampened. Spring forces are calculated first, and then I calculate collision just by using position, velocity, radius and mass, which modifies velocity if there is a collision. So I use the resulting velocity from the spring forces and feed it into the collision detection and response calculation loop, which further modifies it upon collision. Here's a link to the demo: Flag (Remember that the simulation is very delicate and unstable, so if you move the mouse quickly, it will blow up because of the numerical instability, even though the cloth is dampened, so if you move it around gently it will be ok. But that instability is precisely want I want to get rid of) Now, I intend to implement friction in the hopes that it will get rid of the "bounciness" and thus the shaking and the explosions. I need to calculate several things, among them the inertia tensor, but since the colliding objects are perfect spheres, I was thinking if I can substitute the intertia tensor matrix for a scalar. This is the formula I'm thinking of implementing for the linear impulse: J = -vr(e+1)/[1/m1 + 1/m2 + n*[(r1 x n)/I1] x r1 + n*[(r2 x n)/I2] x r2] J = linear impulse vr = relative velocity * = dot product x = cross product I1, I2 = inverse moment of inertia for body1 and body 2 e = Coefficient of resitution n = normal of the impact (unit length) r1, r2 = vector from body's center of gravity to the point of impact Now I would like to make I1 and I2 into a scalar 1.0 if possible to discard them. I have hopes that implementing friction will solve the instability, but if anyone has a quicker suggestion I'd be very thankful. Additionally, here's the important code that does the spring force calculations and the subsequent collision detection and response loop: Remember, this is Actionscript 3.0 and the site can't recognize the syntax, so I'm posting it as C++: And for some reasong the site is getting rid of some addition and subtraction symbols, so don't rely too much on the code below.

/////////// NOT C++ but AS3!!!! ////////////////////////////////

	// Apply wind force
	for(index = 0; index < TestCollisionSphereVertexList.length; index++)
	{
		
		WindX = (randRange(1,2000)-1000.0)/100.0;
		WindY = (randRange(1,400)-200.0)/100.0;
		WindZ = (randRange(1,400)-200.0)/100.0;
		
		var WindMag:Number = Distance3D(0,0,0,WindX,WindY,WindZ);
		
		WindX/=WindMag;
		WindY/=WindMag;
		WindZ/=WindMag;
		
		var WindFactor:Number = (randRange(1,100)/100);
		
		WindX*=0.3;
		WindY*=0.3;
		WindZ*=0.3;		
		
		TestCollisionSphereVertexList[index].ForceX+=WindX;	
		TestCollisionSphereVertexList[index].ForceY+=WindY;		
		TestCollisionSphereVertexList[index].ForceZ+=WindZ;		
		
	}// end for


	// Calculate spring forces
	for (index = 0; index < TestCollisionSphereSpringList.length; index++)
	{
				
		// Calculate difference in position
		var PosDiffX:Number = TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].PosX - TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].PosX;
		var PosDiffY:Number = TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].PosY - TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].PosY;				
		var PosDiffZ:Number = TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].PosZ - TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].PosZ;								
						
		var SegLength:Number = Distance3D(TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].PosX, TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].PosY, TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].PosZ, TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].PosX, TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].PosY, TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].PosZ);
						
		// Calculate difference in velocity
		var VelDiffX:Number = TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].VelX - TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].VelX;
		var VelDiffY:Number = TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].VelY - TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].VelY;				
		var VelDiffZ:Number = TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].VelZ - TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].VelZ;				
										
		var RestLength:Number = TestCollisionSphereSpringList[index].RestLength;
				
		var PosVelDot:Number = PosDiffX*VelDiffX + PosDiffY*VelDiffY + PosDiffZ*VelDiffZ;
				
		var Force1X:Number = -((0.8*(SegLength - RestLength)) + 0.04*(PosVelDot/SegLength))*(PosDiffX/SegLength);
		var Force1Y:Number = -((0.8*(SegLength - RestLength)) + 0.04*(PosVelDot/SegLength))*(PosDiffY/SegLength);
		var Force1Z:Number = -((0.8*(SegLength - RestLength)) + 0.04*(PosVelDot/SegLength))*(PosDiffZ/SegLength);							
									
		var ForceMagnitude:Number = Distance3D(0, 0, 0, Force1X, Force1Y, Force1Z);
			 					
									
		TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].ForceX += Force1X;
		TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].ForceY += Force1Y;
		TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point1].ForceZ += Force1Z;
					
		var Force2X:Number = -Force1X;
		var Force2Y:Number = -Force1Y;					
		var Force2Z:Number = -Force1Z;					
					
		TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].ForceX += Force2X;
		TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].ForceY += Force2Y;
		TestCollisionSphereVertexList[TestCollisionSphereSpringList[index].Point2].ForceZ += Force2Z;
					
	}// end for


	for(index = 0; index < TestCollisionSphereVertexList.length; index++)
	{
		
		// acceleration is determined by force divided by mass
		TestCollisionSphereVertexList[index].AccelX = TestCollisionSphereVertexList[index].ForceX/TestCollisionSphereVertexList[index].Mass;	
		TestCollisionSphereVertexList[index].AccelY = TestCollisionSphereVertexList[index].ForceY/TestCollisionSphereVertexList[index].Mass;		
		TestCollisionSphereVertexList[index].AccelZ = TestCollisionSphereVertexList[index].ForceZ/TestCollisionSphereVertexList[index].Mass;		
		
		// reset forces
		TestCollisionSphereVertexList[index].ForceX = 0;	
		TestCollisionSphereVertexList[index].ForceY = 0;
		TestCollisionSphereVertexList[index].ForceZ = 0;				
		
		// apply resultant acceleration
		TestCollisionSphereVertexList[index].VelX += TestCollisionSphereVertexList[index].AccelX;	
		TestCollisionSphereVertexList[index].VelY += TestCollisionSphereVertexList[index].AccelY;
		TestCollisionSphereVertexList[index].VelZ += TestCollisionSphereVertexList[index].AccelZ;
		
		// apply friction
		TestCollisionSphereVertexList[index].VelX /= 1.1;	
		TestCollisionSphereVertexList[index].VelY /= 1.1;		
		TestCollisionSphereVertexList[index].VelZ /= 1.1;	
		
		// scale back velocity to maintain stability
		var FPRes:Number = 0.1;
		
		var VelXInt:int = TestCollisionSphereVertexList[index].VelX/FPRes;
		var VelYInt:int = TestCollisionSphereVertexList[index].VelY/FPRes;
		var VelZInt:int = TestCollisionSphereVertexList[index].VelZ/FPRes;

		TestCollisionSphereVertexList[index].VelX = VelXInt*FPRes;
		TestCollisionSphereVertexList[index].VelY = VelYInt*FPRes;
		TestCollisionSphereVertexList[index].VelZ = VelZInt*FPRes;
		
	}// end for
	
	
	
	var Iteration:int = 0; 
	
	for(Iteration = 0; Iteration < 3; Iteration++)
	{
	
		var Sphere1:int = 0;
		var Sphere2:int = 0;
		
		// Handle TEST Collision spheres
		for(Sphere1 = 0; Sphere1 < TestCollisionSphereList.length; Sphere1++)
		{	
		
			TestCollisionSphereList[Sphere1].Collided = false;
		
			for(Sphere2 = 0; Sphere2 < TestCollisionSphereList.length; Sphere2++)
			{	
			
				if(Sphere1 != Sphere2)
				{
					
					var SphereDistance:Number = Distance3D(TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].PosX+TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelX, TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].PosY+TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelY, TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].PosZ+TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelZ,
														   TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].PosX+TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelX, TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].PosY+TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelY, TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].PosZ+TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelZ);
					
					
					
					if(SphereDistance <= (TestCollisionSphereList[Sphere1].Radius+TestCollisionSphereList[Sphere2].Radius))
					{
						
						
						
						TestCollisionSphereList[Sphere1].Collided = true;
						
						
						var AuxVelX:Number = TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelX;
						var AuxVelY:Number = TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelY;
						var AuxVelZ:Number = TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelZ;
						
						var e:Number = 1.0;
						

// Apparently lower mass stabilizes the simulation :S						
						var Mass:Number = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;
									
// Remember that this is all a test and some code looks redundant and ugly
// And notice that I'm not considering friction when calculating the resultant
// velocity	

						TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelX = ((1.0+e)*Mass*TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelX + AuxVelX*(Mass - e*Mass))/(Mass + Mass);
						TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelY = ((1.0+e)*Mass*TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelY + AuxVelY*(Mass - e*Mass))/(Mass + Mass);
						TestCollisionSphereVertexList[TestCollisionSphereList[Sphere1].AttachedIndex].VelZ = ((1.0+e)*Mass*TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelZ + AuxVelZ*(Mass - e*Mass))/(Mass + Mass);
						
						TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelX = ((1.0+e)*Mass*AuxVelX - TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelX*(Mass - e*Mass))/(Mass + Mass);
						TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelY = ((1.0+e)*Mass*AuxVelY - TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelY*(Mass - e*Mass))/(Mass + Mass);
						TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelZ = ((1.0+e)*Mass*AuxVelZ - TestCollisionSphereVertexList[TestCollisionSphereList[Sphere2].AttachedIndex].VelZ*(Mass - e*Mass))/(Mass + Mass);					
																						
												
						
					}// end if
					
				}// end if
			
			
			}// end for
			
		}// end for	
		
	}// end for	
	
	
	
	
	for(index = 0; index < TestCollisionSphereVertexList.length; index++)
	{
		
		TestCollisionSphereVertexList[index].PosX += TestCollisionSphereVertexList[index].VelX;	
		TestCollisionSphereVertexList[index].PosY += TestCollisionSphereVertexList[index].VelY;
		TestCollisionSphereVertexList[index].PosZ += TestCollisionSphereVertexList[index].VelZ;

	}// end for	





Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!