graphics网格在BulletPhysicsdebugging图中滞后于碰撞形状

子弹物理中,当我debugging绘制物理世界时,graphics网格落后于collsion形状。

m_DynamicsWorld->stepSimulation(1 / 60.0f, 10); btTransform trans, trans2; trans2 = m_RigidBodies.at("CubeMesh")->m_Body->getWorldTransform(); m_RigidBodies.at("CubeMesh")->m_Body->getMotionState()->getWorldTransform(trans); /* * using * m_RigidBodies.at("CubeMesh")->m_Body->getMotionState()->getWorldTransform(trans); * * causes the graphical mesh to lag behind the collision shape in DebugDraw call * Checking with debugger shows that the lag error keeps on increasing * */ // // glm::mat4 M; trans.getOpenGLMatrix(glm::value_ptr(M)); m_RigidBodies.at("CubeMesh")->GetGraphicalObject()->Model = M; if (m_DebugDraw) { m_DynamicsWorld->debugDrawWorld(); } 

如果我使用trans2中的OpenGLmatrix,那么debugging绘图是非常有用的 。 但是在trans中 ,graphics网格在debugging绘制中滞后于碰撞形状。

设置CubeMesh刚体时使用了btDefaultMotionState。

 btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0.0f, 90.0f, 0.0f)); cubeMesh->m_PhysicsBody->m_MotionState = new btDefaultMotionState(tr); 

有谁能解释这个滞后的原因吗?

请注意,这个答案可能会更完整,但是,因为我不是一个子弹/物理引擎大师,而且我现在无法轻松设置一个项目,所以我没有机会尝试和debugging代码来查看到底发生了什么。

我已经从源头上对代码进行了格式化,以便于阅读。

在代码中仔细研究一下,然后记住文档中有关运动状态的内容,我再次发现这个页面讨论了BulletPhysics中的MotionState ,它指出:

子弹知道如何为你插入身体运动。 如前所述,插值的实现是通过运动状态来处理的。

如果你试图请求一个身体的位置,它会返回在最后一个物理刻度结束的位置。 这对很多事情都很有用,但是对于渲染,你会需要一些插值。 Bullet在将值传递给setWorldTransform之前,对主体进行插值。

如果你想要一个物体的非插值位置(这将是在最后一个物理时间结束时计算的位置),可以使用btRigidBody :: getWorldTransform()直接查询物体。

要获得渲染的插值,必须在渲染循环中调用StepSimulation(deltaTime)。 只包含一个deltaTime参数,没有其他参数。

此外,浏览Bullet的代码,源于int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep)部分:

 for (int i=0;i<clampedSimulationSteps;i++) { internalSingleStepSimulation(fixedTimeStep); synchronizeMotionStates(); } 

我们find这个function:

 void btRigidBody::predictIntegratedTransform(btScalar timeStep,btTransform& predictedTransform) { btTransformUtil::integrateTransform( m_worldTransform, m_linearVelocity, m_angularVelocity, timeStep, predictedTransform ); } 

这被称为在某一点做一个模拟步骤来更新body世界变换( predictedTransform变换这里调用body->getInterpolationWorldTransform() ); 和另一个被调用来更新MotionState

 void btDiscreteDynamicsWorld::synchronizeSingleMotionState(btRigidBody* body) { btAssert(body); if (body->getMotionState() && !body->isStaticOrKinematicObject()) { btTransform interpolatedTransform; btTransformUtil::integrateTransform( body->getInterpolationWorldTransform(), body->getInterpolationLinearVelocity(), body->getInterpolationAngularVelocity(), (m_latencyMotionStateInterpolation && m_fixedTimeStep) ? m_localTime - m_fixedTimeStep : m_localTime*body->getHitFraction(), interpolatedTransform); body->getMotionState()->setWorldTransform(interpolatedTransform); } } 

我们看到有一个额外的步骤来synchronizeMotionStates ,这似乎是基于计算的body信息计算,并可能在不同的时间步骤进行整合。

这里的关键元素是m_latencyMotionStateInterpolation ,默认情况下是true 。 看看这个variables的文档(重点是我的):

先前和当前变换之间的运动状态插值,而不是当前和下一个变换。 由于渗透,这可以减轻渲染中的不连续性

似乎是为什么你使用运动状态的值,而不是身体的价值时,得到滞后。


在你的情况下,如果你能够每秒更新你的graphics60次,而且你能够每秒更新60次物理模拟,而且你是以1:1的比例来做的,并且不关心移动预测,似乎建议打电话给:

 m_DynamicsWorld->stepSimulation(1 / 60.0f, 1, 1 / 60.0f); 

并像你所发现的那样,直接从身体中获得变换。

我希望它有助于:)