Autor Wątek: Tarcie i restytucja.  (Przeczytany 670 razy)

Offline taki_tam

  • Użytkownik

# Lipiec 04, 2011, 15:02:19
Siema, dawno mnie nie było ;)

Napisana przeze mnie fizyka ciała sztywnego działała elegancko do czasu kiedy nie zaimplementowałem tarcia i restytucji. Nadmienię tutaj, że wykorzystałem tutaj integracje Verleta(ciała zbudowane z punktów materialnych połączone sztywnymi sprężynami). Napisze teraz bardziej ogólnie co się dzieje po kolei.
Sprawdzam czy Bounding-Box'y ciał nachodzą na siebie - jeśli tak sprawdzam kolizje SAT'em i jeśli kolizja zchodzi pobieram poszczególne informacje: Normalna kolizji, długość tego wektora, ściana jednego ciała, wierzchołek drugiego ciała. Przeszukując internet jak napisać odpowiedź kolizji dla takich ciał(gdyż nie jest to w zasadzie bryła sztywna i zasady dynamiki bryły sztywnej na nic się tu praktycznie nie zdadzą) znalazłem dobry artykuł na gamedev.net "A Verlet based approuch for 2D game physics". Jest tam wyjaśniona kwestia odpowiedzi kolizji w zrozumiały i klarowny sposób. Jedyny mankament jest taki, że koleś nie uwzględnił właściwości tarcia i restytucji tłumacząc sie, że to już nie będzie takie proste. I owszem dla ześlizgiwania się ciała(ściany) po wierzchołku drugiego ciała może i proste nie jest(nic mi do głowy nie przychodzi jak to zrobić) ale dla wierzchołków wydawało mi się to banalne do póki okazało się, że coś tu nie działa. Przytoczę tu kod procedurki odpowiedzialnej za odpowiedź kolizji wraz z komentarzami, a Wy jeśli możecie napiszcie czemu to nie działa(już pare dni mi to mamuci w głowie i kompletnie nie mam pojęcia dlaczego nie działa) i czy w zasadzie ma prawo działać ;)

//INFORMACJE O KOLIZJI
  TUnCollisionInfo2D = record
    sDepth: Single;
    vNormal: TV2D;

    xEdge: TUnConstraint2D;
    xParticle: TUnParticle2D;
  end;

//ODPOWIEDŹ KOLIZJI
procedure TUnPhysX2D.ProcessCollision();
var
  vCollisionVector: TV2D; 
  T, Lambda: Single;
  xPA, xPB: TUnParticle2D;
  sEdgeMass: Single;
  sInvCollisionMass: Single;
  sRatio1, sRatio2: Single;
  vVelocity, vVelT, vVelN: TV2D;
  sRestitution, sFriction: Single;
begin
  //Cząsteczki należące do krawędzi, na której jest kolizja (ciało 1)
  xPA:= TUnBody2D(m_xCollisionInfo.xEdge.Parent).Particle[m_xCollisionInfo.xEdge.ParticleA];
  xPB:= TUnBody2D(m_xCollisionInfo.xEdge.Parent).Particle[m_xCollisionInfo.xEdge.ParticleB];

  //Właściwości kolidującego ciała.
  sRestitution:= TUnBody2D(m_xCollisionInfo.xEdge.Parent).Restitution;
  sFriction:= TUnBody2D(m_xCollisionInfo.xEdge.Parent).Friction;

  //Wektor kolizji.
  vCollisionVector:= V2D_Scale(m_xCollisionInfo.vNormal, m_xCollisionInfo.sDepth);

  if Abs(xPA.Position.X - xPB.Position.X) > (xPA.Position.Y - xPB.Position.Y) then
   T:= (m_xCollisionInfo.xParticle.Position.X - vCollisionVector.X - xPA.Position.X) / (xPB.Position.X - xPA.Position.X)
  else
   T:= (m_xCollisionInfo.xParticle.Position.Y - vCollisionVector.Y - xPA.Position.Y) / (xPB.Position.Y - xPA.Position.Y);

  Lambda:= 1.0 / (T * T + (1.0 - T) * (1.0 - T));

  sEdgeMass:= T * xPB.Mass + (1.0 - T) * xPA.Mass;
  sInvCollisionMass:= 1.0 / (sEdgeMass + m_xCollisionInfo.xParticle.Mass);

  sRatio1:= m_xCollisionInfo.xParticle.Mass * sInvCollisionMass;
  sRatio2:= sEdgeMass * sInvCollisionMass;

  //Odpowiedź kolizji dla cząsteczek z krawędzi na której jest kolizją (ciało 1)
  if xPA.Active then
   xPA.Position:= V2D_Sub(xPA.Position, V2D_Scale(vCollisionVector, (1.0 - T) * sRatio1 * Lambda));
  if xPB.Active then
   xPB.Position:= V2D_Sub(xPB.Position, V2D_Scale(vCollisionVector, T * sRatio1 * Lambda));

  //Odpowiedź kolizji dla cząsteczki która koliduje z ciałem 1. (ciało 2)
  if m_xCollisionInfo.xParticle.Active then
   begin
     //najpierw odsuwam ją od ciała 1     
     m_xCollisionInfo.xParticle.Position:= V2D_Add(m_xCollisionInfo.xParticle.Position, V2D_Scale(vCollisionVector, sRatio2));

     //Tutaj liczę prędkość cząsteczki po kolizji uwzględniając tarcie i restytucję. Nie mam zielonego pojęcia dlaczego to nie działa.
     vVelN:= V2D_Scale(m_xCollisionInfo.vNormal, V2D_Dot(m_xCollisionInfo.vNormal, m_xCollisionInfo.xParticle.Velocity));
     vVelT:= V2D_Sub(m_xCollisionInfo.xParticle.Velocity, vVelN);
     vVelocity:= V2D_Add(V2D_Scale(vVelT, 1.0 - sFriction), V2D_Scale(vVelN, -sRestitution));

     m_xCollisionInfo.xParticle.Velocity:= vVelocity;
   end;
end;

Dodam też, że czasem przy kolizji (uwzględniając tarcie i restytucję) ciała potrafią zniknąć (pozycja w nieskończoność idzie).

Jeśli ktoś ma jakiś pomysł będę bardzo wdzięczny bo w sumie bez tego stoję w miejscu. Jeśli ktoś nie rozumie wzorów na prędkość wliczając restytucję i tarcie mogę podesłać kawałem objaśnienia wraz z rysunkiem.

Pozdrawiam!

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline taki_tam

  • Użytkownik

# Lipiec 04, 2011, 19:35:14
Problem rozwiązany. Nie uwzględniłem iteracji na klatkę symulacji. Przez to prędkość wypadkowa była za każdym razem znikomo mała.

Pozdrawiam! ;)