简介:本资源面向使用MSVC2017工具链进行三维地理可视化开发的C++/Qt工程师与学习者,提供OSG 3.63、osgEarth 2.10与Qt 5.14的完整预编译库及一个可直接运行的简单Qt工程,帮助读者跳过繁琐的源码编译环节,快速搭建地球场景与三维渲染环境。压缩包为7z格式,约530MB,内含约2000个文件,以hpp与h头文件为主,辅以dll、lib、pdb、ilk等库与调试文件,另有exe示例程序、earth与shp/dbf/prj等地理数据、glsl着色器及jpg、png贴图资源,覆盖开发、调试与运行所需。资源还包含GraphicsWindowQt、QGraphicsViewAdapter等Qt与OSG集成源码,便于理解渲染窗口嵌入Qt界面的实现方式。目前已有536人学习下载,适合需要快速验证osgEarth加载影像、高程与矢量图层的开发者参考,也可作为二次开发的基础工程模板。
1. 拿到 msvc2017+osg3.63+osgearth2.10+qt5.14.7z 之后:这套编译环境到底省掉了多少事
如果你在 Windows 上从源码编译过 osgEarth,大概率经历过这样的夜晚:CMake 报错说找不到 GDAL,换了 GDAL 版本又说 PROJ 不兼容,好不容易编译通过,Qt 那边又提示链接不到 osgQOpenGL。这套 msvc2017+osg3.63+osgearth2.10+qt5.14.7z 就是把这些环节全部前置做完的产物——编译器、OSG、osgEarth、Qt 以及它们之间的胶水层已经对齐,解压后配好环境变量就能直接跑三维地球。它解决的不是“怎么编译”的问题,而是“怎么跳过编译直接验证业务逻辑”的问题。适合做地理信息可视化、三维态势、飞行模拟方向的开发者,尤其是那些不想在环境上耗三天、只想先跑通一个 Demo 验证可行性的人。下面按“先确认里面有什么、再配环境、再跑第一个地球、最后处理常见翻车”的顺序拆一遍。
2. 解压后先别急着编译:目录结构与版本对齐检查
2.1 先确认压缩包里到底有什么
拿到压缩包后不要直接扔到 C 盘根目录就开搞。先解压到一个路径里没有中文、没有空格的目录,比如D:\dev\osg_qt_env。路径带空格是后面 CMake 和 Qt Creator 出玄学问题的头号来源,血泪经验。
解压完先看顶层目录,常见结构是include、lib、bin、3rdparty这几类。bin里放的是运行时 DLL,lib里是导入库,include是头文件,3rdparty里通常塞着 GDAL、PROJ、sqlite3、zlib 这些 osgEarth 的依赖。你要做的第一件事不是写代码,而是确认这几个目录都存在且非空。
# 在解压目录下执行,快速看结构 cd /d D:\dev\osg_qt_env dir /b # 期望看到 include lib bin 3rdparty 之类的目录如果bin里只有 osg 的 DLL 没有 osgEarth 的,或者3rdparty是空的,那这个包大概率不完整,后面链接一定失败。这一步花两分钟,能省掉后面两小时的排查。
2.2 版本对齐:为什么必须是 msvc2017 + Qt5.14
这套组合不是随便凑的。OSG 3.6.3 和 osgEarth 2.10 在 Windows 上的官方预编译包,主流就是按 MSVC 2017 工具集(v141)出的。Qt 5.14.7 是 Qt5 后期一个相对稳定的版本,它的msvc2017_64套件和 v141 ABI 兼容。如果你用 MSVC 2019 或 2022 去链接这些 lib,大概率会遇到LNK2038运行库不匹配,或者更隐蔽的堆损坏崩溃。
| 组件 | 版本 | 关键约束 |
|---|---|---|
| 编译器 | MSVC 2017 (v141) | 必须与 lib 的 ABI 一致 |
| OSG | 3.6.3 | 依赖 OpenThreads、osgDB 等 |
| osgEarth | 2.10 | 依赖 GDAL、PROJ、sqlite3 |
| Qt | 5.14.7 | 使用 msvc2017_64 套件 |
| CMake | 3.15+ | 生成 VS 工程或供 Qt Creator 使用 |
提示:如果你机器上装了多个 VS 版本,用
cl命令确认当前命令行环境是 v141。在 “x64 Native Tools Command Prompt for VS 2017” 里执行cl,输出里应带19.16之类的版本号。
2.3 环境变量怎么配才不互相打架
环境变量是这套东西最容易翻车的地方。核心就三条:PATH加bin,OSG_FILE_PATH指向数据目录,QT_PLUGIN_PATH指向 Qt 插件。但顺序有讲究——bin要放在系统目录之前,否则可能加载到系统里旧版的zlib1.dll或sqlite3.dll。
# 以管理员或当前用户设置,示例路径按实际改 setx OSG_ROOT "D:\dev\osg_qt_env" setx PATH "%OSG_ROOT%\bin;%PATH%" setx OSG_FILE_PATH "%OSG_ROOT%\data" setx QT_PLUGIN_PATH "D:\Qt\5.14.7\msvc2017_64\plugins"OSG_FILE_PATH是 osgDB 找模型、纹理、地球瓦片的搜索路径,不设的话readNodeFile会返回空指针。QT_PLUGIN_PATH不设,Qt 程序启动时会报 “could not find or load the Qt platform plugin windows”,这是新手最常遇到的第一个拦路虎。
3. 用 Qt Creator 建第一个 osgEarth 工程:从 CMakeLists 到地球渲染
3.1 CMakeLists.txt 怎么写才找得到 osgEarth
Qt Creator 打开后新建一个空工程,或者直接手写CMakeLists.txt。关键是用find_package把 OSG 和 osgEarth 找出来,再链接到 Qt 的 Widgets 模块。很多人卡在find_package(osgEarth)返回 not found,原因是OSG_DIR或osgEarth_DIR没指向包里的lib/cmake目录。
cmake_minimum_required(VERSION 3.15) project(EarthDemo LANGUAGES CXX) # 让 CMake 去包里找配置,路径按实际解压位置改 set(OSG_DIR "D:/dev/osg_qt_env/lib/cmake/osg") set(osgEarth_DIR "D:/dev/osg_qt_env/lib/cmake/osgEarth") find_package(OpenSceneGraph REQUIRED COMPONENTS osgDB osgViewer osgGA) find_package(osgEarth REQUIRED) find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL) add_executable(EarthDemo main.cpp) target_link_libraries(EarthDemo ${OSG_LIBRARIES} ${OSGEARTH_LIBRARIES} Qt5::Widgets Qt5::OpenGL )find_package的COMPONENTS里列的是你真正用到的模块,少列会导致链接时符号缺失。OSG_DIR指向的目录里应该有OpenSceneGraphConfig.cmake,osgEarth_DIR里应该有osgEarthConfig.cmake。如果这两个文件不在,说明这个包是“裸库”没有 CMake 配置,那就得手动include_directories和link_directories,麻烦不少。
3.2 最小可运行代码:一个能转的地球
main.cpp不用写复杂,先让地球出来。osgEarth 2.10 的 API 和 3.x 有差异,Map、ImageLayer、ElevationLayer的用法要按 2.10 的来。下面这段是能跑通的最小骨架。
#include <osgViewer/Viewer> #include <osgEarth/MapNode> #include <osgEarth/ImageLayer> #include <osgEarth/ElevationLayer> #include <osgEarth/XYZ> #include <osgEarth/Registry> int main(int argc, char** argv) { osgViewer::Viewer viewer; // 创建地图对象,2.10 里 Map 是核心容器 osg::ref_ptr<osgEarth::Map> map = new osgEarth::Map(); // 加一个 XYZ 影像层,指向本地或在线瓦片 osgEarth::XYZImageLayerOptions imgOpt("world imagery"); imgOpt.url() = "D:/dev/osg_qt_env/data/tiles/{z}/{x}/{y}.png"; map->addLayer(new osgEarth::XYZImageLayer(imgOpt)); // 加高程层,没有高程地球是平的 osgEarth::ElevationLayerOptions elevOpt("srtm"); elevOpt.url() = "D:/dev/osg_qt_env/data/elevation"; map->addLayer(new osgEarth::ElevationLayer(elevOpt)); // 用 MapNode 把地图挂到场景图 osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map); viewer.setSceneData(mapNode); return viewer.run(); }XYZImageLayerOptions的url()支持本地路径和网络地址,本地路径用正斜杠或双反斜杠。ElevationLayer不加的话地球是个光滑球体,看不出地形起伏。MapNode是 osgEarth 场景图的根,所有图层都挂在Map上,再由MapNode统一管理。
3.3 编译链接时最容易缺的 DLL
编译通过不代表能跑。bin目录下的 DLL 要跟 exe 放一起,或者确保PATH里有。常见的缺失清单:osg163-osgDB.dll、osgEarth.dll、gdal204.dll、proj_6_2.dll、sqlite3.dll、zlib1.dll。少一个就是启动即崩,而且报错信息往往很模糊。
# 用 dumpbin 看 exe 依赖哪些 DLL,缺哪个一目了然 dumpbin /dependents EarthDemo.exe如果dumpbin输出里有一堆名字但bin里找不到,那就是包不完整或者版本对不上。另一个办法是用 Dependencies 工具图形化看,但那个工具本身在 Win10 上也有兼容问题,命令行dumpbin更稳。
4. 避坑与排查:这套环境里最容易翻车的五个点
4.1 现象:程序启动报 “no Qt platform plugin could be initialized”
原因:QT_PLUGIN_PATH没设,或者platforms/qwindows.dll不在搜索路径里。Qt 5.14 的程序启动时必须加载平台插件,找不到就直接退出。
解决:确认QT_PLUGIN_PATH指向Qt\5.14.7\msvc2017_64\plugins,并且该目录下有platforms\qwindows.dll。如果还不行,在 exe 同级建platforms目录,把qwindows.dll拷进去。
4.2 现象:链接时报LNK2038: mismatch detected for 'RuntimeLibrary'
原因:你的工程用/MDd而预编译库用/MD,或者反过来。Debug 和 Release 的运行库不能混用。
解决:统一配置。如果库是 Release 版,你的工程也切 Release;如果必须 Debug,确认包里有对应的 Debug 版 lib(名字通常带d后缀)。混用是 ABI 层面的问题,没有后悔药。
4.3 现象:地球能显示但纹理全黑或全白
原因:OSG_FILE_PATH没设,或者瓦片路径写错,osgDB 读不到图片就返回空纹理,渲染出来就是纯色。
解决:先确认OSG_FILE_PATH包含数据根目录,再用绝对路径试一次。如果绝对路径能显示,说明是搜索路径问题;如果还是黑,检查图片格式是否被 osgDB 的插件支持(png、jpg 一般没问题,webp 需要额外插件)。
4.4 现象:CMake 配置时find_package(osgEarth)找不到
原因:osgEarth_DIR没设,或者包里的 cmake 配置文件路径不对。有些打包方式会把 cmake 文件放在lib/cmake/osgEarth,有些放在share/osgEarth。
解决:在解压目录里搜osgEarthConfig.cmake,找到后把它的父目录赋给osgEarth_DIR。如果压根没有这个文件,就只能手动指定 include 和 lib 路径。
4.5 现象:运行时崩溃在osg::Texture或osgEarth::TileSource内部
原因:多线程加载瓦片时,GDAL 或 PROJ 的全局状态被并发访问。osgEarth 2.10 默认用多线程缓存,某些 GDAL 版本不是线程安全的。
解决:在main开头调用osgEarth::Registry::instance()->setDefaultCachePolicy限制并发,或者把OSGEARTH_HTTP_THREADS环境变量设为 1 先排除并发因素。确认是并发问题后再逐步放开。
5. 进阶技巧:用 osgEarth 的缓存与图层控制做快速验证
5.1 打开本地缓存,避免每次启动都重新加载
osgEarth 的Cache可以把下载或读取过的瓦片存到本地,第二次启动直接读缓存。对于做原型验证来说,这能省掉大量等待时间。在Map创建后加一行:
osgEarth::CacheOptions cacheOpt; cacheOpt.path() = "D:/dev/osg_qt_env/cache"; map->setCache(new osgEarth::Cache(cacheOpt));path()指向一个可写目录,osgEarth 会按图层名和层级建子目录。缓存文件是二进制格式,不要手动改。如果发现缓存导致显示异常,删掉整个缓存目录重启即可,这是最快的“后悔药”。
5.2 用 Layer 的可见性做多方案对比
验证阶段经常需要切换不同数据源。与其改代码重编译,不如把多个图层都加进去,用setVisible控制。
osg::ref_ptr<osgEarth::ImageLayer> layerA = new osgEarth::XYZImageLayer(imgOptA); osg::ref_ptr<osgEarth::ImageLayer> layerB = new osgEarth::XYZImageLayer(imgOptB); map->addLayer(layerA); map->addLayer(layerB); layerB->setVisible(false); // 默认只显示 A这样在调试时可以通过改一个布尔值快速对比两套瓦片的效果,不用反复改 URL 重编译。对于做地理信息可视化的团队来说,这个技巧在选型阶段特别实用。
5.3 验证清单:跑通之后确认这几件事
地球出来只是第一步。建议按下面这个清单过一遍,确认环境真的可用:
| 检查项 | 方法 | 通过标准 |
|---|---|---|
| 高程生效 | 放大到山区 | 有起伏而非平面 |
| 纹理加载 | 放大到城市 | 能看到街道或影像 |
| 缓存写入 | 看 cache 目录 | 有文件生成 |
| 多图层切换 | 改 setVisible | 显示对应图层 |
| 退出无崩溃 | 正常关闭窗口 | 进程干净退出 |
这套环境的价值在于让你把时间花在业务逻辑上,而不是环境配置上。我自己的习惯是每拿到一个新的预编译包,先按这个清单跑一遍,确认无误再开始写正式代码。从那以后我每次配新环境都强制走一遍这个流程,省下来的时间够多写好几个功能。希望帮到你。
本文还有配套的精品资源,点击获取