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.
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
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. –
Yeah chỉ cần kiểm tra nó và nó chắc chắn ảnh hưởng trực tiếp đến nó. –