
简介一套基于Unity3D引擎实现的太阳系三维模拟项目完整工程面向游戏开发者、天文爱好者以及需要学习Unity物理模拟、光照系统与粒子特效的初中级开发者也适合作为课程设计与毕业设计的参考。项目使用C#脚本实现牛顿万有引力定律与开普勒轨道计算通过质量、距离和速度等参数驱动行星沿椭圆轨道运转内置光照系统模拟日光强度与角度变化粒子系统生成行星轨道的发光尾迹三个摄像头分别提供地球视角、行星特写与太空俯瞰两个按钮可控制时间加速或减速以观察合相、冲日等长期天体现象。压缩包共2000个文件大小约91.19MB以C#脚本733个、PNG纹理315个、材质50个、Markdown文档140个以及Unity场景资源、预制体为主另含PSD源文件、DLL库和JSON配置目录结构完整清晰。已有908人学习或下载可直接打开工程查看场景与运行效果适合二次开发也能帮助理解天体运动模拟、时间控制和Unity项目的整体组织方式。1. 一个太阳系zip包为什么值得你花一小时拆开拿到“Unity3D太阳系标准.zip”这种命名第一反应可能是“又一个上课交作业的demo”。但如果你真把它解压开会发现在这个几十兆的包里藏着一条从Transform旋转到物理尺度缩放的完整技术链路。这个zip解决的是三类人的同一类问题学生想交一份能答辩的作业老师想找个能改参数讲公转自转原理的教具而刚入行的开发者想找一个“没有联网、没有服务器、打开就能跑”的最小宇宙。所谓“标准”我理解为不依赖第三方付费插件、只用Unity内置组件和基础Shader、按真实行星比例关系做了合理化缩放的经典太阳系项目。它不惊艳但能让你在一小时内搞懂天体模拟的骨架。这篇文章就带你把zip里的每个文件夹、每段旋转代码、每个坑都过一遍。2. 拿到zip先别急着导Unity3D太阳系项目结构里藏着什么2.1 从Assets到Scenes太阳系项目zip的标准目录长什么样一个正常的Unity工程zip解压后应该看到Assets、Packages或Library、ProjectSettings这三个核心目录。如果你打开zip发现只有Assets一个文件夹也没关系Unity打开时会自动重建Library和ProjectSettings缓存但Packages/manifest.json缺失可能会导致默认包版本漂移常见做法是直接用Unity Hub打开根目录让它自己补全。“标准”太阳系项目的Assets目录通常有这几个子文件夹目录里面装什么缺了会怎样ScenesMain.unity或SolarSystem.unity打开工程一片黑没有可运行场景Scripts行星公转自转、相机控制、轨道线绘制脚本天体全部静止Materials各行星表面材质、太阳发光材质模型显示紫色或纯白无法辨认Prefabs封装好的天体预设体含Scale和Collider只能从Empty Object重建Textures行星表面贴图、法线贴图、太阳纹理球体表面是纯色观感像塑料模型Resources可选运行时动态加载的材质或贴图不致命但某些代码会报空引用打开场景后建议先看Hierarchy面板的顶层节点。太阳系的组织方式基本只有两类一是“扁平式”所有行星都挂在场景根节点下各自带脚本控制旋转二是“层级式”一个Planets空物体下挂Earth、Mars等子节点脚本统一管理子物体数组。后者更常见因为公转参数可以在Inspector里统一拖拽赋值。2.2 判断“标准”还是“魔改”用文件夹结构快速辨别项目可用性很多人解压zip后直接双击.sln或者场景文件然后被一堆Missing Script红字搞到心态崩溃。实际上zip里的Unity项目不带跨版本兼容承诺你用Unity 2021打开Unity 2019创建的工程脚本和Prefab大概率有序列化字段丢失问题。项目里是否存在.meta文件是第一个判断点如果zip里没有.meta文件Unity会在导入时按路径重新生成GUID这时场景里所有引用关系都会断掉Prefab会丢材质和脚本关联。第二个判断点是ProjectSettings/ProjectVersion.txt打开它能看到创建这个项目时用的Unity版本比如m_EditorVersion: 2019.4.40f1。你本机版本和它差一个大版本就要做好升级管线批处理的心理准备差两个以上大版本建议直接用“先打开空工程再拷贝Assets”的方式迁移比直接开旧工程省事得多。提示解压时如果系统提示“文件路径过长”或“包含非法字符”检查zip里是否有嵌套的同名文件夹比如solar_system/solar_system/Assets。这种双层嵌套通常是Mac下用zip -r命令压缩导致的解决方法很简单把内层文件夹拖出来放到工作目录顶层再拷贝Assets进新工程。第三个判断点是Scenes里的场景文件大小。一个只含9大行星的太阳系场景.unity文件通常在100KB到1MB之间。如果看到场景文件超过10MB说明里面塞了大量未压缩的Terrain数据或者内嵌贴图这种“标准”包就不标准了运行在你低配笔记本上大概率掉帧后续改参数也会卡得怀疑人生。3. 让地球转起来太阳系公转自转脚本的复刻与参数解读3.1 最小公转脚本Update里的三行代码和它的物理含义标准太阳系项目的核心脚本名字五花八门常见的有Orbit.cs、Rotate.cs、PlanetMotion.cs但脱离命名看本质它做的就是“绕父节点原点旋转”加“绕自身轴旋转”两件事。我复刻一个最小可实现版本using UnityEngine; public class PlanetOrbit : MonoBehaviour { // 公转速度单位是“度/秒”不是真实物理单位 [Header(公转参数)] public float orbitSpeed 10f; // 每小时绕太阳转10度 public Vector3 orbitAxis Vector3.up; [Header(自转参数)] public float rotationSpeed 30f; // 每秒钟自转30度 public Vector3 rotationAxis Vector3.up; [Header(可选星体倾斜)] [Range(0, 180)] public float axialTilt 23.5f; // 地球实际倾角是23.44度 void Start() { // 把“轴向倾斜”转成初始姿态 transform.rotation Quaternion.Euler(0, 0, axialTilt); } void Update() { // 公转围绕父节点一般是太阳的位置作Y轴圆周运动 transform.RotateAround( transform.parent.position, orbitAxis, orbitSpeed * Time.deltaTime ); // 自转绕自身本地坐标轴旋转 transform.Rotate( rotationAxis, rotationSpeed * Time.deltaTime, Space.Self ); } }这段代码的核心逻辑在于RotateAround和Rotate的区分。RotateAround不是简单的transform.Rotate它内部会同时修改物体的position和rotation让物体以指定点为中心做圆周运动Rotate则是纯粹的姿态旋转只改rotation不动position。一句话公转改变位置自转只改变朝向。Time.deltaTime必须每帧都乘否则帧率高的机器上行星会转得飞快帧率低的机器上又原地踏步——这是最常见的初学翻车点。3.2 公转周期、轨道半径与缩放比例这三个参数决定画面是否“翻车”太阳系模拟里物理上最“对”的往往是最不好看的。真实地球公转周期约365天如果你老老实实把代码里orbitSpeed设成0.00001度/秒运行后镜头里地球十年都挪不动一步答辩时老师只会看到一颗静止的蓝色球体。标准项目中常见的做法是引入timeScale时间缩放系数用“假设1游戏秒现实1天”来玩耍。具体的换算逻辑是这样真实公转周期T天 360度 / 公转角速度。如果想让地球12秒转一圈则公转角速度 360 / 12 30度/秒。但屏幕上看起来更“科学”的做法是保持各行星公转速度的相对比例即地球转10圈时木星只转1圈左右。这时不应照抄真实角速度数值而应该用“基准速度 × 比例系数”。行星真实公转周期地球年推荐运行角速度基数度/秒理由水星0.2462靠近太阳轨道小转角速度快才看得到运动金星0.6224逆自转注意轴向参数地球1.015作为其他行星比例基准火星1.888比地月系统慢一倍以上木星11.861.3大行星轨道大维持肉眼可见但慢的律动土星29.450.5轨道环需要看清不能转太快天王星84.020.18几乎“躺”着绕转轴向倾斜要单独设海王星164.80.1外侧行星转速慢反而真实感更强轨道半径的坑比速度更大。如果按真实平均日距水星5790万km到海王星45亿km直接映射进Unity小行星带和柯伊伯带全变成浮点精度灾难几十亿单位的坐标会让相机抖动到怀疑人生。标准项目里普遍采用“平方根压缩”或“对数压缩”把半径压到0.5到60的视觉舒适区// 从真实日距万km换算到Unity单位 float RealDistanceToUnity(float realDistanceKm) { // 地球日距14960万km → 单位置是10其他行星按平方根比例缩放 float scaleFactor 10f / Mathf.Sqrt(14960f); return Mathf.Sqrt(realDistanceKm) * scaleFactor; }参数说明这里用Mathf.Sqrt做压缩是为了让内侧行星水星、金星和外侧行星天王星、海王星在屏幕上拉开视觉距离而不是挤在一起。如果你想突出“环”土星环的半径在Transform.localScale里调让环的Scale.x/z是土星本体的1.8到2.5倍同时把环的Mesh Renderer阴影关掉否则环会在行星表面投下一块诡异的黑斑。3.3 为什么用RotateAround而不是直接改position两种做法的边界差异有人会把transform.position transform.right * speed * Time.deltaTime写进Update里然后配一个LookAt(target)来冒充公转这样做在单行星时看不出毛病一旦复制给8颗行星问题立刻暴露速度改成向量后方向混乱轨道半径无法保持恒定运行几分钟后行星就越飞越远直接飘出太阳系。RotateAround天然保证“以父节点为圆心以初始距离为半径”的约束你永远不需要手动修正离心漂移。另一个细节在Start()里给transform.position设置初始位置时位置必须是相对太阳的世界坐标偏置。比如地球放在new Vector3(10, 0, 0)并且transform.SetParent(sunTransform, true)保持世界位置不变。如果忘掉这一步直接拖拽时保留了原来的坐标行星可能会从场景原点直接跳回几万单位之外看起来像是“瞬移出了银河系”——之前我调项目时在这上面浪费过一下午。4. 把“标准”调成“我的太阳系”五个必调参数与场景布光4.1 相机与光照从黑匣子到能看清土星环先动这四个值太阳系场景最容易出现的问题是“打开后视线里全是阴影地球半边脸是黑的”原因不是脚本错了而是参数没调。检查Main Camera的Far Clip Plane如果低于500场景深处的天王星和海王星会被直接裁剪掉。标准项目中相机远裁剪面至少1000近裁剪面设0.3即可这样从太阳表面到柯伊伯带都能入镜。第二处是平行光的Rotation。模拟太阳光照时平行光不需要真实放在太阳位置因为Directional Light只关心方向不关心位置。正确的方向是让光线从太阳位置指向场景中心即光照角度大约Rotation (50, -30, 0)就能照亮所有行星面向太阳的一面。如果调成(0, 0, 0)光线会从侧面横切导致每颗行星都黑白对半开。第三处是Environment Lighting下的Ambient Mode。若设成Color并选深灰色场景暗部会一片死黑这时可以在菜单Window Rendering Lighting里把Ambient Mode改成Trilight或Skybox让暗部带一点点环境反射。最后是Adaptive Resolution中低端显卡上设Off或Fixed不然高动态分辨率会让土星环产生闪烁的摩尔纹。4.2 行星材质参数把“塑料球”变回“岩石球”的三个关键数值标准太阳系项目的行星材质一般用Unity内置的Universal Render Pipeline/Lit或StandardShader。这两套系统的参数名不通用但规律一致主要调三个地方参数建议值坑Smoothness0.1~0.3岩石行星0.9气态巨行星全设0.5会让地球像抛光大理石Metallic0.0地球/火星0.2~0.5木星土星设成1会让行星变成镜面球Normal Map勾选并赋表面法线贴图没有贴图就关掉硬编法线强度会让表面出现网格线如果你想把Standard材质升级到URP或HDRP直接换Shader会让所有行星材质变成洋红色。常见做法是右键材质球选择Convert to URP/Lit需安装URP Package或者手动重新赋材质并重填贴图。此操作没有一键全自动的路子纯体力活但对后期帧数影响极大。4.3 让太阳“看起来对”Billboard光晕和自发光的配合太阳在这个项目里通常只是个带自发光材质的大球体在场景视角下毫无生气。实际工程里我会给它加两个东西一个Light点光源Range覆盖到木星轨道即可强度1.2以及一个始终面向相机的Quad作为光晕面片。光晕面片使用Particles/Standard Unlit材质配合半透明贴图挂在太阳子节点下Z轴朝向相机——这样无论相机怎么转光晕永远正对玩家。这步不写代码也能做给光晕物体挂一个脚本每帧让transform.LookAt(Camera.main.transform)然后绕Z轴旋转180度把背面翻出来因为默认的Quad正面朝向-Z直接LookAt会让三角贴在球面上看不见。自发光材质的关键参数是Emission Color选偏橙黄色RGB约255, 180, 100Intensity设2~3视觉上就像“正在燃烧”又不至于把屏幕亮度闪崩。千万不要把太阳的Scale调得过大否则相机进到太阳内部时近裁剪面会被球体包裹画面出现全屏橙色噪点那是后处理特效的锅不是项目坏了。5. 太阳系项目避开这些坑导包、运行与发布的常见问题排查5.1 现象导入Unity后所有材质变成紫色打开场景后行星全部是紫色或洋红色通常是Shader丢失或渲染管线不匹配。标准太阳系跑在Built-in Render Pipeline上但你的工程模板选了URP或HDRP两者Shader互不兼容。解决在Assets里选中所有材质球Edit Rendering Materials Convert to URP/Lit。如果找不到这个选项说明URP包没装先Window Package Manager安装Universal RP再执行转换。更快的土办法是直接在新工程里从Asset Store或模型包重贴一遍材质——项目不大时手动替换10来个材质比折腾管线转换更快。5.2 现象行星要么疯转要么原地不动打开工程后有的行星像开了加速器一样疯狂打转有的又完全静止。原因几乎都出在Time.deltaTime和速度初值上。脚本如果忘记乘以Time.deltaTime转速就变成“每帧转X度”主频144Hz的显示器和60Hz的显示器上转速相差2.4倍。而“静止”的行星多半是它的orbitSpeed或rotationSpeed被设成了0检查一下Inspector里脚本组件是否被Loading默认值覆盖。解决所有运动脚本统一改成速度 × Time.deltaTime如果场景里天体数量多可以写一个SpeedManager单例统一放倍率避免每颗行星的Transform参数呈指数式失控。5.3 现象行星绕太阳转的半径越来越大最后飘走这个我在做轨道验证时翻车过。典型的写法是每帧执行position direction * speed * deltaTime但方向是用Vector3.Right算的没有使用圆周切向量导致运动轨迹不是圆而是螺旋线。越走越远的螺旋在视觉上就像“行星被太阳甩出去了”。解决检查脚本里是否用了RotateAround或者手工计算轨道位置时用cos(θ), 0, sin(θ)。要确认是否出现漂移在Inspector里选行星观察Position的XZ平方和在运行10秒内是否稳定。如果稳定说明轨道半径没跑偏如果有明显增长必然是位置累加逻辑写错了。5.4 现象zip解压后缺文件或场景打不开zip包在Windows和macOS之间传递后常见的问题是文件名编码不一致导致文件夹层级错乱。比如中文环境下解压出Assets重复一层让Unity找不到Scenes。更隐蔽的是某些第三方压缩工具会把.meta文件的隐藏属性丢失Unity回读时直接重建GUID场景中的所有Prefab引用全部断开清空Hierarchy面板。解决压缩时统一用zip -r或7-Zip默认参数不要用“仅存储文件名但不保留绝对路径”的选项解压后做一次完整性检查确认Assets/Scenes下至少有一个.unity文件。如果场景内Prefab被断开选择场景里丢失引用的物体在Inspector里手动拖拽替换其Mesh和Material即可不用重新搭整个场景。5.5 现象发布WebGL后太阳系不显示文字或性能卡顿WebGL会重编译所有Shader如果场景里用了自定义Shader或Shader Graph在桌面能跑、发布WebGL却全屏报错。同时在WebGL上Lightmap和实时阴影质量高时帧率会被拖到个位数。解决发布WebGL前把所有材质换成URP/Lit或Standard内置类型Player Settings Publishing Settings里关掉Compression的Brotli改用Disable或Gzip减少解压视觉卡顿。阴影质量Quality Settings Shadows设为Low或No Shadows太阳系这种远景为主的项目阴影根本看不清性能却贵得很。6. 进阶让太阳系从“能跑”到“能讲”——轨道可视化、时标切换与你的第一个教学场景把行星转起来只是第一步真正能让答辩或课堂“讲”起来的是一个时间流速切换器加一条可见的轨道线。按键数字1、2、3分别对应1倍、10倍和60倍时间流速使用全局静态变量public static float timeScale 1f; void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) timeScale 1f; if (Input.GetKeyDown(KeyCode.Alpha2)) timeScale 10f; if (Input.GetKeyDown(KeyCode.Alpha3)) timeScale 60f; }这段代码挂在Sun或空物体GameManager上行星脚本里把orbitSpeed * Time.deltaTime改成orbitSpeed * timeScale * Time.deltaTime。这里的timeScale不要和Time.timeScale混用——后者是Unity全局的物理时间控制直接改变它会让所有动画和粒子一并加速容易导致“火都烧歪了”这种诡异观感。轨道线我习惯用LineRenderer实现先把行星未来40个轨道采样点的坐标预生成然后每帧更新点位置。提前预生成的好处是不需要运行时计算大量三角函数曲线顺滑度极高避免出现折线轨道视觉砸场void DrawOrbit(Transform planet, float radius) { LineRenderer lr planet.gameObject.AddComponentLineRenderer(); lr.positionCount 64; lr.startWidth 0.05f; lr.endWidth 0.05f; lr.useWorldSpace true; // 设定一条半径为radius的圆周线 for (int i 0; i 64; i) { float angle i * Mathf.PI * 2f / 64f; lr.SetPosition(i, new Vector3(Mathf.Cos(angle) * radius, 0, Mathf.Sin(angle) * radius)); } }这一步做出来后整个太阳系的教学演示闭环就完整了用数字键切换时间流速展示“顺行—逆行—冲日”的相对运动用轨道线说明“行星绕太阳轨道近似圆形”用相机自由穿梭展示“内侧行星快、外侧行星慢”的规律。就我自己的血泪经验做教学项目时最不该贪的是“忠实还原星际空间真实距离”——那只会让所有行星在屏幕上消失成像素点。宁可把数据压成舒适的视觉比例也要保证“学的人看得懂、讲的人指得清”。希望这个zip里的小宇宙能成为你下一堂天体课的上手捷径。本文还有配套的精品资源点击获取