
简介这是基于Windows 10与Visual Studio 2019环境手工编译完成的OSG 3.6.5与OsgEarth 3.1完整三维图形开发库目标用户是需要快速集成三维渲染能力的C开发者可省去从零配置编译环境的精力。整个压缩包约53.55MB共含1325个文件按bin、include、lib三个目录清晰组织bin目录提供302个DLL动态运行库lib目录提供38个导入库另有头文件、版本信息及众多插件配置文件同时覆盖Release与Debug两种构建目标便于直接链接调试或发布版本。作者在资源描述中说明该库经过多日反复编译与测试文件齐全、结构完整能支持场景渲染、地形显示、模型加载与OsgEarth常见功能调用适合在win10vs2019环境下直接配置工程属性后使用。目前已有855人学习下载适合有一定C基础、希望快速获得可用三维图形库的开发者参考使用。1. 拿到这个完整编译库先想清楚它替你省掉了什么我第一次手动从源码编 OsgEarth 3.1 是在一个周五下午到了周一早上才跑通第一个 viewer期间被 CMake 缓存、GDAL 版本、OSG 源码分支反复折腾。而标题里这个 Osg3.6.5-OsgEarth3.1-x64-vs2019-release-debug-win10.rar 完整编译库就是有人把 OSG 3.6.5 和 OsgEarth 3.1 在 win10 vs2019 x64 环境下编译好的全套产物打包成了 rar。它解决的问题很具体你不用再面对 osgEarth 那棵第三方依赖树GDAL、CURL、GEOS、SQLite、zlib、protobuf直接拿到 include、lib、bin 就能开始写业务代码。适合做三维 GIS 可视化、仿真场景集成、以及在 C 项目里快速接入 osgEarth 的人。如果你打算深入改造 osgEarth 内核源码那这份库反而会碍事还是走源码构建更合适。以下内容就是围绕这一份库的配置、链接和排错实操。2. 在 vs2019 里配置完整编译库include、lib、bin 三段式路径与最小示例2.1 解压后先认清目录结构这类打包的“完整编译库”解压出来一般不会是乱七八糟的一堆 DLL而是按编译期和运行期分好的三层目录。我习惯先花五分钟把结构摸清再开始配 VS 工程省得后面反复怀疑路径写错。目录/文件里面是什么什么时候用到includeosg、osgEarth 相关的头文件编译期告诉编译器类和函数长什么样lib供链接用的 .lib 文件链接期把符号引用解析到具体实现bin运行期需要的 .dll 文件以及 osgPlugins-3.6.5 插件目录运行期exe 启动时被动态加载注意 lib 目录里的文件名凡是名字以 d 结尾的比如 osgEarthd.lib、osgViewerd.lib是 Debug 配置用的版本不带 d 的 osgEarth.lib、osgViewer.lib 是 Release 配置用的。这不是某个人的个人习惯而是 OSG/CMake 体系里约定俗成的命名规则VS 项目里链接哪个文件取决于你当前激活的是 Debug 还是 Release 配置。另外bin 目录下通常会有一个 osgPlugins-3.6.5 子目录里面是 osgdb_* 系列插件 DLL。osgEarth 的 .earth 文件、GDAL 影像、各种模型格式的读取全都要靠这些插件在运行期动态完成不是由主程序直接链接的。所以这个插件目录在运行期必须能被 osgDB 找到后面的环境变量配置就与此相关。提示如果你解压出来的目录里 debug 和 release 的 lib 被分成了两个子目录那么在 VS 里附加库目录时就要分别指向如果只有一个 lib 目录靠 d 后缀区分即可。2.2 先把环境变量配到系统级VS 工程内的属性配置只能解决编译和链接期的问题exe 运行起来之后Windows 加载器要按 PATH 顺序去找 DLLosgDB 要按 OSG_LIBRARY_PATH 去找插件。所以我拿到库的第一件事不是开 VS而是先把三个环境变量固定下来。# 注意把 D:\dev\osgEarth 替换成你实际解压的位置 # 建议以管理员身份通过“系统属性 - 环境变量”写入避免每次开新终端都要重设 $env:OSG_FILE_PATH D:\dev\osgEarth\data $env:OSG_LIBRARY_PATH D:\dev\osgEarth\bin\osgPlugins-3.6.5 $env:PATH D:\dev\osgEarth\bin;$env:PATH这里三个变量的分工不一样PATH 里加 bin是为了让 exe 启动时能直接找到 osgEarth.dll、osgViewer.dll 这些动态库OSG_LIBRARY_PATH 指向 osgPlugins-3.6.5是告诉 osgDB 去哪个目录扫插件OSG_FILE_PATH 是可选的它作为 osgDB 读取数据文件的默认搜索路径如果你有固定的地图数据目录设了之后 .earth 里写相对路径也能找到文件。强调一下PowerShell 窗口里用 $env: 赋值只对当前窗口和这个窗口拉起的子进程生效关了就没了。我一般直接写到系统环境变量这样 osgviewer.exe 在任意终端下都能用。如果你机器上还没装 vs2019安装时记得勾选“使用 C 的桌面开发”工作负载否则连 cl.exe 都没有这份库也就无从用起。写完后要重开所有 VS 和终端让环境变量生效。2.3 VS2019 项目属性按 x64 平台填库标题写得很清楚x64。这意味着它是按 AMD64/Intel 64 指令集编译的。你可能会碰到 arm64 和 x64 有什么区别这类问题简化理解就是arm64 是 ARM 处理器的 64 位指令集x64 是 PC 上 Intel/AMD 的 64 位指令集二者二进制不能互相加载。所以 VS 的解决方案平台一定要选 x64Win32 和 ARM64 都不行。具体配置我建议用属性表Property Sheet而不是每次新建项目手动填尤其是团队协作时一份 props 传下去大家的 include/lib 路径就统一了。在“属性管理器”里给 Debug|x64 和 Release|x64 各建或共用一张属性表然后填下面几项配置项填法C/C - 常规 - 附加包含目录D:\dev\osgEarth\include链接器 - 常规 - 附加库目录D:\dev\osgEarth\lib链接器 - 输入 - 附加依赖项Debug 与 Release 分别按库名后缀填写见下表配置典型附加依赖项按实际引用模块增减Debug|x64osgEarthd.lib osgEarthUtild.lib osgViewerd.lib osgGAd.lib osgUtild.lib osgDBd.lib osgd.lib OpenThreadsd.libRelease|x64osgEarth.lib osgEarthUtil.lib osgViewer.lib osgGA.lib osgUtil.lib osgDB.lib osg.lib OpenThreads.lib这里最容易被忽略的是附加依赖项。OSG 的 lib 不会自己跑进你的链接命令必须手写。Debug 和 Release 的差别只在文件名里的 d 后缀。如果你在“所有配置”里只填了一份不带 d 的切到 Debug 编译时链接器找不到 osgEarthd.lib保准报 LNK1104 failed to open file这是新人最容易出现的链接期“翻车现场”。2.4 用最小 C 工程加载一个 earth 文件环境变量和工程属性都配好后验证库能不能用最直接是做一个最小 C 工程。下面这个程序只做一件事用 osgDB 读取一个 .earth 文件把它挂到 osgEarth 的 EarthManipulator 上然后用 osgViewer 跑起来。// main.cpp #include osgViewer/Viewer #include osgDB/ReadFile #include osgEarthUtil/EarthManipulator #include osg/Group int main(int argc, char** argv) { osg::ArgumentParser arguments(argc, argv); osgViewer::Viewer viewer(arguments); // 从命令行第一个参数取 earth 文件不给就尝试读取 world.earth const char* file arguments.argc() 1 ? arguments[1] : world.earth; osg::ref_ptrosg::Node node osgDB::readNodeFile(file); if (!node) { OSG_WARN failed to load: file std::endl; return 1; } osg::ref_ptrosg::Group root new osg::Group; root-addChild(node); viewer.setSceneData(root); viewer.setCameraManipulator(new osgEarth::Util::EarthManipulator); return viewer.run(); }这段代码里osgDB::readNodeFile 是按扩展名把读取请求分发给插件机制的看到 .earth 就会交给 osgEarth 的 ReaderWriter 处理。所以这个例子能跑通同时验证了四件事OSG 头文件和 lib 链接正确、osgEarth 的插件 DLL 能被 osgDB 找到、earth 文件里的图层驱动比如 gdal可用以及 viewer 能正常创建窗口。如果你手边还没有现成的 .earth可以先写一个最小地图文件再用上面程序打开map namesimple typegeocentric options profileplate-carree/profile /options image nametex drivergdal urlD:/dev/data/your_texture.tif/url /image /mapdrivergdal 表示影像层用 GDAL 驱动读取这要求 bin/osgPlugins-3.6.5 里有 osgdb_gdal 插件。如果你没有 TIF 数据先拿任意一张 GDAL 能读的 GeoTIFF 试试实在没有就把 image 层删掉只留 options 也能启动地球只是看不到贴图这算是最低成本的链路验证。命令行用 osgviewer.exe 快速验证也可以但 C 工程验证的深度更高至少能排除你自身工程配置的问题。3. Release 与 Debug 双版本库链接器的两条硬规则与配置陷阱3.1 debug 为什么不能链 release 库标题里写着 release-debug 双配置这是这类完整编译库最值钱的部分也是最容易让人犯迷糊的地方。很多人拿到库后想省事Debug 工程也链 Release 的 lib结果链接期报 LNK2038 RuntimeLibrary 不匹配或者编译过了运行时直接崩。这不是玄学背后是 MSVC 的运行时库规则。VS2019 默认对 Release 使用 /MD多线程 DLL对 Debug 使用 /MDd多线程调试 DLL。这两套 CRT 的堆管理、迭代器调试级别、STL 容器内部布局都不一样。Debug 程序里对象的成员偏移可能和 Release 编译出的库对不上跨 DLL 边界 new 出来的对象放到 Release DLL 里 delete或者把 std::string 从 Release 库传进 Debug 模块都属于未定义行为表现常常是“偶尔崩溃、不好复现、查不出原因”。所以原则只有一条Debug 程序只管链所有带 d 后缀的库Release 程序只链不带 d 的库不要混。osgEarth 3.1 对 OSG 3.6.5 的依赖尤其敏感它的 util 模块里大量使用模板和智能指针如果 OSG 库本身是 release 编的而你的工程是 debug即使链接器没拦住运行期也会在某次 ref_ptr 的引用计数释放中翻车。库作者打包时把 debug/release 都编出来就是为了让你不用动这个脑筋你也别辜负这份好意。3.2 在 VS2019 里同时配好 debug/release靠文件名后缀区分OSG 和 osgEarth 的库命名非常规律Debug 一律在最后加 dRelease 不加。当 lib 目录里同时存在 osgEarth.lib 和 osgEarthd.lib 时VS 工程要分别给两个配置填写附加依赖项。我建议把公共路径写进属性表把差异项单独留在各自配置里。打开“项目 - 属性”时注意属性页左上角的“配置”下拉框。你可以在 Debug 里单独编辑再切到 Release 单独编辑也可以只创建一张把附加包含目录和附加库目录写死、链接输入留空的属性表然后两个配置分别填各自的 lib 清单。我一般把附加包含目录、附加库目录、预处理宏这些都放进 props把 lib 名留在 .vcxproj 的两个配置里后续加新模块时改动面最小。另外如果你是从旧工程升级过来的检查一下“配置管理器”里的活动解决方案平台是不是 x64。很多老工程默认 Win32切到 x64 之前VS 会把 x86 的链接器指向 x64 的 lib 目录结果报一堆架构不匹配的 LNK1112这跟库本身没关系。Debug 下如果遇到奇怪的重复符号或增量链接失败把“链接器 - 常规 - 启用增量链接”临时关掉再编译往往也能绕过去。3.3 强制“所有配置”导致链接翻车常见配置误区我在同事的机器上不止一次看到同一个错误他图省事在属性页的配置下拉框里选了“所有配置”然后把 osgEarth.lib不带 d填进了附加依赖项。编译 Release 没问题一切到 Debug链接器报 LNK1104 cannot open file osgEarth.lib因为他根本没有单独为 Debug 填 osgEarthd.lib。这种“所有配置”的便利是有代价的。附加依赖项这种按配置区分的内容不适合做公共项。如果一定要用“所有配置”也有补救在 lib 名里用宏比如把路径写成$(SolutionDir)..\osgEarth\lib\osgEarth$(ConfigurationName).lib这样 Debug 配置会自动拼出 osgEarthDebug.lib。但 OSG 的命名是 d 后缀Debug 拼出来是 osgEarthDebug.lib和实际的 osgEarthd.lib 对不上所以这个宏方案在 OSG 这里并不通用。更干净的办法是打开属性页先选 Debug|x64填 osgEarthd.lib再选 Release|x64填 osgEarth.lib。两个配置各填各的互不污染。检查是否配错还有一种廉价方法切到 Release 编译一次再切到 Debug 编译一次把两次的“链接器 - 命令行”拉出来对比。Debug 行里应该全部带 dRelease 行里全部不带。只要有一个反了链接器后面就会跟着报一堆莫名奇妙的符号重复或运行时函数找不到尤其 LNK2005 和 LNK4099 这类十有八九是运行时库混配而不是代码问题。4. 常见问题排查从链接到运行五类高频报错现场下面这五类现场按现象、原因、解决的顺序写。每一类都是我在完整编译库交付和后续集成时真实遇见的按出现频率排序。4.1 LNK2019 无法解析的外部符号先查附加依赖项和顺序现象编译正常链接时报一堆 unresolved external symbol例如osgEarth::Util::EarthManipulator相关的符号无法解析。原因通常是三类附加依赖项漏写 osgEarthUtil 或 osgEarthlib 顺序反了或者是 Debug 工程链了不带 d 的 release 库。其中 EarthManipulator 的实现在 osgEarthUtild.lib 里osgEarthUtild.lib 又依赖 osgEarthd.lib 和 osgViewerd.lib如果你只填了 osgEarthd.lib 没填 osgEarthUtild.lib链接器解析 util 里的符号照样失败。解决按第 3.2 节的配表把 Debug 的全部 d 系列填进去Release 同理。定位时先看两处一是错误输出里是否出现 osgEarthUtil 字样二是把附加依赖项里带 d 的和不带 d 的分别列出来核对当前活动配置。补充一点静态库之间的依赖顺序在 MSVC 里也有讲究被依赖的库尽量放在后面虽然 VS2019 的自动库依赖机制能兜底一部分但手写清单时还是把 osgEarthUtil 放前面、osgEarth 放后面更稳。4.2 运行时报找不到 DLL 或 api-ms-win-*.dll先查 PATH 与 VC 运行库现象编译链接都过了双击 exe 弹窗“由于找不到 osgEarth.dll无法继续执行代码”或者 64 位程序在干净的 Windows 上报缺少 api-ms-win-*.dll 这类系统 API 集文件。原因前者是 PATH 没包含 bin 目录Windows 加载器按 PATH 顺序找不到 osgEarth.dll后者常见于精简版系统或没装 VC 运行库——VS2019 编出的程序默认依赖 vcruntime140.dll、msvcp140.dll 这一组微软的 vc redist x64 完整装一遍才是正解。解决把 bin 目录追加到系统 PATH 后重启终端同时确认系统已安装对应版本的 VC Redistributable x64。应急手段是把 bin 下的 DLL 全部复制到 exe 同目录但这只适合临时分发团队开发还是统一 PATH 更省心。定位时在 VS 调试器里打开“模块”窗口直接看 osgEarth.dll 是从哪个路径加载的一眼就能看出是不是命中了旧目录。注意 32 位和 64 位程序的 PATH 解析不一样你的 exe 是 x64就只认 PATH 里的 x64 DLL 目录不要在 x86 目录里找。4.3 .earth 文件打开黑屏或直接退出插件搜索路径没对上现象同一份 .earthrelease 下能出地球debug 下黑屏退出或两个配置都打不开日志里提示不能找到处理 .earth 的 ReaderWriter。原因osgDB 在运行期通过 OSG_LIBRARY_PATH 和 osgPlugins-3.6.5 目录扫插件。Debug 程序找的是形如 osgdb_xxxd.dll 的调试版插件如果插件目录里只有 release 版不带 ddebug 程序就会“找不到插件”。这不像链接错误那么直白很多人在业务代码里翻半天。解决先确认 OSG_LIBRARY_PATH 指向正确再看插件目录里有没有对应的调试版插件。如果只有不带 d 的理论上可以让 debug 程序通过 OSG_LIBRARY_PATH 指到另一个 release 插件目录但这样会引入 debug 主程序挂 release 插件的混跑风险不建议长期用。最好的办法是用完整编译库自带的成对插件debug 配 debugrelease 配 release。排错时可以把 OSG_NOTIFY_LEVEL 设成 DEBUGosgDB 会打印插件搜索路径和加载失败原因这是最快的定位入口。4.4 程序崩在奇怪位置多个 osg 版本 DLL 抢加载现象程序启动正常进入主循环后几十秒随机崩溃调用栈堆在 osgDB 的注册表初始化或某个纹理加载函数里而同样的代码在同事机器上没问题。原因PATH 里同时存在另一套 OSG 版本比如之前装过的 osg 3.4 或 osgEarth 2.x它们的 osg.dll、osgDB.dll 版本和当前这套 lib 不匹配运行期 DLL 加载顺序又优先命中了旧版本。解决用where osgEarth.dll查一下实际命中路径把当前编译库的 bin 目录移到 PATH 最前面更干脆的是把系统里其他 OSG 相关路径从 PATH 里摘掉只留这一份。这类问题最难受的点在于链接期一切正常运行期才暴露而且不是每次必现。养成拿到新库先检查 PATH 的习惯能少踩很多这种暗坑。也可以用 Process Explorer 或 Dependencies 工具看 osgEarth.dll 的实际加载路径确认不是系统目录里残留的旧副本。4.5 debug 与 release 表现不一致第三方库配置交错现象同一个工程Release 流畅Debug 一拖动视角就崩溃或者反过来。原因主程序用的是 /MDd 的 debug 运行时但某个依赖模块比如 GDAL 或 sqlite只编了 release 版且以静态库方式被链进插件。这个模块在 debug 主程序里分配内存又在不同运行时边界释放堆管理不一致崩是家常便饭。解决优先找完整的双配置库别为了省空间只留 release如果非要混集中检查 osgEarth 的 GDAL 相关 dll 版本是否与主程序一致。排错时可以把调试器的 first-chance exception 打开看崩溃点落在哪个模块。如果堆栈停在 gdal 的 tif 读取函数基本就是 GDAL 运行库配置交错。临时在 C/C - 代码生成 - 运行库里把 debug 也改成 /MD多线程 DLL试一下能跑通就说明确实是运行时库冲突但这只能作为定位手段正式调试还是要回到全 debug 环境。5. 进阶验证把 osgDB 插件注册表打出来确认这份库的边界5.1 让 osgDB 把插件加载列表吐出来当你打算在完整编译库之上扩展业务第一个要确认的问题是这份库到底支持哪些格式、哪些图层驱动。不要靠猜用一段十几行的小程序直接问 osgDB。// dump_plugins.cpp #include osgDB/Registry #include iostream int main() { osgDB::Registry::ReaderWriterInfoList infoList; osgDB::Registry::instance()-getReaderWriterInfoList(infoList); for (auto info : infoList) { std::cout ext: info-extensions desc: info-description std::endl; } return 0; }这段代码跑起来之后你会看到一大堆类似 .earth 和 osgEarth 的条目也能看到 gdal、tif、ive、gltf 等格式的加载器。哪一行缺失就说明对应的插件没有加载成功。如果你的业务要接 GeoTIFF而列表里没有 gdal 相关的 ReaderWriter那问题多半出在 OSG_LIBRARY_PATH 没指对而不是 GDAL 本身没编进去。这个黑匣子一旦打开很多“为什么我的 osgEarth 读不了本地影像”的疑问就自然解开了。5.2 新增自定义插件的放置规矩如果后续你自己写了 osgdb_mydata 插件想挂进这套完整编译库规则同样由插件搜索机制决定把生成的 DLL 放进 osgPlugins-3.6.5 即可。但要注意 debug/release 后缀osgDB 在 debug 程序里默认找 osgdb_mydatad.dllrelease 程序找 osgdb_mydata.dll只放一个会有一半场景加载失败。另外如果插件用到了 GDAL最好让插件链接与库里 osgdb_gdal 同一套 GDAL 运行库否则同一进程里两套 GDAL 同时初始化资源句柄一串运行期会非常难查。我自己的习惯是每次拿到这类完整编译库先花十分钟做三件事——配好 PATH跑通最小 earth再 dump 一遍插件列表把输出存成文本放在工程文档里。这样将来同事问“为什么某个格式读不了”翻一眼记录就知道是插件缺失还是环境变量被改了。这套验证流程走过一遍你对这份库的信任度才真正建立起来希望帮到你。本文还有配套的精品资源点击获取