ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OSG3.6.5+OSGEarth+VS2019编译环境搭建与避坑指南

OSG3.6.5+OSGEarth+VS2019编译环境搭建与避坑指南

简介:基于 Visual Studio 2019 预编译的 64 位第三方依赖库包,面向需要集成 OSG 3.6.5 与 OSGEarth 2.10 的开发者,省去自行编译 freetype、curl、geos、gdal 等依赖的繁琐流程,也解决依赖版本不匹配导致渲染起不来的问题。包内目录按功能归类,头文件与库文件一一对应,便于在 CMake 中直接指定依赖路径。压缩包共约 2000 个文件,体积 137.76MB,内容以 1351 个 h 头文件、56 个 lib 库文件、32 个 cmake 配置和 14 个 dll 为主体;同时包含 28 个 inc 包含文件、22 个 c 源文件、17 个 inl 内联文件、14 个 proto 协议文件与 14 个 hpp 头文件,并附完整时区数据库名称文件,适合 GIS 地球展示、地形加载类项目直接引用。目前已有 626 人下载学习,适合熟悉 CMake 建工程、希望在 VS2019 下快速跑通 OSGEarth 渲染管线的中高级开发者。拿到后可直接配置头文件与库路径,复用已编译好的第三方库,把精力集中在场景构建与 Earth 地形加载上,无需再纠结底层依赖。

1. 装 OSG 环境的第一道门槛:3rdParty 三方库选型

某开发者在机房换了一台新机器,要在 VS2019 上把 OSG3.6.5 + OSGEarth 的渲染链重搭一遍,结果卡了整整三天。第一天 OSG 的 configure 全绿,编译时 zlib、curl、freetype 轮番报“找不到”;第二天编译过了,OSGEarth 又找不到 OSG 的 CMake 配置;第三天干脆用老项目的 3rdParty 顶上去,运行时直接崩溃。这三天的血泪经验都指向同一件事:OSG3.6.5 和 OSGEarth 的编译,难点从来不在 OSG 源码本身,而在那套预编译好的 3rdParty 三方库。它管理着几十个底层依赖,你选 VS2019 还是 VS2015、选 v142 还是 v141,都在这一层决定。很多老项目至今锁定 OSG 3.6.5,并与 OSGEarth 组合成固定的编译流程;这篇笔记就是把这套流程拆开,供正卡在 OSG3.6.5 + OSGEarth + VS2019 环境搭建上的开发者直接照着走。

2. 版本体检:OSG3.6.5 到底该配哪一套 VS2019 预编译库

2.1 3rdParty 里到底装了什么

解压这套 zip 后,最直观的感受是“把 OSG 项目里最难凑的那部分外包了”。目录中会看到 include、lib、bin 三个标准目录,里面按功能分成几组:zlib 管压缩,libpng、libjpeg、libtiff 管纹理格式,freetype 管字体,curl 管网络数据抓取,gdal、geos 管地理数据解析,sqlite3 管瓦片缓存,glut 负责窗口与输入回调。别小看这些依赖,OSG 加载一张 jpg 纹理、OSGEarth 读一个 shp 数据文件,背后都是它们在干活。

自己编译这套依赖是另一番光景。以 gdal 为例,它的构建脚本在不同版本之间差异很大,还会牵扯到 proj 和 netcdf,在 Windows 上折腾一轮,顺利的话也要两三天,不顺利就掉进“编译 gdal 前要先装 gdal 的依赖”这种循环里。预编译包的意义就在于跳过这一轮:依赖版本已经互相验证过,编译器也统一了,你只需要把它当成黑匣子直接用。

2.2 为什么 VS2019 必须配 v142 工具集

这里有个新手容易忽略的概念:MSVC 的二进制兼容是按工具集版本划分的。VS2015 是 v140,VS2017 是 v141,VS2019 是 v142,三个工具集编译出来的 C++ 代码,在面对模板、异常、标准库实现时并不总是能互相链接。OSG 和 OSGEarth 都是重度使用模板和标准库的 C++ 项目,一旦 3rdParty 是 v141 编的,而 OSG 是 v142 编的,链接阶段可能不出错,运行期却会崩得莫名其妙。

我一般会把口径收死:OSG3.6.5 的源码、OSGEarth 的源码、3rdParty 预编译库、最终应用,四者的工具集必须保持一致。这套 3rdParty 就是按 VS2019 的 v142 出品的,所以编译 OSG 时生成器必须选 Visual Studio 16 2019,平台选 x64。手上如果还有老项目留下的 v141 预编译库,别混用,省下的时间会在调试链接错误时加倍还回去。

2.3 装机前的环境体检清单

动手之前,先把工具链过一遍。我用下面的命令确认 CMake 版本和编译器可用性:

cmake --version cl

cl 命令要能看到 Microsoft C/C++ Optimizing Compiler Version 19.2x 之类的输出,说明 VS2019 的 C++ 桌面开发负载装好了。不止是编译器,Windows 10 SDK 也得勾上,OSG 的窗口系统编译会引用它。需要注意的是,只装 Build Tools 而没有完整 IDE 也能编译绝大多数工程,但排查 cmake 问题时我还是建议装完整负载,省得后面找原因找到环境差异上。

目录规划也顺手定好,这一步能规避一半的路径类报错:

目录用途
D:/OSG/srcOSG 3.6.5 源码解压目录
D:/OSG/3rdparty预编译三方库解压目录
D:/OSG/buildOSG 构建目录
D:/OSG/installOSG 安装目录

四个目录全部用英文、无空格、无中文。CMake 生成的工程里有大量带引号和反斜杠的路径变量,遇到中文或空格时,很多脚本逻辑会断在你根本想不到的位置,这类问题排查起来特别费时,不如一开始就从路径上避掉。

2.4 解压后先做一次产物校验

zip 解压命令建议用命令行,避免右键解压时把路径搞乱。假设下载的 zip 放在 D:/downloads 下:

powershell Expand-Archive -Path D:\downloads\3rdParty.zip -DestinationPath D:\OSG\3rdparty

解压后看看目标目录的最外层结构,我踩过一个坑:有人把 zip 解压成了 D:/OSG/3rdparty/3rdParty,cmake 指到外层,结果 include 目录不存在,配置出来的工程全是空链接。所以解压后先确认 include 目录下确实有 zlib.h 这类头文件,lib 目录下有 zlib.lib,bin 目录下有对应 dll。验证命令很简单:

dir D:\OSG\3rdparty\include\zlib.h dir D:\OSG\3rdparty\lib\zlib.lib

这两条过了,产物才算真正可用。另外注意,lib 目录里同一个库会有两个版本,文件名带 d 后缀的是 Debug 专用,OSG 的 cmake 会按当前构建配置自动挑选,不需要手动指定。

3. 编译 OSG3.6.5:cmake 配置与出包流程

3.1 生成 OSG 工程前必须理清的两组变量

cmake-gui 打开后,source 目录指到 D:/OSG/src,build 目录指到 D:/OSG/build,首次点 Configure 时选择 Visual Studio 16 2019 与 x64 平台。这里要留意:平台选错,x86 的生成器也能跑完 configure,但后面链接第三方库时,位数会对不上,报错会非常诡异。

Configure 完成后,把搜索框切到 3rdparty,重点看两个变量:3RDPARTY_DIR 和 ACTUAL_3RDPARTY_DIR。OSG 的老式脚本逻辑里,3RDPARTY_DIR 原本是留给“第三方库源码包”用的,而我们手里是预编译产物,所以需要把两个变量都指到 D:/OSG/3rdparty,让它跳过源码构建、直接认这个现成目录。很多人在这一步只改了 3RDPARTY_DIR,第二轮 configure 依旧提示 ZLIB not found,就是这个原因。

改完再点一次 Configure,观察输出里第三方库的检测结果。如果出现 ZLIB FOUND、CURL FOUND 这类信息,说明变量生效了。随后把 CMAKE_INSTALL_PREFIX 改成 D:/OSG/install,顺手把 BUILD_OSG_EXAMPLES 打开;示例工程在验证阶段会用到,关掉编译能省十分钟,但后续想跑 cow.osg 这类演示时还得重编,不划算。

3.2 三组开关的取舍逻辑

说下其余几个高频开关:

BUILD_OSG_EXAMPLES,建议 ON。osgviewer、osgversion 这些工具在示例目标里,验证环境离不开它们;如果嫌编译量大,可以在最终构建时用命令行只编指定目标,不用重新 configure。

OSG_WINDOWING_SYSTEM 保持 Win32。OSG 在 Windows 上还有 WindowsGL 和 SDL 等备选项,但没有特殊需求不要动它,切换窗口系统会影响事件循环和鼠标交互的实现方式。

OSG_USE_QT 默认是 OFF,保持 OFF。开这个开关的前提是机器上已经装了 Qt5,并且 CMAKE_PREFIX_PATH 里能搜索到 Qt 的 cmake 配置;没有 Qt 却开了它,configure 会一直卡在 Qt5 相关组件的查找上。这套 3rdParty 里没有打包 Qt,所以这一步不做任何特殊处理。

这组开关的原则只有一句:能用默认就用默认。OSG 的 cmake 脚本经历过多轮迭代,默认值基本就是维护者验证过的配置,手痒改它,反倒给自己制造变量。

3.3 编译与安装

Generate 生成解决方案后,先编 Release。我习惯用命令行而非在 VS 里点按钮,编译进度可回看、报错可重定向,后续排障时也方便留存日志:

cmake --build D:\OSG\build --config Release

全量编译 OSG 3.6.5 在普通配置的机器上大约要 30 到 50 分钟,主要是 osgPlugins 和示例工程多。等 Release 完成后,再补一轮 Debug:

cmake --build D:\OSG\build --config Debug

Debug 也要编一遍的原因在后面调 OSGEarth 时会体现:如果只编了 Release,Debug 项目的链接阶段会找不到带 d 后缀的 OSG 库,届时要么回头补编,要么临时改配置,两头都是事。两条命令都跑完后,执行安装目标:

cmake --build D:\OSG\build --config Release --target INSTALL cmake --build D:\OSG\build --config Debug --target INSTALL

安装产物会落到 D:/OSG/install。此时检查 D:/OSG/install/bin/ 下有没有 osgversion.exe,D:/OSG/install/bin/osgPlugins-3.6.5/ 下有没有 osgdb_osgb.dll 之类的插件文件。插件目录是整个渲染链最容易缺失的一环,OSGEarth 运行时加载数据,最终都要通过这里的 osgdb 插件转发。

3.4 环境变量:OSG 运行为什么要加这三处

编译成功后先别急着跑 demo,环境变量只配两处,少了必翻车:

set PATH=D:\OSG\install\bin;D:\OSG\install\bin\osgPlugins-3.6.5;%PATH% set OSG_FILE_PATH=D:\OSG\data

PATH 里加上 install/bin 是为了让 exe 能加载 OSG 的 dll,加上 osgPlugins 子目录是为了让 osgDB 能扫到插件。OSG_FILE_PATH 则指向模型数据目录,osgviewer 不带参数直接运行时会从这里找默认模型。data 目录不在 3rdParty 包里,通常从旧项目或示例资源里拷贝一份,路径指到那份数据的根目录即可。

如果不加 osgPlugins 路径,表现会很有意思:exe 能启动,窗口也能弹出来,但模型和纹理加载全部失败,控制台报的还都是 Warning: could not find plugin to read objects from file。这类报错看起来像数据问题,实际是插件搜索路径的问题,把它排在排查列表的前三名。

4. 编译 OSGEarth:让 CMake 准确找到 OSG 的完整方法

4.1 osgEarth 是如何发现 OSG 的

osgEarth 的 cmake 脚本通过 find_package(OpenSceneGraph REQUIRED) 来找 OSG,这个命令会去搜索含 OpenSceneGraph 配置文件的目录。OSG 在安装阶段已经把 OpenSceneGraphConfig.cmake 写进了 D:/OSG/install 的 lib/cmake 附近,只要你的 cmake 搜索路径覆盖到那里,OSGEarth 就能拿到 OSG 的头文件目录、库文件路径和版本号。搜索路径的设置入口就是 CMAKE_PREFIX_PATH。

如果 configure osgEarth 时这个变量没设,最常见的后果是 OSG not found,或者找到了系统里残留的另一个 OSG 版本。机器上装过多个 OSG 的情况下,这种错乱很隐蔽,版本新旧混着,出的错千奇百怪。我的做法是给 osgEarth 单独开一个干净构建目录,并在配置命令里把 CMAKE_PREFIX_PATH 显式写死。

4.2 一次成功的 osgEarth 配置长什么样

假设 OSGEarth 源码解压在 D:/OSGEarth/src,配置命令如下:

cmake -S D:\OSGEarth\src -B D:\OSGEarth\build -G "Visual Studio 16 2019" -A x64 -DCMAKE_PREFIX_PATH=D:/OSG/install

这里有一个细节:CMAKE_PREFIX_PATH 是一个列表,多个路径用分号分隔。如果一会儿还要给 Qt 留位置,可以写成 D:/OSG/install;D:/Qt/5.15.2/msvc2019_64 的形式,但前提是确实装了 Qt;没装就只写 OSG 的安装前缀。

生成器照样是 VS2019 + x64,与 OSG 保持一致。配置输出里找 OpenSceneGraph 关键字,确认找到的版本是 3.6.5;还可以顺带看 GDAL、GEOS、CURL 的支持状态,这三个功能依赖 3rdParty 里的地理库和网络库,正常是打开的,如果显示关闭,回头检查 OSG 安装时是否把这些库的开关也带过去了。

4.3 别把 3rdParty 指给 osgEarth

有个常见误操作:编译 osgEarth 时,把 D:/OSG/3rdparty 也填进 CMAKE_PREFIX_PATH。理由是“osgEarth 也要用第三方库”。其实 osgEarth 并不直接链接 zlib 或 libpng,它对外部依赖的获取全部通过 OSG 的导出目标完成,OSG 编译时已经把需要的头文件目录和库目录固化在自己的配置里了。再指一次 3rdparty,不仅重复,还可能引入与 OSG 导出信息相矛盾的查找结果,让链接阶段出现两套同名库。

这条记下来,能省不少排查时间。OSGEarth 的构建系统设计得很直接:你先装好 OSG,它跟着 OSG 走;OSG 找不到的依赖,osgEarth 通常也不需要。

4.4 运行时 dll 的依赖顺序

编译成功后,跑 osgearth_viewer 之前,PATH 需要同时包含 OSG 和 OSGEarth 两边的输出目录:

set PATH=D:\OSG\install\bin;D:\OSGEarth\build\lib\Release;%PATH% set PATH=D:\OSG\install\bin\osgPlugins-3.6.5;%PATH%

注意顺序:OSG 的 bin 放在最前。Windows 加载 dll 时按 PATH 顺序搜索,如果机器上还残留旧版本 OSG 的 bin,loader 会先命中旧 dll,轻则功能异常,重则启动即崩。把准确的 OSG 目录顶到最前,是最直接的后悔药。

osgEarth 的 dll 生产在 build/lib/Release 或 Debug 下,osgearth_viewer.exe 则在 build/bin/Release 下。如果运行时提示找不到 osgEarth.dll,多半是这两条路径没加到 PATH 里,而不是程序本身有问题。

5. 避坑清单:OSG + OSGEarth 编译期五个高频翻车点

5.1 3rdParty 路径填了,zlib 还是找不着

现象:cmake-gui 里把 3RDPARTY_DIR 填成了 D:/OSG/3rdparty/x64,configure 后依旧输出 Could NOT find ZLIB。

原因:预编译包解压后,最外层是 include/lib/bin 三件套,x64 只是其中一层组织目录,不一定包含完整的头文件根。指向到内层之后,cmake 找不到 include/zlib.h,自然判定没有第三方库;另外第一次 configure 失败会在缓存里留下坏状态,第二次即便路径改对,也可能继续沿用旧结果。

解决:回到目录根,确认 include 目录能直接看到 zlib.h,然后把 3RDPARTY_DIR 和 ACTUAL_3RDPARTY_DIR 都指到这一层。清掉 build 目录重跑 configure,不要相信缓存:

rmdir /s D:\OSG\build

这条经验很关键:OSG 的 cmake 脚本对 3rdParty 的探测结果会缓存,路径变了但缓存不刷新,是这类“明明改对了还报错”的头号原因。

5.2 启动即崩 0xc000007b 或 vcruntime140.dll 加载失败

现象:osgviewer 双击后弹“应用程序无法正常启动 0xc000007b”,或者直接提示找不到 vcruntime140.dll。

原因:0xc000007b 常见于 x64 程序试图加载 x86 依赖库,或者是加载链里混入了不同工具集版本编出的 dll。vcruntime140.dll 缺失则往往是 PATH 里混进了旧版 VS 的运行库目录,或 3rdParty 本身是 v141 的产物。两种情况本质都是“依赖链不统一”。

解决:逐项确认生成器平台是 x64、3rdParty 是 v142、OSG 是 v142、应用也是 v142。确认无误后,把系统里其他 VS 版本的 bin 目录从 PATH 中剔除。最简单的探路方式是把编译出的 exe 放到一个新开的干净 cmd 窗口里跑,PATH 里只有系统和当前编译链,隔离外部变量。我一般用 where osgversion 看看当前命中的 osg 来自哪里,如果指向的不是 D:/OSG/install/bin,说明 PATH 顺序有问题,调整后重试。

5.3 osgviewer 窗口能弹,但场景全黑

现象:窗口出来了,没有模型,也没有网格,控制台一行行刷 Warning: could not find plugin ...。

原因:OSG 渲染并没问题,问题在数据与插件。一是 OSG_FILE_PATH 没指对,默认数据加载不到;二是 osgPlugins-3.6.5 没进 PATH,osgDB 找不到读模型的插件。这两个原因在报错文本上几乎一样,都是 could not find plugin。

解决:先验证数据路径,再看插件目录。检查命令:

echo %OSG_FILE_PATH% dir D:\OSG\install\bin\osgPlugins-3.6.5\osgdb_jpg.dll

插件文件存在就把插件目录加到 PATH 最前,数据目录不存在就换一个正确的 OSG_FILE_PATH。这里插一句玄学:有时候 dll 都在,但是复制的 osgPlugins 与 OSG dll 版本不配套,照样黑屏;判断标准是 osgPlugins 子目录版本号与安装目录里的 OSG dll 版本一致。

5.4 osgEarth 编译报 C1083 找不到 OpenThreads/Thread

现象:编译 osgEarth 时,fatal error C1083: Cannot open include file: 'OpenThreads/Thread'。

原因:OSG 的安装没做完整,或 CMAKE_PREFIX_PATH 指向的目录里缺少 OpenThreads 头文件。更常见的是 CMAKE_PREFIX_PATH 只写了 D:/OSG/src,而 src 里并没有 OSG 的安装产物;cmake 找到了源码目录里的空结构,误以为定位成功,头文件却无处可寻。

解决:确保 CMAKE_PREFIX_PATH 写的是 D:/OSG/install 而不是 D:/OSG/src。同时确认刚才的 INSTALL 目标确实执行过,头文件在 D:/OSG/install/include/OpenThreads 下。修改变量后要删掉 osgEarth 的 build 缓存再 configure,否则 find 结果会残留:

rmdir /s D:\OSGEarth\build

配置完成后,在 Visual Studio 里检查 osgEarth 工程的 VC++ 包含目录,能看到 install/include 才说明路径生效。

5.5 Release 和 Debug 混链,报 LNK2038 或迭代器级别冲突

现象:链接 osgEarth 时报 LNK2038 mismatch detected for '_ITERATOR_DEBUG_LEVEL',或一堆 std:: 相关重定义。

原因:OSG 的 Debug 库文件名带 d 后缀,而 osgEarth 项目配置没跟上。最常见的是 OSG 只编了 Release,却拿 Debug 配置去编 osgEarth;或反过来,3rdParty 里 Debug 库缺失,cmake 找不到带 d 的依赖,被迫用 Release 库顶替。

解决:规则只有一条,Debug 配 Debug,Release 配 Release。编译前检查 D:/OSG/install/lib 下同库是否有带 d 后缀文件,比如 osgDBd.lib;没有就回头补跑 Debug 的 INSTALL。osgEarth 的 Debug 构建需要 OSG Debug 库完整到位,这点无法偷懒。链接错误往往只出现在换配置之后,所以我会在第一次构建时就把两侧都编齐,省得日后翻车。

6. 装完怎么验证:三连命令跑通整条渲染链

装完之后最怕的是“看起来全绿,实际一个都跑不起来”。我给自己的硬性要求是执行三连验证,三次全过才认为环境搭建完成。

第一步,版本命令:

osgversion osgearth_version

osgversion 输出 3.6.5,osgearth_version 输出对应版本号,这一步确认两个库都安装了正确版本。如果版本对不上,立即回头检查 PATH 顺序,大概率是命中了旧目录。

第二步,渲染验证。用一张本地图片,比如 D:/temp/test.jpg:

osgviewer D:\temp\test.jpg

窗口弹出并显示图片纹理,说明 OSG 渲染管线和 osgdb 图像插件都是完整的。这一步比直接跑模型更可靠,因为它不依赖额外的数据包,只验证核心链路。

第三步,地球加载验证:

osgearth_viewer D:\OSGEarth\examples\xxx.earth

如果你有现成的 earth 文件,直接用它。osgEarth 源码 examples 目录里的示例 earth 文件一般不需要外部网络数据,能弹出一个可拖拽旋转的地球模型,说明从 osgearth 到 OSG 再到第三方库的整条链路是通的。此时画面里地形、瓦片、图层调度全部在工作,黑匣子才算是真的打开了。

这套三连走完,才能说 OSG3.6.5 + OSGEarth 在 VS2019 上的环境装好了。从那以后我每次装完 OSG 环境,都强制自己把 osgversion、osgearth_version、osgviewer 三连过一遍才算数,这一套流程帮我拦住过至少三次“假装装好”的翻车现场。希望帮到你。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进