我希望利用子弹物理学或类似的物理引擎来创建具有两条腿的类人身体的逼真的骨架模拟。也就是说,在两个“腿”的顶部创建一个由圆形质量制成的“身体”的模拟,其中每个腿由通过3个关节连接的3个实体块制成,每个关节在一定程度上具有自由度,并且运动范围有限每个方向,类似于人的臀部,膝盖和脚踝。
我的目标是建立一个现实的模型,因此,只有在所有关节都正确平衡的情况下,它才会“站立”,否则它将掉落。
任何对现有教程或资源的指导,建议或指针都将受到赞赏!这似乎是从头开始进行的大量工作...
最佳答案
我目前正在研究类似的代码。我的方法是使用Bullet Physics破布娃娃演示作为起点。它有一个布娃娃,身体部位通过关节相连。
然后,我将使用Bullet Physics动态控制演示来学习如何弯曲关节。目前最具挑战性的部分是设置所有参数。
我建议您学习如何创建通过约束连接的两个刚体,然后激活约束电动机以弯曲关节。
以下是我正在使用的一些代码,以了解刚体和约束在Bullet Physics中的工作方式。该代码创建了两个通过铰链约束连接的块。更新功能会随着时间的推移缓慢弯曲铰链约束。
现在,有了这个,我将回到抹布娃娃并调整关节。
class Simple
{
private:
btScalar targetAngle;
btCollisionShape* alphaCollisionShape;
btCollisionShape* bravoCollisionShape;
btRigidBody* alphaRigidBody;
btRigidBody* bravoRigidBody;
btHingeConstraint* hingeConstraint;
btDynamicsWorld* dynamicsWorld;
public:
~Simple( void )
{
}
btRigidBody* createRigidBody( btCollisionShape* collisionShape,
btScalar mass,
const btTransform& transform ) const
{
// calculate inertia
btVector3 localInertia( 0.0f, 0.0f, 0.0f );
collisionShape->calculateLocalInertia( mass, localInertia );
// create motion state
btDefaultMotionState* defaultMotionState
= new btDefaultMotionState( transform );
// create rigid body
btRigidBody::btRigidBodyConstructionInfo rigidBodyConstructionInfo(
mass, defaultMotionState, collisionShape, localInertia );
btRigidBody* rigidBody = new btRigidBody( rigidBodyConstructionInfo );
return rigidBody;
}
void Init( btDynamicsWorld* dynamicsWorld )
{
this->targetAngle = 0.0f;
this->dynamicsWorld = dynamicsWorld;
// create collision shapes
const btVector3 alphaBoxHalfExtents( 0.5f, 0.5f, 0.5f );
alphaCollisionShape = new btBoxShape( alphaBoxHalfExtents );
//
const btVector3 bravoBoxHalfExtents( 0.5f, 0.5f, 0.5f );
bravoCollisionShape = new btBoxShape( bravoBoxHalfExtents );
// create alpha rigid body
const btScalar alphaMass = 10.0f;
btTransform alphaTransform;
alphaTransform.setIdentity();
const btVector3 alphaOrigin( 54.0f, 0.5f, 50.0f );
alphaTransform.setOrigin( alphaOrigin );
alphaRigidBody = createRigidBody( alphaCollisionShape, alphaMass, alphaTransform );
dynamicsWorld->addRigidBody( alphaRigidBody );
// create bravo rigid body
const btScalar bravoMass = 1.0f;
btTransform bravoTransform;
bravoTransform.setIdentity();
const btVector3 bravoOrigin( 56.0f, 0.5f, 50.0f );
bravoTransform.setOrigin( bravoOrigin );
bravoRigidBody = createRigidBody( bravoCollisionShape, bravoMass, bravoTransform );
dynamicsWorld->addRigidBody( bravoRigidBody );
// create a constraint
const btVector3 pivotInA( 1.0f, 0.0f, 0.0f );
const btVector3 pivotInB( -1.0f, 0.0f, 0.0f );
btVector3 axisInA( 0.0f, 1.0f, 0.0f );
btVector3 axisInB( 0.0f, 1.0f, 0.0f );
bool useReferenceFrameA = false;
hingeConstraint = new btHingeConstraint(
*alphaRigidBody,
*bravoRigidBody,
pivotInA,
pivotInB,
axisInA,
axisInB,
useReferenceFrameA );
// set constraint limit
const btScalar low = -M_PI;
const btScalar high = M_PI;
hingeConstraint->setLimit( low, high );
// add constraint to the world
const bool isDisableCollisionsBetweenLinkedBodies = false;
dynamicsWorld->addConstraint( hingeConstraint,
isDisableCollisionsBetweenLinkedBodies );
}
void Update( float deltaTime )
{
alphaRigidBody->activate();
bravoRigidBody->activate();
bool isEnableMotor = true;
btScalar maxMotorImpulse = 1.0f; // 1.0f / 8.0f is about the minimum
hingeConstraint->enableMotor( isEnableMotor );
hingeConstraint->setMaxMotorImpulse( maxMotorImpulse );
targetAngle += 0.1f * deltaTime;
hingeConstraint->setMotorTarget( targetAngle, deltaTime );
}
};