2013-01-23 53 views
5

我目前正在研究3D剛體仿真程序。我目前設法使剛體與地面碰撞並使用衝動正確彈跳。然而,我的問題是,一旦他們反彈,他們會不斷加速,儘管使用摩擦力矢量試圖減慢他們的速度。剛體仿真摩擦

這是代碼,當你走在路上

Rvector fDirection(m_Bodies[i].Vel.x,0.0,m_Bodies[i].Vel.z); 
Rvector relativeVelocities = m_Bodies[i].Vel - floorVelocity; 
fDirection.normalize(); 


Real impulse = -(1+e) * (Rvector::dotProduct(relativeVelocities,floorNormal)) 
/(1/m_Bodies[i].mass + floorMass); 
Rvector friction = fDirection*mu*gravity.length()*m_Bodies[i].mass; 

Rvector collision_forces = Rvector(0,1,0)*impulse; 
collision_forces += friction ; 

m_Bodies[i].Vel += (collision_forces/m_Bodies[i].mass); 

感謝

編輯: 這裏是集成代碼。

void RigidBodySimulation::eulerIntegration(float dTime) 
{ 
    Rvector newVel; 
    Rvector newPos; 
    Rvector zero(0.0, 0.0, 0.0); 
    Real one_over_mass; 
    Rvector accel; 
    for(unsigned int i = 0 ; i < m_Bodies.size(); i++) 
    { 
     one_over_mass = 1/m_Bodies[i].mass; 
     newVel = m_Bodies[i].Vel + m_Bodies[i].force*one_over_mass*dTime; 
     newPos = m_Bodies[i].Pos + m_Bodies[i].Vel*dTime; 
     accel = m_Bodies[i].force/m_Bodies[i].mass; 
     m_Bodies[i].acceleration = accel; 
     m_Bodies[i].newPos = newPos; 
     m_Bodies[i].Vel = newVel; 
     m_Bodies[i].Pos = newPos; 
    } 
} 
+0

你確定'fDirection.normalize()'影響fDirection嗎?難道這個函數只是返回一個矢量的標準化版本而不會影響'fDirection'本身? – Joey

+0

如果身體在反彈後加速,那麼看到隨着時間的推移整合的代碼將會非常棒。 –

+0

只是檢查它,它直接影響它。 –

回答

6

我不得不說,這是一個非常可怕的代碼片段,我已經這麼做了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剛體動力學比這更復雜)。另外,你的整合法律很糟糕,但這是一個完全不同的故事。

+0

也許你可以稍微調整一下,但仔細分析+1。同樣很好的指出,歐拉的方法是可能的最差選擇。也許鏈接到http://en.wikipedia.org/wiki/Numerical_ordinary_differential_equations會有所幫助。 –

+0

謝謝。糟糕的代碼對我來說並不合適,它目前適用於大學模塊,並且框架和許多代碼都給了我們。我很掙扎,因爲它很糟糕!下次我在它面前我會用你的建議。感謝您的回覆。 –

+0

非常感謝您的幫助,現在一切正常。 –

0

摩擦力是倒退的,不是嗎?

Rvector fDirection(m_Bodies[i].Vel.x,0.0,m_Bodies[i].Vel.z); 

這是速度的方向。然後,您可以通過一些常量乘以它,然後把它添加到速度(與衝動沿)

collision_forces += friction ; 
m_Bodies[i].Vel += (collision_forces/m_Bodies[i].mass); 

所以這將起到增加沿着地面的速度。


還有其他一些奇怪的事情:
你的衝動詞有:(1/m_Bodies[i].mass + floorMass)這是加入1 /質量質量。它不應該是(1/(m_Bodies[i].mass + floorMass))

然後在積分器中,你可以從力計算加速度,但不能積分它,你也直接對力的速度施加力。那麼acceleration會員是什麼?

+0

是的,我已經嘗試過,我得到了一些奇怪的抖動。他們向後跳躍,然後繼續前進。 –

+0

1)你確定碰撞碼每次碰撞只調用一次嗎? 2)你在哪裏設置'body.force'? – AShelly

+0

是的,每次碰撞肯定只會調用一次碰撞。身體。在對象初始化時,force被設置爲零向量。 –