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

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