您的位置:首页 > 其它

Bullet Physics Engine(物理引擎)中使用约束

2016-05-14 12:25 417 查看
Bullet(version 2.77)中提供了6中基本的约束:

点点约束 btPoint2PointConstraint
铰链约束 btHingeConstraint
滑动约束 btSliderConstraint
锥形约束 btConeTwistConstraint
通用的6自由度约束 btGeneric6DofConstraint
接触点约束 btContactConstraint

全部继承自btTypedConstraint。
前4个约束在使用上都比较简单,其功能也容易顾名思义,可以参考SDK带的例子ConstraintDemo。
btGeneric6DofConstraint的6自由度分别是表示平移的3个分量和表示旋转的欧拉角的3个分量,欧拉角使用Roll-Yaw-Pitch的旋转顺序,即相当于对X的旋转矩阵Y的旋转矩阵Z的旋转矩阵的复合。
(欧拉角:http://www.cnitblog.com/luckydmz/archive/2010/09/07/68674.html)
btContactConstraint貌似是一个已经被废弃的约束,现在并没有被使用,而且实现是空的。
在btSequentialImpulseConstraintSolver中将碰撞信息创建成了btSolverConstraint,而它没有继承自btTypedConstraint。
接下来主要讨论btGeneric6DofConstraint的用法及其使用上的限制和绕过限制的方法。
先看一个简单的例子:
btVector3 pivotInA(0,5,0);

btTransform trans(btTransform::getIdentity());

trans.setOrigin(pivotInA);

btTypedConstraint* p2p = new btGeneric6DofConstraint(*body0, trans, true);
这段代码使用btGeneric6DofConstraint创建了一个点点约束,body0被约束到保持到它上方5个单位处的定点的距离不变,而可以绕该定点任意旋转。

相当于等价的用btPoint2PointConstraint创建出的如下约束:

btVector3 pivotInA(0,5,0);

btTypedConstraint* p2p = new btPoint2PointConstraint(*body0,
pivotInA);
上例中btGeneric6DofConstraint的构造函数参数的意义如下:

btGeneric6DofConstraint(

btRigidBody& rbB, //被约束的刚体

const btTransform& frameInB, //对约束刚体的变换,约束条件是建立在变换后的刚体上

bool useLinearReferenceFrameB); //true表示约束条件参考由frameInB定义的坐标系否则参考世界坐标系

在创建出btGeneric6DofConstraint之后还应该使用如下函数设置6个自由度的约束条件

void setLinearLowerLimit(const btVector3& linearLower);

void setLinearUpperLimit(const btVector3& linearUpper);

void setAngularLowerLimit(const btVector3& angularLower);

void setAngularUpperLimit(const btVector3& angularUpper);
Lowerlimit == Upperlimit -> axis is locked.

Lowerlimit > Upperlimit -> axis is free

Lowerlimit < Upperlimit -> axis it limited in that range

如果不设置约束条件,默认情况平移将被锁住,而旋转是自由的。

所以上面的例子创建的通用6自由度约束的意义是:将刚体“向上”平移5个单位后将平移锁死而允许自由旋转。

约束刚体的变换 在刚体的worldTransform之前作用与刚体,所以这里的“向上”是不对刚体进行worldTransform时的向上。

这就是为什么它等价于上述的btPoint2PointConstraint约束。

上面旋转是自由的,当然我们可以进行限制,比如只允许刚体绕某个轴进行旋转,下面的例子中我们分别限制只允许绕X轴、Y轴、Z轴旋转。

{ //允许绕X轴自由旋转,将Y轴、Z轴锁死

trans.setOrigin(btVector3(-10,0,0));

d6body0 = localCreateRigidBody( mass,trans,shape);

d6body0->setActivationState(DISABLE_DEACTIVATION);

spSlider6Dof = new btGeneric6DofConstraint(*d6body0,btTransform::getIdentity(),true);

spSlider6Dof->setAngularLowerLimit(btVector3(1.0, 0, 0));

spSlider6Dof->setAngularUpperLimit(btVector3(-1.0,0, 0));

m_dynamicsWorld->addConstraint(spSlider6Dof);

spSlider6Dof->setDbgDrawSize(btScalar(5.f));

}

{ //允许绕Y轴自由旋转,将X轴、Z轴锁死

trans.setOrigin(btVector3(0,0,0));

d6body0 = localCreateRigidBody( mass,trans,shape);

d6body0->setActivationState(DISABLE_DEACTIVATION);

spSlider6Dof = new btGeneric6DofConstraint(*d6body0,btTransform::getIdentity(),true);

spSlider6Dof->setAngularLowerLimit(btVector3(0, 1.0, 0));

spSlider6Dof->setAngularUpperLimit(btVector3(0, -1.0, 0));

m_dynamicsWorld->addConstraint(spSlider6Dof);

spSlider6Dof->setDbgDrawSize(btScalar(5.f));

}

{ //允许绕Z轴自由旋转,将X轴、Y轴锁死

trans.setOrigin(btVector3(10,0,0));

d6body0 = localCreateRigidBody( mass,trans,shape);

d6body0->setActivationState(DISABLE_DEACTIVATION);

spSlider6Dof = new btGeneric6DofConstraint(*d6body0,btTransform::getIdentity(),true);

spSlider6Dof->setAngularLowerLimit(btVector3(0, 0, 1.0));

spSlider6Dof->setAngularUpperLimit(btVector3(0, 0,-1.0));

m_dynamicsWorld->addConstraint(spSlider6Dof);

spSlider6Dof->setDbgDrawSize(btScalar(5.f));

}
你可以下载附件中的代码替换ConstraintDemo中的同名文件来观看上面代码的效果 ConstraintDemo.rar



可以看到绕X轴自由旋转和绕Z轴自由旋转的约束都是正确的,而绕Y轴自由旋转的约束出现了异常。
从btGeneric6DofConstraint的注释中我们可以发现对转角的约束是有限制的

AXISMIN ANGLEMAX ANGLE
X-PIPI
Y-PI/2PI/2
Z-PIPI
这个限制的存在应该和欧拉角的唯一性有关。(一个相似的例子是经纬度)

当定义超过限制的约束时,约束会变得十分诡异,另外,限制使得对Y轴的约束只能是locked或limited而不能是free

当我们想创建一个不会翻的车子,我们需要让Y轴自由旋转,而X轴和Z轴有一定限制,这时候怎么办?

一个解决办法如下:

{

trans.setOrigin(btVector3(0,0,0));

d6body0 = localCreateRigidBody( mass,trans,shape);

d6body0->setActivationState(DISABLE_DEACTIVATION);

btRigidBody* _bt_balancer_body = new btRigidBody(0,0,0);

m_dynamicsWorld->addRigidBody(_bt_balancer_body);

// must use X axis as Y axis because 6dof wont spin freely on Y

btTransform rotateZ( btTransform::getIdentity() );

rotateZ.getBasis().setEulerZYX( 0, 0, SIMD_HALF_PI );

spSlider6Dof = new btGeneric6DofConstraint(*d6body0, *_bt_balancer_body, rotateZ, rotateZ,true);

// 这里的约束条件是参照rotateZ表示的坐标系,是经过绕Z轴旋转的坐标系,这里的X轴是世界坐标系的Y轴,所以只需要设置旋转的X自由,而锁死Y,Z即可绕过对Y轴不能设置自由的限制。

spSlider6Dof->setAngularLowerLimit(btVector3(1.0, 0, 0));

spSlider6Dof->setAngularUpperLimit(btVector3(-1.0, 0, 0));

m_dynamicsWorld->addConstraint(spSlider6Dof);

spSlider6Dof->setDbgDrawSize(btScalar(5.f));

}
效果如图:



附件为错误和正确限制示例的可执行文件 AppConstraintDemo_exe.rar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: