2013-01-23 40 views
5

Tôi hiện đang làm việc trên một chương trình mô phỏng 3D Rigid Body. Tôi hiện đang quản lý để có được các cơ quan cứng nhắc va chạm với sàn nhà và nảy một cách chính xác bằng cách sử dụng xung. Tuy nhiên, vấn đề của tôi là một khi họ đã bị trả lại họ tăng tốc liên tục mặc dù sử dụng một ma sát vector để thử và làm chậm chúng.Ma sát mô phỏng cứng nhắc

Đây là mã khi bạn rơi xuống đất

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); 

Cảm ơn

Edit: Đây là mã tích hợp.

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

Bạn có chắc chắn rằng 'fDirection.normalize()' ảnh hưởng đến fDirection không? Có thể nào hàm này chỉ trả về một phiên bản chuẩn hóa của vectơ mà không ảnh hưởng đến 'fDirection'? – Joey

+0

Nếu các cơ quan tăng tốc sau khi chúng bị trả lại, nó sẽ là tuyệt vời để xem đoạn mã mà bạn tích hợp theo thời gian. –

+0

Yeah chỉ cần kiểm tra nó và nó chắc chắn ảnh hưởng trực tiếp đến nó. –

Trả lời

6

Tôi phải nói, đây là một đoạn mã khá khủng khiếp mà bạn có ở đó và tôi đã làm điều này trong hơn 10 năm. Bạn sẽ nhận được một sách giáo khoa cơ bản về động lực (như Hibbeler).

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

Phương trình này có vẻ như bạn đang cố tính xung động từ tác động (mặc dù tính toán sai). Đầu tiên, bạn phải hiểu rằng xung lực không giống như một lực. Một xung là tích phân của lực trong một khoảng thời gian nhất định. Trong một tác động, bạn có thể giả định rằng khoảng thời gian thực sự nhỏ và đó là lý do tại sao bạn thực hiện thay đổi tốc độ tức thời. Và đó là lý do tại sao bạn nên xác định rằng mã tích hợp không có gì liên quan đến phép tính va chạm, bởi vì nó được truyền cho tức thời, hoặc ít nhất, nó sẽ là nếu bạn thực hiện phép tính dựa trên xung. Đây là những gì các tính toán thực tế sẽ giống như thế:

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; 

nào thực sự đơn giản để một dòng như sau:

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); 

Tuy nhiên, nếu bạn giả sàn có khối lượng vô hạn (hoặc lớn hơn nhiều so với của cơ thể), sau đó bạn chỉ cần có:

Real body_rel_vel_after = -e * Rvector::dotProduct(relativeVelocities, floorNormal); 
Real body_vel_after = Rvector::dotProduct(floorVelocity, floorNormal) + body_rel_vel_after; 

Thật đơn giản. Nhưng, theo giả định đó, bạn không có bảo tồn động lượng.Nhưng trong mọi trường hợp, sự thúc đẩy bồi thường từ các tác động có thể được tính như sau:

Real impulse = m_Bodies[i].mass * (body_vel_after - Rvector::dotProduct(m_Bodies[i].Vel, floorNormal)); 

Bây giờ, vì sự thúc đẩy bồi thường là không thể thiếu của lực lượng bình thường trong khoảng thời gian nhỏ của tác động, các xung từ ma sát trong thời gian tác động có thể được tính toán từ tác động bồi thường đó. Lực ma sát bằng với "mu" nhân lực bình thường, tức là, |Ff| = mu * |Fn|, điều này cũng hợp lệ cho xung, tức là, |If| = mu * |In|. Vì vậy, bạn có thể tính toán trực tiếp:

Real friction_impulse = mu * fabs(impulse); 

Nhưng đó chỉ là tầm quan trọng của xung ma sát. Đó là hướng đối diện từ vận tốc tiếp tuyến tương đối, đó là:

Rvector tangent_rel_vel = relativeVelocities - Rvector::dotProduct(relativeVelocities, floorNormal) * floorNormal; 

Và nó hướng là:

Rvector dir_rel_vel = tangent_rel_vel; 
dir_rel_vel.normalize(); 

(Chú ý rằng tôi cần phải giữ cho vận tốc tiếp tuyến còn nguyên vẹn, bởi vì nó sẽ là cần thiết sau Tại thời điểm này, bạn có thể tính toán vận tốc tiếp tuyến sau khi tác động như sau (một lần nữa, theo giả định của một tầng khối lượng vô hạn, nếu không, nó phức tạp hơn):

Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * friction_impulse/m_Bodies[i].mass; 

Tuy nhiên, điều gì sẽ xảy ra nếu xung ma sát gây ra vận tốc tương đối tiếp tuyến tới 0? Đó là một vấn đề, bởi vì, với công thức trên, một phần của xung ma sát có thể đảo ngược hướng của vận tốc tương đối tiếp tuyến, có nghĩa là trong phần sau của tác động, lực ma sát thực sự tác động theo hướng vận tốc (không tốt). Ma sát nhất có thể làm là dừng chuyển động tương đối. Vì vậy, bạn cần phải kiểm tra các điều kiện:

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. 

Tại thời điểm này, tất cả các bạn cần làm là kết hợp hai vận tốc cuối cùng:

m_Bodies[i].Vel = floorVelocity + tangent_rel_vel_after + body_rel_vel_after * floorNormal; 

Và đó là nó, ít nhất, cho điều này rất vấn đề đơn giản (khối lượng vô hạn của sàn). Trong thực tế, phương pháp dựa trên xung này ngày càng trở nên khó giải quyết khi bạn làm phức tạp mọi thứ: hai vật thể khối lượng hữu hạn, nhiều vật thể và động lực cứng nhắc thực tế (vì bạn chỉ làm động lực hạt ở đây). Cách tiếp cận dựa trên xung động hiếm khi được thấy ở bất cứ đâu ngoài các ví dụ sân trường đơn giản của những quả bóng nảy trên sàn nhà. Btw, bạn không nên gọi đây là mô phỏng "cứng nhắc" vì tất cả các bạn thực sự đang làm một động lực hạt (và động cơ cứng nhắc 3D là cách phức tạp hơn thế này). Ngoài ra, luật tích hợp của bạn là khủng khiếp, nhưng đó là một câu chuyện hoàn toàn khác.

+0

Có thể bạn có thể giảm âm lượng xuống một chút, nhưng +1 cho một phân tích cẩn thận. Cũng tốt để chỉ ra rằng phương pháp Euler là sự lựa chọn tồi tệ nhất có thể. Có lẽ một liên kết đến http://en.wikipedia.org/wiki/Numerical_ordinary_differential_equations sẽ giúp ích cho bạn. –

+0

Cảm ơn. Mã người nghèo không phải là tôi, nó hiện đang làm việc cho một mô-đun đại học và khuôn khổ và rất nhiều mã đã được trao cho chúng tôi. Im đấu tranh với nó rất nhiều vì nó xấu! Lần sau, tôi sẽ sử dụng lời khuyên của bạn. Cảm ơn vì đã trả lời. –

+0

Cảm ơn rất nhiều vì sự giúp đỡ của bạn, tất cả đều hoạt động tốt ngay bây giờ. –

0

Ma sát là ngược, phải không?

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

Đây là hướng của vận tốc. Sau đó, nhân nó với một số hằng số, sau đó thêm nó vào vận tốc (cùng với xung lực)

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

Vì vậy sẽ hành động để tăng vận tốc dọc theo sàn nhà.


Có một số điều kỳ lạ khác:
hạn xung của bạn có: (1/m_Bodies[i].mass + floorMass) này được bổ sung thêm 1/khối lượng tới hàng loạt. Không phải là (1/(m_Bodies[i].mass + floorMass))

Và sau đó trong trình tích hợp, bạn tính toán gia tốc từ lực, nhưng sau đó không bao giờ tích hợp nó, bạn cũng áp dụng lực để vận tốc trực tiếp. Vậy thành viên acceleration là gì?

+0

Vâng tôi đã thử điều đó và tôi nhận được một số loại kỳ lạ của jittering. Chúng nhảy ngược về phía sau và sau đó tiếp tục trượt về phía trước. –

+0

1) bạn có chắc chắn mã xung đột chỉ được gọi một lần cho mỗi va chạm? 2) nơi bạn đặt 'body.force'? – AShelly

+0

Yeah va chạm chắc chắn chỉ được gọi một lần cho mỗi va chạm. thân hình.lực được đặt thành véc tơ bằng không khi khởi tạo các đối tượng. –