编程 · 数据可视化 · 已上线 · 2026.10.26
CASE 04

中国地形 3D 沙盘

给六岁的孩子做一张能转、能放大、能讲的中国地形图

Three.js 真实 DEM 等距圆锥投影 数据管线 已上线
立项2026-10-26
迭代5 轮反馈迭代
技术Three.js · Python 数据管线 · EdgeOne
方向地球科学 / 亲子教育
一句话核心

把 864 张真实高程与卫星影像瓦片,用等距圆锥投影重投影成 4882km × 4219km 的画布,在浏览器里做成一块可转、可放大、点一下就讲解的 3D 地形沙盘。

02BACKGROUND

背景

六岁孩子问"中国长什么样",地图册回答不了

// 问题
给孩子讲中国地理,最难讲的不是"有哪些省",而是高低、干湿、走向这些看不见的东西。纸地图是平的,孩子看不出青藏高原到底有多高、沙漠为什么在那边、河流为什么往东流。我要的不是一张更漂亮的地图,而是一块能用手转起来、能看出来的地形。
// 需求拆解
  • 高度要能看出来:西高东低的三级阶梯,是第一课
  • 颜色要真实:沙漠黄、森林绿、雪山白,不能靠手工上色瞎配
  • 河流要能追:从源头看到入海口,孩子才知道"水往哪儿流"
  • 比例要尽量真:宁可山看不见,也不做假比例
用户故事:作为家长,我想和孩子一起把中国"转着看",指着一块地方问他"这里高还是低、是沙子还是树",而不是让他背地图册上的名字。
03SOLUTION

方案

先用 Python 把地球"拍平",再用 WebGL 把它立起来

// 数据管线
① 取瓦片DEM + 影像 864 张 → ② 拼大图6144×4608 墨卡托 → ③ 重投影等距圆锥 → ④ 上色真实地表配色 → ⑤ 建网格768×664 顶点
// 关键决策:为什么是等距圆锥
"等比例"是这个项目的最高优先级,它直接决定了投影选型。等距圆锥投影沿经线严格等距,是唯一能同时满足"南北不拉伸"和"形状不走形"的折中。

我先试过 Albers 等积投影(国内标准地图常用),但它的包围盒会变成 4938km × 5739km——南北方向凭空多出 34%,对"看高度"这件事是致命的。最终等距圆锥的包围盒是 4882km × 4219km,1.589 km/像素。
// 技术栈
  • 数据:Terrarium DEM(AWS S3,z=7)+ Esri World Imagery 卫星瓦片,各 432 张
  • 管线:Python(numpy + Pillow)重投影、双线性采样、地形配色
  • 渲染:Three.js 0.160 + esbuild 打包,768×664 网格
  • 边界:Natural Earth 国界,用线段计数法分离国界与省界(相邻两省共享边界被画两次,国界只出现一次)
  • 水系:97 段主要河流 + 108 个湖泊,用国界掩膜剔除境外水体
中国地形 3D 沙盘界面截图
桌面端 · 开启经纬网 · 西高东低三级阶梯与真实地表配色
04APPLICATION

应用

孩子怎么玩,家长怎么讲

// 三种典型用法
  • 看高低:点「俯视」看整块地形,拉「高度夸张」滑块从 1 倍到 60 倍,看山是怎么长出来的
  • 追河流:打开「河流」图层,从源头一路点到入海口,看长江黄河为什么都往东走
  • 点着问:点任意地名弹出讲解卡,有海拔、有冷知识,还能朗读给孩子听
// 交互设计
指向缩放滚轮放大时以鼠标所指地面点为不动点,指哪儿放大哪儿
空格平移按住空格拖动即平移,松开立刻恢复旋转
触屏手势单指旋转 · 双指平移缩放 · 三指纯平移(防小孩误缩放)
方向系统小地图 + 指北针 + 四方位标 + 可开关经纬网
"孩子不会问'这是哪个投影',他只会问'为什么这边是黄的'——所以颜色必须是真实的,不是我配的。"
05RESULT

效果

全真实数据,没有一处手工上色

864
真实瓦片(DEM + 影像)
4882km
画布宽度 · 1.589 km/px
32
地理讲解点
// 精度校验
校验点采样海拔真实海拔
珠穆朗玛峰7,815 m8,848 m(DEM 网格略平)
青藏高原5,093 m4,500–5,000 m
四川盆地347 m250–500 m
华北平原42 m20–100 m
// 视觉成果
沙漠是金黄、森林是浓绿、雪山是纯白、水系统一成一个蓝——全部来自卫星影像本身,只做了提亮提饱和与按海拔叠岩灰/雪白。境外压暗 52%,让中国像一块浮雕从大陆里浮出来。
06REVIEW

复盘

"我以为做对了"和"用户一眼就信了",中间隔了五轮迭代

// 做对了什么
  • 真实数据不打折:宁可用真实卫星影像提亮,也不手工上色——孩子看到的每一块颜色都能对应真实地表
  • 投影为需求让路:为了"等比例"放弃更常见的 Albers,这是唯一一次正确的技术选型
  • 把验证脚本当交付物:写了对照图脚本、方位打点脚本、手势自动化测试,问题能被证伪而不是靠争
// 踩了什么坑(最贵的一课)
  • 相机 180° 翻转:俯视角度太垂直时 up 向量退化,整张图南北颠倒,看起来像"数据全错"
  • 轮廓线不到 1 像素:国界宽 0.13/100 世界单位,默认视角折算不足 1px,等于中国轮廓没画出来——用户看到的是一块无边界色块,自然判不出方位
  • 没有方向参照:视角可转却没有指北针、没有小地图、没有经纬网,用户只能靠颜色猜,猜错是必然
  • 放大只能朝中心:OrbitControls 的 dolly 永远朝视点推,导致"想放大看珠三角"根本做不到
// 最重要的教训
用户连着三次说"地图反了",而我三次都在证明"数据是对的"。投影、高程、标注我核了三遍,确实是准的——但用户要的不是我的证明,是他自己一眼能确认。

真正解决问题的是三件小事:把国界画到看得见、加一张正北朝上的小地图、加一层可开关的经纬网。把"我的判断"换成"用户自己能读的量",争议就消失了。

以后做任何地图类交付,第一优先级不是数据精度,而是边界可见 + 方向可读。
// 下一步
待办:
- 补南海诸岛附图(公开传播中国地图的合规必需项)
- 跟着长江漂流的镜头动画
- 沿北纬 30° 切一刀,看三级阶梯剖面
- height.bin 分级加载(当前首屏 6.7MB)
"先让他能看清边界,再谈数据有多准。"