• 13
• 18
• 19
• 27
• 10

# calculating two spheres sandwiching a third difficulties

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

## Recommended Posts

I can calculate two spheres colliding fine, but I'm having trouble when theres more than 2. One scenario would be two spheres sandwiching a third one between them. All have the same mass, and the two have equal but opposite velocities. I know the answer, that the two moving spheres would swap velocities and the third will stay stationary between them after the collision. But I'm having trouble getting my code to do that, because currently I do two separate calculations for the collisions which just causes the two balls to stop and the third also sits stationary between them. (ie when applying velocities after all collision calculations have been done) this is because sphere1 stops and then sends sphere3 to the right, but sphere2 also stops and stops sphere3. I thought of applying new velocities straight away, but that causes a problem in another scenario, ie sphere3 is sitting slightly higher than the other two. In my code it causes sphere3 to move up but to the right (as the collision between sphere1 [moving to the right] and sphere3 [stationary] is calculated first) Although I'm not too sure on why that is happening yet, and when just thinking about it, it seems like that shouldn't happen and that way should work for both scenarios. Thanks. edit heres my game compiled, showing the scenarios above. [Edited by - johnnyBravo on May 16, 2007 8:21:27 AM]

##### Share on other sites
Well, it sounds like your code is wrong...

...and that's probably the best answer you're going to get until you post a little of it. :)

##### Share on other sites
This is it in order:
-detect collisions
-move everything forward till first collision (or if none just move everything by timestep)
-calculate new velocities
-apply new velocities

this loops over till all collisions in that time step have been handled

double timeLeft = timeLapse;while(timeLeft > 0) {	double moveTime = timeLeft;	//find sphereCollisions in shortest time	vector<Sphere*> sphereCollisions;	for(unsigned int i=0;i<spheres.size()-1;i++) {		for(unsigned int j=i+1;j<spheres.size();j++) {			if(spheres->collidable && spheres[j]->collidable) {				Vector pos = spheres->position - spheres[j]->position;				Vector vel = spheres->velocity - spheres[j]->velocity;				double a = vel.x*vel.x + vel.y*vel.y + vel.z*vel.z;				double b = 2*(pos.x*vel.x + pos.y*vel.y + pos.z*vel.z);				double r = spheres->radius + spheres[j]->radius;				double c = pos.x*pos.x + pos.y*pos.y + pos.z*pos.z - r*r;				double det = b*b - 4*a*c;				if(det >= 0) {					double colTime = (-b - sqrt(det))/(2*a);					if(colTime >= 0 && colTime <= moveTime) {						if(colTime < moveTime) {							moveTime = colTime;							sphereCollisions.clear();						}						sphereCollisions.push_back(spheres);						sphereCollisions.push_back(spheres[j]);					}				}			}		}	}	//move spheres forward by lowest collison time	for(unsigned int i=0;i<spheres.size();i++){		spheres->position+= spheres->velocity*moveTime;	}	//calculate new velocities of sphereCollisions	vector<Vector> velocities;	for(unsigned int i=0;i<sphereCollisions.size()/2;i++) {		int i1 = i*2;		int i2 = i*2+1;		//		double m1 = sphereCollisions[i1]->mass;		double m2 = sphereCollisions[i2]->mass;		Vector v1i = sphereCollisions[i1]->velocity;		Vector v2i = sphereCollisions[i2]->velocity;		//normal		Vector n = (sphereCollisions[i1]->position - sphereCollisions[i2]->position).normal();		//initial normal velocity		Vector vn1i = (n*-1.0) * v1i.dot(n*-1.0); //n * v1i.dot(n);		Vector vn2i = n * v2i.dot(n);		//tangential velocity		Vector vt1 = v1i - vn1i;		Vector vt2 = v2i - vn2i;		//final normal velocity		double cor = 1;		Vector vn1f = (vn1i*m1 + vn2i*m2 + (vn2i - vn1i)*m2*cor)/(m1 + m2);		Vector vn2f = (vn1i*m1 + vn2i*m2 - (vn2i - vn1i)*m1*cor)/(m1 + m2);		//final velocity		Vector v1f = vn1f + vt1;		Vector v2f = vn2f + vt2;		//change in velocity		velocities.push_back(v1f - v1i);		velocities.push_back(v2f - v2i);	}	//apply new velocities	for(unsigned int i=0;i<sphereCollisions.size()/2;i++) {		int i1 = i*2;		int i2 = i*2+1;		sphereCollisions[i1]->velocity+= velocities[i1];		sphereCollisions[i2]->velocity+= velocities[i2];	}	//subtract lowest collision time	timeLeft -= moveTime;}

thx

##### Share on other sites
I just found something weird, with the two spheres sandwiching the third.

If I have the sandwiched third sphere sitting at x=0, it doesn't work.

But if I shift everything on x + 1, it then works.

I'm trying to workout why this is, it has to be something to do with the calculating new velocity section of my code,

but the only thing in there that has anything to do with position is the normal vector between the balls. But I checked what the normal was between both scenarios and they're all the same.

I am utterly perplexed.

edit:
heres my game showing the scenario above.

thx

##### Share on other sites
Well, based on that description I was expecting to find something based on a position normal that would be 0, I didn't find that, but there are two things that do stick out:

It looks like when a collision is detected, a time is worked out for when the collision happens. I may be reading this wrong, but it looks like you only advance the colliding objects by that time, and not the whole thing.

The biggest error that stick out is this line:

for(unsigned int i=0;i<sphereCollisions.size()/2;i++)
i1 = i*2;
i2 = i*2+1;

What if there are three colliding objects?
That gives you i = 0..1.

So you operate on 0,1, but that's it. What about object index 2?

##### Share on other sites
Quote:
 Original post by erissianWell, based on that description I was expecting to find something based on a position normal that would be 0, I didn't find that,

I just realized, probably due to precision errors it detects sphere1 to sphere3 and sphere2 to sphere3 collisions in a different collision time.

Quote:
 Original post by erissianIt looks like when a collision is detected, a time is worked out for when the collision happens. I may be reading this wrong, but it looks like you only advance the colliding objects by that time, and not the whole thing.

Nup all the objects are being moved forward, it does it straight after the earliest collision time has been found, else if there are no collisions it just moves every forward by either the time step or the remaining time left.

Quote:
 Original post by erissianThe biggest error that stick out is this line:for(unsigned int i=0;i

the array would look like this:
//collision 1
sphereCollisions[0] = spheres1
sphereCollisions[1] = spheres3

//collision 2
sphereCollisions[2] = spheres2
sphereCollisions[3] = spheres3

So I handled collisions 1 on 1 in that loop, thats what I'm thinking might be a problem, maybe I should be handling all 3 in the same calculation, but I'm not sure how to do that.

thx

edit:

I think my problem is working out how to calculate the response when there are more than 2 spheres colliding, that is all the spheres which are 'touching' or related through the touching of another sphere, eg sphere1 and sphere2 arn't touching but are both touching sphere3, so they are relateed in the calculations.