
上面是 65,536 颗恒星的星系碰撞,GPU 逐对计算引力,2.25 倍速。它来自我刚发布的 N·Body 2.0:从物理引擎到渲染、界面、音乐,全部用 C# 写成,最后打包成一个 3MB 的 exe。
一年前立的 flag
2025 年 8 月,我写过一篇《当物理定律与高精度计算相遇:我的新开源项目 N-Body》。那篇文章立了不少 flag:要用 ODE45、Cash-Karp 这些数值方法把误差压下去,要接入我自己的高精度库 Sdcb.Arithmetic,要做性能基准,要跟 double 比精度......
当时的项目长这样:

一个 2D 窗口,几个小球拖着尾巴转圈。整个仓库 25 个文件、1562 行代码。立完 flag 之后,最后一次提交是 2025 年 8 月 10 日,改了 8 行,提交信息叫 flys 208。
然后就没有然后了。
Sdcb.Arithmetic 呢?翻遍 csproj,一个引用都没有。
站在 2026 年全面进入 AI 时代的今天回头看,这玩意儿就是人类 Slop。

交给 AI
10 月 19 日晚上 8 点多,我在 VS Code 里打开 GitHub Copilot,模型选 Claude Opus 5.5,大意就一句话:这个项目太原始了,给它来个脱胎换骨的重构,场景多加点,要一打开就让人"哇塞"。
它先把代码读了一遍,然后问了我两轮问题:渲染用 Direct3D 11 计算着色器,还是继续 Direct2D,还是干脆改成网页;2D 还是 3D;界面用 ImGui 还是自己画一套毛玻璃 HUD;要哪些场景;要不要音乐、要不要 Native AOT......顺便它还注意到我的显卡是 RTX 3080 Ti。
我基本都选了最难的那个:D3D11、全 3D、自绘 HUD、全部场景、程序化音乐、AOT、CI。
然后它就开干了。物理核心交给一个并行的子代理去重写,它自己同时写渲染器。
一打开就是"哇塞"

先看结果。35 个场景里随便挑 8 个,每个 2 秒:

依次是:十二星冠、飞蛾 I、Hénon 42、环双星行星(就是塔图因)、原行星盘、冷坍缩、旋涡星系、银河系与仙女座。
双击 exe 直接全屏,进入"自动巡游":镜头自己慢慢转,场景自己轮播,不碰键盘也能看半天。按 G 打开场景画廊,点一下就切过去:

星系碰撞
就是文章开头那张。两个盘状星系一共 65,536 颗恒星,每一步都在 GPU 上两两计算引力,一步就是 40 多亿对相互作用(65536² ≈ 4.3×10⁹)。没有用树算法,也没有近似,就是暴力 O(N²),一个分块的 HLSL 计算着色器搞定。在我的 3080 Ti 上能跑满 60 帧。
为了让两个星系真的能合并,而不是互相穿过去,它还加了暗物质晕和动力学摩擦。这一点我一开始都没想到。
三体周期解
三体问题一般没有解析解,但在一些特殊的初始条件下,三颗星会沿着固定的图案周而复始地运动。2013 年,两位塞尔维亚物理学家 Šuvakov 和 Dmitrašinović 一口气找到了 13 族新解,起名叫蝴蝶、飞蛾、蜻蜓、阴阳、大黄蜂......2.0 把这些都放了进来。这是"蝴蝶 I":

蝴蝶效应
这是我最喜欢的场景。屏幕上同时跑两份毕达哥拉斯三体系统,初始位置只差十亿分之一(10⁻⁹)。一开始两份完全重合,看起来只有一组白色的星;跑一阵子之后它们分道扬镳,一份变橙,一份变蓝,各走各的路:

右上角"相空间分离"那一行,就是两份系统之间的差距,从 10⁻⁹ 一路往上涨。
真实太阳系
八大行星的位置、质量、倾角,全部来自 JPL 的 J2000 轨道根数。单位是天文单位和年,画面上 1 秒约等于 4 年:

引力沙盒
按住 Shift 拖动鼠标,就能往恒星系里扔新天体,拖得越长,初速度越快;撞到一起的天体会合并:

不只是好看
当年那些 flag 里,我最在意的是精度。
2.0 的物理核心里有四种积分器:Leapfrog、Yoshida 4、RK4,以及自适应步长的 Dormand--Prince 5(4),也就是 MATLAB 里的 ODE45。按 I 可以现场切换。
右上角实时显示能量误差,下面还有一条能量漂移曲线。拿 8 字形轨道来说,默认的 Dormand--Prince 能量误差在 10⁻¹⁴ 量级;切到 RK4 跑一会儿,曲线往上跳了一截,误差变成 10⁻⁶ 量级:

另外还配了 xUnit 测试,检查能量、动量、角动量守恒,以及周期轨道转一圈之后能不能回到原点。
至于 Sdcb.Arithmetic 高精度......2.0 里依然一行都没用上。flag 屹立不倒。
一个纯 C# 的 3MB 宇宙
整个项目基于 .NET 10,C# 代码约 5000 行,HLSL 着色器不到 600 行,除此之外没有一行 C++。
物理核心 :Sdcb.NBody 是一个 net10.0 的普通类库,标记了 IsAotCompatible,不依赖任何图形 API,拿到 Linux 上也能跑。天体数据按 SoA(结构数组)存成几个 double[],算引力时用 Vector<double> 做 SIMD,天体多了再套一层 Parallel.For。核心循环大概长这样:
csharp
ReadOnlySpan<Vector<double>> PX = MemoryMarshal.Cast<double, Vector<double>>(px.AsSpan(0, n));
// ......PY、PZ、M 同理
for (int k = 0; k < PX.Length; ++k)
{
Vector<double> dx = PX[k] - vxi, dy = PY[k] - vyi, dz = PZ[k] - vzi;
Vector<double> r2 = dx * dx + dy * dy + dz * dz + veps;
Vector<double> inv = one / Vector.SquareRoot(r2);
Vector<double> s = M[k] * inv * inv * inv;
sx += dx * s; sy += dy * s; sz += dz * s;
}
一个 MemoryMarshal.Cast 就把 double[] 当成向量数组来用,没有 unsafe,也不用手写 AVX 指令。三体、太阳系这类小场景走这条 CPU 路线,全程双精度;星系那种几万颗星的场景才交给 GPU。
渲染与界面 :通过 Vortice 直接调 Direct3D 11,HLSL 着色器作为嵌入资源打进 exe,运行时编译;HUD 用 Direct2D 画毛玻璃;窗口是原生 Win32,没有 WinForms 也没有 WPF。
音乐:用 XAudio2 实时合成,仓库里一个音频文件都没有。
发布 :Native AOT 单文件。Release 里的 NBody-win-x64.exe 只有 3.3MB,不用装 .NET 运行时,双击就能跑。另外还有中英文界面切换、F12 截图、按显卡自动选择画质档位。
谁说 C# 只能写 CRUD?
那一晚
从晚上 8 点多开始,到 11 点半多提交,前后大约三个半小时。
这期间我基本就是个"甲方":偶尔运行一下,告诉它哪里报错了、启动时闪屏了、界面有点重叠,剩下的全是它自己搞定。中间它还给程序加了个截图参数,自己跑、自己截图、自己看图找问题,后来就不怎么需要我了。

最后的成果:77 个文件,新增 6396 行,删掉 1528 行。
账单
会话记录里,每一次模型调用的 token 数都有。我统计了一下:
| 项目 | 数值 |
|---|---|
| 模型调用 | 239 次 |
| 输入 token | 约 6924 万 |
| 输出 token | 约 35.3 万(其中推理 11.2 万) |
| 工具调用 | 302 次(PowerShell 121、编辑 61、看文件 54、新建文件 47) |
| 单次最大上下文 | 约 48.8 万 token |
| 纯模型耗时 | 约 69 分钟 |
输入差不多是输出的 200 倍。这是 Agent 干活的典型特征:每一轮都要把整个上下文重新喂一遍,真正写出来的代码反而没多少。
好在每一轮的上下文前缀几乎都和上一轮一样,绝大部分都能命中提示缓存。按 Anthropic 官方 API 价格折算,这一晚大约 25 美元。

我是用 GitHub Copilot 跑的,上面只是折算成 API 价格,给大家一个量级参考。25 美元、一个晚上,把一个烂尾了一年多的项目做成这样。
线上版:浏览器里也能玩
2.0 只能在 Windows 上跑。为了让手边没有 Windows 的朋友也能看看,第二天下午我又让它在我的网站上做了一个网页版:

网页版是用 TypeScript 和 WebGPU 写的(不支持 WebGPU 的浏览器会退回 WebGL2),35 个场景、HUD、音乐都有。它相当于照着 C# 版重写了一遍,代码没有开源,这里就不展开了。推荐用新版的 Chrome 或 Edge 打开。
下载
- 源码:https://github.com/sdcb/n-body(MIT)
- 下载:Release v2.0.0 里的
NBody-win-x64.exe,双击即可运行 - 要求:Windows 10 及以上 x64,显卡支持 Direct3D 11
默认全屏启动,Esc 退出;想在窗口里跑,加上 --windowed 参数。常用按键:
| 按键 | 功能 |
|---|---|
| 左键拖动 / 右键拖动 / 滚轮 | 旋转 / 平移 / 缩放 |
← → |
上一个 / 下一个场景 |
↑ ↓ |
加速 / 减速 |
G |
场景画廊 |
I |
切换积分器 |
Shift + 拖动 |
在沙盒里发射天体 |
Tab |
隐藏界面 |
L |
中文 / English |
H |
完整帮助 |
最后
一年前,我在那篇文章里把"AI 辅助开发"列为三块拼图之一。现在看来,当时的我还是太保守了。而 C# 和 .NET 这块拼图,从一开始就是够用的:SIMD、并行、直接调 Direct3D、AOT 出一个 3MB 的 exe,这些它早就都能做,只是以前没人愿意花这么多时间去写。

交流
感谢阅读到这里,如果觉得 N·Body 好玩,欢迎去 GitHub 点个 Star ,也欢迎评论 和点赞,这是我持续创作的动力!
欢迎关注微信公众号 .NET骚操作 ,或者扫码加入 .NET骚操作2群 微信交流群:

(如果微信群二维码过期,请加入 .NET骚操作交流QQ群 :495782587)