当前位置: 首页 > news >正文

【OSG学习笔记】Day 18: 碰撞检测与物理交互

在这里插入图片描述

物理引擎(Physics Engine)

物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。

它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚拟现实(VR)、机器人仿真 等领域。

物理引擎的核心功能
  1. 碰撞检测:判断物体是否发生碰撞或接触。
  2. 物理模拟:根据物理定律(如牛顿力学)计算物体的运动轨迹、速度、加速度等。
  3. 交互反馈:处理物体碰撞后的力学反应(如反弹、摩擦、破碎)。
  4. 约束系统:模拟物体间的连接关系(如铰链、弹簧、绳索等)。
常见物理引擎
  • Bullet:开源、跨平台,适合刚体和软体模拟,常用于游戏和仿真(OSG开发)。
  • PhysX:NVIDIA开发的商业引擎,广泛用于3A游戏(如《绝地求生》)。
  • Havok:商业引擎,支持复杂物理效果,应用于影视和游戏。
  • Box2D:2D物理引擎,适合2D游戏(如《愤怒的小鸟》)。
物理引擎的工作流程
  1. 更新物理世界:根据时间步长计算物体运动。
  2. 碰撞检测:识别所有碰撞对。
  3. 物理响应:计算碰撞后的速度、力和动量变化。
  4. 同步渲染:将物理模拟结果反映到图形界面。

刚体(Rigid Body)

刚体 是物理学中的一个理想模型,指在运动和受力过程中 形状和大小完全不变 的物体。换句话说,刚体的任意两点间的距离始终保持不变,忽略形变(如压缩、弯曲、旋转时的体积变化)。

刚体的特点
  • 无弹性形变:碰撞时能量守恒(完全弹性碰撞)或部分损失(非弹性碰撞),但形状不变。
  • 自由度:刚体在三维空间中有 6个自由度(3个平移自由度 + 3个旋转自由度)。
  • 应用场景:适用于模拟 硬物体 的运动,如石块、车辆、机械零件等。
与软体的区别
  • 软体:允许形变(如布料、液体、果冻),模拟更复杂(需考虑弹性、粘性等)。
  • 刚体:简化模型,计算效率高,适合大规模物理模拟。
刚体在物理引擎中的应用
  • 通过 质量、惯性矩、摩擦力、 restitution(恢复系数) 等参数定义物理属性。
  • 结合碰撞形状(如球体、立方体、胶囊体)进行碰撞检测,减少计算量。

物理引擎与刚体的关系

物理引擎通过算法模拟刚体的运动和交互,例如:

  • 当两个刚体碰撞时,物理引擎根据 动量守恒定律 计算碰撞后的速度和方向。
  • 利用 约束(Constraint) 限制刚体的自由度(如用铰链连接两个刚体,使其只能绕轴旋转)。

在您的学习场景中(OSG + Bullet),Bullet作为物理引擎,负责处理刚体的碰撞检测和物理模拟,而OSG负责图形渲染,两者结合实现逼真的物理交互效果(如物体掉落、碰撞反弹等)。

实战

#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();
}    

运行效果

在这里插入图片描述

在这里插入图片描述

相关文章:

  • 腾讯开源 AniPortrait:音频驱动的逼真肖像动画生成革命
  • LeetCode:912归并排序,洛谷:ACM风格
  • leetcode:42. 接雨水(秒变简单题)
  • 聊一聊 - 如何像开源项目一样,去设计一个组件
  • Linux系统编程-DAY12
  • Ubuntu下挂载NTFS格式磁盘
  • 延伸大疆AI能力:Coovally一键训练模型,直通无人机部署
  • SALOME源码分析: libBatch
  • [FX5U-PLC] 双重联锁正反转的继电接触控制线路
  • Matlab点云合并函数pcmerge全解析
  • 【算法篇】逐步理解动态规划模型5(子序列问题)
  • 《Playwright:微软的自动化测试工具详解》
  • MySQL学习之---索引
  • 关于类型断言的小细节
  • 【SAP MM SD FICO】销售视图和会计视图
  • 数据库——MongoDB
  • Java判断规则工具类
  • 【杂谈】-递归进化:人工智能的自我改进与监管挑战
  • 60天python训练计划----day50
  • 如何判断Cursor邮箱被封?
  • 网站建设的一般流程/关键词优化排名的步骤
  • 迅雷下载宝 做网站/百度门店推广
  • 崇安区网站建设价格/网站在线客服系统免费
  • 重庆璧山网站制作公司电话/精准营销理论
  • web service做网站/数据指数
  • 做网站用什么框架好/手游推广去哪里找客源