十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OSG/OSGEarth 3rdParty三方库配置全攻略:从依赖解析到编译避坑

OSG/OSGEarth 3rdParty三方库配置全攻略:从依赖解析到编译避坑 简介一套适用于Visual Studio 2019环境的OSG3.6.5与OSGEarth2.10预编译64位三方依赖库包面向需要编译这两款图形引擎的C开发者解决第三方库获取难、版本不匹配等常见问题。压缩包共2000个文件约137.76MB以1351个h头文件为主体搭配56个lib导入库、32个cmake配置脚本以及c/inl/hpp等源文件另有少量dll动态库供运行时调用头文件、库文件与配置脚本分类存放便于在VS2019工程中直接配置包含目录和库目录。依赖范围覆盖OSG与OSGEarth编译链接所需的常用组件省去手动下载、编译和维护第三方库的繁琐步骤。资源还包含完整时区数据库文件适合实现全球范围的时间区域渲染与地理信息可视化场景。离线环境下可直接解压使用避免网络受限时无法拉取依赖。目前已有619人学习下载适合正在搭建或升级OSG/OSGEarth开发环境的中高级图形开发者可有效缩短环境配置周期让开发精力更集中在三维功能与场景的实现上。 开始写之前先交代一下背景这几天后台好多人在问同一件事——拿到一份“OSG3.6.5和OSGEarth预编译好的3rdParty.zip三方库”之后到底怎么配置才能顺利编译出项目跑通一个最简单的demo。问的人多了我决定把整个流程和自己踩过的坑一次性整理出来顺便把最近搜得比较多的“osgearth如何计算点是否在featurenode内”也一起捋一遍这篇尽量把从零到能跑的通路讲清楚少走几天弯路。1. 3rdParty.zip里到底打包了什么一份依赖清单也是一张避坑地图1.1 为什么OSG/OSGEarth绕不开这些三方库OpenSceneGraph本身是一个纯C的3D渲染引擎负责场景图管理、渲染状态、节点遍历、动画更新这一整套东西。但它并不打算自己去实现“读图片、连网络、解压数据、解析地理坐标”这些琐碎又繁重的基础能力而是采用插件机制把外部库接进来。比如你加载一张jpg贴图引擎会去找osgdb_jpeg.dll而这个插件背后就是libjpeg你要加载高程tif背后就是GDAL你要从网络加载瓦片背后就是libcurl。OSGEarth是在OSG之上做地形和地理数据渲染的库它把OSG插件的这场“接力赛”又拉高了一档地形数据、矢量要素、标注、影像金字塔全都要跟GDAL、GEOS、CURL、Freetype这些底层库打交道。所以编译OSG的时候没有三方库编译能过但很多插件是空的编译OSGEarth的时候没有三方库CMake直接列出十几个红叉根本走不下去。这就是3rdParty.zip存在的意义它们是Windows下把所有依赖预先编译好打包成一份“开箱即用”的库集合。用户拿到后只需要在CMake里给它指个路径就能让头文件、lib、dll全部对上号不需要自己动手编译十来个第三方库。1.2 核心依赖逐个拆解我见过的3rdParty.zip一般是include、lib、bin三件套的目录结构不同压缩包的名字略有差别但内容基本围绕下面这张表展开。三方库作用在OSG/OSGEarth中被谁使用zlib数据压缩解压压缩纹理、OSG的slave压缩、部分模型格式libpng / libjpeg / libtiff常用图像格式解码贴图加载插件 osgdb_png/jpeg/tiffjasper / openexrJPEG2000、HDR高动态图像高质量贴图、雷达影像等freetypeTrueType字体渲染文字标注、屏幕文字、片尾字幕libcurlHTTP/FTP网络传输加载在线瓦片服务、WMS、TMSlibxml2XML解析读取OSGEarth的earth文件、样式表gdal栅格和矢量地理数据抽象地形高程、影像、矢量要素的读写geos空间几何拓扑算法OSGEarth矢量空间分析与几何操作sqlite3 / spatialite嵌入式数据库TMS/MBTiles本地瓦片库、矢量存储glut/freeglutOpenGL工具库部分官方示例窗口程序其中GDAL和GEOS是所有依赖里最“重”的两个。GDAL自己要编依赖GEOS又是一套C库手动编译时往往都要单独折腾。你要是用的3rdParty.zip里有它们恭喜最难啃的骨头已经有人帮你啃完了。1.3 版本与平台匹配解压前先对着检查表看一眼拿到zip第一件事不是解压是看它的版本和你的工具链是不是同一个“世界线”。OSG 3.6.5和OSGEarth的版本匹配比较常规常见的组合是OSG 3.6.5搭配osgEarth 2.10.2或2.9。真正容易出问题的是VS版本和架构。第三方库的lib和dll内部都绑定了编译时用的CRTC运行时库。用VS2015编出来的静态lib拿到VS2019的项目里链接十有八九报LNK2038: mismatch detected for RuntimeLibrary。64位和32位更不用说库目录直接对不上。所以解压前一定确认三件事VS版本VS2015vc14、VS2017vc15、VS2019vc16对应不同的预编译包别混用。架构x64还是Win32检查包内lib目录下是x64子目录还是一个扁平的lib要看清楚。Debug/Release好的3rdParty包会在lib文件上区分调试版和发布版比如zlibd.lib是debugzlib.lib是release。如果你的包只有一个版本编译时就必须严格用对应配置。建议在解压根目录先建一个README.txt把上面三项信息写进去免得过两个月自己都忘了这份包是干什么用的。2. 拿到预编译3rdParty.zip后从解压到出Demo的完整操作流2.1 解压、目录结构与PATH环境变量的安排假设下载到的包是3rdParty-VS2017-x64.zip我的习惯是解压到D:/3rdParty这样没有空格和中文的路径下避免一些老牌库的预处理器被路径里的空格搞得精神错乱。解压后目录大致是这个样子D:/3rdParty/ include/ zlib.h gdal/ curl/ ... lib/ debug/ release/ bin/ debug/ release/接下来处理环境变量。OSG运行时主要靠OSG_ROOT定位主程序目录PATH里的dll目录则决定了能不能快速加载三方库。如果你把OSG和OSGEarth都安装到D:/OSG给系统变量或用户变量追加下面几项OSG_ROOT D:/OSG PATH D:/OSG/bin;D:/3rdParty/bin/release注意Windows系统环境变量修改后需要重新打开命令行或重启VS才能生效。这一步很多新手会忽略结果运行示例程序报“找不到DLL”先把环境变量刷新一遍再怀疑其他问题。2.2 CMake里最关键的3个配置区域用CMake-gui配置OSG时我的做法是先把源码目录和构建目录填好点Configure一次让所有缓存变量暴露出来然后再重点看下面三个区域。第一个是三方库路径。最直接的方式是把ACTIVE_3RD_PARTY_DIR指向D:/3rdParty。有些版本的3rdParty包还需要额外设置CMAKE_PREFIX_PATH填D:/3rdParty也能让CMake的find_package和find_library在搜索时自动找到对应目录里的include和lib。第二个是插件的开关。OSG的CMake里有大量OSG_USE_XXX、BUILD_OSG_PLUGINS_BY_DEFAULT这类选项。如果你用的是预编译3rdParty包通常所有依赖都能找到直接把默认值留着就行。但如果某些选项显示NOT-FOUND先别急着“三连关”看一下是不是路径没指对。关插件虽然省时间但牺牲的是功能。第三个是安装路径。OSG和OSGEarth都需要执行INSTALL步骤把头文件、库、dll统一安装到指定目录所以我会先改CMAKE_INSTALL_PREFIX设置成D:/OSG。这样后续OSGEarth的CMake找OSG时只指这一个目录就够了。配置完成后点Generate生成VS工程文件前最后确认一次构建配置和生成器平台是x64还是Win32。之前见过有人CMake选的是Win32三方库是x64编译到一半冒出几百个无法解析的外部符号怎么查都是库没对上。2.3 编译OSG和OSGEarth的顺序与验证顺序是严格的先OSG再OSGEarth。在VS里打开生成的OpenSceneGraph.sln把配置从Debug或Release二选一。我推荐先用Release跑通全流程因为Debug版的三方库在预编译包里有时候不齐全而Release几乎永远是齐的。右键ALL_BUILD生成然后右键INSTALL生成。OSG编译大约需要10到20分钟取决于机器性能。编完后验证一下osgversion命令行输出3.6.5然后运行示例osgviewer cow.osg能看到奶牛模型旋转起来说明OSG基本OK。接着用CMake配置osgEarth源码。构建目录指向需要写可写的目录配置时指定OSG的安装前缀D:/OSG通常会自动找到OSG的头文件与库。同样点击Configure看到所有依赖项都变白没有红色NOT-FOUND再Generate、ALL_BUILD、INSTALL。osgEarth编完个人建议去examples下找osgearth_viewer让它加载一个简单earth文件。看到地球转起来才算整个链路完整跑通。3. 常见编译/运行坑排查实录从报错信息反推根因3.1 VS版本错配的LNK2038一次典型的Runtime Library冲突这个坑我犯过网上也最多人问。现象是链接.lib的时候报error LNK2038: mismatch detected for RuntimeLibrary: value MDd_DynamicDebug doesnt match value MTd_StaticDebug翻译成人话你给三方的lib是拿/MDd动态运行时编的但当前项目用的是/MTd静态运行时编的两边不想跟对方一起玩。排查链路也很清晰先用dumpbin /headers xxx.lib查看三方库的DLL characteristics或者直接用VS的属性页打开项目看到“运行库”选的是“多线程调试 (/MTd)”。比对三方包里的说明确认它是用哪个VS版本和运行库方式编译的。如果是VS版本错重新找对应版本的3rdParty.zip或者用vcpkg自己编一套不要试图在项目属性里硬把运行库改成和三方库里一样的设置强行改会引发新的运行时崩溃。注意预编译三方库通常默认用的是动态库/MDd或/MDOSG和OSGEarth的CMake默认也是动态库所以最稳妥的方案是保持默认不动别去折腾静态运行库。3.2 GDAL版本不对影像加载不出来时的检查顺序还有种情况是编过了、跑起来了但OSGEarth加载tif地形或影像时整块地形是空的或者屏幕显示一片黑。别急着去改代码。先怀疑数据源再怀疑OSGEarth配置最后怀疑三方库里的GDAL。OSGEarth对GDAL的版本要求比较敏感如果3rdParty里打包的GDAL太老或者你自己手动装了另一个GDAL并被PATH提前搜到会导致运行时加载的dll不是你CMake配置时指定的那个。程序加载GDAL插件后调用一些新接口直接失败表面看就是“影像加载不出来”。我的检查顺序是在命令行执行osgearth_viewer --caps看输出里GDAL的版本号。用Process Explorer或listdlls查看进程实际加载的gdalXXXX.dll路径。按路径找到dll确认它来自3rdParty包而不是系统盘里某个GIS软件自带的GDAL。如果确认是被系统路径污染了把3rdParty的bin目录挪到PATH更靠前的位置或者把项目工作目录下的dll都统一清理掉。3.3 动态库加载失败先分清是PATH问题还是依赖链问题运行时弹窗“无法定位程序输入点 XXXX 于动态链接库 gdalXXX.dll 上”这是另一个高频问题。它跟“找不到DLL”不一样。“找不到”是路径没配好而“无法定位程序输入点”99%是dll版本混用比如A.exe运行时找到了B.dll但B.dll内部又依赖C.dll而C.dll是另一个更老或更新的版本里面缺少某个导出函数。我自己的排查方式分两步第一步先确认OSG的bin目录和3rdParty的bin目录都在PATH里并且只用一套。第二步用Dependencies工具就是以前Dependency Walker的替代品打开出问题的exe或dll它会列出完整的依赖树能看到哪一层依赖断掉了。这类问题很多时候是因为你把不同版本的3rdParty混合使用比如GDAL用A包、curl用B包A包里的GDAL调用了B包curl没有的函数崩溃就来了。所以三方库包尽量不要混搭最好整套来自同一个作者或同一个版本。3.4 定位问题的通用排查链路把上面几种坑合并成一个通用套路可以解决九成问题拿到报错先看是编译期链接错误还是运行期dll错误。链接错误去项目属性页看附加依赖项里的lib路径确认是不是指向3rdParty目录再看VS版本和平台。运行错误先跑osgversion、osgearth_version这类工具能加载基础插件如果它都崩说明环境变量没配好。用Process Explorer检查实际加载的dll确认没有“串包”。最小化复现新建一个空项目只调OSG和OSGEarth基础接口逐步加功能找到崩溃触发点。这套排查链路看起来朴素但每一条都能单独干掉一类坑。遇到问题别盲目重装先定位是哪一层出的错。4. 不用这套zip也能编译的备选路线4.1 vcpkg自动化依赖管理如果你不想用别人打包的预编译库或者你手头的VS版本和网上的3rdParty包匹配不上我的建议是用vcpkg。vcpkg install osg osgearthvcpkg会从源码编译OSG、OSGEarth以及它们需要的三方依赖整个过程自动化程度高而且会按你当前的VS版本生成对应库。劣势是耗时长——首次编译这几百个依赖可能要一两个小时而且vcpkg默认的triplet是x86需要指定--tripletx64-windows或者x64-windows-release。用vcpkg编完后CMake里只要设置CMAKE_TOOLCHAIN_FILE D:/vcpkg/scripts/buildsystems/vcpkg.cmakeOSG和OSGEarth的依赖会自动被找到省心程度比手动配置3rdParty高很多。4.2 Linux下的系统包方案如果你是在Ubuntu这类发行版上编译其实根本不需要第三方zip。直接用系统包sudo apt install libopenscenegraph-dev libosgearth-dev系统包仓库已经把三方依赖全部处理好了你只用写业务代码。缺点是版本通常比官方最新版老而且有些新特性没有但如果只是学习和业务开发完全够用。4.3 官方安装包与混用注意OSG官方在GitHub的Release页面会发布Windows安装包比如OpenSceneGraph-3.6.5-VC2017-x64-release.exe装上以后自带OSG和一部分三方库。但注意官方安装包并不包含OSGEarth的三方库完整依赖。如果你想只装官方包然后自己单独编译OSGEarth最稳妥的做法是先确认官方包带的GDAL、curl能跑通再去编译OSGEarth。之前有同事这么干过结果OSGEarth的CMake找不到GDAL头文件后来还是回去找第三方包补全。所以我的建议是既然你手里已经有编译好的3rdParty.zip就老老实实用整套别和官方安装包混着来混用dll是出问题最多的场景。5. 附判断点是否落在FeatureNode内的两种落地做法5.1 为什么“点是否在Feature内”看起来简单却容易搞错最近搜“osgearth如何计算点是否在featurenode内”的人不少。这个需求的典型场景是屏幕上某个坐标点点击下去要判断是否命中了某个矢量要素标注区域比如一块多边形的行政区划、一个封闭建筑轮廓。很多人第一反应是拿点去跟Feature的几何坐标做射线法判断但实际做起来往往会遇到两个问题FeatureNode里的Feature几何坐标通常是经纬度直接按平面坐标算射线法在高纬度地区误差会变大。Feature可能有洞可能有多边形而不是简单一个外轮廓这导致判断逻辑要写完整。想避开这些坑有两种落地做法。5.2 射线法从Feature取出几何并在平面坐标系内判定先讲最直观的射线法。通过featureNode-getFeature()拿到osgEarth::Features::Feature再拿到它的几何集合。对每个多边形做“从点向任意方向引一条射线统计与多边形边界相交次数奇数次在内部偶数次在外部”。关键点是要先把经纬度坐标投影到平面。我通常用Feature自带SRS的transform方法把点坐标转换到适合当前区域的投影坐标再做射线法避免直接用经纬度当平面坐标点算。代码逻辑大致是这个骨架osgEarth::Features::Feature* feature featureNode-getFeature(); const osgEarth::Features::Geometry* geom feature-getGeometry(); for (auto it geom-getComponents().begin(); it ! geom-getComponents().end(); it) { const osgEarth::Features::Polygon* poly dynamic_castconst osgEarth::Features::Polygon*(*it); if (poly pointInPolygon(projectedPoint, poly)) { return true; } }这段代码里pointInPolygon就是标准的射线法实现。边界情况要处理点在多边形边界上、点与顶点重合这些在实际点击场景里经常发生。我的建议是给“相交”判断加一个很小的容差epsilon避免因为浮点精度漏判。5.3 更省事的拾取思路用Intersector处理三维场景如果你只是想实现“鼠标点到屏幕上的某个Feature”没必要手动做点与多边形的关系计算直接用OSG的相交检测更靠谱。做法是把屏幕坐标转换成射线用osgUtil::LineSegmentIntersector对场景求交然后遍历交点检查相交节点路径里是否包含目标FeatureNode。这种思路天然支持三维地形和相机视角变化代码量也更少。osg::ref_ptrosgUtil::LineSegmentIntersector intersector new osgUtil::LineSegmentIntersector(near, far); osgUtil::IntersectionVisitor visitor(intersector.get()); node-accept(visitor); if (intersector-containsIntersections()) { // 遍历 intersection.nodePath 查找 FeatureNode }这种方法有个好处就是不关心Feature到底是面还是线还是点只要它被渲染成了可拾取节点就能命中。如果你是在做点击选中的交互功能优先考虑这种方案。射线法适合你已经有明确的点坐标和Feature想独立做算法判断的场景Intersector适合鼠标拾取交互。两个思路搭配起来基本能覆盖所有“点在FeatureNode内”的判断需求。最后说句实在话预编译三方库这玩意儿关键不是“下载下来用”而是“知道它解决了什么问题”。你理解了OSG和OSGEarth对第三方库的依赖关系理解了版本匹配的原理后面无论是换VS版本还是换Linux环境都能举一反三。上面这些坑我基本都亲自踩过写出来就是希望你能直接绕过去省下来的时间多跑几个demo比啥都值。本文还有配套的精品资源点击获取
返回列表