
什么是程序化东京?
程序化东京是一个在浏览器中运行的东京实时 3D 模型。它将真实建筑、道路、地形、铁路和地理特征,与立面、窗户、街道设施、交通、照明、水体、天气和鸟类等程序化细节结合起来。
该项目使用来自 PLATEAU 项目、OpenStreetMap 和日本国土地理院的公开数据。离线编译器会将源记录转换为紧凑的二进制瓦片,而浏览器则流式加载摄像机附近的瓦片并生成网格。
你可以在 jeantimex.github.io/tokyo 体验托管版本。该体验面向桌面浏览器设计,不建议在移动浏览器中使用。
探索可用场景
每个场景覆盖约 3.4 × 2.8 千米的区域。包含的区域如下:
- 东京:东京站、丸之内和皇居护城河。
- 芝:东京塔、增上寺和芝公园。
- 涩谷:涩谷十字路口、涩谷站和高速公路。
- 新宿:新宿站、摩天大楼街区、歌舞伎町和新宿御苑。
- 千代田:秋叶原、神田和御茶之水。
- 中央:筑地、胜哄、月岛、晴海、滨水区域和运河。
- 富士宫:一座靠近富士山的小镇,拥有 60 千米的地形背景。
PLATEAU 覆盖数百座日本城市,但可用的细节等级各不相同。城市中心可能包含详细的屋顶形状和航空照片纹理,而较小的城镇可能使用更简单的建筑模块。
主要功能
逼真的建筑与地面
建筑使用真实的轮廓、高度、楼层数和用途信息。PLATEAU 提供详细建筑外壳和屋顶摄影数据的地方,会直接使用这些资源。生成的立面、窗户、阳台、女儿墙、屋顶设备和商店招牌带,会在近距离观察时增添细节。
地面使用五米分辨率的高程模型、航空摄影、道路表面、路缘、公园、树林和水体。道路标线包括车道线、斑马线、停车线、箭头、日本的 止まれ 标记和涂绘的限速标志。
动态城市生活
交通沿真实道路图行驶,靠左行驶,遵守单行道和信号灯规则,在路口排队,并使用高速公路和匝道。列车沿真实铁路线路运行。场景还包含电线杆、电线、街灯、交通信号灯、自动售货机、鸟居、车站月台、人行天桥、树木和停放的汽车。
时间、天气与反射
时间滑块或实时东京时钟控制太阳、月亮、天空、阴影和曝光。傍晚来临时,城市灯光会先亮起,随后在暮光中逐渐入夜。渲染器还支持体积云、大气透视、波纹水面、窗户反射、发光招牌、车头灯和东京塔照明。
鸟群可以在树上停留,也可以再次飞走。在富士宫场景中,可选的粗略地形背景会将富士山置于小镇后方,并包含航空影像和雪顶。
安装并运行项目
克隆代码仓库并使用 npm 安装依赖:
npm install
下载项目使用的 CC0 纹理。此步骤只需执行一次,并会在 public/textures/ 中存储约 14 MB 的数据:
node tools/assets/fetch_textures.mjs
接下来,获取某个区域的原始数据。以下示例会下载东京的源数据:
npm run fetch -- --area=tokyo
将下载的记录编译为浏览器可用的瓦片:
npm run compile -- --area=tokyo
最后,启动开发服务器:
npm run dev
在桌面浏览器中打开 http://localhost:5280。编译后的城市文件不会提交到代码仓库,因此每个区域都必须根据其源数据重新构建。
了解数据处理流程
该流程分为两个主要阶段。fetch 命令会将源文件下载到 data/raw/<area>/,并将航空影像下载到 public/ortho/<area>/。compile 命令会将这些记录转换为位于 public/tiles/<area>/ 下的流式加载瓦片。
使用以下命令为指定区域运行完整流程:
npm run fetch -- --area=shibuya
npm run compile -- --area=shibuya
原始下载文件可能很大,因为其中包含 PLATEAU 建筑摄影数据。README 列出的数据量约为:东京 3.6 GB、芝 3.0 GB、涩谷 1.3 GB、富士宫 0.2 GB。编译时间取决于区域大小,从几秒到几分钟不等。
检查并测试编译后的数据
使用以下命令创建区域的俯视预览:
npm run preview -- --area=tokyo
运行项目测试,检查瓦片往返处理和道路标线间距:
npm test
这些检查对于地形对齐尤其有用。道路表面、车道标线和符号会沿地形网格三角形进行拆分,使其保持在倾斜地面上方,并避免穿过瓦片边界下沉。
使用浏览器控件
- 拖动以平移。
- 按住鼠标右键拖动以旋转。
- 使用鼠标滚轮缩放。
- 使用
WASD移动。 - 移动时按住
Shift可加快移动速度。 - 按
N在白天和夜间之间切换。 - 点击建筑物以查看详情。
右上角的设置面板可用于切换区域,以及调整时间、交通、云层、光照和渲染质量。设置会保存在浏览器中。
使用 URL 参数打开场景
URL 参数适合分享特定视图或测试渲染配置。例如:
https://jeantimex.github.io/tokyo/?area=shibuya&time=18.5&traffic=0
支持的参数包括:
area=tokyo|shiba|shibuya|shinjuku|chiyoda|chuo|fujinomiya选择区域。time=18.5设置东京当地时间。night=1切换到夜间模式。cam=x,z,distance,azimuth,elevation设置摄像机。radius=900控制活动视图半径。traffic=0禁用交通。cars=600更改车辆数量。birds=150更改鸟群数量。clouds=0.25控制云层覆盖率。ortho=0禁用正交模式。
使用 URL 参数打开的页面不会覆盖浏览器中已保存的设置。
编译瓦片的工作方式
客户端使用以区域中心为原点的本地米制坐标系。x 轴指向东,y 轴指向上方,z 轴指向南方。瓦片为 256 米见方,并在 Web Worker 中进行网格化;网站会持续加载当前视图附近的瓦片。
一个已编译区域包含以下文件:
manifest.json存储原点、边界、瓦片列表、地形网格、桥面和署名信息。t_<x>_<z>.bin存储一个瓦片中的建筑物、地面、道路标线、物件、电线和标志。terrain.bin存储间距为五米的 Float32 地形高度网格。roads.json存储道路图、点位高度和信号灯路口。rails.json和structures.json存储铁路线路、站台、雨棚和人行天桥。backdrop.bin存储区域周边可选的粗略地形。
添加或配置区域
要添加另一个由 PLATEAU 覆盖的城市,请在 tools/pipeline/config.mjs 中定义一个条目。区域需要指定中心点和要处理的 PLATEAU 网格方格,也可以定义可选的背景尺寸和初始摄像机视图。
所有管线脚本都接受相同的区域选项:
npm run fetch -- --area=my-area
npm run compile -- --area=my-area
npm run preview -- --area=my-area
PLATEAU 文件通过 PLATEAU 数据目录 API 获取。管线会根据 gml:id 对记录去重;当东京数据集中的某个方格出现在多个区下时,这一点非常重要。不同城市的覆盖范围有所差异,因此当详细外壳、照片纹理或街道设施不可用时,客户端会回退到生成的细节。
高级技术细节
地形、道路和桥梁
PLATEAU、OpenStreetMap 和 GSI 数据会投影到同一个本地米制网格中。共享的五米高程网格可确保相邻瓦片在边缘处具有相同高度。编译期间会根据地形检查建筑物基座,并记录高度差。
缺少详细信息的道路轮廓会使用 OpenStreetMap 中心线拆分为车行道和人行道。桥梁和立交桥使用独立的剖面:街道桥梁会从一侧桥岸到另一侧桥岸进行调平,高速公路会按层抬升,匝道则进行坡度处理以实现正确连接。
光照和反射
路灯和车灯不会为每盏灯单独创建动态光源,而是绘制到光照贴图中。重叠光源会保留较亮的值,同时利用灯具高度数据避免立交桥下方的灯光照亮桥面。
水面反射会在水面下方再次绘制城市。波纹会使结果产生扭曲,云层反射则会采样天气贴图。窗玻璃会在颜色缓冲区的 alpha 通道中标记,并在屏幕空间反射阶段进行处理。
渲染和性能
渲染器使用 three.js 及 pmndrs 的 postprocessing 合成器。其效果包括 n8ao 环境光遮蔽、反射、大气、云层、泛光和色调映射。鸟群的位置在顶点着色器中计算,因此大量鸟群只需占用很少的 CPU 时间。
要提升性能,请保持适中的活动半径,减少车辆和鸟群数量,禁用云层,或在设置面板中降低渲染质量。默认的流式模式会加载附近的瓦片;整个城市选项会加载所有可用瓦片,可能需要多得多的内存。
部署已编译的网站
编译完要发布的区域后,运行:
npm run deploy
该命令会构建发布版本,并将 dist/ 作为单个提交强制推送到仓库 origin 的 gh-pages 分支。部署内容包括该机器上已编译的城市。README 估算,包含的七个区域约需 650 MB。
数据署名和许可
代码采用 MIT 许可证发布,但城市数据仍受其原始来源条款的约束。Project PLATEAU 提供 3D 城市模型、屋顶照片、桥梁和街道设施。GSI 提供高程数据和航空摄影。OpenStreetMap 贡献者根据 ODbL 提供道路、铁路和地点数据。Poly Haven 纹理采用 CC0 许可,树木使用 MIT 许可的 ez-tree,大气和云组件来自采用 MIT 许可的 three-geospatial。
结论
Procedural Tokyo 展示了公共地理空间数据集如何转化为内容丰富且动画效果生动的浏览器体验。要使用该项目,请安装依赖项,下载纹理和区域数据,将数据编译为图块,然后启动开发服务器。之后,可以通过 URL 参数、管线配置、测试和部署命令,以实用的方式探索和扩展该项目。
