简介:面向三维GIS、虚拟仿真与地理信息可视化开发者的MSVC2017编译环境配套包,集成OSG 3.6.3、osgEarth 2.10与Qt 5.14,重点解决三维渲染库依赖繁多、编译配置繁琐以及Qt界面嵌入OSG窗口困难等问题,适合具备一定C++与Qt基础的中级开发者。压缩包约530.29MB,共2000个文件,以hpp/h头文件、dll/lib库文件、exe/pdb/ilk运行调试文件为主,并包含earth场景配置、图片纹理、着色器及shp/dbf/prj等地理数据,覆盖开发、调试与示例运行所需。已有536人学习。包内提供预编译的OSG与osgEarth库和一个简洁Qt工程,工程涉及OSG渲染窗口嵌入Qt、视图适配、主窗口组织及基础数据表创建等示例,可用于快速搭建三维地球场景、加载earth文件并验证Qt与OSG的交互显示,也可按配套博文思路创建自己的工程,减少从源码编译和联调环境的时间。
1. 一个 CMake 大版本,把 msvc2017 下的 osg3.63 编译卡了一下午
拿到 msvc2017+osg3.63+osgearth2.10+qt5.14 这套组合的人,多半以为解压就能跑。我第一次在这台机器上配,CMake 装的是 4.x,configure 走到一半直接甩出Compatibility with CMake < 3.5 has been removed,因为 OSG 3.6.3 的顶层 CMakeLists 里还写着cmake_minimum_required(VERSION 2.8.0)。不是 OSG 的错,是工具链版本没对齐。
这套组合在三维 GIS、态势显示、飞行仿真里出现频率极高,装不好就是满屏 LNK2038 和双击闪退的 0xc000007b。下面按我自己走通的顺序,从版本咬合、OSG 编译、osgEarth 依赖、Qt 接管一路写到验证,适合手上已经有源码包、想在 VS2017 下从头走一遍的人。
2. 环境对齐:VS2017 工具集、Qt 5.14.7 与 OSG 3.6.3 的版本咬合
这套环境最容易翻车的地方不是编译参数,是版本。四个组件之间存在硬约束,任意一个往上跳一个小版本,都可能让后面几天的编译白做。我一般先把这张表抄在纸上,装一个划一个,避免装到一半发现 Qt 是 msvc2019 的包。
2.1 四个组件的版本对应关系
| 组件 | 建议版本 | 关键说明 |
|---|---|---|
| Visual Studio | 2017 15.9(v141) | MSVC2017 的最后一版,平台工具集固定 v141 |
| Qt | 5.14.7 msvc2017_64 | 必须选带 msvc2017 字样的预编译包 |
| OSG | 3.6.3 源码 | 用 v141 自己编,别下别人的二进制 |
| osgEarth | 2.10 源码 | 依赖 OSG 3.6.x,C++11 起步 |
| CMake | 3.19 或 3.20 | 4.x 会直接拒绝 OSG 的老 CMakeLists |
| GDAL | 2.4.x | 3.x 的坐标轴序会坑到 osgEarth 2.10 |
| PROJ | 5.2.0 | 6.x 删了 proj_api.h,2.10 编不过 |
| GEOS | 3.8.x | 3.9 之后接口有调整 |
| curl | 7.6x | 只要 libcurl,别带 SSL 依赖也行 |
Qt 5.14.7 是 5.14 分支最后一个补丁版,官方安装器里给的就是 msvc2017 64-bit 和 32-bit 两个预编译包,没有 msvc2019 的。有人图省事拿 VS2019 打开,靠「重定解决方案目标」把 v141 改成 v142,编译能过,运行期一调 Qt 的信号槽就崩,因为 CRT 已经不匹配了。这条红线别碰。
提示:安装 Qt 时把「Sources」和「Qt Debug Information Files」勾掉,能省两个 G。Qt Creator 一般随包带 4.13 版本,够用。
2.2 目录规划:源码、构建、安装三段分开
我见过太多人把 build 目录直接建在源码树里,编崩一次想重来就得重新解压。固定成三段式,后面 osgEarth 找 OSG 的时候路径也好写。
D:\dev\ ├── src\ 源码,解压后不再动 │ ├── OpenSceneGraph-3.6.3\ │ ├── osgearth-2.10\ │ └── osgQt-master\ ├── build\ 每个工程一个子目录,编崩了直接删 │ ├── osg-3.6.3\ │ ├── osgearth-2.10\ │ └── osgqt\ ├── install\ 最终产物,只增不改 │ ├── osg-3.6.3\ │ └── osgearth-2.10\ └── deps\ 第三方预编译库 ├── 3rdParty_VS2017_v141_x64_V14\ ├── gdal-2.4.4\ ├── proj-5.2.0\ ├── geos-3.8.0\ └── curl-7.65\install目录只放编译成功的结果,build 目录随时可删,src 目录保持原始状态。后面排查问题时,只要确认 install 里的 bin/lib/include 三处齐全,基本能排除一半的「找不到库」。
2.3 VS2017 组件勾选与 Qt 安装后的路径处理
VS2017 安装器里只勾两项就够:「使用 C++ 的桌面开发」和「Windows 10 SDK 10.0.17763」。C++ 桌面开发里再确认「MSVC v141 - VS 2017 C++ x64/x86 生成工具」和「Windows 10 SDK」都在,缺了 CMake 生成工程时找不到cl.exe。
Qt 装完,把D:\Qt\5.14.7\msvc2017_64\bin加进 PATH。这一步不做,后面 osgQt 编译时 CMake 找不到Qt5Config.cmake,报的错是Could NOT find Qt5,看起来像 Qt 没装,其实是路径没喂进去。
:: 只在当前命令行窗口生效,先试,确认没问题再写进系统变量 set OSG_ROOT=D:\dev\install\osg-3.6.3 set OSG_FILE_PATH=%OSG_ROOT%\data set PATH=%OSG_ROOT%\bin;D:\Qt\5.14.7\msvc2017_64\bin;D:\dev\deps\3rdParty_VS2017_v141_x64_V14\bin;%PATH%OSG_FILE_PATH是 OSG 找cow.osg这类示例数据的搜索路径,不设也能跑,但osgviewer cow.osg会提示找不到文件。PATH 里我习惯把 3rdParty 的 bin 也塞进去,因为 OSG 插件依赖的 zlib、libpng、jpeg 这些 DLL 都在那儿,少一个就是运行时崩溃。
注意:
setx有 1024 字符长度限制,PATH 长了会被截断,系统变量建议直接在「环境变量」图形界面里改。命令行set只用于临时验证。
3. 编译 OSG 3.6.3:CMake 参数逐项对照与 INSTALL 目标
OSG 是整个链条的地基,它编不干净,后面 osgEarth 一定是连锁失败。我的做法是不用 cmake-gui 点选,全部走命令行,把参数写进一个 bat 文件,出问题能一行一行回看。VS 是多配置生成器,CMAKE_BUILD_TYPE在这套组合里其实不起作用,真正决定 Release 的是构建时的--config。
3.1 生成工程:一条命令里每个 -D 的作用
cd /d D:\dev\build\osg-3.6.3 cmake -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX=D:/dev/install/osg-3.6.3 ^ -DBUILD_OSG_APPLICATIONS=ON ^ -DBUILD_OSG_EXAMPLES=OFF ^ -DBUILD_DOCUMENTATION=OFF ^ -DDYNAMIC_OPENSCENEGRAPH=ON ^ -DDYNAMIC_OPENTHREADS=ON ^ -DCMAKE_INCLUDE_PATH=D:/dev/deps/3rdParty_VS2017_v141_x64_V14/include ^ -DCMAKE_LIBRARY_PATH=D:/dev/deps/3rdParty_VS2017_v141_x64_V14/lib ^ D:/dev/src/OpenSceneGraph-3.6.3-G "Visual Studio 15 2017 Win64"里的 15 是 VS2017 的内部版本号,写成Visual Studio 16会直接找不到生成器。CMAKE_INSTALL_PREFIX用正斜杠,反斜杠在 CMake 里当转义符,D:\dev会被吃掉一个字符。
BUILD_OSG_APPLICATIONS=ON决定要不要生成osgviewer.exe、osgversion.exe这些工具。有人为了省时间关掉,结果最后验证环节没东西可跑,还得重编一遍。BUILD_OSG_EXAMPLES=OFF是真心建议关,例子工程里有几个依赖冷门库,编到 70% 断掉很折磨人。
DYNAMIC_OPENSCENEGRAPH和DYNAMIC_OPENTHREADS保持 ON,产出osg160-osg.dll这类动态库。Qt 程序如果静态链接 OSG,一个 exe 轻松上百兆,调试时符号加载也慢。CMAKE_INCLUDE_PATH/CMAKE_LIBRARY_PATH是给 Find 系列模块用的搜索提示,OSG 找 zlib、libpng、jpeg 全靠它们。
提示:
OPENGL_PROFILE默认是 GL3。如果目标机器显卡驱动比较老,跑起来报OpenGL 3.3 not supported,可以改成-DOPENGL_PROFILE=GL2重编一次。
3.2 编译与安装:为什么要显式指定 INSTALL 目标
cmake --build . --config Release --target INSTALL -- /m:8这一条同时干了两件事:先编ALL_BUILD,再执行INSTALL把产物按 prefix 铺开。只写--build . --config Release的话,库文件散落在 build 目录各个子文件夹里,osgEarth 那边找一个osg.lib要翻半天。
/m:8是透传给 MSBuild 的并行数,按物理核数填。这里有个血泪经验:OSG 3.6.3 的某些插件在并行编译下会有偶发的头文件竞争,如果编译报出莫名其妙的cannot open include file,把/m:8去掉单线程再编一次,往往就过了。
编译时长在 8 核机器上大约 25 到 40 分钟,取决于插件开了多少。中途失败最常见的是osgdb_fbx,因为没装 FBX SDK。这种情况不用重来,在 CMake 缓存里搜FBX,把对应的插件开关改成 OFF,重新 configure 再 build,已编好的目标会跳过。
3.3 产物自检:bin、lib、include 三处对齐
编完先别急着往下走,花两分钟确认结构。install\osg-3.6.3下应该有三个目录:bin里有osg160-osg.dll、osgviewer.exe、osgversion.exe;lib里有osg.lib、osgDB.lib、osgViewer.lib等导入库;include下是osg/、osgDB/、osgViewer/这些头文件目录。
D:\dev\install\osg-3.6.3\bin\osgversion.exe正常输出类似OpenSceneGraph Library 3.6.3。如果这条命令报「找不到 VCRUNTIME140.dll」,说明当前命令行没有继承 VS 的环境,用「x64 Native Tools Command Prompt for VS 2017」再开一个窗口。如果报找不到osg160-osgd.dll,那是 Debug 版的名字,说明 PATH 里混进了 Debug 目录,这在后面第 5 章会详细说。
4. 编译 osgEarth 2.10:先把 GDAL/PROJ 钉死,再补 osgQt
osgEarth 2.10 是这套组合里脾气最大的一个。它不像 OSG 那样自给自足,GDAL、PROJ、GEOS、curl 全要外部提供,而且版本窗口很窄。我第一次编的时候用了手头最新的 GDAL 3.0 和 PROJ 6.1,configure 阶段就报proj_api.h not found,换回 PROJ 5.2 才继续。
4.1 依赖版本红线:PROJ 别过 5.2,GDAL 别过 2.4
PROJ 从 6.0 开始把老的proj_api.h换成了proj.h,接口从pj_init_plus变成proj_create_crs_to_crs。osgEarth 2.10 的src/osgEarth/SpatialReference.cpp里还在用老接口,所以 PROJ 6 及以上是编不过的,报错位置在#include <proj_api.h>。这不是改个宏能绕过去的,直接降到 5.2.0 最省事。
GDAL 3.x 的问题更隐蔽:它默认按 OAMS_TRADITIONAL_GIS_ORDER 处理轴序,而 GDAL 2.x 里EPSG:4326是「纬度, 经度」,3.x 改成了「经度, 纬度」。osgEarth 2.10 内部按老顺序解析,编是能编过,运行起来地图整个转 90 度,或者定位到南极。这种问题在日志里没有任何报错,只能靠肉眼看出不对。
GEOS 用 3.8.x,主要给 osgEarth 做几何运算;curl 用 7.6x 的静态库或导入库都行,只影响网络图层(WMS/WMTS)能不能拉数据,本地 earth 文件不依赖它。
注意:这些依赖库自己也要用 v141 编,或者直接用官方给的 msvc2017 x64 预编译包。拿 v142 编的 GDAL 来链接,一样会出 LNK2038。
4.2 CMake 配置:三个必须手填的路径
osgEarth 的 Find 模块写得比较老实,GDAL_INCLUDE_DIR、PROJ4_LIBRARY这些变量在 PATH 里搜不到,必须显式给。用CMAKE_PREFIX_PATH能覆盖一部分,但 GDAL 的导入库叫gdal_i.lib,名字不标准,FindGDAL 经常识别不出来。
cd /d D:\dev\build\osgearth-2.10 cmake -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX=D:/dev/install/osgearth-2.10 ^ -DCMAKE_PREFIX_PATH="D:/dev/install/osg-3.6.3" ^ -DGDAL_INCLUDE_DIR=D:/dev/deps/gdal-2.4.4/include ^ -DGDAL_LIBRARY=D:/dev/deps/gdal-2.4.4/lib/gdal_i.lib ^ -DPROJ4_INCLUDE_DIR=D:/dev/deps/proj-5.2.0/include ^ -DPROJ4_LIBRARY=D:/dev/deps/proj-5.2.0/lib/proj.lib ^ -DGEOS_INCLUDE_DIR=D:/dev/deps/geos-3.8.0/include ^ -DGEOS_LIBRARY=D:/dev/deps/geos-3.8.0/lib/geos_c.lib ^ -DCURL_INCLUDE_DIR=D:/dev/deps/curl-7.65/include ^ -DCURL_LIBRARY=D:/dev/deps/curl-7.65/lib/libcurl.lib ^ -DBUILD_OSGEARTH_EXAMPLES=ON ^ D:/dev/src/osgearth-2.10CMAKE_PREFIX_PATH指向 OSG 的 install 目录,osgEarth 靠它找osgConfig.cmake。如果这行写错,报错是Could not find OSG,但不会告诉你它去了哪些路径找,得加--debug-find才能看到搜索列表。
PROJ4_LIBRARY的名字里带 4,但 5.2 也能用,因为 5.x 还保留了proj_api.h兼容层。这就是为什么版本红线卡在 5.2 而不是 6。
BUILD_OSGEARTH_EXAMPLES=ON一定要开,osgearth_viewer.exe是后面验证的核心工具,关了等于自断双臂。编的时候同样用 INSTALL 目标:
cmake --build . --config Release --target INSTALL -- /m:8时长大约 15 到 25 分钟。中途如果报osgEarth::Util::...未定义符号,八成是 OSG 那边 Debug/Release 混了,回到 3.2 节确认只编过 Release。
4.3 补上 osgQt:OSG 3.6 已经不带了
这是个很多人不知道的变更:从 OSG 3.4 之后,osgQt从主仓库拆出去成了独立项目。所以编译完 OSG 3.6.3,install 目录里是找不到osgQt.lib的,Qt 程序里#include <osgQOpenGL/osgQOpenGLWidget>直接报文件不存在。
需要用 OSG 官方的 osgQt 仓库源码单独编一次,它支持 Qt5,产出的osgQOpenGLWidget就是 Qt 里嵌 OSG 的标准控件。
cd /d D:\dev\build\osgqt cmake -G "Visual Studio 15 2017 Win64" ^ -DCMAKE_INSTALL_PREFIX=D:/dev/install/osg-3.6.3 ^ -DCMAKE_PREFIX_PATH="D:/dev/install/osg-3.6.3;D:/Qt/5.14.7/msvc2017_64" ^ -DBUILD_OSG_EXAMPLES=OFF ^ D:/dev/src/osgQt-masterCMAKE_INSTALL_PREFIX故意指到 OSG 的 install 目录,这样osgQt.lib和osgQOpenGLWidget的头文件会直接并进 OSG 那套结构里,后面工程只需要配一个 OSG 路径。CMAKE_PREFIX_PATH里同时给 OSG 和 Qt,少一个都会在 configure 阶段停下。
编完检查D:\dev\install\osg-3.6.3\include\osgQOpenGL目录是否存在,以及lib下有没有osgQt.lib。没有的话,把 CMake 输出往上翻,通常是 Qt5 的Widgets组件没找到。
提示:osgQt 的 master 分支跟着 OSG 主线走,配 3.6.3 没问题。如果 configure 报 OSG 版本不匹配,检查
CMAKE_PREFIX_PATH里是不是混进了别的 OSG 安装。
5. 排查:五个让编译和启动一起翻车的地方
下面这五条是我在这套环境上真实踩过的,按发生阶段排序。每条都按「现象、原因、解决」写,遇到对得上的直接照做,不用从头推。
5.1 编译期:找不到库与运行库不匹配
第一条:CMake 报Could NOT find GDAL,但 GDAL 明明在 PATH 里。
现象是 configure 结束时打印一串Could NOT find GDAL (missing: GDAL_LIBRARY GDAL_INCLUDE_DIR),可gdalinfo.exe在命令行里能正常跑。原因是 osgEarth 用的 FindGDAL 模块只认GDAL_INCLUDE_DIR和GDAL_LIBRARY两个缓存变量,压根不看 PATH。解决就是把这两个变量手工填进去,而且GDAL_LIBRARY必须指到gdal_i.lib这个导入库,不能指gdal.dll。填完删掉 CMakeCache.txt 重新 configure,别在旧缓存上改。
第二条:链接阶段报LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'。
现象是编译全过,链接到一半突然停,报错里带着zlib.lib或libcurl.lib的名字。原因是 OSG 和 osgEarth 默认用/MD(动态运行库),而某些第三方静态库是用/MT编的,两套 CRT 不能混在一个 exe 里。解决办法有两个:一是换成/MD版本的依赖库,这也是我一般推荐的做法,Qt 官方包本身就是/MD;二是把整个工程的CMAKE_CXX_FLAGS_RELEASE改成/MT,但这样 Qt 那边又会报同样的错,等于把问题挪了个位置。所以优先换库。
5.2 启动期:DLL 找不到、坐标错乱与黑屏
第三条:双击 exe 弹「应用程序无法正常启动 0xc000007b」,或者提示缺少osg160-osgd.dll。
现象很分裂:Debug 配置下能跑,Release 下崩;或者反过来。原因是文件名里的d后缀,osg160-osgd.dll是 Debug 版,osg160-osg.dll是 Release 版。PATH 里如果只放了其中一个目录,另一个配置启动时就会去找不存在的 DLL。解决是把 install 目录下的 bin 全量加进 PATH,并且确认没有把 build 目录里的中间产物目录也塞进去,那里面两套 DLL 混着放,更容易加载错。
第四条:osgearth_viewer打开 .earth 文件后直接退出,控制台没有任何输出。
现象是窗口一闪而过,命令行里连报错都没有。原因是 PROJ 的数据目录没配。PROJ 6 之后需要proj.db这个数据库文件,通过PROJ_LIB环境变量指向它所在目录;PROJ 5.2 时代还没有这个文件,所以按 4.1 节降到 5.2 的话通常不会遇到。如果确实用了高版本 PROJ,设set PROJ_LIB=D:\dev\deps\proj-5.2.0\share\proj,再跑一次就能看到真正的错误信息。这类「无输出退出」的情况,我习惯先加--log-level debug之类的参数把日志打开再判断。
第五条:Qt 程序里osgQOpenGLWidget显示为纯黑,鼠标拖动也没反应。
现象是窗口出来了,但里面全黑,控制台没有 OpenGL 报错。原因有两个:一是没有在QApplication构造之前设置默认的QSurfaceFormat,Qt 默认给的是兼容模式加低版本,OSG 初始化时拿不到合适的上下文;二是setSceneData调用时机太早,控件还没完成initializeGL。解决顺序是先QSurfaceFormat::setDefaultFormat,再构造QApplication,控件show()之后再调setSceneData。下一章的最小工程就是按这个顺序写的。
6. 验证跑通:三条命令加一个最小 Qt 窗口
装完不验证,等于没装。我一般按从低到高的顺序过三关,任何一关不过就停下修,不带着问题上下一层。
第一关是 OSG 自身。命令行执行D:\dev\install\osg-3.6.3\bin\osgversion.exe,看到3.6.3才算数。第二关是渲染管线,跑osgviewer.exe cow.osg,能出现一头可以鼠标拖动的牛,说明 OpenGL 上下文、插件加载、DLL 依赖三条链路都通。第三关才是 osgEarth,跑osgearth_viewer.exe加载一个最简单的 earth 文件。
| 验证项 | 命令 | 期望结果 | 失败先看 |
|---|---|---|---|
| OSG 版本 | osgversion.exe | 输出 3.6.3 | PATH 是否指向 Release 的 bin |
| OSG 渲染 | osgviewer.exe cow.osg | 出现可交互模型 | 显卡驱动、OSG_FILE_PATH |
| osgEarth | osgearth_viewer.exe test.earth | 出现地球或影像 | PROJ 数据目录、GDAL DLL |
| Qt 嵌入 | 运行最小工程 | 窗口内出现模型 | QSurfaceFormat、链接顺序 |
最小 Qt 工程的main.cpp就二十来行,关键是格式设置放在最前面:
#include <QApplication> #include <QSurfaceFormat> #include <osgQOpenGL/osgQOpenGLWidget> #include <osgDB/ReadFile> #include <osgGA/TrackballManipulator> int main(int argc, char** argv) { // 必须在 QApplication 之前设置,否则 OSG 拿到的是低版本上下文 QSurfaceFormat fmt; fmt.setRenderableType(QSurfaceFormat::OpenGL); fmt.setVersion(3, 3); fmt.setProfile(QSurfaceFormat::CompatibilityProfile); fmt.setDepthBufferSize(24); QSurfaceFormat::setDefaultFormat(fmt); QApplication app(argc, argv); osgQOpenGLWidget* viewer = new osgQOpenGLWidget; viewer->resize(960, 540); viewer->setCameraManipulator(new osgGA::TrackballManipulator); viewer->show(); // show 之后再灌场景,保证 initializeGL 已经跑过 viewer->setSceneData(osgDB::readNodeFile("D:/dev/install/osg-3.6.3/data/cow.osg")); return app.exec(); }setVersion(3, 3)要和编译 OSG 时的OPENGL_PROFILE对上,OSG 用 GL3 编的,这里给 3.3 兼容模式最稳。CMakeLists 里find_package找不到 osgQt 的话,别死磕,直接把osgQt.lib和头文件路径写死进target_link_libraries,一样能编过。
从那以后我每装一套 OSG 环境,都强迫自己先把osgversion和osgviewer cow.osg这两条跑完再动 osgEarth,因为所有依赖问题都会在这两步暴露,越往后查代价越大。这套顺序帮我省下的时间,比任何调试技巧都多。希望帮到你。
本文还有配套的精品资源,点击获取