简介:使用VS2019在x64平台编译生成的OpenSceneGraph 3.7整合包,集成osgearth-3.4、osgQt、sqlite3与GDAL 3.0.4,面向需要进行三维GIS、仿真或地理空间应用的开发者,免去逐组件下载、编译与配置的繁琐流程。压缩包共2000个文件,包含1122个hpp与878个h头文件,总大小约727.48MB,头文件覆盖OSG核心渲染、osgEarth地形、Qt交互、SQLite存储及GDAL读写等接口,可支撑二次开发与工程集成。已有123人浏览学习,该资源既可作为依赖库直接引用,也能通过目录结构理解各组件间的版本搭配。实际使用时,能有效避免因编译版本不一致导致的错误,大幅缩短构建三维地理信息应用的前期准备时间,适合需要快速搭建开发环境的开发者和研究人员。
1. 为什么非要在VS2019下自己编译这套三维GIS组合:官方包给不了的三个能力
在Windows上做三维GIS的人,迟早会面对一个尴尬:OpenSceneGraph官方那台预编译包要么版本停留在3.6,要么没带GDAL插件,更不要指望它给你编好osgEarth和osgQt。我自己被逼到VS2019下从源码编译这套组合——OpenSceneGraph 3.7、osgEarth 3.4、osgQt,外加sqlite3 release-1911与gdal-3-0-4-ma两个x64依赖,一次把地形加载、矢量缓存和Qt窗口嵌入全部打通。它能解决的,是那些"官网下载exe却跑不起来""版本不对哭都没地方哭"的落地问题。适合要在Qt里做三维GIS界面、又离不开GDAL栅格读写的从业者;新手照做能避开一堆编译坑,老手可以拿这套参数和链接顺序当参照。编译OSG本身不难,难的是把osgEarth、GDAL、sqlite3的版本卡在同一个时间点。
2. 依赖梳理与目录规划:GDAL 3.0.4、sqlite3 release-1911与x64工具链的版本对齐
2.1 依赖链与编译顺序
这套组合从名字上拆,是六个组件:VS2019的x64工具链、OpenSceneGraph 3.7、osgEarth 3.4、osgQt、sqlite3 release-1911、gdal-3-0-4-ma。我第一次弄的时候上来就编译osgEarth,CMake报一堆找不到OSG的错误,那时候才意识到顺序这事不能跳。
依赖关系是一条链:OSG是底座,osgEarth跑在OSG之上;osgEarth生成地形时要用GDAL读高程和影像,矢量数据缓存落在sqlite3上;osgQt则负责把三维窗口嵌进Qt界面。所以顺序必须是先编译OSG 3.7,再编译osgEarth 3.4,最后处理osgQt的集成。理由不复杂:osgEarth的CMake在配置阶段就要检测OSG的库路径和版本,OSG的install目录不对,后面所有模块都在那打转。很多人问能不能直接从osgEarth的github拉代码编译,理论上可以,实际CMake会因为找不到OpenThreads而直接退出。
这两个第三方依赖也不是随便选。GDAL 3.x把很多栅格函数签名改了,osgEarth 3.4是按GDAL 2.x/3.x的API混合写的,gdal-3-0-4-ma正好卡在它API预期附近;sqlite3 release-1911是源码发布版,osgEarth用它的C API做矢量要素缓存和空间索引,功能上完全覆盖需求。
2.2 目录规划与第三方包解压检查
我习惯把第三方库放在一个统一目录,这套组合依赖多,目录乱了后面CMAKE_PREFIX_PATH会找错库。
D:/3rdparty/ gdal-3-0-4-ma/ include/ lib/ bin/ sqlite3-release-1911/ include/ lib/ qt5-msvc2019_x64/ OSG-build/ osgEarth-build/这个布局的用意是:每个第三方包保持一个根目录,CMake的find_package通过前缀路径找到include和lib子目录,不用为每个变量手工指路。GDAL和sqlite3解压后一定要先看目录结构,有的压缩包把头文件直接放在根目录,没有include层级,这种就要自己在CMake里加GDAL_INCLUDE_DIR变量指过去。这里有一个我每次都提的检查项:用dumpbin /headers看一眼第三方库的机器类型,确认是x64。
| 组件 | 版本/标记 | 在组合中的角色 |
|---|---|---|
| Visual Studio 2019 | v16.x,x64工具链 | 编译器 |
| CMake | 3.15+ | 构建配置 |
| OpenSceneGraph | 3.7开发分支 | 三维渲染底座 |
| osgEarth | 3.4 | 地形/影像加载 |
| GDAL | gdal-3-0-4-ma(x64) | 栅格与矢量格式读写 |
| sqlite3 | release-1911 | 矢量与缓存存储 |
| Qt | Qt 5.15 MSVC x64 | 界面框架,osgQt依赖它 |
2.3 x64工具链检查与CMake生成器
编译前先确认你打开的是VS2019的x64 Native Tools Command Prompt,不是普通cmd。我见过太多人在cmd里执行cl然后问为什么找不到编译器。打开后先跑一条命令验证:
cl 2>&1 | findstr /i x64如果输出里能看到for x64,说明工具链正确。如果显示的是x86,你开错终端了。这个检查为什么重要?因为CMake的-A x64参数会强制目标平台,但前提是CMake能拿到x64的编译器;一旦VS2019没装C++的x64工具组件,CMake会静默回退到x86,后面所有库都会变成32位,等编译osgEarth时LNK1112就来了。
CMake生成器我用的是Visual Studio 16 2019。项目文件是.sln,好处是可以随时打开Visual Studio查看某几个target单独编译,不用整库重来。命令行配置时固定写成:
cmake .. -G "Visual Studio 16 2019" -A x64-A x64指定目标平台,这个参数必须和后面osgEarth、osgQt保持一致。我后面会反复强调版本一致性:OSG是x64、osgEarth是x64、Qt是x64,三个生成器的-A参数只要有一个落空,最后链接阶段准翻车。
3. 编译OpenSceneGraph 3.7核心:CMake选项、构建顺序与安装校验
3.1 CMake GUI里的关键选项
用CMake GUI打开OSG 3.7源码,第一次configure之前,先按顺序改这几个选项。首先是CMAKE_BUILD_TYPE,我用Release。Debug库调试信息全但体积大一倍,而且osgEarth的Release链接器参数配的是优化过的导入库,混着用后面会有符号匹配问题。CMAKE_INSTALL_PREFIX我设成D:/OSG-install,这个路径要记好,osgEarth的CMake全靠它找OSG。
然后是qt相关的开关。3.7分支里osgQt已经被拆成独立模块,CMake里有BUILD_OSG_QT和OSG_USE_QT两个入口。两者的区别要讲清楚:OSG_USE_QT是让OSG核心和已有工具链感知Qt的存在,BUILD_OSG_QT是决定要不要生成osgQt库和示例。只开前者不编osgQt,你后面拿不到osgQt.lib。所以两个都开,别省。
CMAKE_PREFIX_PATH要把Qt的MSVC x64目录指进去:
D:/3rdparty/qt5-msvc2019_x64这里有一个CMake的搜索逻辑:它会在这个路径下找lib/cmake/Qt5/Qt5Config.cmake。如果你的Qt是离线安装包装的,路径里有版本号目录,比如D:/Qt/Qt5.15.2/5.15.2/msvc2019_64,那前缀路径就要写到最后那层msvc2019_64,写浅了Qt5Config找不到。我试过一次把前缀直接写到Qt/5.15.2,configure阶段Qt相关选项全是灰色,浪费了二十分钟。
3.2 GDAL插件与第三方依赖的检测
OSG本身自带的gdal插件不是必须的,但建议编上。它的作用是让OSG直接用GDAL读GeoTIFF、IMAGINE等格式,避免转成osgb或ive再加载宿影。CMake配置时会走find_package(GDAL),把CMAKE_PREFIX_PATH指到D:/3rdparty/gdal-3-0-4-ma即可。如果检测失败,手动指定两个变量:
GDAL_INCLUDE_DIR -> D:/3rdparty/gdal-3-0-4-ma/include GDAL_LIBRARY -> D:/3rdparty/gdal-3-0-4-ma/lib/gdal_i.lib注意gdal_i.lib这个命名,它是GDAL的导入库,运行时对应的是gdal.dll,不是静态链接的gdal.lib。很多预编译GDAL包里同时放这两个文件,CMake经常能找到静态库导致链接方式变化——这里我的习惯是指向gdal_i.lib,运行期只依赖DLL,应用程序目录干净,替换GDAL版本也方便。
SQlite3在OSG编译阶段用不到,它是osgEarth的依赖。OSG只需要Qt和GDAL,其他第三方模块比如curl、freetype这个资源没用到,我就没开,减少编译时长。
3.3 命令行构建与安装
配置完之后,我一般不在CMake GUI里直接点Generate,而是回到命令行统一构建,这样可以把参数固化成一个脚本,后面重编时不用再翻GUI。构建命令是:
cmake --build . --config Release --parallel 8--parallel 8表示并行8个任务,这个值取决于你的CPU核数,不是越大越好。我之前用--parallel 16在8核机器上编,内存直接吃满,编译中途OOM杀进程。建议先看任务管理器,物理核数少于8就降成4。OSG全量编下来大约十五到二十分钟,取决于插件开得多不多,这个时长正常。构建过程中如果报了某个第三方库的头文件找不到,先看CMakeCache.txt里对应的_DIR变量,多半是路径指错了。
构建完再安装:
cmake --install . --config Release--install会把头文件、库、DLL、插件和示例数据拷贝到CMAKE_INSTALL_PREFIX指向的目录。这个目录就是后面osgEarth配置时的依赖来源。安装完成后检查一下:
dir D:/OSG-install/binbin目录下应该有一堆osgXXX.dll和otXXX.dll,还有一个关键文件osgPlugins-3.7目录,里面是模型和图像插件。如果这个插件目录不存在,说明你的插件构建被关了,后面osgviewer加载任何模型都会提示找不到插件。
3.4 安装校验
安装完先别急着配osgEarth,花两分钟验证OSG本身是好的。把bin目录加进PATH,然后执行:
osgversion正确输出是OpenSceneGraph Library 3.7.x。有个小概率情况是输出一个很奇怪的字符串,比如OpenSceneGraph Library 3.7.x (developer build)——不用慌,这只是说明构建时标记了开发版。真正要警惕的是版本号对不上,比如你源码是3.7但输出3.6,那说明CMake缓存里残留了旧配置,需要删掉整个build目录重来。
接着验证渲染管线:
osgviewer cow.osgcow.osg是OSG自带的牛模型,在安装目录的share/OpenSceneGraph/data下。如果窗口弹出来显示一只牛,OSG核心和OpenGL上下文都没问题。这里有一个日常玄学:窗口弹出来但黑屏,先查显卡驱动,再查是不是在远程桌面里跑的,远程桌面通常拿不到可用的GL context。如果你是在服务器上编译,这一步可以跳过,用osgversion的结果为准。
4. 编译osgEarth 3.4并把osgQt挂进去:GDAL插件链接与Qt模块集成
4.1 osgEarth的CMake配置
osgEarth 3.4的CMake配置是整套流程里最敏感的环节。源码根目录下执行:
cmake .. -G "Visual Studio 16 2019" -A x64 ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_INSTALL_PREFIX=D:/osgEarth-install ^ -DCMAKE_PREFIX_PATH="D:/OSG-install;D:/3rdparty/gdal-3-0-4-ma;D:/3rdparty/sqlite3-release-1911;D:/3rdparty/qt5-msvc2019_x64" ^ -DOSG_DIR=D:/OSG-install/lib/cmake/OpenThreads这些参数各有用处。CMAKE_PREFIX_PATH用分号分隔多个路径,CMake会依次在这些目录下搜索OSG、GDAL、SQLite3和Qt的配置文件。OSG_DIR我单独指到D:/OSG-install/lib/cmake/OpenThreads,因为osgEarth配置时先找OpenThreads再找osgDB,如果这个路径不明确,它有时会去系统盘里找一套旧版OSG,结果版本检测失败。这会让你怀疑人生,因为CMake报错信息很直接:Could NOT find OpenThreads,但你自己觉得明明装了。
4.2 GDAL与sqlite3的手工指定
如果configure输出里GDAL显示为NOTFOUND或者版本不对,用CMake GUI的搜索框直接查GDAL,然后手工指定:
GDAL_INCLUDE_DIR -> D:/3rdparty/gdal-3-0-4-ma/include GDAL_LIBRARY -> D:/3rdparty/gdal-3-0-4-ma/lib/gdal_i.libsqlite3同理,osgEarth的CMake用find_package(SQLite3),有些3.4小版本里模块名是FindSQLite3.cmake,大小写敏感。手动指定时用这两个变量:
SQLITE3_INCLUDE_DIR -> D:/3rdparty/sqlite3-release-1911/include SQLITE3_LIBRARY -> D:/3rdparty/sqlite3-release-1911/lib/sqlite3.lib这里有一个经常让人卡壳的点:sqlite3的lib文件是编出来的。如果你拿到的资源里没有现成的sqlite3.lib,只有源码和sqlite3.dll,那就要想办法补一个导入库。常见做法是用VS2019自带的lib.exe工具从DLL生成:
lib /def:sqlite3.def /out:sqlite3.lib /machine:x64前提是手上有sqlite3.def导出定义文件。如果没有def文件,用dumpbin /exports sqlite3.dll把导出的函数名拉出来,手工建def文件,sqlite3导出的符号就那么十来个,写起来不费劲。我曾经偷懒直接跳过lib,让CMake链sqlite3.dll,结果链接器报LNK1107,因为不是导入库格式,白折腾半小时。
4.3 osgQt模块的编译与Qt版本细节
osgQt在OSG 3.7里既可以随OSG一起编,也可以单独编译。如果你是按我上面的顺序已经编完OSG,但当时没开BUILD_OSG_QT,不用重新编整个OSG,回到OSG的build目录,单独构建osgQt这个target就行:
cmake --build . --config Release --target osgQt --parallel 4单独构建的好处是省时间,OSG全量重编一次要二十分钟,只编osgQt两三分钟就完事。编完后确认生成的是osgQt.lib和osgQt.dll。
Qt版本这里要重点提醒。osgQt是围绕QOpenGLWidget重写过的模块,它依赖Qt5的Widgets模块。你在CMake里指的前缀路径必须最终落到msvc2019_64这个目录,不是Qt的安装根目录。如果前缀指错,CMake会在lib/cmake/Qt5找不到配置,然后自行退化到系统里任何可疑的Qt版本,最典型的结果是编译报错Cannot open include file: 'QOpenGLWidget'。看到这个错误,第一反应别去查代码,直接查Qt5_DIR这个CMake变量。
4.4 构建与链接顺序
配置完成后,构建osgEarth:
cmake --build . --config Release --parallel 8osgEarth的源码量比OSG小,但模板展开多,编译时间一般在五到十分钟。构建完成后同样执行安装:
cmake --install . --config Release安装完成后,bin目录下会有osgEarth.dll、osgEarthQt.dll(如果你把Qt模块编进去了)以及一堆插件。检查插件目录里有没有osgdb_earth.dll、osgdb_gdal.dll这些,没有的话说明插件开关没开。
这里要讲一个链接顺序的细节:osgEarth的导入库是osgEarth.lib,它在编译时依赖osgDB、osgUtil、osgGA等OSG模块。你的工程如果直接链接osgEarth.lib,还需要把OSG的那串lib都带上。这个顺序不是随便排的,链接器按从左到右解析符号,被依赖的库要放右边。我见到的典型错误是把osgEarth.lib放在链接列表最后,然后一串LNK2019。正确的链接列表顺序是:
osgEarth.lib osgEarthQt.lib osgQt.lib osgDB.lib osgUtil.lib osgGA.lib osgViewer.lib osg.lib OpenThreads.lib5. 避坑指南:这个组合上我踩过的五个坑与排查路径
5.1 坑一:GDAL包名里的"ma"标记,决定了一堆DLL依赖
现象:osgEarth编译过了,但只要跑起来就弹"无法定位程序输入点"或"找不到gdal.dll",有时候甚至是osgEarth启动后加载地形崩溃。
原因:gdal-3-0-4-ma是第三方预编译的GDAL包,不同分发渠道的构建差异很大。有的包依赖内部插件目录,需要在环境变量里设置GDAL_DRIVER_PATH指向它的gdalplugins目录;有的包还依赖额外的libssl、libcurl等DLL。如果你的系统里恰好装了另一个版本的GDAL,DLL搜索顺序会把两个版本混在一起,接口对不上直接崩。
解决:把GDAL包的bin目录放到PATH的最前面,并且只保留这一个GDAL。运行osgEarth前用dumpbin /dependents看exe依赖:
dumpbin /dependents osgEarth.dll执行输出里如果出现两个路径下的gdal dll,就是DLL搜索顺序乱了。我处理的办法是在启动程序的脚本里用set PATH=D:/3rdparty/gdal-3-0-4-ma/bin;%PATH%,强制优先使用这一个版本,同时把系统里其他GDAL暂时移出PATH。
5.2 坑二:osgEarth的CMake找不到OpenThreads或版本判断失败
现象:configure时报Could NOT find OpenThreads,或者找到了但提示unexpected OSG version,CMake直接退出。
原因:osgEarth 3.4的CMake模块对OSG版本的判断依赖osgVersion.h里的OPENSCENEGRAPH_VERSION。而OSG 3.7这种开发分支,版本号写法在不同小版本之间变过,osgEarth的FindOpenSceneGraph.cmake解析出的版本可能是个空值或乱码,于是它认为OSG没装好。
解决:先确认D:/OSG-install/include/osg/Version.h里是有OPENSCENEGRAPH_VERSION这个宏的。如果宏是OPENSCENEGRAPH_MAJOR_VERSION这类,说明你下载的3.7快照太早,CMake模块还没有统一版本口径。最省事的临时做法是打开osgEarth的CMakeLists.txt,找到OSG版本检测这段:
set(OPENSCENEGRAPH_REQUIRED_VERSION 3.6)临时改成:
set(OPENSCENEGRAPH_REQUIRED_VERSION 3.7)这只是让configure通过,不影响最终生成的代码。这个方法治标不治本,但能把编译往前推进。
5.3 坑三:LNK1112,x86和x64的库混在一起
现象:编译osgEarth的某个target时报module machine type 'x64' conflicts with target machine type 'x86'。
原因:CMake缓存里残留了x86配置,或者CMAKE_PREFIX_PATH里混进了一个32位的Qt/GDAL。最常见的是Qt装了两个版本,CMake搜索时优先找到了32位的那个。
解决:不要在这里纠结,直接删掉整个build目录重新来。CMake的缓存一旦混入机器类型,很难通过改变量纠正,因为很多子模块已经按旧配置生成了中间文件。重新configure时,确认生成器的-A x64参数在OSG、osgEarth、osgQt三处一致,并且用dumpbin /headers检查每一个依赖库的机器类型。Qt的检查尤其重要,预编译Qt的目录名里虽然写着msvc2019_64,但实际库里夹带32位构建的情况我也遇过。
5.4 坑四:sqlite3源码包编出来的lib是空壳
现象:sqlite3.lib存在,但链接时一坨LNK2001,sqlite3_open等核心函数找不到。
原因:sqlite3的源码默认不导出任何符号,它的API导出是要通过编译宏显式指定的。直接对源码执行cl sqlite3.c只能产出无导出符号的库,链接器看着有lib文件,实际一个函数地址都拿不到。
解决:用这条命令重新编译sqlite3的动态库:
cl sqlite3.c -c -DSQLITE_API=__declspec(dllexport) -DSQLITE_ENABLE_RTREESQLITE_API=__declspec(dllexport)让编译器把sqlite3的公开函数导出,生成sqlite3.obj后还要用link命令组装dll和lib:
link /dll sqlite3.obj /out:sqlite3.dll /out:sqlite3.lib如果你不想折腾这些细节,直接下载官方编译好的sqlite dll包,解压到sqlite3-release-1911目录里,省事得多。从那以后我每次用sqlite3都先确认lib里有没有符号,不再默认源码包是好的。
5.5 坑五:osgQt编译报错找不到QOpenGLWidget,或运行期窗口黑屏
现象:编译osgQt时报cannot open include file: QOpenGLWidget;或者编译过了,程序运行后窗口能弹出来但内容全黑。
原因:osgQt在3.7分支里已经迁移到QOpenGLWidget,但部分早期快照的代码还停留在QGLWidget。如果你的Qt 5.15里没有QGLWidget头文件,就会报找不到;如果编译时把两套API混用了,运行期GL上下文无法正确绑定,窗口黑屏。
解决:确认CMake变量Qt5_DIR指向的是Qt5.15的lib/cmake/Qt5目录,并且CMAKE_PREFIX_PATH里没有其他Qt版本干扰。如果源码里确实还引用QGLWidget,手动改三个文件:GraphicsWindowQt.cpp、QWidgetWindowProxy.cpp、还有osgQt示例里的QtWindget.cpp,把QGLWidget替换为QOpenGLWidget,GLboolean等相关类型按Qt5的要求调整。这是个体力活,但改完能一劳永逸。
6. 跑通验证与一键部署:自检清单和那个救命的bat脚本
6.1 三条命令的自检清单
编译安装全部完成后,我习惯用一个固定顺序来验证,每一条命令都有它的作用。第一条:
osgversion确认OSG是3.7;第二条:
osgviewer D:/OSG-install/share/OpenSceneGraph/data/cow.osg确认渲染管线正常,能弹出带牛模型的窗口;第三条:
osgearth_viewer --help确认osgEarth的exe已经装好且能正常加载它的插件库。这三句都过了,你再往上跑自己的业务代码,基本不会因为编译环境本身的问题翻车。
6.2 环境变量脚本
运行期最烦的就是DLL找不到。我把环境变量固化成一个bat脚本放在项目根目录,每次开新终端先跑一遍:
@echo off set OSG_FILE_PATH=D:/OSG-install/share/OpenSceneGraph/data set PATH=D:/OSG-install/bin;D:/osgEarth-install/bin;D:/3rdparty/gdal-3-0-4-ma/bin;D:/3rdparty/sqlite3-release-1911/bin;%PATH% echo 三维GIS运行环境已配置OSG_FILE_PATH是给OSG的示例模型定位用的,PATH里把OSG、osgEarth、GDAL、sqlite3的bin目录依次放前面,确保运行时优先加载这套组合的DLL。这条脚本治好了我大半的DLL地狱,从那以后我每次在这个环境里编译完新的组合,都强制走一遍三条自检命令加这个脚本,确认版本号和依赖不串,再继续写业务。希望这套流程能帮你也少走几趟弯路。
本文还有配套的精品资源,点击获取