拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

VS2017 64位下OSG+osgworks+Bullet3+osgbullet编译与碰撞检测集成指南

VS2017 64位下OSG+osgworks+Bullet3+osgbullet编译与碰撞检测集成指南

简介:本资源为VS2017 64位环境下编译生成的osg、osgWorks、Bullet3与osgbullet库集合,面向从事三维游戏开发、物理仿真与可视化应用的C++开发者,尤其适合需要在Windows平台快速集成3D渲染与碰撞检测的中高级技术人员。压缩包为rar格式,大小约228.02MB,内含动态库与静态库两类文件,动态库便于运行时加载、减小应用体积,静态库则可将代码直接嵌入目标程序,开发者可按项目需求灵活选择。资源核心价值在于打通了OpenSceneGraph场景管理与Bullet3物理引擎的协作链路:osg负责几何建模、动画与渲染优化,osgWorks补充地形、粒子与光照模块,Bullet3提供刚体、软体及多边形网格的碰撞检测,osgbullet则让物理世界与视觉表现无缝同步。已有801人学习下载,适合需要快速搭建真实物理行为三维场景的开发者参考使用。

1. VS2017 64 位下 osg+osgworks+bullet3+osgbullet 编译:一条链上四个库的依赖顺序不能乱

如果你正在 Windows 上做三维仿真、虚拟现实或者机器人可视化,大概率绕不开 OSG 这套场景图引擎。但光有 OSG 还不够——物理碰撞检测得靠 Bullet,OSG 和 Bullet 之间的桥接得靠 osgbullet,而 osgworks 又是 osgbullet 的前置依赖。这四个库串在一起,在 VS2017 64 位环境下编译,坑多到让人怀疑人生。

我前后搭过不下十次这套环境,从 VS2013 一路跟到 VS2017,每次换机器或者换版本都要重新踩一遍。最要命的是依赖顺序:osgworks 依赖 OSG,osgbullet 同时依赖 OSG、osgworks 和 Bullet,任何一个库的编译配置出错,后面全盘崩。而且 64 位和 32 位的坑完全不一样,Debug 和 Release 的配置也得分开处理。

这篇内容面向的是需要在 Windows 平台从源码编译这套工具链的开发者,不管你是第一次搭还是被某个链接错误卡住了,下面的步骤和参数都能直接对照操作。我会按依赖顺序从底层往上讲,每一步给出 CMake 配置、编译命令和关键参数说明,最后集中说几个我踩过的血泪坑。

2. 编译前的环境准备与依赖关系梳理

2.1 四个库的依赖层级与编译顺序

先把依赖关系理清楚,这决定了你动手的先后顺序:

层级库名依赖项产出物
第一层OSG第三方库(zlib、libpng、libjpeg 等)osg.lib、osgDB.lib、osgUtil.lib 等
第二层osgworksOSGosgwTools.lib、osgwQuery.lib 等
第三层Bullet3无(可独立编译)BulletCollision.lib、BulletDynamics.lib 等
第四层osgbulletOSG + osgworks + Bullet3osgbullet.lib

编译顺序必须是:OSG → osgworks → Bullet3 → osgbullet。Bullet3 和 osgworks 之间没有依赖,理论上可以并行编译,但 osgbullet 必须等前面三个全部完成。

这里有个容易忽略的点:osgworks 和 osgbullet 都是基于 CMake 构建的,但它们的 CMakeLists.txt 里查找依赖的方式不太一样。osgworks 找 OSG 用的是find_package(OpenSceneGraph),而 osgbullet 找 osgworks 用的是自定义的FindosgWorks.cmake。如果你不把 osgworks 的安装路径加到CMAKE_PREFIX_PATH里,osgbullet 的 CMake 配置阶段就会直接报找不到 osgworks。

2.2 VS2017 环境与第三方依赖的准备

VS2017 安装时务必勾选「使用 C++ 的桌面开发」工作负载,并且确认安装了 Windows 10 SDK(版本选 10.0.17763.0 或更高)。64 位编译需要 x64 本机工具链,这个在默认安装里是包含的。

第三方依赖库我建议用 vcpkg 来管理,省得手动一个个编译 zlib、libpng 这些。用 vcpkg 安装依赖的命令如下:

# 克隆 vcpkg(如果还没有的话) git clone https://github.com/microsoft/vcpkg.git cd vcpkg # 引导 vcpkg bootstrap-vcpkg.bat # 安装 OSG 需要的第三方库,指定 64 位 vcpkg install zlib:x64-windows libpng:x64-windows libjpeg-turbo:x64-windows vcpkg install freetype:x64-windows curl:x64-windows

安装完成后,vcpkg 会把这些库放在vcpkg/installed/x64-windows/目录下。后面 CMake 配置时需要把这个路径传给CMAKE_PREFIX_PATH。

注意:vcpkg 默认编译的是 Release 版本,如果你需要 Debug 版本的第三方库,要加--triplet x64-windows并在 CMake 中正确设置CMAKE_BUILD_TYPE。混用 Debug/Release 的第三方库是链接错误的常见根源。

如果你不想用 vcpkg,也可以手动下载 OSG 官方提供的第三方依赖包(3rdParty),但那个包更新不及时,有些库版本偏老。我一般会优先用 vcpkg,版本可控,升级也方便。

3. OSG 与 osgworks 的 64 位编译实操

3.1 OSG 源码编译:CMake 参数与生成命令

从 OSG 官网或者 GitHub 拉取源码,我用的版本是 3.6.5,这个版本在 VS2017 下比较稳定。解压后建一个build目录,在 build 目录里打开 CMake GUI 或者直接用命令行。

命令行方式的完整配置如下:

# 在 OSG 源码根目录下创建 build 目录 mkdir build && cd build # CMake 配置,关键参数逐个说明 cmake .. ^ -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX="D:/Libs/OSG-3.6.5-x64" ^ -DCMAKE_PREFIX_PATH="D:/vcpkg/installed/x64-windows" ^ -DCMAKE_BUILD_TYPE=Release ^ -DBUILD_OSG_APPLICATIONS=ON ^ -DOSG_BUILD_PLUGINS=ON ^ -DDYNAMIC_OSG=ON ^ -DBUILD_DOCUMENTATION=OFF ^ -DCMAKE_DEBUG_POSTFIX="d"

参数说明:

  • -G "Visual Studio 15 2017 Win64":指定生成 VS2017 的 64 位工程文件,这个必须写对,否则默认生成 32 位。
  • -DCMAKE_INSTALL_PREFIX:安装路径,后面 osgworks 和 osgbullet 都要从这里找 OSG。
  • -DCMAKE_PREFIX_PATH:指向 vcpkg 安装的第三方库路径。
  • -DDYNAMIC_OSG=ON:生成动态库(DLL),如果你要静态库就设为 OFF。
  • -DCMAKE_DEBUG_POSTFIX="d":Debug 版本库文件加 "d" 后缀,避免和 Release 版本冲突。

配置完成后执行编译和安装:

# 编译 Release 版本,8 线程并行 cmake --build . --config Release --target INSTALL -- /m:8

编译过程大概需要 15 到 30 分钟,取决于机器性能。完成后检查D:/Libs/OSG-3.6.5-x64目录下是否有include、lib、bin三个目录,bin里应该有osg160-osg.dll、osg160-osgDB.dll等文件。

3.2 osgworks 编译:FindosgWorks 路径配置与常见报错

osgworks 的源码在 GitHub 上可以找到,它没有正式的 release 包,直接 clone 主分支即可。同样建 build 目录,CMake 配置如下:

mkdir build && cd build cmake .. ^ -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX="D:/Libs/osgworks-x64" ^ -DCMAKE_PREFIX_PATH="D:/Libs/OSG-3.6.5-x64;D:/vcpkg/installed/x64-windows" ^ -DCMAKE_BUILD_TYPE=Release ^ -DOSGWORKS_BUILD_EXAMPLES=OFF ^ -DOSGWORKS_BUILD_TESTS=OFF

这里CMAKE_PREFIX_PATH里同时放了 OSG 的安装路径和 vcpkg 的路径,用分号隔开。osgworks 的 CMakeLists.txt 会通过find_package(OpenSceneGraph)来找 OSG,如果找不到,检查OSG_DIR这个变量是否被正确设置。有时候 CMake 缓存了旧的路径,需要删掉 build 目录重新来。

编译安装:

cmake --build . --config Release --target INSTALL -- /m:8

安装完成后,D:/Libs/osgworks-x64下应该有include/osgwTools/、lib/osgwTools.lib等。特别注意lib目录下是否生成了osgwTools.lib、osgwQuery.lib、osgwMx.lib这几个核心库。

提示:osgworks 编译时如果报错「无法打开 osg.lib」,大概率是 OSG 的 lib 路径没传对。检查CMAKE_PREFIX_PATH里的 OSG 路径是否指向了包含lib目录的那一层,而不是源码目录。

4. Bullet3 与 osgbullet 的编译与碰撞检测集成

4.1 Bullet3 编译:用 CMake 生成 64 位动态库与静态库

Bullet3 的源码在 GitHub 上,版本用 3.25 比较稳。Bullet 的 CMake 选项比较多,但核心的就那几个:

mkdir build && cd build cmake .. ^ -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX="D:/Libs/bullet3-x64" ^ -DCMAKE_BUILD_TYPE=Release ^ -DBUILD_SHARED_LIBS=ON ^ -DBULLET2_MULTITHREADING=ON ^ -DUSE_GRAPHICAL_BENCHMARK=OFF ^ -DBUILD_BULLET2_DEMOS=OFF ^ -DBUILD_UNIT_TESTS=OFF ^ -DBUILD_CPU_DEMOS=OFF ^ -DBUILD_OPENGL3_DEMOS=OFF

关键参数:

  • -DBUILD_SHARED_LIBS=ON:生成动态库(DLL)。如果你要静态库,设为 OFF,但注意 osgbullet 链接静态 Bullet 时需要额外处理运行时库的匹配问题。
  • -DBULLET2_MULTITHREADING=ON:开启多线程支持,碰撞检测性能会好很多。
  • -DUSE_GRAPHICAL_BENCHMARK=OFF:关掉图形化 benchmark,我们只需要库本身。

编译安装:

cmake --build . --config Release --target INSTALL -- /m:8

安装完成后,D:/Libs/bullet3-x64/lib下会有BulletCollision.lib、BulletDynamics.lib、LinearMath.lib、BulletSoftBody.lib等。bin目录下是对应的 DLL。

4.2 osgbullet 编译:打通 OSG 场景图与 Bullet 物理世界

osgbullet 是 OSG 和 Bullet 之间的桥接层,它把 Bullet 的物理对象映射成 OSG 的节点,让你可以在场景图里直接做碰撞检测和刚体模拟。编译配置如下:

mkdir build && cd build cmake .. ^ -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX="D:/Libs/osgbullet-x64" ^ -DCMAKE_PREFIX_PATH="D:/Libs/OSG-3.6.5-x64;D:/Libs/osgworks-x64;D:/Libs/bullet3-x64;D:/vcpkg/installed/x64-windows" ^ -DCMAKE_BUILD_TYPE=Release ^ -DOSGBULLET_BUILD_EXAMPLES=OFF

这里CMAKE_PREFIX_PATH里塞了四个路径,缺一不可。osgbullet 的 CMakeLists.txt 会依次查找 OSG、osgworks、Bullet。如果 osgworks 找不到,检查FindosgWorks.cmake是否在CMAKE_MODULE_PATH里,或者手动指定osgWorks_DIR变量。

编译安装:

cmake --build . --config Release --target INSTALL -- /m:8

安装完成后,D:/Libs/osgbullet-x64/lib下应该有osgbullet.lib,bin下是osgbullet.dll。

4.3 用 osgbullet 做碰撞检测的最小验证代码

编译完了得验证一下能不能用。下面这段代码创建一个简单的 OSG 场景,加两个碰撞体,用 Bullet 做碰撞检测:

#include <osgViewer/Viewer> #include <osg/ShapeDrawable> #include <osgbullet/Utils> #include <osgbullet/World> #include <btBulletDynamicsCommon.h> int main() { // 创建 Bullet 物理世界 osgbullet::World* world = new osgbullet::World(); world->getDynamicsWorld()->setGravity(btVector3(0, 0, -9.81)); // 创建一个 OSG 球体节点 osg::ref_ptr<osg::Sphere> sphere = new osg::Sphere(osg::Vec3(0, 0, 5), 1.0f); osg::ref_ptr<osg::ShapeDrawable> sphereDrawable = new osg::ShapeDrawable(sphere); osg::ref_ptr<osg::Geode> geode = new osg::Geode(); geode->addDrawable(sphereDrawable); // 把 OSG 节点转成 Bullet 刚体,质量 1.0 osgbullet::RigidBody* body = world->addRigidBody(geode.get(), 1.0f); if (body) { // 设置碰撞形状为球体,半径 1.0 body->setCollisionShape(new btSphereShape(1.0f)); } // 创建地面 osg::ref_ptr<osg::Box> ground = new osg::Box(osg::Vec3(0, 0, 0), 100, 100, 0.1f); osg::ref_ptr<osg::ShapeDrawable> groundDrawable = new osg::ShapeDrawable(ground); osg::ref_ptr<osg::Geode> groundGeode = new osg::Geode(); groundGeode->addDrawable(groundDrawable); osgbullet::RigidBody* groundBody = world->addRigidBody(groundGeode.get(), 0.0f); // 质量 0 表示静态 groundBody->setCollisionShape(new btBoxShape(btVector3(50, 50, 0.05f))); // 运行仿真 osgViewer::Viewer viewer; viewer.setSceneData(world->getRoot()); while (!viewer.done()) { world->stepSimulation(1.0f / 60.0f); // 每帧步进 1/60 秒 viewer.frame(); } return 0; }

逻辑说明:osgbullet::World封装了 Bullet 的btDiscreteDynamicsWorld,addRigidBody方法把 OSG 节点和 Bullet 刚体绑定在一起。stepSimulation每帧调用一次,驱动物理世界更新。碰撞检测的结果可以通过world->getDynamicsWorld()->getDispatcher()的回调来获取。

参数说明:setGravity设置重力加速度,addRigidBody的第二个参数是质量,质量为 0 表示静态物体。stepSimulation的参数是时间步长,一般用 1/60 秒对应 60 FPS。

注意:osgbullet 的 API 在不同版本间有变化,上面代码基于 osgbullet 的常见接口。如果你的版本里addRigidBody签名不同,查一下头文件里的声明。

5. 编译过程中最容易翻车的五个地方

5.1 现象:LNK2038 检测到「RuntimeLibrary」的不匹配

原因:Debug 版本的库链接了 Release 版本的运行时库,或者反过来。VS2017 里 Debug 用MDd,Release 用MD,混用就会报这个错。

解决:确保所有库的CMAKE_BUILD_TYPE一致。如果你要 Debug 版本,OSG、osgworks、Bullet、osgbullet 全部用 Debug 编译,第三方库也要用 Debug 版本。vcpkg 默认只装 Release,Debug 版本需要额外指定--triplet x64-windows并加--debug参数重新安装。

5.2 现象:CMake 配置时报「Could NOT find OpenSceneGraph」

原因:CMAKE_PREFIX_PATH没设对,或者 OSG 的安装路径下缺少lib/cmake/OpenSceneGraph/OpenSceneGraphConfig.cmake文件。

解决:检查 OSG 安装目录下是否有lib/cmake/OpenSceneGraph/这个路径。如果没有,说明 OSG 编译时没有生成 CMake 配置文件,需要在 OSG 的 CMake 配置里加上-DCMAKE_EXPORT_PACKAGE_REGISTRY=ON重新编译安装。或者手动设置OSG_DIR环境变量指向lib/cmake/OpenSceneGraph。

5.3 现象:osgbullet 链接时报「无法解析的外部符号 btCollisionWorld::...」

原因:Bullet 的库没链接全,或者链接顺序不对。Bullet 的库之间有依赖关系,BulletDynamics依赖BulletCollision,BulletCollision依赖LinearMath。

解决:在链接器输入里按顺序添加:BulletDynamics.lib、BulletCollision.lib、LinearMath.lib、BulletSoftBody.lib。顺序不能乱,否则符号解析会失败。如果用的是 CMake,检查target_link_libraries里的顺序。

5.4 现象:运行时崩溃,提示「无法找到 osg160-osg.dll」

原因:DLL 不在可执行文件的搜索路径里。Windows 加载 DLL 的顺序是:exe 所在目录 → 系统目录 → PATH 环境变量。

解决:把 OSG、osgworks、Bullet、osgbullet 的bin目录全部加到系统 PATH 里,或者把所有需要的 DLL 拷贝到 exe 同级目录。我一般写一个copy_dlls.bat脚本,编译完自动拷贝:

@echo off set DEST=%~dp0 copy /Y D:\Libs\OSG-3.6.5-x64\bin\*.dll %DEST% copy /Y D:\Libs\osgworks-x64\bin\*.dll %DEST% copy /Y D:\Libs\bullet3-x64\bin\*.dll %DEST% copy /Y D:\Libs\osgbullet-x64\bin\*.dll %DEST% echo DLLs copied.

5.5 现象:碰撞检测结果不稳定,物体穿透或抖动

原因:Bullet 的仿真步长设置不合理,或者碰撞形状的 margin 值太大。默认的btSphereShapemargin 是 0.04,对于小尺寸物体来说太大了。

解决:把stepSimulation的固定步长设为 1/60 秒,并且开启子步进:world->stepSimulation(1.0f/60.0f, 10)。第二个参数是最大子步数,10 表示最多做 10 次子步进。另外,对于小物体,把碰撞形状的 margin 调小:shape->setMargin(0.001f)。

6. 从编译到落地:碰撞检测的进阶调参与性能验证

编译通过只是第一步,真正用到项目里还得调参数。Bullet 的碰撞检测性能主要受三个因素影响:碰撞形状的复杂度、物体数量、以及 broadphase 算法的选择。

对于大量物体的场景,默认的btDbvtBroadphase已经够用,但如果物体超过几千个,可以考虑btAxisSweep3。在 osgbullet 里切换 broadphase 的方式是直接操作btDiscreteDynamicsWorld:

// 创建 AxisSweep3 broadphase,参数是世界范围 btVector3 worldMin(-1000, -1000, -1000); btVector3 worldMax(1000, 1000, 1000); btBroadphaseInterface* broadphase = new btAxisSweep3(worldMin, worldMax); // 替换默认的 broadphase btDiscreteDynamicsWorld* dynamicsWorld = world->getDynamicsWorld(); // 注意:需要先移除旧的 broadphase,再设置新的

验证碰撞检测是否正确,我一般用两种方法:一是可视化调试,把 Bullet 的碰撞形状用 OSG 的线框画出来,和实际模型对比;二是记录碰撞对的数量,在仿真过程中打印getNumManifolds()的值,如果数量异常(比如一直为 0 或者突然暴增),说明碰撞形状或者 broadphase 配置有问题。

还有一个容易忽略的点:osgbullet 的RigidBody在析构时不会自动从物理世界里移除,需要手动调用world->removeRigidBody()。如果动态创建和销毁物体,忘记移除会导致内存泄漏和物理世界里的幽灵碰撞体。

我自己的习惯是,每次编译完这套库,先跑一个最简单的球体落地场景,确认物理仿真正常,再往项目里集成。这个习惯帮我省了很多「编译过了但跑起来不对」的后悔药。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表