当前位置: 首页 > 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();
}    

运行效果

在这里插入图片描述

在这里插入图片描述

http://www.xdnf.cn/news/967987.html

相关文章:

  • opencv RGB图像转灰度图
  • yolo11-seg 推理测试infer
  • Java正则表达式:贪婪、懒惰与独占模式解析
  • Tunna工具实战:基于HTTP隧道的RDP端口转发技术
  • java 数据结构-HashMap
  • 睡岗检测算法AI智能分析网关V4全场景智能守护,筑牢安全效率防线
  • golang -- unsafe 包
  • gitlab-runner 如何配置使用 Overwrite generated pod specifications
  • 图注意力卷积神经网络GAT在无线通信网络拓扑推理中的应用
  • 第四章 软件需求工程
  • 上位机开发:C# 读写 PLC 数据块数据
  • CppCon 2015 学习:Racing the File System
  • “详规一张图”——上海土地利用数据
  • 《大模型RAG进阶实战训练营毕业总结》
  • 多模态2025:技术路线“神仙打架”,视频生成冲上云霄
  • 雷卯针对易百纳海鸥派海思SD3403 SS928智能视觉AI视觉国产化4K视频开发板防雷防静电方案
  • 香橙派3B学习笔记9:Linux基础gcc/g++编译__C/C++中动态链接库(.so)的编译与使用
  • Vim 匹配跳转与搜索命令完整学习笔记
  • ArcGIS Pro 3.4 二次开发 - 任务
  • word的目录和正文之间存在一张空白纸,目录后面的分节符为什么调不上去?
  • 《函数之恋》
  • STL 4函数对象
  • 工控类UI设计经常接触到10.1寸迪文屏
  • React【回顾】 深层次面试详解:函数式组件核心原理与高级优化
  • 香港科技大学(广州)机器人与自主系统学域(ROAS)2025年度夏令营招募!
  • 《高等数学》(同济大学·第7版)第三章第六节函数图形的描绘
  • 如何判断Cursor邮箱被封?
  • 【Dv3Admin】系统视图角色菜单API文件解析
  • 钉钉告警集成部署指南
  • DataSource学习