PDA

View Full Version : Point to Line Collision response and Mass (Verlet)

jdarling
29-07-2009, 02:05 AM
Hey all, got a question for anyone who knows something about integrators (specifically Verlet, but any should do). I'm having problems with my Point to Line Collision response (code below). Basically if you draw two points with a mass over 0 (0 represents static elements in my implementation) and connect them with a rigid connector (the wooden stick button) then place a static point (circle with a red dot in it) below that and step through you will notice that the line does not react as you would expect. Instead of falling off to the side with the most mass its falling upwards to the side with the least mass :(.

Full Code: http://www.eonclash.com/physics/Verlet2.zip

Point to Line specific function (from uVerlet.pas)

procedure TVerletSystem.SatisfyPointLineCollision(P: TVerletPoint;
L: TVerletConstraint);
var
N : IVector;
massTotal, D1, D2, LineMass,
aLineMass, PM,
dist : TVectorNumber;
begin
if(P=L.P1)or(P=L.P2)then
exit;
dist := DistancePointToSegment(P.Pos, L.P1.Pos, L.P2.Pos);
if dist < P.Radius then
begin
aLineMass := ((L.P1.Mass+L.P2.Mass) / 2);
LineMass := aLineMass;
PM := P.Mass;
if(PM=0)then
PM := 10000000;
if(LineMass=0)then
LineMass := 10000000;
dist := P.Radius - dist;
N := L.P1.Pos - L.P2.Pos;
N := (N - P.Pos).Normal;
massTotal := LineMass+PM;
if(aLineMass>0)then
begin
D1:= PM/massTotal;
if(L.P2.Mass>0)then
L.P2.Pos := L.P2.Pos + (N * D1);
if(L.P1.Mass>0)then
L.P1.Pos := L.P1.Pos + (N * D1);
end;
if(P.Mass>0)then
begin
D2:= LineMass/massTotal;
P.Pos := P.Pos + (N * D2);
end;
end;
end;

One other problem I'm having is that is seems that Mass is not affecting integration properly. I can have two points one with a very high mass and one with a lower mass collide. You would expect that the higher mass would tend to stay more on its existing path while pushing the lower mass more in the opposing direction, instead they are both affected equally.

// From uVerlet.pas
procedure TVerletSystem.Update;
...
for i := 0 to Count-1 do
begin
Item[i].Force := Item[i].Mass * Force;
Item[i].GatherForces;
end;
for i := 0 to Count-1 do
Item[i].Integrate(TimeFrame);
...
end;

// From uVerletItems.pas
procedure TVerletItem.GatherForces;
var
i : Integer;
tmp : IVector;
begin
tmp := Vector(Force);
for i := 0 to ConstraintCount-1 do
tmp += Constraint[i].GetForce(self);
Force.setto(tmp);
end;

procedure TVerletItem.Integrate(timeStep: TVectorNumber);
var
calc, fm,
last : IVector;
t2 : TVectorNumber;
begin
last := Vector(Pos);

fm := Force / Mass;
calc := Pos-LastPos;
t2 := (timeStep * timeStep);
Pos := Pos + (calc + (fm * t2));

LastPos.setto(last);
end;

Any help greatly appreciated.

- Jeremy

jdarling
29-07-2009, 02:25 AM
Just in case a few screen shots would help, below is a series of 4 shots (left to right, top to bottom) showing just before collision, the initial collision, a few steps further, and even further. As you can see, you would expect the bar to drop right and down, but instead its moving left and up.

http://www.eonclash.com/physics/ver_prob.jpg

paul_nicholls
29-07-2009, 03:44 AM

http://www.teknikus.dk/tj/gdc2001.htm

You probably have, but I will post it anyway :)

cheers,
Paul

jdarling
29-07-2009, 01:45 PM
Yep, read that article several times.

In fact, I managed to figure out what my problem is, just can't figure out how to solve for it. The basic issue is that when a point (p) moves past a segment (s) it is moved to the "corrected path". But p's last position isn't updated properly so that the verlet system can utilize the last position to create the next frames movement vector.

Need to figure out a way to calculate angle of incidence and angle of reflection using vectors instead of algebra :(. Also need to find the proper last position for p using vector math. If I have time I'll post up an image showing what I'm talking about.

- Jeremy

jdarling
29-07-2009, 07:21 PM
Ok, here is a quick capture of two simulations that show the problem better. On the left is a single particle striking a static bar and bouncing in the wrong direction. Given the angle of the line you would expect it to follow (sort of) the green arrows, instead it follows the red (as seen).

The right contains a bar falling and striking a single point. Instead of the right side of the bar moving upwards with the left continuing downward (as expected and shown with the green and blue arrows) it always moves up and left. No matter what every time a bar and a point collide the result is to move left :(.

Any ideas now?

http://eonclash.com/physics/problem.jpg

grudzio
29-07-2009, 07:40 PM
The line

procedure TVerletSystem.Update
...
Item[i].Force := Item[i].Mass * Force;
...

looks susopicious to me (units don't match :)). Since the force acting on the item is multiplied by its mass, the acceleration ( calculated in the TVerletItem.Integrate procedure) is the same for all items. That is why mass does not affect the motion.
I think You should remove multiplication by mass.

jdarling
30-07-2009, 01:51 AM
I think you might be misreading the code;

The initial Item.Force = Force * Item.Mass calculation is using the global force to perform a scale on the local mass of the object.
Thus presenting a basic force vector to representing basic gravity (if in affect).
Then inside of the item.gatherforces all other local (constraint) forces are added to this initial value.
Integrate utilizes this final force along with the objects mass, last-position, and the time-step to calculate the actual movement of the object for the frame.

Of course, that's if I understand the theory properly :)

jdarling
30-07-2009, 03:10 AM
Oh wait, I'm an idiot who misread the theory LOL. Your right, the division by mass inside the integration step isn't necessary. By removing it you get proper reaction of a V2=M1*2*V1 (or an object with twice the mass should have twice the velocity as another object).

Ok, well that fixes that. Now, back to the problem of the bouncing balls and sticks :(

paul_nicholls
30-07-2009, 03:37 AM
Oh wait, I'm an idiot who misread the theory LOL. Your right, the division by mass inside the integration step isn't necessary. By removing it you get proper reaction of a V2=M1*2*V1 (or an object with twice the mass should have twice the velocity as another object).

Ok, well that fixes that. Now, back to the problem of the bouncing balls and sticks :(

Good to see you got that bit working :)

Now back to reflection rays you were wanting...

Here is the code I use in my raytracer for calculating a reflection ray, and it doesn't use any trigonometry at all :)

// calculate reflection
refl := prim.Material.Reflection;
If refl > 0.0 Then
Begin
If ADepth < FMaxTraceDepth Then
// spawn secondary rays
Begin
N := prim.GetNormalAt(pi);
R := VectorSub(ARay.Direction,VectorScale(N,2.0 * DotProduct(ARay.Direction,N)));
rcol := Color4f(0, 0, 0);
reflray.Direction := R;
Raytrace(reflray, rcol, ADepth + 1, ARIndex, dist);
AAcc.r := AAcc.r + refl * rcol.r * primColor.r;
AAcc.g := AAcc.g + refl * rcol.g * primColor.g;
AAcc.b := AAcc.b + refl * rcol.b * primColor.b;
End;
End;

I hope it helps :)
cheers,
Paul

jdarling
30-07-2009, 03:43 PM
Making minor changes to your code, it would appear that the parts I actually need would be:

// calculate reflection
N := prim.GetNormalAt(pi);
R := VectorSub(ARay.Direction,VectorScale(N,2.0 * DotProduct(ARay.Direction,N)));

That would suggest that I first need to know pi (and I'm guessing that isn't 3.1415). In this case, is pi the intersection of the point on the surface?

Lets go to a visual aid:
http://www.eonclash.com/physics/p2s_calc.jpg

Given your above code I think that the following mapping is appropriate:
N - Normal of the intersection point of [V-1]->V to A->B
A.RayDirection - V - [V-1]
cEpsilon - Proper Scaled Epsilon (please tell me you arn't using static 0.0000001 :) in a ray tracer)

My response (using dts as Delta Time Step difference) [nV-dts]->nV would then be equal to reflray.Origin->R correct?

paul_nicholls
30-07-2009, 08:36 PM
sorry, pi is point of intersection of the incident ray. I got the calculations from this page about raytracing:

http://www.devmaster.net/articles/raytracing_series/part2.php

LOL...yes I AM using a fixed cEpsilon value, but it is

Const
cEpsilon = 0.001;

cheers,
Paul