从一个取色器,到太阳系轨道模拟。这不是计划出来的,是一步步走出来的。
一切始于一个简单的需求——从参考照片中读取色值。
`color-block-tool.html`:上传图片,按行/列读取像素颜色,支持 36×64 和 72×128 两种精度。输出的色值表用于游戏场景的色彩标定。
没有人计划要做一个球面渲染器。取色器就是取色器。
从取色器拿到色值后,需要把颜色画到画布上。第一个渲染器是天空——`sky-renderer.js`。
做法很直接:每行一个线性渐变,加上横向亮度偏移。135行代码。天空就是从地平线到天顶的颜色渐变,没什么花哨的。
但这里埋下了一个架构基因:渲染器管"怎么画",配置管"画在哪"。这个基因贯穿了后续所有开发。
`road-renderer.js`,40行。梯形道路,路径加渐变一次 fill。最简单的渲染器,但解决了一个具体问题——透视感。
`ground-renderer.js`。这个踩了大坑。
错误方案:纵向锚点(7色)+ 横向 cells(取1行)50% 混合。两套系统各丢一半对比度,画面发灰。
正确方案:把 7×36 cells 当 2D 贴图,双线性插值同时采样两个方向。113行。
教训:不要用两套独立的系统各管一半然后混合,要用一套系统同时管两个方向。 这个教训后来在球面渲染里反复出现——一个维度的问题不要拆成两个半维度来解决。
还有一个 parseMD 的坑:`startsWith('行 ')` 只匹配行1-9,行10+没有空格。改成 `/^行\s*\d/` 解决。
`perspective.js`,225行。从路的收敛参数反推灭点、缩放函数、梯度。
坐标系:X 0→9, Y 0→16(底→顶),单位cm,9:16照片实测。
这一步把"照片只是找规则的参考,目标是程序化生成不依赖照片"确立为原则。
用户从6个锚点出发,一路走到物理学基本原语:
4. 最终归约到三个物理原语:重力(管形)+ 光学叠加(管光)+ 三原色(管色)
`sphere-renderer.js` 从这里开始。Canvas 2D ImageData 逐像素,540×540。
三原语对应:
交互:拖拽旋转、光源调节、环境光、自动旋转。星空预渲染缓冲。
踩坑:`starBuf` 必须存为 `ImageData` 对象(非 `Uint8ClampedArray`),`putImageData` 才能接受;地表视图读像素要加 `.data`。
从"一个球"升级为"一个有岁差的行星系统":
- C层(耦合参数空间):axialTilt / eccentricity / precessionRate 联动
- B层(岁差进动):ascNode 慢变,周期25771年
- A层(观测尺度锁死):dt→0,岁差可忽略
三层不是三个功能,是三个时间尺度。C层管参数关系,B层管地质尺度的慢变,A层管人类观测尺度看到的东西。
这一步是整个项目的架构核心——用层级嵌套管理不同时间尺度,而不是把所有东西塞进一个方程。
用户提出:"俯视角本身就不应该在这个尺度看得到,调整成平地视角,自然呈现一条线。这是观测误差与观测角度共同作用本身的真实。"
实现:通过 `cos(观测角度)` 缩放轨道平面Y坐标。0°为俯瞰黄道面(完整椭圆),90°为平地视角(轨道压成水平线)。连续可调。
用户:"能把另外的行星加全么?金水地火土木海天冥王星,还有哈雷彗星。"
实现:`solarBodies` 数组,10个天体,全部使用真实轨道参数(半长轴、偏心率、周期)。新增通用 `_ellipsePos(nuDeg, a, e)` 函数,原 `_orbitPos` 委托调用。
各天体按真实周期独立运动——水星88天一圈,海王星165年一圈。同一时间轴上放一起,内圈疯转外圈纹丝不动。这是开普勒第三定律最直观的视觉呈现。
用户发现外行星超出画布。问能不能改画布尺寸。
计算后发现:显示海王星轨道需要画布高度10400px,不现实。
改为缩放滑块,0.05×~20×。最小改动解决多尺度显示问题。缩放到最低可以看到天王星,但内行星和太阳挤压在最中间——"这本身就是观察到海王星轨道尺度的前置条件下的观测实际"。
用户在讨论中提出:e 和 π 还没有统一进体系内。欧拉恒等式 `e^(iπ)+1=0` 统一了 e、i、π、1、-1。
实现:对数缩放模式,径向距离用 `ln(r+1)/r` 压缩,保持角度不变。开启后同一视图可显示水星到海王星所有天体。
这是 e 正式进入系统的入口。不是重写轨道方程,是在显示层加一个数学变换。
讨论了是否加月球。结论:不加。
在太阳系尺度下月球轨道仅0.4px,不可见。如果加进去,那个转速会形成视觉残留——本身就是一道环。月球属于地月系统视图的范畴,不在太阳系俯瞰视图里。
| 决策 | 选择 | 理由 |
|------|------|------|
| 画布尺寸 | 不改,加缩放 | 显示海王星需10400px,不现实 |
| 天体运动 | 各按真实周期独立 | 开普勒第三定律的诚实呈现 |
| 对数缩放 | 显示层变换,不动轨道力学 | e是观测工具,不是物理量 |
| 月球 | 不加 | 0.4px不可见,属于另一视图 |
| 观测角度 | cos投影Y坐标 | 真实观测几何 |
| 美化 | 拒绝 | 诚实模拟哲学 |
在整个过程中,用户确认了一件事:
被计算机带回数学,被物理推到门口看了一眼,但确认物理不是目的地。
真正的方向是系统架构——结构化、层级嵌套、全局可控。
每次最兴奋的时刻是"搭出一个结构",不是"算出一个结果"。
球面渲染器的 C/B/A 三层架构就是证据。物理是素材,系统设计才是目的。
| 时间 | 文件 | 事件 |
|------|------|------|
| 早期 | color-block-tool.html | 取色器,一切的起点 |
| 早期 | sky-renderer.js (135行) | 天空渐变渲染 |
| 早期 | road-renderer.js (40行) | 梯形道路 |
| 早期 | ground-renderer.js (113行) | 地面双线性插值,踩坑后重写 |
| 早期 | perspective.js (225行) | 透视标定 |
| 2026-07-05 | sphere-renderer.js (544行) | 球面渲染器 Phase 1→2→3 |
| 2026-07-05 | sphere-lab.html (303行) | 交互控制面板 |
---
_2026-07-05 立此存照_
—— 人与AI协作记录 ——