1. 新版本关注点:从“能用”到“好用”的GISBox 2.1.3
最近一直在折腾3DTiles相关的数据生产流程,日常用GISBox的频率很高。2.1.3版本发布以后,我第一时间升级体验了一周,整体感受是这次更新没有堆花活,而是把两个最影响成片质量的问题给补上了:矢量样式扩展和3DTiles位置优化。
先说下背景,GISBox在GIS圈子里其实已经不算小众,它主打的是本地化的三维数据切片与发布,核心路径就是shp转3dtiles、osgb转3dtiles、影像转3dtiles这一类工作。以前用它在做矢量转3dtiles的时候,很多朋友应该都有同感:数据转出来了,能看了,但“能看”和“好看”之间有一条鸿沟——默认样式千篇一律,线是裸线、面是素面,到了项目汇报或者平台集成阶段,还得导出到其他工具里重新配色、调整位置,流程被撕成两截。2.1.3这版更新的价值就在于,把这两段补到一起了。
我给这次更新总结了一句人话:**GISBox 2.1.3想做的不只是“切片工具”,而是“从数据到可用的三维要素”的一站式通道。**文章后面会依次拆解矢量样式扩展和3DTiles位置优化的具体玩法和踩坑点,同时把最新被问爆的shp转3dtiles操作流程、3dtiles如何打开这两个问题一并捋清楚。如果你正在做三维GIS数据生产、Cesium平台对接、或者单位内部的三维数据底座搭建,这篇应该能帮你省下不少摸索时间。
2. 矢量样式扩展拆解:样式才是三维要素的“最后一公里”
2.1 为什么默认样式撑不起项目需求
以前用GISBox转矢量3DTiles,只要数据进去、参数对了,半分钟就能出一版结果。但问题出在“结果默认长得太素”。默认样式通常是单一颜色、固定透明度、线面不分,这在快速预览数据范围时完全够用,可一旦进入正式场景——比如要把建筑基底、规划用地、道路中心线放在同一个三维场景里做分层展示,默认样式就明显不够看了。
我在之前的一个项目里要做一个片区规划三维态势图,光是地类图斑就有六大类,每一类还要区分审批状态、建设状态,如果不在切片阶段把样式定义好,后面到了Cesium里再单独改,工作量会非常痛苦。因为3DTiles的样式控制主要在tileset的样式JSON里(Cesium style engine),如果切片工具不支持样式预定义,就得到处手动写表达式、调颜色、重新指定属性,效率极低。
2.1.3的矢量样式扩展,解决的就是这个痛点:在进入切片流程之前,把矢量数据的属性字段与三维渲染规则做映射,让转出来的3DTiles“自带样式”。
2.2 样式扩展具体支持了哪些能力
这一版的矢量样式扩展,我整理下来主要有这么几个层面:
- 分类渲染:按属性字段值进行分类,比如按“用地类型”字段,把居住、商业、工业分别赋予不同颜色,支持精确值匹配和范围匹配两种方式。
- 视觉变量调整:包括填充色、透明度、边线颜色、边线宽度、是否显示边线等,都是以图层为维度统一设置的。
- 高度与拉伸控制:矢量的面数据可以按某个属性字段做高度拉伸,比如建筑楼层数乘以层高,这个功能对快速构建白模非常实用。
- 标签与注记辅助:可选的属性标签显示配置,虽然3DTiles标签在性能上要谨慎使用,但做简单标注够用。
- 样式模板复用:把一套配色方案保存为模板,同一个项目里的多个图层可以复用,不用重新配置。
我实际测试下来,比较有感觉的是分类渲染+高度拉伸的组合。比如手头有一份建筑轮廓shp,属性里有层数字段,直接把拉伸字段指向“层高”或者“楼层数*3.2”,再按建筑功能分类配色,一版不用进建模软件就能在场景里看到接近白模效果的三维体块。
2.3 样式配置实操:核心参数说明
这个版本在切片设置面板里新增了样式编辑器,交互上比较直观。我习惯的配置顺序是这样:
先明确数据属性结构。打开shp的属性表,确认要用来做分类的字段名、字段类型(文本还是数字)、取值范围,这一步很关键,因为样式规则里字段名写错或类型不匹配,规则会直接失效。
然后进入矢量切片设置,选择对应的shp图层,打开“样式设置”。这里有一个样式规则列表,每一行对应一条分类规则。
以一块规划用地数据为例,假设用地字段名为“LandUse”,值是R2(二类住宅)、C2(商业金融)、M1(一类工业):
- 新建一条规则,条件设为“LandUse == 'R2'”,填充色选暖黄色,透明度80%,边线白色,宽度1.0。
- 第二条,“LandUse == 'C2'”,填充色选偏红色的色系,透明度90%。
- 第三条,“LandUse == 'M1'”,填充色选灰色系,透明度85%。
注意,规则顺序从上往下匹配,命中了前面的规则后,后面的规则就不会再判断,所以具体值要放在“其他”之前。
如果是按数字字段做范围分类,比如建筑年代:
- “Year >= 2020”,颜色浅绿。
- “Year >= 2015 and Year < 2020”,颜色中绿。
- “其余值”,默认色。
这样的好处是生成的结果天然带语义,无论你后期是直接Cesium加载还是进其他平台,都不用再写样式表达式。如果在平台里还想动态切换颜色,Cesium的style engine也允许后续再覆盖,所以预置样式并不会把数据“锁死”,兼容性没有牺牲。
2.4 样式扩展中最容易翻车的几个细节
第一,属性字段类型不一致。很多时候shp里的数字字段读出来是字符串,特别是从Excel转过来的shp,字段看起来是“2020”,但类型是文本。这时候用“Year >= 2020”来判断会失败。建议在切片之前先用工具检查一下字段类型,必要时做一个类型转换处理。
第二,中文字段名的兼容性。有些shp是从老系统里导出来的,字段名是中文,GISBox在读取时通常没问题,但样式规则里建议还是用拼音或英文字段名,避免部分三维引擎处理中文属性时出现字符编码上的怪问题。
第三,边线宽度的单位。3DTiles中样式边线宽度受到渲染引擎限制,并不是设置越宽就越明显,太宽反而会引发渲染走样,我一般控制在0.5到2.0像素之间。如果觉得边线不明显,优先考虑加深边线颜色而不是单纯加宽度。
3. 3DTiles位置优化:防止模型“飘在空中”和“扎进地里”
3.1 位置偏移的根因:坐标系、原点与高程基准
用过倾斜摄影或者BIM模型转3DTiles的朋友,大概率遇过这类问题:模型加载到场景里,要么整体悬浮在半空中,要么陷进地表以下,要么水平位置偏出去几百米。每次遇到这种情况,第一反应就是检查坐标,但实际原因往往是多个因素叠加的。
第一个因素是源数据的坐标系不统一。常见的情况是shp是CGCS2000经纬度,倾斜摄影是地方独立坐标系,BIM模型用的是项目本地坐标原点。转出来的3DTiles如果没有经过坐标归一化,放到同一场景时就会互相错位。
第二个因素是原点设置。3DTiles本身是全球地形金字塔方案的一部分,它的tileset有两种定位方式:一种是基于真实地理坐标的全球定位,另一种是基于局部坐标加变换矩阵的相对定位。切片工具如果默认处理不当,就会出现“全球坐标当局部坐标”或“局部坐标套全球矩阵”的情况,后者典型表现就是模型跑到海里或跑到非洲去了。
第三个因素是高程基准。矢量数据通常没有高度值,转到3DTiles时默认贴地,但贴地的算法不一样,有的用地形高度,有的用椭球高,一旦基准混用,模型不是抬高了就是沉下去了。
GISBox 2.1.3更新的3DTiles位置优化,核心就是把这几个层面的偏差放在一个面板里统一解决。
3.2 位置优化面板核心参数解读
这个版本的位置优化设置在数据源特性和切片输出的交界处,我实际用下来,核心参数可以分成三类:
坐标纠正类:
- 源坐标系设置:指定shp或者模型原始的坐标系,如果工具自动检测不准,可以手动指定。
- 目标坐标系:切片输出的坐标系,建议与场景内其他数据保持一致。
- 七参数/平移参数:用于不同椭球基准或者地方坐标系之间的纠偏。
场景变换类:
- X/Y/Z平移量:以米为单位进行场景内偏移调整。
- 旋转角:绕Z轴、X轴、Y轴旋转。
- 缩放系数:用于局部坐标拉伸或缩小的场景。
高程修正类:
- 高程模式:可选贴地模式、绝对高程模式、相对高程模式。
- 高程基准偏移:对整体高度做固定偏移值调整。
我最常用的是“平移量”和“高程模式”两个选项。举个之前遇到的案例:有一批建筑shp,转出来的3DTiles在Cesium里加载后,整体南偏了大概36米,东偏了约12米,高度上又比地表低了1.8米。如果回到数据源头去改shp非常麻烦,直接用位置优化面板输入平移参数,南偏就加Y,东偏就加X,高度低了就在高程偏移里加1.8米,前后不到两分钟就校准到位。
3.3 位置校准的一个实用技巧:先打点再切片
我的习惯是在切片前先在原平台里找到一到两个特征点,比如某个建筑的角点或者道路交叉口,记录下它的真实经纬度坐标和高程。切片完成以后,在Cesium或者其他查看器里找到模型对应角点,看它的实际显示位置。这两个值的差值,就是需要输入到平移参数里的数值。用这个“前后对照”的方式,能避免反复试错。方向要特别注意:真实值减去显示值,才是平移参数的增量,很多人这里正负号弄反了,越调越偏。
3.4 定位参考数据:本地应用和全球场景的区别
做本地项目时,经常把三维模型套到地方坐标系里,不接全球地形。这时位置优化的重点在于“模型与模型之间的相对关系”,而不是绝对经纬度。这种情况下,我通常建议整套数据统一用“相对坐标+中心点定位”的方式:所有模型都以场景中心点为原点转出,接入平台后再做一次整体的地理配准。这样能大幅降低坐标换算带来的位置误差。
而涉及全球场景、需要与在线地形和影像叠加时,就必须把所有数据统一到一个坐标系,我一般统一用CGCS2000经纬度加椭球高,然后再切片。位置优化面板里把源坐标系指定为对应投影,目标坐标系选经纬度,高程模式选绝对高度,这样模型与全球地形能精准贴合。
4. 从数据到场景:shp转3dtiles的最优实操路径
4.1 shp转3dtiles的正确流程与参数选择
之前不少朋友私信问shp转3dtiles的具体流程,在这版里,配合样式扩展和位置优化,我的推荐路径是这样的:
第一步,数据预处理。先检查shp的属性表,确认字段类型没有异常,坐标系信息完整。推荐在GIS软件里做一次“修复几何”,避免因拓扑错误导致切片报错。数据量大时,还可以先做要素简化,减少顶点数。需要注意,简化不要过度,不然直角边线会被拉成锯齿。
第二步,在GISBox中新建项目,导入shp文件。导入后,在地图预览里确认数据范围正确,如果范围出现在奇怪的位置,多半是坐标系识别错了。
第三步,配置矢量样式。按照前面说的分类渲染方式,设置好各类型颜色、透明度、拉伸高度。如果只是为了出范围图,可以快速选一套默认样式,后面发布到Cesium再改也行,但既然新版支持样式预设,建议一步到位。
第四步,设置输出坐标系和位置参数。这一步是决定“模型放哪里”的关键。我的建议是:
- 如果是本地场景集成:选“保持源坐标系”,然后在“位置优化”里输入中心点坐标。
- 如果是要进在线地图:转成CGCS2000经纬度或WGS84经纬度,高程模式选贴地或绝对高程。
第五步,执行切片。切完以后,在输出目录里检查tileset.json、b3dm文件是否生成完整。不要急着关软件,直接点开内置的三维预览,检查颜色样式、位置、高度是否正常。如果发现异常,回到参数面板调整,重新切片。我试过最常用的切片输出在几十MB到几百MB之间,速度都很快,一次调整再重新切基本在一分钟内能完成。
4.2 3dtiles如何打开:几种常见查看方式
“3dtiles如何打开”这个问题在搜索词里热度很高,估计很多朋友是第一次拿到3dtiles文件,不知道拿什么软件看。这里把几种常见打开方式罗列一下,按推荐程度排序:
方式一,GISBox内置三维预览。这是最直接的办法,切片后直接在软件里加载查看,不需要额外配置环境,适合快速检查切片结果。位置对不对、样式对不对、拉伸对不对,一眼就能看出来。
方式二,CesiumJS加载。如果你有自己的前端页面环境,可以用Cesium的Cesium3DTileset类来加载。核心逻辑是:
const viewer = new Cesium.Viewer("cesiumContainer"); const tileset = await Cesium.Cesium3DTileset.fromUrl("http://localhost:8080/data/tileset.json"); viewer.scene.primitives.add(tileset); viewer.zoomTo(tileset);这种方式适合做平台集成,但需要先有一个web服务把3dtiles目录发布出来,本地方案可以用nginx或者直接以静态服务器方式启动。
方式三,本地静态服务器加浏览器。如果暂时不想写前端代码,可以把tileset.json所在的整个目录放到静态服务器里,然后在Cesium官方示例页面或一些开源三维地球工具里填写tileset地址来预览。比如用Cesium的Sandcastle直接改url参数,操作成本很低。
方式四,离线三维地球工具。部分三维数据管理软件(比如一些开源的三维地球终端)也支持直接加载本地或远程3dtiles目录,适合非开发人员做数据检查。
有朋友问过能不能直接用浏览器双击tileset.json打开,这个方式是不行的,因为3dtiles涉及跨域读取和异步加载纹理等资源,必须通过HTTP服务访问。这一点建议记清楚,省得在本地文件协议上浪费时间。
4.3 发布与集成的注意点
切片完成不是终点。如果要把3dtiles接入已有的三维平台,还涉及服务和缓存的问题。GISBox本身带了发布能力,能把本地目录发布成一个HTTP服务,局域网内其他机器通过地址就能访问。我在项目里常用它做数据校验和临时展示,开发测试阶段比较方便。
发布之后的访问路径有讲究。通常访问的入口是tileset.json,但要注意它的相对路径引用了子文件夹中的b3dm,整个目录都要保证在同一个静态服务下,不能只拷贝一个json文件到其他机器上,否则会404。常见的做法是把整个输出目录直接放进web根目录,通过“http://ip:端口/目录名/tileset.json”访问。
5. 常见问题与排查技巧实录
5.1 样式不生效,排查思路是什么
样式配置完,切片也成功了,结果预览里还是默认样式。这类问题我遇到过不止一次,排查顺序建议如下:
- 先看属性字段名是否完全一致,包括大小写,因为shp属性在部分情况下对大小写敏感。
- 再看字段类型是否匹配,数字类型字段用字符串值做条件判断,会导致所有规则落空。
- 再看规则顺序,具体值是否被前面的“其他”或范围规则覆盖。
- 最后在切片时确认样式设置确实是应用到了当前图层,而不是新建了图层忘了切换。
一个很容易被忽略的细节是,shp文件里同名字段在不同图层中值类型可能不完全一致,比如A图层的“code”字段是整数,B图层的“code”字段是字符串,如果两个图层复用了同一套样式模板,后者的规则可能全部失效。建议每个图层单独校验一遍提取样例值。
5.2 位置偏了,先别急着调整平移参数
位置偏移发生时,很多人第一反应就是加平移量。但我的经验是,先做一步“坐标系确认”。如果源坐标系和目标坐标系没配对,偏移量往往不是几十米而是几十万个单位,这时候单纯加平移参数只能算治标不治本,而且换一台电脑或换个场景可能又变了。
排查步骤:
- 检查shp原始坐标范围。如果经纬度shp的X范围是110到114左右,说明是经纬度;如果X范围是几百万,那就说明是投影坐标。两种数据混在一批导入时,极易发生错位。
- 检查切片输出设置里的坐标系选项。确保输出坐标系和场景内其他数据一致。
- 如果以上都没问题,再测量显示的偏差值,用“真实值-显示值”的方式计算平移参数。
5.3 模型悬浮或下沉,调高程的模式选择
高程问题最简单的判断方法是看数据本身有没有高度。纯二维shp转出来的矢量,高度值默认是0,如果场景地形高程是200米,理论上矢量要素应该贴着地形表面,但如果你在切片时选择了“绝对高程模式”,它就会按椭球高0去放置,这时候模型会沉到地下非常深的位置。
针对shp数据的建议是:
- 如果只是做地块边界、路网等贴地要素,选择“贴地模式”,让3DTiles渲染时自动与地形贴合。
- 如果要做建筑体块拉伸,需要根据楼层数乘以层高计算高度值,建议先在属性表里生成一个“高度”字段,然后拉伸字段指向它,不要依赖默认值。
- 如果和倾斜摄影叠加时发现矢量整体比实景高或低,用“高程基准偏移”统一调整,偏移量是源数据高程与目标地形高程的差值。
5.4 性能问题:大shp转3dtiles卡顿或结果太大
数据量大是另一个高频问题。一个几百MB的shp,要素几十万个,直接转3dtiles的结果文件会非常大,加载起来帧率很低。我在做这种数据时的建议是分两次处理:
第一次,在GIS软件里做属性筛选或空间筛选,把要素数量控制在合理范围,比如只保留面积大于某阈值的图斑。第二次再做切片,并在切片设置里降低细节层次、合理设置最大误差,让生成的LOD层级更精简。导出后如果还是大,可以检查一下是否有大量重复属性或零碎要素,做合并处理。
另外,3dtiles的纹理图片尺寸和压缩格式对体积影响很大,转出后如果发现纹理过大,可以统一压缩成通用网络格式,能明显减少加载时间。
5.5 3dtiles资源加载显示空白
这类问题常见于本地调试,往往表现为场景里没有模型,或者模型只有包围盒没有内容。原因基本就几种:
- 资源路径指向不对,控制台报404。
- CORS跨域未配置,本地服务没开允许跨域头。
- tileset.json里引用的相对路径与实际文件结构不一致。
- 显卡不支持WebGL2或版本过旧,Cesium没法渲染部分材质。
排查时打开开发者工具看网络面板和控制台。若看到404,就检查路径;若看到CORS报错,就在静态服务里加跨域响应头。如果是偏老的浏览器或设备,建议换Chrome最新版或升级显卡驱动后再试。
6. 一些个人心得和习惯
这次用2.1.3版本做了一阵子实际生产,最后分享几个我自己的工作习惯。第一个习惯是“切片前多花两分钟做字段检查”,磨刀不误砍柴工,属性字段名、类型、样例值都确认一遍,能省掉后面一大半的返工。第二个习惯是“每次调整参数后重新预览再发布”,不要图省事跳过预览,尤其位置和高程,凭数据猜是猜不准的,看一遍场景实测才靠谱。第三个习惯是“用于不同场景的3dtiles分开目录存放”,本地相对坐标的、全球经纬度的、不同样式的版本分开管理,避免后期搞混。
另外我建议在做位置校准时,把每次调整的数值记录下来,形成一个小台账,包括源坐标系、目标坐标系、平移量、高程偏移、参考点坐标。以后再接入类似数据时,直接套用已有的参数组合,不用从头试。这套办法我用下来,位置类问题的处理时间从半小时降到了几分钟。
GISBox 2.1.3这版说到底没有太多花哨功能,但矢量样式扩展和3DTiles位置优化正好打在三维数据生产的两处痛点上。如果你之前被默认样式和坐标偏移折磨过,这版值得升级试试,按文章里的流程走一遍,应该能少踩几个坑。