34-lightweight-city-massing.md 7.0 KB

34: 沅陵县城轻量体块模型(替代被否的 cesiumlab 导出)

What to build: 甲方那份 yuanlingSHP(cesiumlab model2tiles)经维护者目测判定 「明显错位 + 只是白色立方体,效果非常差」,不采用。按维护者定的替代方向做一版 轻量建模:参照 GIS 数据(路网 / 建成区 / 水系 / 真实轮廓)程序化生成县城体块, 远景基本达标、不要求近景细节、楼房模型可复用;地理配准由构造保证(不再靠猜原点)。

Status: resolved Labels: ready-for-agent

Answer

已交付,但维护者目测否决 —— 本条就此关闭,重做见 票 35。

否决理由(维护者 2026-09-18 看渲染图后给出,逐条记下以免重做时再犯):

  1. 远景看不清、近景完全不像房屋、屋顶是漏的:楼房看起来是一个个漏顶的盒子。 根因(自查):emitBuilding() 里平屋顶那一片四边形的绕序与法线不匹配,而材质是 doubleSided: false → 顶面被背面剔除,于是"漏顶";坡屋顶那段还先 push 了一个占位四边形再回退, 几何不干净。这是可以确定的技术缺陷,不是口味问题。
  2. 建筑尺寸与卫星图完全不搭边:单元尺寸(9×7.2 / 14×10 / 26×11 m)与实际县城房屋尺度不符, 且密度/排布方式一眼是"程序生成"。
  3. 模型图层压在 Cesium 之上、不被地形遮挡(明显 bug):楼房没有真正贴合地形, 高处飘、洼处陷 —— 根因是高程取自 17×17 的粗网格双线性插值(94–188 m 区间, 局部误差可达十几米),不是逐栋按 DEM 采样。
  4. 维护者明确要求:重做时房屋要稍微加点细节,使中近景也能辨认出是房屋。

注意:本条的机器验证(坐标链、GLB 结构、加载三态)都是真的,错在几何质量与地形贴合上 —— 教训是"能加载 + 坐标对"不等于"看起来对",视觉验收必须由维护者做,且生成器要有可调的形态参数。

依赖与事实

  • 被否的那版:D:\GIS\GIS\yuanlingSHP 缺根 tileset.json、分块是局部坐标。为看效果曾补过一版 合成根文件(锚定"县城稠密簇 == 目标坐标"),维护者目测错位且只有白方块 → 该合成根文件已删除, /gis/models 挂载也已移除。教训:靠推测锚点 + 单色方块 = 不可接受。
  • 本机可用的真原料:OSM buildings/roads/waterways(城区内 169 个真实轮廓 + 85 条路 + 沅江)、 1:5 万居民地面 output/resa.json(148 个建成区多边形)、本地 DEM(yuanlingDEM)。
  • 关键洞察:原料是经纬度,所以这次的地理配准是"由构造保证"的 —— 投影到以目标点为原点的 ENU 米制坐标,再写成 3D Tiles 根的 transform,不存在"猜模型原点"。

验收

  • 有一套可重跑的生成工具(不是一次性手搓产物):tools/city-massing/build-town.mjs。
  • 地理配准正确:真实轮廓在模型里的位置与源经纬度一致(回验脚本可证伪整条坐标链)。
  • 不是单一白色:按单元类型分配 13 种材质(墙 8 + 屋顶 5),且同一输入结果稳定(可复现)。
  • 体块坐到地形上(本地 DEM 采样网格插值),而不是浮在椭球 0 米里。
  • 明确标注"示意体块、非实测建筑、不得用于量测/统计/决策"(meta.json + README + 本票)。
  • 真机加载无报错、内容真的被请求(tileset.json + town.glb 都 200,瓦片 visited/selected=1)。
  • 远景是否达标 —— 维护者目测判定:不达标(三项缺陷见 Answer),故本条不采用其产物。

进度:100%

实现与机器验证完成 → 维护者目测否决(三项缺陷,见 Answer)→ 本条关闭,重做转票 35。

做法

  1. 投影:经纬度 → 以目标点(110.39028164, 28.4436787)为原点的 ENU 米制坐标; glTF 是 Y-up,顶点写 (east, up, -north),由 Cesium 按 (x, -z, y) 转回局部 Z-up。
  2. 体块来源(优先级):① OSM 真实轮廓(74 个,按外接盒起楼)→ ② 沿街排布(每条可沿街线段 两侧各按 23 m 间距放楼,退让 11–17 m)→ ③ 建成区补白(居民地面内 30 m 抖动网格,留 28% 空隙)。
  3. 可复用单元:house(9×7.2 m,1–2 层,坡屋顶)/ block(14×10 m,3–5 层,平顶)/ slab(26×11 m,6–8 层,平顶);层数按"离中心距离 + 位置哈希"给,配色从 13 种里按哈希取。
  4. 地形落地:先用本地 DEM 采 17×17 高程网格(terrain-grid.json,94–188 m), 生成时按双线性插值给每栋楼定基准高程(略埋 0.6 m 避免露缝)。
  5. 避让:中心点距水系 < 22–26 m 的体块直接不生成(沅江两岸不"长"楼)。
  6. 产物:D:\GIS\GIS\cityMassing\{town.glb, tileset.json, meta.json}(4.8 MB,单瓦片 13 图元)。

验证证据

  • 回验脚本 tools/city-massing/verify-town.mjs → 全部通过:
    • 真实轮廓落点:窗口内最大的 8/8 个真实轮廓,其外接盒角点在 GLB 顶点里 2 m 内命中 —— 这条专门证伪"经纬度 → ENU → glTF Y-up"整条链(写反任何一步都对不上);
    • transform 自洽:局部原点经 transform 回算经纬度误差 0.000 m;包围盒中心落在目标城区窗口内;
    • GLB 结构:header/JSON/BIN 长度自洽、13 个 POSITION accessor 的 min/max 合法、 16.9 万顶点 / 7.07 万三角、NaN 0;
    • 免责声明在 meta.json 里可检出。
  • 真机加载:stats.tilesets=1、tilesetErrors=[]、零页面报错;网络里 tileset.json 与 town.glb 都是 200;三个视点(2400 m / 1200 m / 1800 m 侧视)下诊断均为 visited=1, selected=1, contentReady=1(没被视锥剔除、被选中、内容就绪)。
  • 截图(供维护者判定):C:\Users\ASUS\AppData\Local\Temp\cockpit-city-probe\ (1-overview-2400m-pitch-55.png、2-mid-1200m-pitch-45.png、3-oblique-1800m-pitch-20.png)。
  • 生成统计:5000 栋(真实轮廓 74 / 民居 3450 / 条楼 1449 / 板楼 27,避让水系 8), 局部范围 x ±1966 m、y ±1662 m、z 99–197 m。

踩到并修掉的一个真 bug

tileset 级 geometricError 写成 0 时 Cesium 不请求根瓦片内容 —— 现象是 tileset.json 拉到了、 town.glb 始终不下载,页面上一栋楼都没有。是靠新加的诊断读数(getTilesetDiagnostics(): visited/selected/contentReady/rootContentState)定位的。改成 800 后内容正常加载。

下一步

  1. 等维护者目测:远景是否达标。达标 → 把 map.tilesets 配上(.env.local 已挂 /gis/city); 不达标 → 调参数(层数分布、沿街间距、配色)或换更强的数据源重做。
  2. 若正式采用,需要在部署手册与项目说明里显著标注这是示意体块(避免被当作实测建筑使用)。