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的注释中我们可以发现对转角的约束是有限制的
这个限制的存在应该和欧拉角的唯一性有关。(一个相似的例子是经纬度)
当定义超过限制的约束时,约束会变得十分诡异,另外,限制使得对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
点点约束 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的注释中我们可以发现对转角的约束是有限制的
AXIS | MIN ANGLE | MAX ANGLE |
X | -PI | PI |
Y | -PI/2 | PI/2 |
Z | -PI | PI |
当定义超过限制的约束时,约束会变得十分诡异,另外,限制使得对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
相关文章推荐
- eclipse + pydev 创建django项目
- C++ 传递对象---用值传递对象
- Spring Boot 中使用log4jdbc记录SQL的运行时参数
- 下载Google地图,瓦片数据和经纬坐标的切换
- PhpStorm许可server地址
- Matlab Tricks(七)—— 矩阵列/列的归一化/单位化(normalize)
- 大数据学习线路图
- Android高阶之AS如何打.aar包,并应用
- 自定义Dialog(2)
- jupyter notebook 各种用法记录(陆续更新)
- (3)使用IntelliJ IDEA建立maven项目
- 【中间件】(一):中间件原来和分布式有关系……
- PHP设计模式:观察者模式
- Guido von Rossum - i wrote python
- HDU 1029 Ignatius and the Princess IV
- Qt中控件类的提升
- 第10、11周项目3 警察和厨师(2)
- 使用Gulp和Browserify创建多个绑定文件
- Android Studio 快捷键 for Mac OS X
- win7 类似Linux which命令