我不得不說,這是一個非常可怕的代碼片段,我已經這麼做了10多年。你應該獲得關於動力學的基本教科書(如Hibbeler)。
Real impulse = -(1+e) * (Rvector::dotProduct(relativeVelocities,floorNormal))
/(1/m_Bodies[i].mass + floorMass);
這個公式看起來有點像你試圖計算從衝擊歸還衝動(雖然計算是錯誤的)。首先,你必須明白衝動與武力不是一回事。衝動是在一段時間內力的積分。在碰撞過程中,你可以假定這段時間非常小,這就是爲什麼你瞬時改變速度的原因。這就是爲什麼你應該指定整合代碼與碰撞計算無關,因爲它在那個瞬間被旁路,或者至少應該是如果你進行基於脈衝的計算。這是實際的計算應該是什麼樣子:
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;
這實際上可以簡化爲一條線,如下所示:
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);
但是,如果假定地板有無限的質量(或比其更大),那麼你只需要:
Real body_rel_vel_after = -e * Rvector::dotProduct(relativeVelocities, floorNormal);
Real body_vel_after = Rvector::dotProduct(floorVelocity, floorNormal) + body_rel_vel_after;
就這麼簡單。但是,在這個假設下,你沒有動力守恆。現在
Real impulse = m_Bodies[i].mass * (body_vel_after - Rvector::dotProduct(m_Bodies[i].Vel, floorNormal));
,因爲歸還衝動是在衝擊的一小段時間內的正常力的積分,衝動來自:但在任何情況下,從影響恢復衝動可以作爲計算影響期間的摩擦可以從恢復原狀影響中計算出來。摩擦力等於法向力的「mu」倍,即|Ff| = mu * |Fn|
,這對衝動也是有效的,即|If| = mu * |In|
。所以,你可以直接計算它:
Real friction_impulse = mu * fabs(impulse);
但這只是摩擦衝量的大小。它的方向是從相對切向速度,這是相反的:
Rvector tangent_rel_vel = relativeVelocities - Rvector::dotProduct(relativeVelocities, floorNormal) * floorNormal;
而且它的方向是:
Rvector dir_rel_vel = tangent_rel_vel;
dir_rel_vel.normalize();
(請注意,我需要保持切向速度不變,因爲這將在後面需要)
此時,您可以按如下方式計算碰撞後的切向速度(同樣,在無限質量樓層的假設下,否則,它比這更復雜):
Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * friction_impulse/m_Bodies[i].mass;
但是,如果摩擦脈衝導致切向相對速度達到零,會怎麼樣?這是一個問題,因爲利用上述公式,摩擦脈衝的一部分可能會扭轉切向相對速度的方向,這將意味着在撞擊的後半部分,摩擦力實際上作用於速度(不好)。大部分摩擦力可以停止相對運動。所以,你需要檢查該條件:
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.
在這一點上,所有你需要做的是將二者結合起來的最終速度:
m_Bodies[i].Vel = floorVelocity + tangent_rel_vel_after + body_rel_vel_after * floorNormal;
就是這樣,至少,這很簡單的問題(地板的無限質量)。實際上,當你將事物複雜化時,這種基於脈衝的方法變得越來越難以處理:兩個有限質量對象,多個對象和實際的剛體動力學(因爲你只是在這裏做粒子動力學)。基於衝動的方法除了簡單的校園球例子在地板上跳動之外幾乎看不到任何地方。順便說一句,你不應該真的把它稱爲「剛體」模擬器,因爲你真的在做一個粒子動力學(和3D剛體動力學比這更復雜)。另外,你的整合法律很糟糕,但這是一個完全不同的故事。
你確定'fDirection.normalize()'影響fDirection嗎?難道這個函數只是返回一個矢量的標準化版本而不會影響'fDirection'本身? – Joey
如果身體在反彈後加速,那麼看到隨着時間的推移整合的代碼將會非常棒。 –
只是檢查它,它直接影響它。 –