物理引擎如何计算刚体运动?为什么不同的引擎给我不同的结果

How physics engine calcute the rigid body motion? And why different engine give me different result

我想模拟一个由扭矩 T={1,1,1} 参考世界坐标系施加的物体。物体质量为1Kg,其惯性张量的对角线元素为{2, 1, 1}。但是 bullet2.7 和 bullet2.8 给了我完全不同的结果

#include <btBulletDynamicsCommon.h>  
#include <stdio.h>
#include <iostream>
#include <fstream> 
using namespace std;

/// This is a Hello World program for running a basic Bullet physics simulation

int main(int argc, char** argv)
{

btBroadphaseInterface* broadphase = new btDbvtBroadphase();

///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();

///use the default collision dispatcher. For parallel processing you can use a differnt dispatcher
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);

///the default constraint solver. For parallel processing you can use a different solver
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

///instantiate the dynamics world
btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);

///sets the gravity
dynamicsWorld->setGravity(btVector3(0, 0, 0));


btCollisionShape* Shape = new btSphereShape(1);


//The btTransform class supports rigid transforms with only translation and rotation 
btDefaultMotionState* MotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 50, 0)));

btScalar mass = 1;
btVector3 Inertia(2, 1, 1);
btVector3 torque(1, 1, 1);
btVector3 angularVelocity(0, 0, 0);

///when bodies are constructed, they are passed certain parameters. This is done through a special structure Bullet provides for this.
///rigid body is dynamic if and only if mass is non zero, otherwise static  
btRigidBody::btRigidBodyConstructionInfo RigidBodyCI(mass, MotionState, Shape, Inertia);
btRigidBody* RigidBody = new btRigidBody(RigidBodyCI);
dynamicsWorld->addRigidBody(RigidBody);

ofstream outfile("data.csv", ios::out);
for (int i = 0; i < 300; i++) {

    RigidBody->applyTorque(torque);

    dynamicsWorld->stepSimulation(1 / 60.f, 10);

    angularVelocity = RigidBody->getAngularVelocity();

    outfile << angularVelocity.getX() << "," << angularVelocity.getY() << "," << angularVelocity.getZ() << endl;
}

outfile.close();

delete Shape;


delete dynamicsWorld;
delete solver;
delete dispatcher;
delete collisionConfiguration;
delete broadphase;

printf("Press a key to exit\n");
getchar();
}

项目符号 2.78:

项目符号 2.83:

物理引擎当然会给出不同的结果,因为它们如何计算它们是不同的。这就是您所注意到的。

交互式物理引擎或 "real-time"(如 Box2D 和 Bullet)通常不会提供 100% 准确的结果。它们旨在提供 "good enough" 的结果。这通常意味着足以在视频游戏环境中提供物理感。这是因为他们可以使用捷径来更快地计算结果。

来自 Box2D 常见问题解答:

Box2D uses approximate methods for a few reasons.

  • Performance
  • Some differential equations don't have known solutions
  • Some constraints cannot be determined uniquely

就现实主义而言,不同引擎制造的这些近似值和权衡之类的东西可能并且确实会因引擎而异。如果引擎使用迭代求解器,那么任何差异都会放大方差。引擎也会对碰撞裕度等因素做出不同的选择,这使得引擎之间的同类比较变得更加困难。

由于这些近似值,即使物理引擎如何计算由重力等力引起的速度,它们之间也可能不同。要深入了解 Box2D 和牛顿物理学之间的差异,请查看 iforce2d 在他的 Projected trajectories tutorial.

中的解释

有些事情可以提高这类引擎的准确性。然而,这些是以牺牲性能为代价的。例如使用更小的时间步长、更高的迭代次数或更高精度的数字类型(例如从使用 float 切换到使用 double)。

我发现比较 ODE 0.11、PhysX 和 Newton 3.11 的资源是:A comparison between 3 physics engines. This doesn't discuss the why of the differences as I've explained them however. There's also a discussion on increasing realism in Bulletphysics at: How can I increase the physical realism of my simulation?

希望对您有所帮助!