简介:面向Windows三维地理信息系统开发者的osgEarth自编译版,基于OpenSceneGraph(OSG)3.6.5构建,适配Visual Studio 2022 64位环境,可用于三维地形渲染、影像叠加与地理数据可视化等场景。相比手动编译依赖,这套产物可直接集成进工程,省去vcpkg等工具链的版本匹配与编译报错。压缩包共2000个文件,以C++头文件为主,约1948个h声明文件与47个hpp模板文件,另附PDF说明、TXT记录、Markdown笔记及少量C源码,整体约483.88MB。已有1249人学习下载。资源提供Debug和Release双配置的完整编译输出,涵盖exe可执行程序、dll动态库、lib静态库及pdb调试符号;目录按include、lib、bin等分类存放,便于快速在VS2022中建立链接、调试与性能优化;同时,基于OpenGL 2.x渲染管线,支持场景管理、光照、纹理等基础3D功能,osgEarth作为OSG的扩展提供高程、影像、地形等地理数据API,可大幅简化三维地球应用的开发流程,提升三维地理信息系统项目的搭建效率。
1. 为什么折腾三天也要自编译 osgEarth 3.4.0 + OSG 3.6.5 的 Debug+Release 64 位版
大多数从零开始做三维 GIS 的 C++ 工程师,第一步都会栽在同一个地方:想在 VS2022 里用 osgEarth 3.4.0 + OSG 3.6.5 搭一套可调试的地形可视化工程,却发现网上能找到的预编译包几乎都满足不了需求。要么只有 Release 版,打断点时调用栈一片白;要么是 32 位,在 64 位工程里链接直接报错;要么 osgEarth 版本对不上 OSG 版本,插件加载黑匣子一样失败。
这套“自编译版”就是要解决这三个问题:64 位、Debug 与 Release 双配置齐全、符号表与源码完全对应。适合正在做三维 GIS 二次开发、想把 osgEarth 集成进 MFC/Qt/自绘框架的从业者。编译一次,后面能省下无数个查 DLL 报错的深夜。
2. 动手之前:VS2022 工具链与第三方依赖的一次性归置
2.1 VS2022 安装与工作负载:离线安装、SDK 与工具集的三个细节
VS2022 的安装教程容易让人只勾选默认工作负载就点安装,等编译时才后悔。这里有一个固定套路:社区版在官网下载,安装时把工作负载换成“使用 C++ 的桌面开发”,右侧会跟着勾上 MSVC v143 编译器、Windows 10/11 SDK、C++ CMake 工具。这三样缺一不可,SDK 缺失会在 CMake 生成阶段报找不到 Windows SDK 版本,CMake 工具缺失则需要你自己另配一份。
如果你的开发机所在内网无法访问外网,走离线安装是常见做法。用一台能上网的机器执行以下命令,把安装包整个拉下来:
vs_community.exe --layout D:\vs2022_offline --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended --lang zh-CN参数说明:--layout指定离线安装包的存放目录;--add指定要缓存的工作负载,这里只缓存了 C++ 桌面开发;--includeRecommended会把推荐组件一起拉下来,避免拷到内网后装到一半提示缺组件。整个目录体积不小,建议用移动硬盘拷。到了内网机器上直接运行vs_community.exe --offline D:\vs2022_offline就能装。
还有一个容易被忽略的细节:用 CMake 生成 VS2022 工程时,项目默认字符集是“Not Set”,即不定义_UNICODE和_MBCS。很多人习惯性地在项目属性里改成“使用 Unicode 字符集”,改了之后 OSG 和 osgEarth 的字符串处理行为不会有问题,但一旦你混用其他按多字节编译的库,会冷不丁冒出一堆 C2664 编译错误。我的建议是从 CMake 生成阶段就保持 Not Set,不要手动去改 VS 属性页里的字符集选项,后面所有第三方库也都按这个标准编,反而省事。
2.2 第三方依赖怎么选:vcpkg 一键装齐还是逐个源码编译
OSG 3.6.5 和 osgEarth 3.4.0 自己不带第三方库,但编译过程中会找一堆依赖。我把需要的库列一个清单,按功能分:
| 依赖库 | 用途 | 是否必须 |
|---|---|---|
| zlib / libpng / libjpeg-turbo / libtiff | 图片瓦片与纹理解码 | 必须 |
| freetype | 文字标注渲染 | 建议开启 |
| curl | 在线影像、XYZ 瓦片服务 | osgEarth 网络功能必须 |
| gdal | 栅格地形、矢量数据读写 | osgEarth 核心驱动 |
| geos | 几何拓扑运算、图元裁剪 | 建议开启 |
| sqlite3 | 本地瓦片缓存与地形包 | 建议开启 |
| expat | XML 解析 | 必须 |
| openssl | HTTPS 链路支持 | 建议开启 |
这套依赖逐个去源码编译非常耗时,而且每个库都有自己的坑。常见做法是用 vcpkg 一次装齐,指定 x64-windows 动态库 triplet:
git clone https://github.com/microsoft/vcpkg.git cd vcpkg .\bootstrap-vcpkg.bat .\vcpkg install zlib libpng libjpeg-turbo libtiff freetype curl gdal geos sqlite3 expat openssl --triplet x64-windows参数说明:--triplet x64-windows表示生成 64 位动态库版本,动态库模式与 OSG 默认的共享库方式一致,可以避免后续链接时出现运行时库冲突。如果你在三线内网环境,可以提前在能联网的机器上把 vcpkg 的installed目录整个打包带走,或者用 vcpkg 的export命令导出成离线包。
这里用 vcpkg 而不用预处理好的第三方库合集,原因在于 osgEarth 对 GDAL 的版本非常敏感。自己编译的版本可以保证 GDAL 的.lib与你最终链接的.dll完全同源,否则很容易出现头文件 3.x、运行库 2.x 的错位,编译能过,一运行就崩溃。另外建议把 vcpkg 的installed\x64-windows\bin目录加入系统 PATH,后面 osgEarth 运行时要找gdal.dll、libcurl.dll、libeay32.dll这些动态库,路径不配好会输在起跑线上。
2.3 统一的环境变量:CMAKE_PREFIX_PATH 是后续所有编译的地基
两个大工程加上 vcpkg 的库,手工去 CMake GUI 里一个个填路径是不现实的。我习惯先设一个环境变量,把第三步库的根路径固定下来:
setx THIRD_PARTY_ROOT "D:\vcpkg\installed\x64-windows"然后所有 CMake 配置统一传这个根目录。OSG 和 osgEarth 的 CMake 脚本里有相当一部分find_package调用,依赖CMAKE_PREFIX_PATH去定位xxxConfig.cmake,设好这个变量后,像 libpng、libtiff 这些库会自动被检索到。
CMAKE_PREFIX_PATH生效机制其实不复杂:CMake 会在该目录下的lib/cmake、share这些位置查找包配置文件,vcpkg 安装完每个库都会额外生成一份官方的 CMake config 文件,所以这个路径是所有第三方库能找到的核心条件。
血泪经验:OSG 的 CMake 脚本里,第三方库的查找逻辑比较老,不完全靠CMAKE_PREFIX_PATH,它还会去找ACTUAL_3RDPARTY_DIR这个专用变量。如果只设置了CMAKE_PREFIX_PATH,CMake 配置阶段会提示找不到 zlib。我一般两个变量一起传,路径都指向 vcpkg 的同一目录,后面第三、四章的命令里会看到这个组合。
3. 编译 OSG 3.6.5:从 CMake 配置到 Debug+Release 双输出
3.1 生成 VS2022 工程的最小命令
拿到 OSG 3.6.5 源码后,解压到D:\src\OpenSceneGraph-3.6.5,在它的上一级建一个专门的构建目录,不要把构建文件混进源码目录。用命令行生成工程时,建议用一次典型的配置:
cmake -S D:\src\OpenSceneGraph-3.6.5 ^ -B D:\build\osg-3.6.5-vs2022-x64 ^ -G "Visual Studio 17 2022" ^ -A x64 ^ -DCMAKE_INSTALL_PREFIX=D:\libs\osg-3.6.5-x64 ^ -DCMAKE_PREFIX_PATH=D:\vcpkg\installed\x64-windows ^ -DACTUAL_3RDPARTY_DIR=D:\vcpkg\installed\x64-windows ^ -DBUILD_OSG_EXAMPLES=ON参数说明:-G指定 VS2022 生成器,生成器名称必须是Visual Studio 17 2022;-A x64强制生成 64 位工程;CMAKE_INSTALL_PREFIX是安装目录,建议直接用D:\libs下的独立目录而不是 C 盘,后面 osgEarth 配置要找 OSG 的安装位置;ACTUAL_3RDPARTY_DIR是 OSG 专门用来查找第三方库头文件和二进制文件的变量,3.6.5 版本里不设这个,CMake 配置阶段就会因为找不到 libpng 报错。
这一步生成的是多配置工程,VS 解决方案里同时包含 Debug 和 Release 两种配置,不需要像 Linux 下那样指定CMAKE_BUILD_TYPE。运行完 CMake 后检查输出日志,如果看到Found ZLIB、Found PNG这些字样,说明第三方库检索成功;如果看到Could NOT find ZLIB,先绕回确认ACTUAL_3RDPARTY_DIR指向的是installed\x64-windows,而不是installed\x64-windows\lib这种子目录。
3.2 关键编译选项取舍:哪些开、哪些关
OSG 3.6.5 的 CMake 选项很多,但不是所有选项都适合自编译版场景。我用下来推荐这套组合:
| 选项 | 推荐值 | 理由 |
|---|---|---|
| BUILD_OSG_EXAMPLES | ON | 自编译后的验收工具,osgviewer直接能用来验证插件是否正常 |
| BUILD_OSG_APPLICATION | ON | 生成osgviewer、osgversion等命令行工具 |
| BUILD_OSG_PLUGINS | ON | 不编译插件,osgEarth读不了任何格式文件 |
| DYNAMIC_OPENSCENEGRAPH | ON | 生成 DLL 与导入库,osgEarth 链接需要 |
| BUILD_OSG_DEPRECATED_SERIALIZERS | ON | 旧版本.osg场景文件兼容性 |
| OSG_USE_QT | OFF | 不依赖 Qt,纯 Win32 窗口系统 |
一个让我翻车过的点:OSG_USE_QT如果开着,CMake 会在系统里找 Qt 5 的安装路径,能找到就自动把 OSG 编译成带 Qt 支持的样子,找不到也不会报错。但这个选项会影响OPENSCENEGRAPH库对 Qt 库的依赖,等你要把 osgEarth 集成进 MFC 工程时会莫名多出一堆 Qt 依赖。所以这条手动设OFF更省心。
另外,DYNAMIC_OPENSCENEGRAPH=ON意味着生成osgViewerd.dll/osgView.dll,Debug 版带d后缀。这个细节很关键,后面 Debug 与 Release 可以装进同一个安装目录而不互相覆盖。
3.3 Debug 和 Release 两遍构建的先后顺序
用 VS 打开解决方案,在配置管理器里创建 x64 平台的 Debug 和 Release 配置,然后逐个生成所有项目也可以,但命令行更可控、更容易复现:
msbuild D:\build\osg-3.6.5-vs2022-x64\OpenSceneGraph.sln ^ /p:Configuration=Debug /p:Platform=x64 /m msbuild D:\build\osg-3.6.5-vs2022-x64\OpenSceneGraph.sln ^ /p:Configuration=Release /p:Platform=x64 /m/m参数让 MSBuild 并行编译多个项目,能明显缩短整体时间。OSG 项目数量多,插件一个比一个重,串行编译是纯折磨。/p:Configuration和/p:Platform分别指定配置与平台,命令行下必须写全,不然默认按 x86 编,链接阶段就会报unresolved external symbol。
编译完成后,分别安装两个配置:
msbuild D:\build\osg-3.6.5-vs2022-x64\OpenSceneGraph.sln ^ /p:Configuration=Debug /p:Platform=x64 /t:INSTALL msbuild D:\build\osg-3.6.5-vs2022-x64\OpenSceneGraph.sln ^ /p:Configuration=Release /p:Platform=x64 /t:INSTALL/t:INSTALL是 CMake 生成的目标,作用是把头文件、导入库、DLL 统一拷贝到CMAKE_INSTALL_PREFIX目录。Debug 版的 DLL 文件名为osgViewd.dll、osgDBd.dll,Release 版为osgView.dll、osgDB.dll,所以第二次安装不会覆盖第一次。
安装完成后检查一下D:\libs\osg-3.6.5-x64\bin下既要有osgView.dll也要有osgViewd.dll,这样才说明双配置编译成功。如果只看到一个版本,多半是第一个配置没编完或者 INSTALL 目标没跑完。
4. 编译 osgEarth 3.4.0:把每一步依赖都指到刚装好的 OSG
4.1 源码与构建目录的 CMake 配置
osgEarth 3.4.0 对 OSG 的依赖相当直接,CMake 会通过OSG_DIR变量去找OpenSceneGraphConfig.cmake。这段配置不复杂,但容易因为路径风格不一致踩坑。我用一个构建目录文件来解决:解压osgEarth-3.4.0源码到D:\src\osgEarth-3.4.0,然后执行:
cmake -S D:\src\osgEarth-3.4.0 ^ -B D:\build\osgearth-3.4.0-vs2022-x64 ^ -G "Visual Studio 17 2022" ^ -A x64 ^ -DCMAKE_INSTALL_PREFIX=D:\libs\osgearth-3.4.0-x64 ^ -DCMAKE_PREFIX_PATH=D:\vcpkg\installed\x64-windows ^ -DOSG_DIR=D:\libs\osg-3.6.5-x64参数说明:OSG_DIR必须指向 OSG 安装目录的根路径,CMake 会在这里的lib/cmake/OpenSceneGraph下找到对应的XXXConfig.cmake文件,而不是直接指向lib子目录;CMAKE_PREFIX_PATH继续指向 vcpkg 的 x64-windows 目录,osgEarth 的第三方库查找逻辑比 OSG 新,能正确用它检索 GDAL、CURL、GEOS。
配置阶段如果提示Could NOT find OSG,优先检查OSG_DIR路径下是否存在lib/cmake/OpenSceneGraph/OpenSceneGraphConfig.cmake。有些时候安装路径被写成了D:\libs\osg-3.6.5-x64\lib\cmake,那是错的,CMake 里传进去就该是根目录。
4.2 功能开关怎么选:GDAL、CURL、GEOS 各自管什么
osgEarth 3.4.0 的 CMake 功能开关里,最常被问到的是 GDAL、CURL、GEOS、SQLite3 这四个。它们分别对应不同场景:
| 开关 | 依赖 | 功能 | 建议 |
|---|---|---|---|
| OSGEARTH_USE_GDAL | gdal | 读取 tif、img、shp 等地理数据 | ON |
| OSGEARTH_USE_CURL | curl | 加载 http/https 瓦片服务 | ON |
| OSGEARTH_USE_GEOS | geos | 几何运算、图元裁剪、量算 | ON |
| OSGEARTH_USE_SQLITE3 | sqlite3 | TMS/XYZ 瓦片本地缓存、地形包 | ON |
这四个开关不全是开得越多越好。GDAL 一旦开启,OSG 读取 tif 文件时会优先走 osgEarth 的 GDAL 驱动,如果 GDAL 编译有问题,哪怕 OSG 自带的 tiff 插件是好的,地图也加载不出来。CURL 开着的话,osgEarth 里嵌入<driver="xyz">这种在线服务就能用,但偏置的 DNS 与代理环境会导致 osgEarth 启动时卡在 HTTP 连接上,这种情况可以临时用OSGEARTH_NO_HTTP=1环境变量关掉网络初始化。
我一般全开。原因很简单:自编译版本就图一个全功能,关掉 GDAL 或 CURL 之后,后面遇到“地图黑屏但控制台无报错”的问题时,排查方向会多一个“是不是编译开关关了”。调试后的处理,不如现在一次到位。
注意这里也要把 vcpkg 里一大堆 debug 库的作用说清楚。VS 多配置模式下,CMake 会自动选择debug/lib下的库文件和lib下 Release 库文件,前提是 vcpkg 安装时用的是同一个 triplet,不要手动拆分 Debug/Release 目录。
4.3 两遍编译、安装与 PATH 归位
和 OSG 一样,osgEarth 也是多配置工程,两遍编译命令几乎相同,只是解决方案名不同:
msbuild D:\build\osgearth-3.4.0-vs2022-x64\osgEarth.sln ^ /p:Configuration=Debug /p:Platform=x64 /m msbuild D:\build\osgearth-3.4.0-vs2022-x64\osgEarth.sln ^ /p:Configuration=Release /p:Platform=x64 /m生成完成后同样执行两次 INSTALL 目标。安装结束后把两个bin目录都加进 PATH,顺序有讲究,OSG 的 bin 要放在 osgEarth 的前面,这样运行时先找到 OSG 的 DLL:
setx PATH "D:\libs\osg-3.6.5-x64\bin;D:\libs\osgearth-3.4.0-x64\bin;%PATH%"这一步做完后,打开一个新的命令提示符,输入osgearth_version --all验证。如果输出里能同时看到 osgEarth 3.4.0 和 OSG 3.6.5 的版本字符串,说明基础编译链路已经通了。如果提示找不到 DLL,说明 PATH 没有刷新,命令提示符要重开,或者直接在D:\libs\osgearth-3.4.0-x64\bin下手动跑一下再排查缺哪个文件。
5. 自编译版避坑清单:链接、运行时与 DLL 战争的四个典型教训
5.1 Debug 程序加载 Release DLL 的“黑匣子崩溃”
现象:用自编译库新建了一个 Debug 版测试程序,构造osgViewer::Viewer正常,一旦readNodeFile读取 earth 文件,程序直接崩溃,调用栈全堆在 osgEarth 的 dll 加载过程里,根本定位不到自己的代码。
原因:Debug 版 exe 在运行时按搜索顺序加载 DLL,如果 PATH 里同时存在 osgEarth 的 Debug 和 Release 两类库,而 Release 库排在前面,程序就会在符号表不匹配的状态下运行,这属于典型的 Debug/Release 混合加载。另一个可能是链接器在链接阶段就配错了导入库,把 Release 的.lib链进了 Debug 工程。
解决:先确认安装目录里 Debug 的 DLL 是否真的存在,检查D:\libs\osgearth-3.4.0-x64\bin下有没有osgEarthd.dll,没有就重新执行 Debug 的 INSTALL 目标。其次用依赖检查工具确认 exe 实际加载的 DLL 路径,VS2022 开发人员命令提示符里跑一句:
dumpbin /dependents D:\myapp\x64\Debug\myapp.exedumpbin输出里会列出依赖的 DLL 名称,如果看到的是osgEarth.dll而不是osgEarthd.dll,说明链接期就弄错了。自编译版的调试体系再完整,也扛不住 Debug 和 Release 库互相串门造成的黑匣子崩溃,这条是排第一的坑。
5.2 GDAL 数据路径错位:地形加载一半就黑屏
现象:earth 文件里引用了本地D:/data/srtm.tif,Release 版程序能正常显示地形,Debug 版加载到一半画面黑屏,控制台反复输出Unable to open datasource。
原因:osgEarth 通过 GDAL 打开 tif 文件时,GDAL 需要自己的数据文件目录(包含gcs.csv、proj.db、pcs.csv等)才能完成坐标系统解析。vcpkg 安装的 gdal 依赖GDAL_DATA环境变量,Debug 与 Release 下这个变量的值不一致,导致 Debug 版运行时找不到坐标文件。vcpkg 自带的数据目录通常会随安装包固定,但自编译版把 gdal 重编后,这个目录并没有自动拷贝到 osgEarth 安装包里。
解决:把 GDAL 的数据目录固定下来,加到系统环境变量:
setx GDAL_DATA "D:\vcpkg\installed\x64-windows\share\gdal"share\gdal是 vcpkg 安装时存放坐标系数据的地方。设置完成后重新打开终端再跑 Debug 程序,地形正常加载。这个坑很典型,后果是 Debug 与 Release 行为不一致,如果两台机器巡检时没注意到,会以为是自己编译的 Debug 配置有毛病。
5.3 字符集 Not Set:文件名带中文的加载失败与控制台乱码
现象:VS2022 默认生成的工程字符集是 Not Set,程序里用osgDB::readNodeFile("D:/数据/地形.tif")加载文件,Release 偶尔能跑,Debug 频繁报Cannot open file,控制台打印的地图名称乱码。
原因:CMake 生成的工程没有定义_UNICODE和_MBCS,程序按系统默认代码页处理多字节字符串;osgEarth 内部统一用 UTF-8 字符串,Windows 下 ANSI 与 UTF-8 混用时路径解析就会出问题。这跟 VS2022 的字符集设置有关系,但根源不在工程属性的字符集下拉框,而在文件名字符串的编码转换。
解决:不要改工程属性,改在代码里用 osgDB 的编码转换接口。路径经osgDB::convertStringFromUTF8转成 Windows 本地编码后再传给readNodeFile;反过来,从 earth 文件里读出的字符串统一走convertStringToUTF8,保证内部流转一致。中文路径的坑很隐蔽,编译期不报,运行期才翻车。给项目的建议是代码里路径一律用英文目录加英文文件名,省得与系统区域设置纠缠不清。
5.4 链接期依赖配置遗漏:系统库与第三方库被 CMake 漏掉
现象:编译 osgEarth 驱动时,链接器报错一堆unresolved external symbol,其中既有curl_*、GDALDataset::*,也有WSACleanup这类 Windows 系统函数。单独拷出来看 CMake 配置,发现 GDAL、CURL 虽然找到了,但链接命令里没有完整带上它们的传递依赖。
原因:osgEarth 的 CMake 脚本中,部分静态库的链入依赖不会自动传递,需要手工补。比如链接 curl 时还需要ws2_32.lib、wldap32.lib、crypt32.lib;链接 geos 时需要Delaunay相关库,但 CMake 配置里可能没把geos.lib的完整依赖链写上。这种问题很奇怪,不常见,但如果你用的 vcpkg 库恰好是静态编译的,撞上的概率会大很多。
解决:在 VS2022 的工程属性里,链接器 → 输入 → 附加依赖项手动补充ws2_32.lib;wldap32.lib;crypt32.lib;winmm.lib,同时检查 CMakeCache 里CURL_LIBRARY与GDAL_LIBRARY两个变量指向的实际.lib文件:
grep -i curl D:\build\osgearth-3.4.0-vs2022-x64\CMakeCache.txt如果发现 CMake 找到的 curl 库是某个不太相关的版本,比如系统里残留了一份 OpenSSL 的旧库,就用 cmake-gui 把CURL_LIBRARY清空,重新 Configure,让它自动定位到 vcpkg 的库里。链接问题大多是企业网络里装了多套环境导致的,治本的办法是配置阶段就把每一份.lib的实际路径过一遍。
6. 验收与日常使用:写一个最小 earth 文件把自编译成果跑起来
编译安装完成后,别急着往大工程里集成,先花十分钟做一个最小化验收,用实际效果确认 Debug 与 Release 两套库都能正常工作。先写一个最简 earth 文件:
<map name="MinMap" type="geocentric" version="2"> <model name="terrain" driver="gdal"> <url>D:/data/srtm.tif</url> </model> </map>把文件存到D:/data/test.earth,然后用刚编译的osgearth_viewer打开:
osgearth_viewer D:/data/test.earth如果弹出一个可以拖拽旋转的地球窗口,说明 osgEarth 的 GDAL 驱动、OSG 的插件加载、第三方库依赖这一整条链路是通的。
再跑一个 Debug 版的验收,把D:\libs\osg-3.6.5-x64\bin里的osgversiond.exe单独拿出来执行,你会在输出里看到带(Debug)字样的版本信息。这步可以确认 Debug 库确实被正确编译,而不是被 Release 版顶包。
日常开发中还建议把常用的 earth 文件目录加到 OSG 的搜索路径里,这样代码里可以只写文件名,不用每次拼完整路径:
setx OSG_FILE_PATH "D:/data"最后提醒一个新入职工程师常犯的习惯:每次发布前,多看一眼D:\libs\osgearth-3.4.0-x64\bin目录里的 DLL 时间戳,确认 Debug 与 Release 的库都是当天最新编译的,而不是混合了两天的产物。我现在每次自编译完都会把osgViewer和osgearth_version的输出贴到交接文档里作为验收凭据,这个习惯帮我避开了不少次同事误用旧库的尴尬。希望帮到你。
本文还有配套的精品资源,点击获取