Muszę powiedzieć, że jest to dość przerażający fragment kodu, który tam masz, i robię to od ponad 10 lat. Powinieneś dostać podstawowy podręcznik dynamiki (jak Hibbeler).
Real impulse = -(1+e) * (Rvector::dotProduct(relativeVelocities,floorNormal))
/(1/m_Bodies[i].mass + floorMass);
Równanie to rodzaj wygląda próbujesz obliczyć impuls restytucji od wpływu (mimo że wyliczenie jest źle). Po pierwsze, musisz zrozumieć, że impuls nie jest tym samym co siła. Impuls jest całką siły w określonym przedziale czasu. Podczas uderzenia możesz założyć, że ten czas jest naprawdę mały i dlatego dokonujesz natychmiastowej zmiany prędkości. I dlatego powinieneś był sprecyzować, że kod integracji nie ma nic wspólnego z obliczaniem kolizji, ponieważ jest on ominięty w tej chwili, a przynajmniej powinien być, jeśli wykonujesz obliczenia oparte na impulsach. To, co rzeczywiste kalkulacja powinna wyglądać następująco:
Real momentum_before = Rvector::dotProduct(m_Bodies[i].Vel * m_Bodies[i].mass + floorVelocity * floorMass, floorNormal);
Real rel_vel_after = -e * Rvector::dotProduct(relativeVelocities,floorNormal);
// conservation of momentum in normal direction gives this:
Real body_vel_after = (momentum_before + floorMass * rel_vel_after)/(m_Bodies[i].mass + floorMass);
Real floor_vel_after = body_vel_after - rel_vel_after;
Które rzeczywiście upraszcza do jednej linii, co następuje:
Real body_vel_after = ((m_Bodies[i].mass - e * floorMass) * Rvector::dotProduct(m_Bodies[i].Vel, floorNormal)
+ (1.0 + e) * floorMass * Rvector::dotProduct(floorVelocity, floorNormal)
)/(m_Bodies[i].mass + floorMass);
Jeśli jednak zakładać podłogę mieć nieskończoną masę (lub znacznie większy niż ciała), wtedy po prostu masz:
Real body_rel_vel_after = -e * Rvector::dotProduct(relativeVelocities, floorNormal);
Real body_vel_after = Rvector::dotProduct(floorVelocity, floorNormal) + body_rel_vel_after;
To takie proste. Ale przy tym założeniu nie zachowujesz dynamiki.Ale w każdym przypadku, impuls restytucja od uderzenia może być obliczona jako:
Real impulse = m_Bodies[i].mass * (body_vel_after - Rvector::dotProduct(m_Bodies[i].Vel, floorNormal));
Teraz, ponieważ impuls restytucja jest całka siły normalnej nad małym okresie czasu uderzeniu impuls od tarcie podczas uderzenia można obliczyć na podstawie tego wpływu na zadośćuczynienie. Siła tarcia jest równa "mu" razy większa od siły normalnej, tj. |Ff| = mu * |Fn|
, jest to również ważne dla impulsu, tj. |If| = mu * |In|
. Możesz więc obliczyć go bezpośrednio:
Real friction_impulse = mu * fabs(impulse);
Ale to tylko wielkość impulsu tarcia. Jest to kierunek jest odwrotny od względnej prędkości obwodowej, który jest:
Rvector tangent_rel_vel = relativeVelocities - Rvector::dotProduct(relativeVelocities, floorNormal) * floorNormal;
I to kierunek jest:
Rvector dir_rel_vel = tangent_rel_vel;
dir_rel_vel.normalize();
(Zauważ, że muszę utrzymać prędkość styczną nienaruszone, ponieważ będzie ona potrzebna później)
w tym momencie, można obliczyć prędkość styczną po uderzeniu w następujący sposób (znów przy założeniu nieskończonej masowej piętrze, w przeciwnym razie jest to bardziej skomplikowane):
Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * friction_impulse/m_Bodies[i].mass;
Co jednak, jeśli impuls tarcia spowoduje, że styczna prędkość względna dojdzie do zera? To problem, ponieważ dzięki powyższej formule część impulsu tarcia mogłaby skończyć odwracając kierunek stycznej prędkości względnej, co oznaczałoby, że podczas drugiej części uderzenia siła tarcia działa w kierunku prędkość (niedobra). Największym tarciem może być zatrzymanie ruchu względnego. Więc trzeba sprawdzić dla tego warunku:
Real tang_rel_vel_change = friction_impulse/mBodies[i].mass;
Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * tang_rel_vel_change;
if (tang_rel_vel_change > tangent_rel_vel.length())
tangent_rel_vel_after = Rvector(0.0, 0.0, 0.0); // stop relative motion.
W tym momencie, wszystko co musisz zrobić, to połączyć dwa końcowe prędkości:
m_Bodies[i].Vel = floorVelocity + tangent_rel_vel_after + body_rel_vel_after * floorNormal;
I to, co najmniej, za to bardzo prosty problem (nieskończona masa podłogi). W rzeczywistości to podejście oparte na impulsach staje się coraz trudniejsze do opanowania, gdy komplikujesz rzeczy: dwie obiekty o skończonej masie, wiele obiektów i faktyczną dynamikę ciała sztywnego (ponieważ właśnie robisz dynamikę cząstek tutaj). Podejście oparte na impulsie rzadko spotyka się poza zwykłymi szkolnymi przykładami piłek odbijających się od podłogi. Btw, nie powinieneś nazywać tego symulatorem "sztywnego ciała", ponieważ właściwie robisz dynamikę cząstek (a dynamika ciała sztywnego 3D jest o wiele bardziej skomplikowana niż ta). Także twoje prawo integracyjne jest straszne, ale to zupełnie inna historia.
Czy jesteś pewien, że 'fDirection.normalize()' wpływa na fDirection? Czy to możliwe, że ta funkcja po prostu zwraca znormalizowaną wersję wektora bez wpływu na 'fDirection'? – Joey
Jeśli ciała przyspieszają po odbiciu, byłoby świetnie zobaczyć fragment kodu, z którym integrujesz się z czasem. –
Tak, właśnie to sprawdziłem i to zdecydowanie wpływa na to bezpośrednio. –