Devo dire che questo è un codice piuttosto terribile che hai lì, e lo faccio da più di 10 anni. Dovresti ottenere un manuale di base sulla dinamica (come Hibbeler).
Real impulse = -(1+e) * (Rvector::dotProduct(relativeVelocities,floorNormal))
/(1/m_Bodies[i].mass + floorMass);
Questa equazione sorta di sguardi che si sta tentando di calcolare l'impulso restituzione per l'impatto (anche se il calcolo è sbagliato). Primo, devi capire che un impulso non è la stessa cosa di una forza. Un impulso è l'integrale della forza per un certo intervallo di tempo. Durante un impatto, puoi assumere che il periodo di tempo sia veramente piccolo ed è per questo che esegui un cambio di velocità istantaneo. Ed è per questo che dovresti aver specificato che il codice di integrazione non ha nulla a che fare con il calcolo della collisione, perché è by-passato per quell'istante, o almeno dovrebbe essere se fai un calcolo basato sull'impulso. Questo è ciò che il calcolo effettivo dovrebbe essere simile:
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;
che semplifica in realtà ad una riga come segue:
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);
Tuttavia, se si assume il piano di avere massa infinita (o molto più grande di quello del corpo), quindi si avrebbe semplicemente:
Real body_rel_vel_after = -e * Rvector::dotProduct(relativeVelocities, floorNormal);
Real body_vel_after = Rvector::dotProduct(floorVelocity, floorNormal) + body_rel_vel_after;
È così semplice. Ma, sotto quell'ipotesi, non hai la conservazione della quantità di moto.Ma in ogni caso, l'impulso restituzione per l'impatto può essere calcolato come:
Real impulse = m_Bodies[i].mass * (body_vel_after - Rvector::dotProduct(m_Bodies[i].Vel, floorNormal));
Ora, perché l'impulso restituzione è l'integrale della forza normale sul piccolo periodo di tempo di impatto, la impulso dal l'attrito durante l'impatto può essere calcolato dall'impatto di restituzione. La forza di attrito è uguale a "mu" volte la forza normale, cioè |Ff| = mu * |Fn|
, questo vale anche per l'impulso, cioè |If| = mu * |In|
. Quindi, puoi calcolarlo direttamente:
Real friction_impulse = mu * fabs(impulse);
Ma questa è solo la grandezza dell'impulso di attrito. E 'direzione è opposta dalla velocità tangenziale relativa, che è:
Rvector tangent_rel_vel = relativeVelocities - Rvector::dotProduct(relativeVelocities, floorNormal) * floorNormal;
Ed è direzione è:
Rvector dir_rel_vel = tangent_rel_vel;
dir_rel_vel.normalize();
(Si noti che ho bisogno di mantenere la velocità tangenziale intatto, perché sarà necessario in seguito)
a questo punto, si potrebbe calcolare la velocità tangenziale dopo l'impatto nel modo seguente (ancora una volta, sotto l'ipotesi di un piano infinito di massa, in caso contrario, è più complicato di così):
Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * friction_impulse/m_Bodies[i].mass;
Tuttavia, cosa succede se l'impulso di attrito fa sì che la velocità relativa tangenziale arrivi a zero? Questo è un problema, perché, con la formula di cui sopra, parte dell'impulso di attrito potrebbe finire per invertire la direzione della velocità relativa tangenziale, il che significherebbe che durante l'ultima parte dell'impatto, la forza di attrito sta effettivamente agendo nella direzione di la velocità (non buona). La maggior parte dell'attrito può fare è fermare il moto relativo. Quindi, è necessario verificare la presenza di tale condizione:
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.
A questo punto, tutto quello che dovete fare è combinare le due velocità finali:
m_Bodies[i].Vel = floorVelocity + tangent_rel_vel_after + body_rel_vel_after * floorNormal;
E questo è tutto, almeno, proprio per questo problema semplice (massa infinita del pavimento). In realtà, questo approccio basato sull'impulso diventa sempre più difficile da gestire mentre complicate le cose: due oggetti a massa finita, oggetti multipli e dinamiche di corpo rigido effettive (perché qui state facendo solo la dinamica delle particelle). L'approccio basato sull'impulso si vede raramente ovunque, al di là dei semplici esempi di palle da campo rimbalzanti sul pavimento. A proposito, non dovresti davvero chiamarlo simulatore "corpo rigido" poiché tutto ciò che stai facendo è una dinamica particellare (e la dinamica 3D del corpo rigido è molto più complicata di così). Inoltre, la tua legge sull'integrazione è terribile, ma questa è una storia completamente diversa.
Sei sicuro che 'fDirection.normalize()' influenza fDirection? Potrebbe essere che questa funzione restituisca solo una versione normalizzata del vettore senza influenzare 'fDirection' stessa? – Joey
Se i corpi accelerano dopo essere rimbalzati, sarebbe bello vedere il pezzo di codice in cui ci si integra nel tempo. –
Sì, l'ho appena controllato e sicuramente lo riguarda direttamente. –