
物理引擎(Physics Engine)
物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。
它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚拟现实(VR)、机器人仿真 等领域。
物理引擎的核心功能
- 碰撞检测:判断物体是否发生碰撞或接触。
- 物理模拟:根据物理定律(如牛顿力学)计算物体的运动轨迹、速度、加速度等。
- 交互反馈:处理物体碰撞后的力学反应(如反弹、摩擦、破碎)。
- 约束系统:模拟物体间的连接关系(如铰链、弹簧、绳索等)。
常见物理引擎
- Bullet:开源、跨平台,适合刚体和软体模拟,常用于游戏和仿真(OSG开发)。
- PhysX:NVIDIA开发的商业引擎,广泛用于3A游戏(如《绝地求生》)。
- Havok:商业引擎,支持复杂物理效果,应用于影视和游戏。
- Box2D:2D物理引擎,适合2D游戏(如《愤怒的小鸟》)。
物理引擎的工作流程
- 更新物理世界:根据时间步长计算物体运动。
- 碰撞检测:识别所有碰撞对。
- 物理响应:计算碰撞后的速度、力和动量变化。
- 同步渲染:将物理模拟结果反映到图形界面。
刚体(Rigid Body)
刚体 是物理学中的一个理想模型,指在运动和受力过程中 形状和大小完全不变 的物体。换句话说,刚体的任意两点间的距离始终保持不变,忽略形变(如压缩、弯曲、旋转时的体积变化)。
刚体的特点
- 无弹性形变:碰撞时能量守恒(完全弹性碰撞)或部分损失(非弹性碰撞),但形状不变。
- 自由度 :刚体在三维空间中有 6个自由度(3个平移自由度 + 3个旋转自由度)。
- 应用场景 :适用于模拟 硬物体 的运动,如石块、车辆、机械零件等。
与软体的区别
- 软体:允许形变(如布料、液体、果冻),模拟更复杂(需考虑弹性、粘性等)。
- 刚体:简化模型,计算效率高,适合大规模物理模拟。
刚体在物理引擎中的应用
- 通过 质量、惯性矩、摩擦力、 restitution(恢复系数) 等参数定义物理属性。
- 结合碰撞形状(如球体、立方体、胶囊体)进行碰撞检测,减少计算量。
物理引擎与刚体的关系
物理引擎通过算法模拟刚体的运动和交互,例如:
- 当两个刚体碰撞时,物理引擎根据 动量守恒定律 计算碰撞后的速度和方向。
- 利用 约束(Constraint) 限制刚体的自由度(如用铰链连接两个刚体,使其只能绕轴旋转)。
在您的学习场景中(OSG + Bullet),Bullet作为物理引擎,负责处理刚体的碰撞检测和物理模拟,而OSG负责图形渲染,两者结合实现逼真的物理交互效果(如物体掉落、碰撞反弹等)。
实战
cpp
#include <osgViewer/Viewer>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osgGA/TrackballManipulator>
#include <osg/PositionAttitudeTransform>
// Bullet物理引擎头文件
#include <btBulletDynamicsCommon.h>
// OSG与Bullet转换工具
osg::Matrix bulletToOsg(const btTransform& transform) {
osg::Matrix matrix;
btScalar elements[16];
transform.getOpenGLMatrix(elements);
matrix.set(elements);
return matrix;
}
class PhysicsUpdateCallback : public osg::NodeCallback {
public:
PhysicsUpdateCallback(btDynamicsWorld* world,
std::map<btRigidBody*, osg::ref_ptr<osg::MatrixTransform>>& bodyNodeMap)
: _world(world), _bodyNodeMap(bodyNodeMap) {}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
// 更新物理世界
_world->stepSimulation(1.0f/60.0f, 10);
// 更新OSG场景图中的物体位置
for (auto& pair : _bodyNodeMap) {
btRigidBody* body = pair.first;
osg::MatrixTransform* transformNode = pair.second.get();
btTransform trans;
body->getMotionState()->getWorldTransform(trans);
transformNode->setMatrix(bulletToOsg(trans));
}
traverse(node, nv);
}
private:
btDynamicsWorld* _world;
std::map<btRigidBody*, osg::ref_ptr<osg::MatrixTransform>>& _bodyNodeMap;
};
int main() {
// 初始化OSG查看器
osgViewer::Viewer viewer;
viewer.setCameraManipulator(new osgGA::TrackballManipulator);
// 创建根节点
osg::ref_ptr<osg::Group> root = new osg::Group;
// ===== Bullet物理引擎初始化 =====
// 创建碰撞检测配置和调度器
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
// 创建叠代约束求解器
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
// 创建宽广阶段碰撞检测算法
btDbvtBroadphase* overlappingPairCache = new btDbvtBroadphase();
// 创建动力学世界
btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(
dispatcher, overlappingPairCache, solver, collisionConfiguration);
// 设置重力
dynamicsWorld->setGravity(btVector3(0, 0, -9.81));
// ===== 创建物理对象和OSG场景 =====
std::map<btRigidBody*, osg::ref_ptr<osg::MatrixTransform>> bodyNodeMap;
// 1. 创建地面
// OSG部分
osg::ref_ptr<osg::Box> groundShape = new osg::Box(osg::Vec3(0, 0, -1), 20, 20, 1);
osg::ref_ptr<osg::ShapeDrawable> groundDrawable = new osg::ShapeDrawable(groundShape);
osg::ref_ptr<osg::Geode> groundGeode = new osg::Geode;
groundGeode->addDrawable(groundDrawable);
osg::ref_ptr<osg::MatrixTransform> groundTransform = new osg::MatrixTransform;
groundTransform->addChild(groundGeode);
root->addChild(groundTransform);
// Bullet部分
btCollisionShape* groundShapeBullet = new btBoxShape(btVector3(10, 10, 0.5));
btDefaultMotionState* groundMotionState = new btDefaultMotionState(
btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, -1)));
btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(
0, groundMotionState, groundShapeBullet, btVector3(0, 0, 0));
btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
dynamicsWorld->addRigidBody(groundRigidBody);
// 记录地面刚体与OSG节点的映射
bodyNodeMap[groundRigidBody] = groundTransform;
// 2. 创建球体
// OSG部分
osg::ref_ptr<osg::Sphere> sphereShape = new osg::Sphere(osg::Vec3(0, 0, 5), 1.0);
osg::ref_ptr<osg::ShapeDrawable> sphereDrawable = new osg::ShapeDrawable(sphereShape);
osg::ref_ptr<osg::Geode> sphereGeode = new osg::Geode;
sphereGeode->addDrawable(sphereDrawable);
osg::ref_ptr<osg::MatrixTransform> sphereTransform = new osg::MatrixTransform;
sphereTransform->addChild(sphereGeode);
root->addChild(sphereTransform);
// Bullet部分
btCollisionShape* sphereShapeBullet = new btSphereShape(1.0);
btDefaultMotionState* sphereMotionState = new btDefaultMotionState(
btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 5)));
btScalar mass = 1.0;
btVector3 sphereInertia(0, 0, 0);
sphereShapeBullet->calculateLocalInertia(mass, sphereInertia);
btRigidBody::btRigidBodyConstructionInfo sphereRigidBodyCI(
mass, sphereMotionState, sphereShapeBullet, sphereInertia);
btRigidBody* sphereRigidBody = new btRigidBody(sphereRigidBodyCI);
dynamicsWorld->addRigidBody(sphereRigidBody);
// 记录球体刚体与OSG节点的映射
bodyNodeMap[sphereRigidBody] = sphereTransform;
// 3. 创建立方体
// OSG部分
osg::ref_ptr<osg::Box> boxShape = new osg::Box(osg::Vec3(3, 0, 3), 1.0);
osg::ref_ptr<osg::ShapeDrawable> boxDrawable = new osg::ShapeDrawable(boxShape);
osg::ref_ptr<osg::Geode> boxGeode = new osg::Geode;
boxGeode->addDrawable(boxDrawable);
osg::ref_ptr<osg::MatrixTransform> boxTransform = new osg::MatrixTransform;
boxTransform->addChild(boxGeode);
root->addChild(boxTransform);
// Bullet部分
btCollisionShape* boxShapeBullet = new btBoxShape(btVector3(1.0, 1.0, 1.0));
btDefaultMotionState* boxMotionState = new btDefaultMotionState(
btTransform(btQuaternion(0, 0, 0, 1), btVector3(3, 0, 3)));
btRigidBody::btRigidBodyConstructionInfo boxRigidBodyCI(
2.0, boxMotionState, boxShapeBullet, sphereInertia);
btRigidBody* boxRigidBody = new btRigidBody(boxRigidBodyCI);
dynamicsWorld->addRigidBody(boxRigidBody);
// 记录立方体刚体与OSG节点的映射
bodyNodeMap[boxRigidBody] = boxTransform;
// 添加物理更新回调
osg::ref_ptr<PhysicsUpdateCallback> physicsCallback =
new PhysicsUpdateCallback(dynamicsWorld, bodyNodeMap);
root->setUpdateCallback(physicsCallback);
// 设置场景数据并运行查看器
viewer.setSceneData(root);
return viewer.run();
}
运行效果

