Files
planet/docs/earth/earth-celestial-background-plan.md
2026-04-20 15:14:53 +08:00

10 KiB
Raw Blame History

Earth 天球背景与日月位置实施方案

目标

为 Earth 大屏增加一套真正可用的天文背景层,覆盖三件事:

  1. 用真实天球背景替换当前随机星点
  2. 在当前时间下显示太阳与月亮的相对位置
  3. 让太阳方向同时驱动地球受光,形成更可信的昼夜关系

本方案优先追求:

  • 与当前 Three.js Earth 架构兼容
  • 风险可控
  • 先落地一版真实感明显提升的 V1
  • 为后续更严格的天文参考系升级预留余地

当前现状

当前 Earth 的基础条件已经具备:

这意味着:

  • 不需要重写 Earth
  • 可以在现有 scene/world 层新增一个 celestial layer
  • 第一阶段不必拆 Earth / satellite / cable 的参考系

总体策略

采用“两层现实”设计:

1. 世界层world-space celestial layer

用于放置:

  • 天球背景
  • 太阳
  • 月亮
  • 太阳光方向

这些对象不挂在 earthObj 上,而是直接放在 scene 中。

2. 地球层earth-fixed layer

继续保持当前结构:

  • 海缆
  • 登陆点
  • 卫星点与轨迹
  • BGP 覆盖
  • 地球纹理、云层、地形

这些对象继续挂在 earthObj 下,不打断现有交互。

为什么先这样做

当前用户交互是“拖动地球本体”,而不是“移动相机绕惯性系观测”。
如果现在直接做严格惯性参考系改造,会同时影响:

  • earthObj.rotation
  • 卫星轨迹与锁定逻辑
  • 海缆与登陆点附着关系
  • resetView / autoRotate / hover / click 等交互链路

所以第一阶段只做:

  • 真正的天空
  • 真正的日月方向
  • 不碰现有 Earth 附着对象的语义

推荐技术选型

天文计算库

推荐:

原因:

  • 有 JavaScript 版本
  • 支持 Sun / Moon 的矢量与坐标变换
  • 精度、可扩展性都比轻量太阳高度角库更适合本项目
  • 后续若要加行星、月相、黄道、赤道网,也能继续沿用

不作为主选的库:

原因:

  • 更偏本地观察者视角的太阳/月亮高度角
  • 用于“地面日出日落”很好
  • 但不如 Astronomy Engine 适合做真实天球与后续空间参考系扩展

Three.js 表现层

推荐组合:

  • 天球:内翻球壳 + 星图纹理
  • 太阳:THREE.Sprite
  • 月亮:THREE.Sprite 或小型 THREE.Mesh
  • 太阳光:THREE.DirectionalLight

参考:

分阶段实施

Phase 1真实天球背景

目标

用真实全天星图替换当前随机星点背景。

做法

  1. 新增一张全天星图纹理

建议路径:

  • frontend/public/earth/assets/celestial/starmap_equatorial_4k.jpg

纹理要求:

  • 等距矩形投影
  • 赤经/赤纬坐标展开
  • 无地平线、无地景遮挡
  • 尽量深色、弱干扰,适合大屏 HUD 叠加
  1. 新增天球球壳

新增模块:

建议接口:

export function initCelestialLayer(scene)
export function updateCelestialLayer(date, camera, earth)
export function disposeCelestialLayer()
  1. 实现一个大半径内翻球体

建议参数:

  • 半径:600 ~ 900
  • 材质:MeshBasicMaterial
  • side: THREE.BackSide
  • 不受场景光照影响
  • 始终围绕场景中心

验收标准

  • 初始加载后背景不再是随机星点
  • 旋转地球时,背景保持为稳定天球而不是跟地球一起转
  • 不明显干扰海缆/卫星/BGP 的前景识别

Phase 2太阳与月亮真实位置

目标

在当前 UTC 时间下,计算太阳与月亮在天球中的方向,并显示出来。

做法

  1. celestial.js 内封装天体位置计算

建议函数:

function getSunDirection(date)
function getMoonDirection(date)

输出统一为 world-space THREE.Vector3

  1. 太阳显示
  • 一个暖色发光 sprite
  • 比月亮更大、更亮
  • 可选添加柔和 halo
  1. 月亮显示
  • 一个较小 sprite 或 sphere
  • 灰白偏冷色
  • 后续 Phase 3 再做月相
  1. 更新频率

不要每帧重新做完整天文计算,建议:

  • 每 30 秒或 60 秒重算一次真实位置
  • 渲染帧内做平滑过渡

验收标准

  • 页面可见太阳与月亮两个对象
  • 时间变化时位置会更新
  • 日月不会跟随地球局部旋转而错误附着

Phase 3太阳驱动地球受光

目标

让地球光照方向与太阳方向一致,不再使用写死的固定主光。

做法

  1. 替换或接管当前主定向光

当前 frontend/public/earth/js/main.jsaddLights() 里用了固定方向的 DirectionalLight

建议改为:

  • 保留环境补光
  • 主太阳光方向由 sunDirection 决定
  1. 太阳光参数建议
  • DirectionalLight 颜色偏暖白
  • 强度略高于当前主光
  • 保留一个弱背光作为氛围补偿,避免背面过死黑
  1. 先不做物理级大气散射

第一版只要求:

  • 亮面与暗面方向真实
  • 云层和大气仍保持当前风格

验收标准

  • 地球明暗面会随太阳方向改变
  • 太阳 sprite 和地球亮面方向一致
  • 不破坏现有海缆、卫星、BGP 的可见性

Phase 4月相与天文细节增强

目标

在日月真实位置基础上增加更强的“天文可信度”。

可选项

  1. 月相
  • 根据日月夹角计算 illuminated fraction
  • 用月相纹理或 shader 表达盈亏
  1. 赤道/黄道辅助线
  • 可作为开发调试层,不默认显示
  1. 太阳 terminator 增强
  • 给地球夜面加入更自然的 night tint
  • 未来可叠加城市夜光纹理
  1. 天文时间入口
  • 设置中加入“当前时刻 / 指定时刻 / 加速时间”模式

验收标准

  • 月亮不再只是一个静态圆点
  • 后续扩展行星或观测模式时无需推倒重来

Phase 5严格参考系升级可选不作为 V1 必做)

目标

把 Earth 从“用户旋转球体”升级为“真实地球姿态 + 用户观察姿态”的双层模型。

需要处理的问题

  • 地球自转角与 UTC 的一致性
  • 赤道坐标系、地固坐标系、相机交互层分离
  • 卫星轨道显示与 Earth 旋转同步关系
  • resetView 和 autoRotate 的语义重定

风险

这一步会影响:

因此不建议与 V1 同时推进。

代码改造清单

1. 新增文件

职责:

  • 管理天球背景、太阳、月亮
  • 对外暴露 init/update/dispose

2. 修改 constants.js

文件:

新增:

export const CELESTIAL_CONFIG = {
  sphereRadius: 800,
  updateIntervalMs: 60000,
  sunSpriteScale: 28,
  moonSpriteScale: 16,
  sunLightIntensity: 1.25,
  ambientIntensity: 0.28,
  backLightIntensity: 0.18,
};

3. 修改 main.js

文件:

主要改动:

  1. init() 中:
    • 初始化 celestial layer
  2. addLights() 中:
    • 把固定太阳光改成可更新的 celestial sun light
  3. animate() 中:
    • 每帧调 updateCelestialLayer()
  4. destroy() 中:
    • 清理 celestial 资源

4. 修改 earth.js

文件:

主要改动:

  • createStars() 逐步退役
  • 第一阶段可先保留作为 fallback
  • 当真实星图加载成功后,不再显示随机星点

5. 新增资源

目录建议:

  • frontend/public/earth/assets/celestial/

建议至少包含:

  • starmap_equatorial_4k.jpg
  • sun_glow.png
  • moon_albedo_2k.jpg

数据流设计

flowchart TD
    A["main.js:init()"] --> B["initCelestialLayer(scene)"]
    B --> C["创建天球球壳"]
    B --> D["创建太阳 sprite + 主定向光"]
    B --> E["创建月亮 sprite"]

    F["animate()"] --> G["updateCelestialLayer(now, camera, earth)"]
    G --> H["Astronomy Engine 计算 Sun/Moon 方向"]
    H --> I["更新 sun sprite / moon sprite 位置"]
    H --> J["更新太阳 DirectionalLight 方向"]
    J --> K["地球昼夜方向变化"]

风险与注意事项

1. 星图投影方向容易反

这会表现为:

  • 星图左右镜像
  • 赤经方向颠倒
  • 日月位置和背景对不上

建议:

  • 先做一个开发调试模式
  • 显示赤经/赤纬参考点,快速校正纹理朝向

2. 不要让天球跟随 Earth 旋转

天球背景和日月必须属于 scene/world而不是 earthObj

3. 不要每帧做重型天文计算

真实位置更新应节流,否则会浪费 CPU。

4. 月亮先求“方向正确”,再求“月相精致”

月相属于第二步优化,不应阻塞 V1 上线。

推荐实施顺序

  1. 新建 celestial.js
  2. 用星图球壳替换随机星点
  3. 接入 Astronomy Engine
  4. 加太阳/月亮 sprite
  5. 用太阳方向驱动主光
  6. 再决定要不要做月相和更严格参考系

最终建议

对于当前 Planet Earth最稳妥的方案是

  • 先做真实天球背景
  • 再做真实太阳/月亮方向
  • 再让太阳驱动地球受光
  • 暂时不做 Earth 参考系重构

这样可以在不破坏现有 Earth 交互和图层系统的前提下,显著提升空间感、真实感和演示说服力。