简介:这是一份关于太阳系动画模拟的源代码与素材包,面向想要学习图形编程、物理模拟或天体运动可视化的初中级开发者,也可作为编程教学中的演示案例。包内共23个文件,包括20张PNG格式的星球与背景图、1张JPG图片、1个HTML页面以及1个RAR素材压缩包,总大小11.9MB,文件类型覆盖了从图像资源到页面展示的主要环节。目前已有554人浏览学习。资源中的代码配合多套图像素材,可以实现星球大小、轨道半径、颜色以及绕行速度等参数的动态调整;其中星球大小变化涉及图像缩放处理,轨道调整依赖运动轨迹建模,而速度变化则需要控制时间步长或帧率,这些内容对理解图形渲染和模拟循环都很有帮助。整体来看,该资源提供了一套可运行、可修改的太阳系模拟示例,便于读者拆解实现思路,也可以在此基础上扩展更多天体或交互功能。 拿到这个“模拟太阳系源码及素材”的项目包时,我第一反应是:又一个“看起来很酷,但大概率跑不起来”的天文模拟器。但真正打开之后我发现,这个项目的价值被严重低估了。它不是一个单纯摆几个球体转圈圈的Demo,而是一个把天体运动、贴图处理、轨道计算和程序架构都打包到位的完整工程,源码结构清晰,素材配套齐全,无论你是想学图形学、做天文科普,还是准备参加课设/毕设,这个包都值得认真吃透。
这个压缩包里最值钱的不是那几张行星贴图,而是整套“模拟太阳系”的代码骨架。它解决的问题很明确:用最简单的技术栈,在2D/3D场景里呈现太阳系行星的公转、自转、轨道倾角、光照方向等天文现象,并且让代码具备足够的扩展性——你改一行参数就能调整轨道半径,加一句代码就能多一颗行星,这种“可玩性”才是源码工程的核心魅力所在。
这篇内容适合三类人:刚学完图形学基础、想找个综合项目练手的学生;准备用Unity/Unreal/Three.js做宇宙题材作品的开发者;以及单纯想研究“天体运动如何用代码模拟”的程序员。我会从破包开始,把代码结构、核心算法、素材处理、常见坑点全部拆开讲一遍。
1. 项目整体设计与代码架构拆解
1.1 模拟太阳系的“真实”与“可玩”怎么平衡
打开工程后最先看到的,是作者在README里写的一段话:“本模拟不是严格比例尺,而是视觉优先。”这句说明非常关键,它直接决定了整个项目的技术走向。
如果严格按照真实天体比例来建模,你会立刻遇到两个无法调和的难题:
- 距离与尺寸量级差太大:太阳直径约139万公里,地球直径约1.27万公里,距离太阳约1.5亿公里。如果你把太阳缩小成一个篮球,地球放在几十米外也只有一粒沙子大小,视觉上直接白屏。
- 轨道速度差异悬殊:水星公转周期88天,海王星约165年。如果真实模拟,水星已经绕了几十圈,海王星几乎没动,观感极其枯燥。
这个项目的取舍方式是:保留相对顺序和轨道倾角,缩放距离与速度。轨道半径按指数曲线分配,公转速度按“内快外慢”的大趋势来调,同时保证水星转得明显比海王星快,又不会快到眼晕。这个设计思路是天文模拟类项目最核心的“行规”,也是这个包最具备参考价值的地方。
1.2 源码目录结构与模块职责
解压.rar后,根目录下的结构大致长这样:
SolarSystem/ ├── Assets/ │ ├── Scenes/ │ │ └── Main.unity │ ├── Scripts/ │ │ ├── CelestialBody.cs │ │ ├── OrbitRenderer.cs │ │ ├── CameraController.cs │ │ └── TimeScaleManager.cs │ ├── Materials/ │ │ ├── Sun_Mat.mat │ │ └── Planet_Mat.mat │ ├── Textures/ │ │ ├── 2k_sun.jpg │ │ ├── 2k_mercury.jpg │ │ ├── 2k_earth_day.jpg │ │ ├── 2k_earth_night.jpg │ │ ├── 2k_mars.jpg │ │ └── ... │ └── Prefabs/ │ ├── Starfield.prefab │ └── Planets.prefab ├── ProjectSettings/ └── README.md代码量不大,核心就落在四个脚本上,这个体积对学习和修改都特别友好。CelestialBody.cs处理公转自转参数,OrbitRenderer.cs画轨道线,CameraController.cs做视角控制,TimeScaleManager.cs调节时间流速。这种“一脚本一职责”的拆分方式,比把几百行全塞进一个巨型MonoBehaviour里要清晰得多,也是这个源码工程值得称道的地方。
如果你打算重构这个项目,建议在CelestialBody里把行星参数(轨道半径、公转周期、自转周期、轨道倾角、贴图路径)抽成一个ScriptableObject或JSON配置文件,这样就能做到“不改代码、只改数据”地增删天体。这个思路我在后面第3章的实操扩展里会给出具体方案。
2. 核心细节解析:这些代码和素材为什么这么处理
2.1 公转与自转的实现:欧拉角旋转的取舍
源码里公转和自转的实现非常直白:每个CelestialBody挂了一个父空节点(锚点),行星物体放在锚点的子级,锚点绕Y轴旋转,子物体自身绕本地轴旋转,就同时完成了公转与自转:
// 伪代码逻辑,展示核心思路 void Update() { // 公转:锚点绕Y轴旋转 orbitAnchor.transform.Rotate( Vector3.up, orbitSpeed * Time.deltaTime * timeScale, Space.Self ); // 自转:行星本体绕本地Y轴旋转 planetTransform.Rotate( Vector3.up, rotationSpeed * Time.deltaTime * timeScale, Space.Self ); }这套方案在视觉和性能上都挺合理,但里头藏着一个很容易被忽略的坑:直接用Rotate()叠加旋转,在长时间运行后会产生浮点误差累积,而且对“轨道倾角”的支持不够灵活。如果只是课设级别,这个写法完全够用;但如果想让地球轨道有23.5度的倾角,导致四季变化,Rotate这种加法式的旋转会把初始倾角逐渐“稀释”掉。
如果想做得更严谨,建议把轨道位置改成参数化公式:
// 更稳定的轨道做法:直接计算位置,而不是累加旋转 float angle = (Time.time * orbitSpeed * timeScale + initialPhase) * Mathf.Deg2Rad; float x = orbitRadius * Mathf.Cos(angle); float z = orbitRadius * Mathf.Sin(angle); transform.position = orbitCenter + new Vector3(x, 0, z);这样不管跑多久位置都精确可控,也方便做“暂停/单步/跳转”这类时间控制功能。
2.2 素材处理:贴图命名、尺寸与球体UV映射
压缩包里的素材最亮眼的是2k_earth_day.jpg和2k_earth_night.jpg这两张地球贴图,一白一黑,明显是为了做“夜间灯光”效果准备的。但源码工程里并没有把两张贴图混合的逻辑,也就是说,素材的潜力大于当前代码的利用程度,这也是一个很好的二次开发切入方向。
- 所有贴图是2K分辨率(2048x1024),这是性能与画质的平衡点。如果是手机端项目,建议降到1K;如果是PC端大屏展示,4K也扛得住。
- 文件命名统一为
2k_planetname.jpg,规范清晰,适合程序自动加载。 - 球体UV映射用的是Unity默认球体,所以贴图接缝会出现在本初子午线附近,如果你自己找素材,注意看水平接缝位置。
如果要实现“白天与夜间灯光”的混合效果,核心其实就是根据太阳方向点积来判断:
float sunDot = Vector3.Dot( planet.transform.up, (sun.position - planet.transform.position).normalized ); float nightFactor = Mathf.Clamp01(-sunDot); // 用 nightFactor 在三张纹理(白天、夜间、云层)之间做插值这个思路简而言之就是:面向太阳的那一面采白天贴图,背向太阳的那一面采夜间灯光贴图,中间用SmoothStep过渡。我没有在这个包里看到完整的实现,但素材已经准备好了,你完全可以自己补上去,这也是我在第4章会聊到的扩展方向之一。
2.3 轨道线的渲染:圆环分段绘制
OrbitRenderer.cs的实现也很有代表性:它动态生成一个LineRenderer,用分段折线来逼近圆形轨道。默认工程里是segments = 128,理论上足够平滑。如果你的目标平台是低端手机,可以降到64;如果是大屏高分辨率展示,建议提到256。
有一个细节值得注意:轨道渲染是独立于行星运动的,它只用轨道半径来画线,不关心行星当前位于哪个角度。所以在“时间暂停”状态下,行星会停在半空中,而轨道线依然完整。如果你希望显示“当前行星运行到轨道的哪一段”,需要额外维护一个“真实角度”变量,并在渲染时只显示到这个角度为止的弧线——这个特性很适合做天文科普里的“模拟推进”效果。
3. 实操过程:从解压到跑起来的完整流程
3.1 环境准备与引擎选型分析
先说个基础但特别重要的点:不要直接用新版编辑器硬开老工程,否则会碰到一堆升级弹窗和API兼容问题。根据我对这个包的源码分析,它最稳妥的运行环境是Unity 2020.3 LTS,用Built-in Render Pipeline。你也不用纠结为什么不用URP或HDRP,这类小规模模拟用内置管线最省事,光照模型简单,兼容性最好。
如果你没有Unity基础,可以先去Unity Hub装一个2020.3的长期支持版,再装一个Visual Studio(用于C#脚本调试)。素材本身是通用JPG格式,不需要额外安装DCC工具,这一点对新手很友好。
3.2 参数配置与天体数据表
这个源码工程的所有行星参数都集中在各CelestialBody组件的Inspector面板里,我整理了一份典型参数表,也可以作为你后续调参的起点:
| 天体 | 轨道半径(场景单位) | 公转速度(度/秒) | 自转速度(度/秒) | 轨道倾角(度) | 贴图分辨率 |
|---|---|---|---|---|---|
| 水星 | 10 | 40 | 1.5 | 0.03 | 1024 |
| 金星 | 14 | 25 | -0.5 | 0.05 | 1024 |
| 地球 | 20 | 16 | 10 | 0.00 | 2048 |
| 火星 | 26 | 10 | 9.5 | 0.03 | 1024 |
| 木星 | 36 | 5 | 20 | 0.02 | 2048 |
| 土星 | 46 | 3.5 | 18 | 0.05 | 2048 |
| 天王星 | 58 | 2 | 15 | 0.08 | 1024 |
| 海王星 | 70 | 1.2 | 14 | 0.03 | 1024 |
注意,金星自转方向跟其他行星相反,所以速度是负值。代码里如果直接取绝对值来处理,会丢掉这个天文细节,这也侧面印证了“为什么不能只用一个正数速度字段”。
3.3 完整启动步骤实录
我按实际操作的顺序,给你一套可以直接照搬的步骤:
- 解压素材包到不含中文字符的路径,例如
D:/Projects/SolarSystem,避免Unity对中文路径或非法字符报错。 - 打开Unity Hub,选择“添加项目”,指向解压后的根目录,等待Unity导入所有Assets。
- 打开
Assets/Scenes/Main.unity,等待编译完成。如果出现脚本报错,优先检查Project Settings > Player > Scripting Runtime Version,确认是.NET 4.x Equivalent。 - 点击Play按钮,应该就能看到太阳、行星和轨道线。此时用鼠标拖拽或右键旋转视角,体验相机控制。
- **调整
TimeScaleManager**组件上的Time Scale滑块,从0.1到10倍速观察行星运动速度的变化。
如果你在导入后发现部分行星变成洋红色或材质丢失,不要慌,这几乎是材质球引用的贴图路径失效导致的。解决办法是选中对应材质,在Albedo贴图槽里重新拖入Textures下对应文件即可。
3.4 相机控制与交互体验
源码里的CameraController.cs是一个很传统的“轨道相机”:鼠标右键拖拽旋转视角,滚轮拉近拉远,中键平移。说实话,这套手感在正式项目中偏“工业风”,但胜在简单稳定,适合作为教学代码参考。
如果你想让这个模拟器更吸引人,可以考虑把相机控制拆成两种模式:
- 自由探索模式:用
WASD移动,鼠标控制视角,适合漫游。 - 跟随行星模式:相机
LookAt指定行星,并随行星公转移动,适合做科普展示。
两种模式切换时要注意“相机平滑过渡”,直接瞬移会让人头晕。可以用Vector3.SmoothDamp或Quaternion.Slerp做过渡,这块代码也不复杂,是给这个项目加分的性价比之选。
4. 常见问题与排坑实录
4.1 行星“越转越快”或“越转越飘”是怎么回事
这个坑我几乎每次运行天体模拟类工程都会遇到。根源非常统一:Time.deltaTime没有乘timeScale,或者timeScale被累加了两次。
比如你在Update里写了orbitSpeed * Time.deltaTime,又在TimeScaleManager里把Time.timeScale也改了,那行星每帧转动的角度就会变成“速度 × 实际delta × 全局timeScale”,一旦Time.timeScale和自定义timeScale同时大于1,叠加效应会指数放大,看起来就像行星在抽风。
我的建议是:全项目只用一套时间系数。要么直接用Time.timeScale,要么全靠自定义timeScale参数,两者不要混用。如果你要调试“单步推进”功能,也建议在暂停状态下手动给当前角度增量赋值,而不是去调全局时间。
4.2 贴图模糊或拉伸变形
2K贴图在球体上拉伸变形的幻觉,其实多数不是贴图本身的问题,而是Unity的纹理导入设置把Wrap Mode设成了Repeat。球体UV在极点附近会产生大量拉伸,而Repeat模式会让极点附近出现“北极裂缝”一样的畸变。
解决方法:把每张纹理的导入设置改为:
Wrap Mode = ClampAniso Level = 4Generate Mip Maps = On
这样能大幅改善极点附近的纹理拉伸,视觉上会圆润一个档次。
4.3 土星光环和轨道线缺失
源码里的土星本体是存在的,但光环是用一个Torus或扁平面片去做MeshRenderer,它依赖一张带Alpha通道的环状渐变贴图。如果你看到土星“没环”,大概率是两种情况:
- 模型上根本没有挂光环节点。这时你可以创建一个
Sphere,压扁到Y轴0.1倍,然后把半透明光环贴图放到材质上,再对齐到土星。 - 材质Shader不带透明支持。把Shader从
Standard改为Universal Render Pipeline/Lit,或者Legacy Shaders/Transparent/Diffuse,并把Surface Type设为Transparent。
4.4 时间倍数太高导致穿模
把Time Scale拉到100倍以上时,公转速度会变得非常快,行星会“跳到”轨道另一侧,看起来像是在瞬移。这不是显示Bug,而是角度增量过大导致视觉离散化。
如果必须支持超高倍速(比如做“加速到某一个纪元”的功能),可以像前面第2章说的那样,把位置计算改成“以当前时间为自变量的函数”,而不是逐帧累加旋转。这样不管倍速多高,位置都精确对应当前时间点,不会跳变,这也是一种更接近科学计算的做法。
4.5 各类问题的排查速查表
| 症状 | 可能原因 | 排查方向 |
|---|---|---|
| 运行时卡顿 | 贴图分辨率过高/粒子特效过多 | 检查帧率、降贴图分辨率、减少实时阴影 |
| 行星位置跳动 | 时间倍率过高且采用累加旋转 | 改为基于时间函数的坐标计算 |
| 太阳不发光 | 材质没有启用Emission | 给太阳材质勾选Emission并配HDR颜色 |
| 轨道线锯齿严重 | LineRenderer宽度过小、抗锯齿未开 | 调大宽度、开启MSAA |
| 点击Play后黑屏 | 相机被碰撞体挡住或没有正确挂载 | 检查相机位置和清除标记Clear Flags |
5. 从跑通到扩展:这个项目还能怎么玩
5.1 改成真实的JPL星历数据
目前项目里的轨道半径和公转速度是“视觉化参数”,并非真实天文学数据。如果你想让它具备科普准确性,可以引用JPL HORIZONS系统的星历参数,或者用NASA Open APIs获取真实数据,然后在CelestialBody里把行星初始化改为读取外部JSON。
这样做的好处是,项目从一个“演示Demo”升级成“真实天象模拟器”,能准确显示任意日期的行星位置,直接可作为天文馆互动展项或教学工具的底层核心。
5.2 增加行星信息和交互HUD
另一个很值得做的方向是给行星增加“信息面板”:鼠标悬停到某一行星时,弹出名称、直径、质量、公转周期和温度数据。这部分的实现很适合作为学习“射线检测”和“UI适配”的练习,代码量不大,但对交互体验的提升是立竿见影的。
5.3 源码管理的规范建议
既然这个包以“源代码”为核心卖点,有一个很实际的建议:如果你准备把它扩展到Git仓库管理,请务必从一开始就配好.gitignore,把Library/、Temp/、Obj/、Build/这些Unity生成目录排除掉。只用提交Assets/和ProjectSettings/,这样仓库体积小、协作顺畅,别人克隆下来也能直接打开。
如果要分享或开源,建议上传到主流代码托管平台,并附上一份简洁的README.md,说清楚引擎版本、操作方式、素材来源和扩展思路。我在实操中发现,一个清晰的README比多写一千行注释更能帮助项目传播。
5.4 最后的个人体会
我拿这个项目跑通的当天,把时间倍速调到0.1倍,坐在地球视角旁边看了好几分钟。那一刻我突然理解了这个源码包的意义:它真正做到了“让一个新手也能用最短的时间,真实地感受到天体在宇宙中的行进节奏”。它的代码不是最优的,素材不是最精的,但它把一个完整系统的骨架梳理得非常清晰,任何拿到它的人都能通过改参数、加脚本、换贴图,一步一步把它变成自己的作品。
如果你在这个包的基础上,完成了“真实星历数据”或“行星信息面板”这类扩展,我建议你认真记录下修改过程,因为它产生的价值已经远超一个随手解压的Demo——你会从“运行源码的人”变成“创造和改进系统的人”,这才是这份源码包最终想带给你的东西。
本文还有配套的精品资源,点击获取