本文档为项目使用手册,也是对当前代码实现的算法、坐标变换、图形学原理、工程架构与项目约定的完整说明。
StarSky 是一个面向 Unity 6 的 Gaia DR3 恒星可视化项目。它从 Gaia DR3 的 CSV 子集导入恒星天体测量与光度数据,将其转换为紧凑的二进制运行时目录,并在 Unity 中以 ICRS 天球坐标系渲染一个可交互的沉浸式星空。当前项目的目标不是完整天体物理模拟,而是以可解释、可调试、可扩展的方式把 Gaia 星表中的赤经、赤纬、视差、自行和光度字段转换为实时可渲染的屏幕空间恒星 billboard。
项目核心流程如下:
在编辑器阶段读取项目根目录的 gaiadr3.csv。
验证并提取 Gaia 字段:source_id、ra、dec、parallax、pmra、pmdec、phot_g_mean_mag、phot_bp_mean_mag、phot_rp_mean_mag。
写入 Assets/StreamingAssets/StarSky/gaiadr3_icrs_j2016.bin。
运行时加载二进制星表。
将 Gaia J2016.0 ICRS 星表位置传播到指定 TT 时刻。
在有正视差时,将恒星视为有限距离 BCRS/ICRS 位置,并减去观察者位置得到观测方向。
按 G 星等过滤并转换为可视星点的大小、透明度和颜色。
生成由四边形 billboard 构成的 Mesh chunk。
由 Shader 在裁剪空间中按像素半径展开四边形,实现相机旋转时仍保持圆形、稳定的星点。
Gaia DR3;ICRS;BCRS;赤经赤纬;自行;视差;儒略日;TT;天球渲染;Unity Mesh;屏幕空间 billboard;additive blending;恒星色温;星等可视化;clip space expansion。
StarSky 关注的问题可以表述为:
给定 Gaia DR3 的一个恒星样本,如何在 Unity 运行时中以稳定、可交互、可解释的方式将其显示为真实天球方向上的星空?
该问题跨越三个层面:
天体测量层:星表中的 ra、dec、pmra、pmdec、parallax 如何转为三维方向或有限距离位置。
时间传播层:参考历元 Gaia J2016.0 的星表值如何传播到用户指定的可视化时刻。
图形渲染层:大量远距离点状恒星如何以可控亮度、颜色、大小和视觉稳定性渲染到屏幕。
当前代码有意保持范围收敛。它不是完整天文软件,目前仅实现Gaia 星表到实时天球渲染的链路。
暂不覆盖:
径向速度和透视加速度。
太阳系天体、行星历表、恒星本动的高阶模型。
岁差、章动、地球自转、地心到站心坐标转换。
恒星消光、星际红化、真实光谱合成。
大气折射、空气辉、地平坐标、真实观测站模型。
GPU compute streaming 或超大星表的分级 LOD。
默认 Demo 使用:
星等过滤:G <= 8.0。
可视半径:100.0 Unity units。
可视时间:2026-01-01T00:00:00Z,经 TT 转换后用于传播。
初始相机朝向:RA = 60 deg,Dec = 30 deg。
Shader 星点模型:Gaussian / PSF profile。
本项目使用 Unity6 版本,项目版本记录在 ProjectSettings/ProjectVersion.txt:
Unity 6000.4.8f1Packages/manifest.json 当前只启用了很少的 Unity 模块:
xxxxxxxxxx{ "dependencies": { "com.unity.modules.audio": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.imageconversion": "1.0.0" }}这些依赖分别对应:
audio:Demo 相机上附加 AudioListener。
imgui:运行时控制面板 StarVisualSettingsPanel 使用 IMGUI。
imageconversion:编辑器工具可将渲染结果导出为 PNG 预览图。
项目未引入 URP、HDRP、Entities、Burst、Jobs 或第三方包。渲染实现基于内置 Mesh、Material 和 Shader。
导入器默认寻找:
xxxxxxxxxxgaiadr3.csv该文件需要放在 Unity 项目根目录,即与 Assets/、Packages/、ProjectSettings/ 同级。运行时默认读取:
xxxxxxxxxxAssets/StreamingAssets/StarSky/gaiadr3_icrs_j2016.binStreamingAssets 被用于使二进制星表在运行时可通过Application.streamingAssetsPath 定位。
使用 Unity 6 打开本目录。
确认 gaiadr3.csv 位于项目根目录。
等待 Unity 完成脚本编译和资源导入。
在 Unity 菜单中执行:
xxxxxxxxxxStarSky > Import gaiadr3.csv From Project Root或者打开可配置导入窗口:
xxxxxxxxxxStarSky > Gaia DR3 Importer导入成功后应生成:
xxxxxxxxxxAssets/StreamingAssets/StarSky/gaiadr3_icrs_j2016.bin在 Unity 菜单中执行:
xxxxxxxxxxStarSky > Create Demo Scene随后打开:
xxxxxxxxxxAssets/StarSky/Scenes/StarSkyDemo.unity进入 Play Mode 后:
按住鼠标右键并移动鼠标:环视星空。
W/A/S/D:沿相机局部前后左右移动。
Q/E:向下/向上移动。
Left Shift:加速移动。
F1:显示或隐藏运行时控制面板。
可在菜单中执行:
xxxxxxxxxxStarSky > Validate Demo Scene该操作会打开 Demo 场景,调用 GaiaSkySphereRenderer.Rebuild(),并检查是否生成至少一个可渲染 chunk。
可在菜单中执行:
xxxxxxxxxxStarSky > Export Demo Preview PNG该操作会渲染一张 1280 x 720 的 PNG 到:
xxxxxxxxxxAssets/StarSky/Scenes/StarSkyDemoPreview.pngxxxxxxxxxxStarSky/├─ Assets/│ ├─ StreamingAssets/│ │ └─ StarSky/│ │ └─ gaiadr3_icrs_j2016.bin│ └─ StarSky/│ ├─ README.md│ ├─ Editor/│ │ ├─ StarSky.Editor.asmdef│ │ ├─ GaiaDr3CsvImporterWindow.cs│ │ └─ Demo/│ │ └─ StarSkyDemoSceneBuilder.cs│ ├─ Runtime/│ │ ├─ StarSky.Runtime.asmdef│ │ ├─ JulianDateTT.cs│ │ ├─ Math/│ │ │ └─ DVector3.cs│ │ ├─ Catalog/│ │ │ ├─ GaiaStarRecord.cs│ │ │ ├─ GaiaCatalogBinary.cs│ │ │ ├─ GaiaCatalog.cs│ │ │ └─ GaiaStarPropagator.cs│ │ └─ Visualization/│ │ ├─ GaiaSkySphereRenderer.cs│ │ ├─ StarRenderCameraController.cs│ │ ├─ StarVisualSettingsPanel.cs│ │ ├─ Materials/│ │ │ └─ GaiaStarVisualMaterial.mat│ │ └─ Shaders/│ │ └─ StarSkyAdditiveStarBillboard.shader│ └─ Scenes/│ └─ StarSkyDemo.unity├─ Packages/│ └─ manifest.json├─ ProjectSettings/│ └─ ProjectVersion.txt└─ gaiadr3.csv项目使用两个 asmdef:
StarSky.Runtime:运行时代码,可被游戏或可视化场景引用。
StarSky.Editor:编辑器菜单、CSV 导入、Demo 场景构建,只在 Editor 平台编译。
这种划分避免运行时构建引用 UnityEditor 命名空间,也使导入和验证工具不污染最终播放器代码。
检索数据:
访问官方入口:ESA Gaia Archive (https://gea.esac.esa.int/archive/),进入ESA Gaia 检索后台,在顶部导航栏中,点击 Search 标签页,进入检索界面。在检索界面的左上角,从默认的 "Simple"(简单检索)切换到 Advanced (ADQL) 标签页。这里允许我们编写自定义的数据库查询脚本。
在高级检索的文本框中,输入本项目使用的 ADQL 语句:
xxxxxxxxxxSELECT source_id, ra, dec, parallax, pmra, pmdec, phot_g_mean_mag, phot_bp_mean_mag, phot_rp_mean_magFROM gaiadr3.gaia_sourceWHERE phot_g_mean_mag <= 9.5 AND parallax IS NOT NULL AND pmra IS NOT NULL AND pmdec IS NOT NULL字段与筛选逻辑:
gaiadr3.gaia_source:明确指定从 Gaia 官方第三版(DR3)的核心源表中提取数据。其参考历元天然就是 J2016.0 (TT),参考系为 ICRS。
ra, dec:双精度(double)的赤经和赤纬,单位是度(degrees)。
parallax:视差,单位是毫弧秒(mas)。星敏感器仿真中,虽然恒星距离极远,但高精度仿真仍会用它来修正地球/卫星绕日运动产生的周年视差。
pmra, pmdec:自行参数,单位是毫弧秒/年(mas/yr)。注意:pmra 已经是包含了
多波段星等 (phot_g_..., phot_bp_..., phot_rp_...):除了主
IS NOT NULL:强制剔除任何缺失天体解的暗星或异常星,确保导入 Unity 的每一条数据都能在空间中被唯一、连续地传播。
数据集下载:
执行查询:在代码框下方,点击 Submit Query(提交查询)按钮。
注:由于
的恒星大约有 40 万到 50 万颗,这个数量对于 Gaia 数据库来说属于“超小型”任务,服务器通常会在 5-10 秒内完成检索。
查询完成后,在结果面板的工具栏中,找到 Download results 区域。将 Format(格式)下拉菜单修改为 CSV。将压缩方式设为 Gzip 格式可以大幅减少下载时间。点击下载图标,将文件保存到本地,重新命名为 gaiadr3.csv后放置到本仓库的根目录中。
导入器要求 CSV 表头包含以下字段:
| 字段 | 类型 | 单位 | 语义 |
|---|---|---|---|
source_id | ulong | 无 | Gaia 源标识符 |
ra | double | degree | ICRS 赤经 |
dec | double | degree | ICRS 赤纬 |
parallax | double | milliarcsecond | 视差 |
pmra | double | milliarcsecond/year | 赤经方向自行,Gaia 定义为 mu_alpha_star |
pmdec | double | milliarcsecond/year | 赤纬方向自行 |
phot_g_mean_mag | float | magnitude | Gaia G 平均星等 |
phot_bp_mean_mag | float | magnitude | Gaia BP 平均星等 |
phot_rp_mean_mag | float | magnitude | Gaia RP 平均星等 |
phot_g_mean_mag 是必需光度字段。BP/RP 若解析失败,则以 NaN 保存,后续颜色映射会回退到默认颜色指数。
导入器实现位于:
xxxxxxxxxxAssets/StarSky/Editor/GaiaDr3CsvImporterWindow.cs解析策略:
使用第一行表头构造列名到索引的映射。
列名比较使用 StringComparer.OrdinalIgnoreCase。
数据行使用 line.Split(',') 拆分。
数值解析使用 CultureInfo.InvariantCulture。
空行、字段不足、必需字段解析失败都会计入 invalid row,并被跳过。
非正视差行默认保留为“无限远恒星”,也可在导入窗口中选择丢弃。
注意:当前 CSV 解析器假定字段中不包含带引号的逗号。Gaia 数值型导出通常满足这一条件。
运行时每条恒星记录由 GaiaStarRecord 表示:
xxxxxxxxxxpublic readonly struct GaiaStarRecord{ public readonly ulong sourceId; public readonly double raDeg; public readonly double decDeg; public readonly double parallaxMas; public readonly double pmraMasPerYear; public readonly double pmdecMasPerYear; public readonly float photGMeanMag; public readonly float photBpMeanMag; public readonly float photRpMeanMag;}该结构还提供两个派生属性:
HasUsableParallax:视差为有限值且大于 0。
BpMinusRp:若 BP/RP 有效,返回 photBpMeanMag - photRpMeanMag,否则返回 NaN。
二进制读写由 GaiaCatalogBinary 负责。
文件头:
| 顺序 | 写入方法 | 字段 | 当前值 |
|---|---|---|---|
| 1 | BinaryWriter.Write(string) | magic | SSKYGAIA |
| 2 | Write(int) | version | 1 |
| 3 | Write(double) | reference epoch TT JD | 2457389.0 |
| 4 | Write(int) | record count | 当前为 291270 |
随后逐条写入记录:
| 顺序 | 类型 | 字段 |
|---|---|---|
| 1 | UInt64 | sourceId |
| 2 | Double | raDeg |
| 3 | Double | decDeg |
| 4 | Double | parallaxMas |
| 5 | Double | pmraMasPerYear |
| 6 | Double | pmdecMasPerYear |
| 7 | Single | photGMeanMag |
| 8 | Single | photBpMeanMag |
| 9 | Single | photRpMeanMag |
每条记录的定长载荷为:
xxxxxxxxxx8 + 5 * 8 + 3 * 4 = 60 bytes这里 BinaryWriter.Write(string) 是 .NET 的长度前缀字符串写法,而不是固定 8 字节裸 magic。因此跨语言读取时要按 .NET BinaryWriter 字符串格式处理,或在未来格式版本中显式改为固定字节 magic。
读取时执行以下保护:
文件不存在:抛出 FileNotFoundException。
magic 不等于 SSKYGAIA:抛出 InvalidDataException。
version 不等于 1:抛出 InvalidDataException。
reference epoch 与 JulianDateTT.GaiaReferenceEpochJd 差异大于 1e-9:抛出 InvalidDataException。
count 小于 0:抛出 InvalidDataException。
这些检查保证运行时不会悄悄读取错误年代、错误版本或损坏的星表。
ICRS,即 International Celestial Reference System,是 Gaia 星表坐标的基础参考系。StarSky 将 Gaia 的 ra 和 dec 直接解释为 ICRS 中的球面角。
代码中的三维方向向量定义为:
xxxxxxxxxxx = cos(dec) * cos(ra)y = cos(dec) * sin(ra)z = sin(dec)其中 ra 和 dec 先从角度转换为弧度。
这意味着 StarSky 的 Unity 世界坐标被当作 ICRS 直角坐标使用:
Unity +X:RA = 0 deg, Dec = 0 deg。
Unity +Y:RA = 90 deg, Dec = 0 deg。
Unity +Z:Dec = +90 deg,即 ICRS 北极方向。
这不是常见游戏场景中的“Y 轴向上”地面坐标,而是天球坐标直接嵌入 Unity 世界空间。Demo 相机的初始 up 方向由 ICRS 北向量构造,因此视觉上仍有可理解的天球北方向。
代码字段名使用:
xxxxxxxxxxobserverBcrsAuXobserverBcrsAuYobserverBcrsAuZ其语义是观察者在 BCRS/ICRS 直角坐标中的位置,单位为 AU。当前实现没有引入完整 BCRS 相对论框架,而是采用与 ICRS 轴对齐的欧氏位置向量:
xxxxxxxxxxobserverBcrsAu = (x, y, z) AU当恒星有可用正视差时,渲染方向为:
xxxxxxxxxxnormalize(starPositionAu - observerBcrsAu)当恒星没有可用正视差时,系统把它视为无限远,只传播角方向。
项目使用 JulianDateTT 作为传播时间输入。
核心常量:
| 常量 | 值 | 含义 |
|---|---|---|
J2000JulianDate | 2451545.0 | J2000 儒略日 |
GaiaReferenceEpochJulianYear | 2016.0 | Gaia 参考儒略年 |
GaiaReferenceEpochJd | 2457389.0 | Gaia J2016.0 的 TT JD |
DaysPerJulianYear | 365.25 | 儒略年天数 |
TtMinusTaiSeconds | 32.184 | TT 与 TAI 的固定差 |
当用户输入 UTC ISO-8601 时,代码执行:
xxxxxxxxxxJD_TT = JD_UTC + (TAI_minus_UTC + 32.184) / 86400默认:
xxxxxxxxxxTAI_minus_UTC = 37.0 seconds因此默认:
xxxxxxxxxxTT_minus_UTC = 69.184 seconds需要注意,闰秒表未来可能变化。当前实现通过 inspector 字段 visualizationTaiMinusUtcSeconds 暴露该值,而不是自动查询外部闰秒数据。
传播算法使用:
xxxxxxxxxxDeltaYears = (JD_TT - 2457389.0) / 365.25这个差值直接乘以自行切向速度,得到相对于 Gaia 参考历元的角位移近似。
天体测量核心实现位于:
xxxxxxxxxxAssets/StarSky/Runtime/Catalog/GaiaStarPropagator.csxxxxxxxxxxDegreesToRadians = pi / 180MasToRadians = DegreesToRadians / 3600000AuPerParsec = 206264.80624709636其中:
1 degree = 3600 arcsec = 3600000 milliarcsec。
1 parsec = 206264.80624709636 AU。
给定赤经 alpha 和赤纬 delta,ICRS 单位方向为:
xxxxxxxxxxu(alpha, delta) =[ cos(delta) cos(alpha), cos(delta) sin(alpha), sin(delta)]代码:
xdouble ra = star.raDeg * DegreesToRadians;double dec = star.decDeg * DegreesToRadians;double cosDec = Math.Cos(dec);
return new DVector3( cosDec * Math.Cos(ra), cosDec * Math.Sin(ra), Math.Sin(dec));自行是定义在天球切平面上的角速度。StarSky 构造两个局部正交方向:
xxxxxxxxxxeast(alpha) =[ -sin(alpha), cos(alpha), 0]xxxxxxxxxxnorth(alpha, delta) =[ -sin(delta) cos(alpha), -sin(delta) sin(alpha), cos(delta)]它们分别对应:
east:赤经增加方向。
north:赤纬增加方向。
二者均与单位视线方向 u 正交。对于单位球面,east 可理解为沿纬圈切向,north 可理解为沿经圈向北的切向。
pmra 的解释Gaia 的 pmra 不是简单的 d(alpha)/dt,而是:
xxxxxxxxxxmu_alpha_star = d(alpha)/dt * cos(delta)这点非常重要。若直接把 pmra 当作 d(alpha)/dt,在高赤纬区域会出现错误的角速度放大。
StarSky 采用 Gaia 的定义,将 pmra 直接作为 east 方向的切向角速度:
xxxxxxxxxxdu/dt = east * pmra + north * pmdec再乘以 MasToRadians 转为弧度每年:
xxxxxxxxxxtangentRate = (east * pmraMasPerYear + north * pmdecMasPerYear) * MasToRadians对于无限远或只关心方向的恒星,传播公式为:
xxxxxxxxxxu(t) = normalize(u0 + tangentRate * DeltaYears)代码:
xxxxxxxxxxDVector3 direction = ReferenceDirection(star);DVector3 tangentRate = ProperMotionDerivativePerYear(star);return (direction + tangentRate * tt.YearsSinceGaiaJ2016).Normalized;这是一个一阶切平面近似。对当前 Demo 的视觉用途来说,它具有以下优点:
计算简单,适合大量恒星。
保持向量归一化,避免长期漂移导致半径变化。
与 Gaia 的 pmra / pmdec 字段直接对应。
其代价是没有建模高阶球面测地传播、径向速度导致的透视效应和真实空间速度的完整传播。
当 parallaxMas > 0 时,距离估计为:
xxxxxxxxxxdistanceParsec = 1000 / parallaxMasdistanceAu = distanceParsec * AuPerParsec这里使用了经典小角度关系:
xxxxxxxxxxdistance(pc) = 1 / parallax(arcsec)由于 Gaia 输入单位为 milliarcsecond:
xxxxxxxxxxparallax(arcsec) = parallaxMas / 1000所以:
xxxxxxxxxxdistance(pc) = 1000 / parallaxMas当星体有可用正视差时,StarSky 可以构造其在 ICRS/BCRS 轴上的有限距离位置:
xxxxxxxxxxposition0Au = u0 * distanceAu自行切向角速度可转为切向线速度:
xxxxxxxxxxtangentVelocityAuPerYear = tangentRateRadPerYear * distanceAu传播后位置:
xxxxxxxxxxpositionAu(t) = position0Au + tangentVelocityAuPerYear * DeltaYears代码:
xxxxxxxxxxdouble distanceParsec = 1000.0 / star.parallaxMas;double distanceAu = distanceParsec * AuPerParsec;DVector3 tangentVelocityAuPerYear = ProperMotionDerivativePerYear(star) * distanceAu;
return direction * distanceAu + tangentVelocityAuPerYear * tt.YearsSinceGaiaJ2016;这仍然不包含径向速度,因此距离随时间的变化只来自切向位移形成的几何位置变化,而不是星体沿视线方向远离或靠近观察者。
观察者位置为 observerBcrsAu。对于有限距离恒星:
xxxxxxxxxxobservedUnit = normalize(positionAu(t) - observerBcrsAu)对于无可用正视差恒星:
xxxxxxxxxxobservedUnit = propagatedInfiniteDirection这使得相机或观察者在 AU 量级移动时,近距离恒星会出现视差方向变化,而无限远恒星保持方向稳定。
渲染核心实现位于:
xxxxxxxxxxAssets/StarSky/Runtime/Visualization/GaiaSkySphereRenderer.csAssets/StarSky/Runtime/Visualization/Shaders/StarSkyAdditiveStarBillboard.shader真实恒星距离极远。在常规实时渲染中,若按真实 AU 或 parsec 比例放置 Mesh,会遇到:
浮点精度不足。
深度缓冲范围不适合。
相机平移与旋转的视觉效果难以控制。
远距离对象会被裁剪或出现 z-fighting 问题。
StarSky 采用“方向决定位置”的 sky sphere 思想:
xxxxxxxxxxrenderCenter = unitDirection * visualizationRadius即所有星点都被投放到以相机附近为中心、半径固定的可视球面上。真实的天体测量位置只用来决定方向,不直接作为 Unity 世界坐标中的真实距离。
GaiaSkySphereRenderer 在 LateUpdate() 中调用 FollowTarget():
xxxxxxxxxxtransform.position = centerTarget.positiontransform.rotation = Quaternion.identity这带来两个效果:
相机平移时,星空球跟随相机移动,避免相机走出星空球。
星空不跟随相机旋转,因此相机旋转会改变观看方向,符合观察天球的直觉。
在纯星空场景中,相机平移不会产生明显运动视差,除非运行时同步观察者 AU 并重建星表方向。
BuildVisualStars() 执行以下步骤:
遍历星表。
若 photGMeanMag > visualMagnitudeLimit,跳过。
根据 propagateToVisualizationTime 决定使用参考方向或传播后的观察方向。
将 DVector3 转为 Unity Vector3 并归一化。
记录 G 星等和 BP - RP 颜色指数。
按星等升序排序,即亮星在前。
若 maxVisualStars > 0,截断为前 N 个最亮目标。
星等越小越亮,因此排序比较为:
xxxxxxxxxxa.magnitude.CompareTo(b.magnitude)星点屏幕半径由 AnimationCurve sizeByMagnitude 决定:
xxxxxxxxxxG = -1.5 -> 5.5 pxG = 0.0 -> 4.0 pxG = 3.0 -> 2.0 pxG = 8.0 -> 0.75 px最终大小:
xxxxxxxxxxhalfSizePixels = max(0.001, sizeByMagnitude(G) * sizeScale)这里故意采用艺术化曲线,而不是严格物理星等亮度公式。原因是屏幕上的星点不仅表示光通量,也承担可读性、抗闪烁和视觉密度控制的功能。
透明度使用:
xxxxxxxxxxt = InverseLerp(visualMagnitudeLimit, -1.5, magnitude)alpha = Clamp(Lerp(minimumAlpha, 1.0, t), 0.0, 1.0)当 magnitude 接近 visualMagnitudeLimit 时,alpha 接近 minimumAlpha。当 magnitude 接近或亮于 -1.5 时,alpha 接近 1.0。
这种映射具有视觉目的:
暗星不会完全消失,而是保持最低贡献。
亮星更醒目。
用户调低 magnitude limit 时,弱星密度降低,视觉噪声减少。
颜色映射先计算:
xxxxxxxxxxcolorIndex = BP - RP若 BP/RP 缺失,则回退为:
xxxxxxxxxxBP - RP = 0.85随后 clamp 到:
xxxxxxxxxx[-0.4, 2.8]色温近似公式:
xxxxxxxxxxT = 4600 * (1 / (0.92 * colorIndex + 1.7) + 1 / (0.92 * colorIndex + 0.62))该形式常用于从 B-V 类颜色指数估算黑体温度。这里将 Gaia BP-RP 作为视觉近似输入,并不等价于严格的 Gaia passband 光谱反演。
ColorFromTemperature() 将 Kelvin 映射到 RGB:
先令 t = Kelvin / 100,并 clamp 到 [10, 400]。
当 t <= 66 时,红色固定为 255,绿色和蓝色使用对数函数。
当 t > 66 时,蓝色固定为 255,红色和绿色使用幂函数。
这是一种常见的可视近似,可产生:
高温恒星偏蓝白。
中温恒星接近白或淡黄。
低温恒星偏橙红。
每颗星生成 4 个顶点,顶点位置相同,均为:
xxxxxxxxxxcenter = direction * visualizationRadius差异保存在 UV 中:
xxxxxxxxxxuv = (0,0), (1,0), (0,1), (1,1)每个顶点还写入:
xxxxxxxxxxuv2.x = halfSizePixelscolor = starColorWithAlpha三角形索引:
xxxxxxxxxx(0,2,1), (1,2,3)换言之,CPU 端 Mesh 并没有在世界空间中构造真实四边形面积。它只提供 billboard 中心、角标识、像素大小和颜色。真正的四边形展开在 Shader 顶点阶段完成。
如果 CPU 端预先根据相机 right/up 生成四边形,则每次相机旋转都需要重建或更新顶点。StarSky 改为在顶点着色器中进行屏幕空间展开:
xxxxxxxxxxcenterClip = UnityObjectToClipPos(center)corner = uv * 2 - 1pixelToClip = (2 / screenWidth, 2 / screenHeight) * centerClip.whalfSizePixels = max(meshSize * PixelScale, MinPixelRadius)centerClip.xy += corner * halfSizePixels * pixelToClip核心是 clip space 与 NDC 的关系:
xxxxxxxxxxndc.xy = clip.xy / clip.w屏幕中 1 像素对应的 NDC 距离约为:
xxxxxxxxxx2 / screenWidth2 / screenHeight若希望在投影除法后移动 p 像素,则 clip space 中应移动:
xxxxxxxxxxdeltaClip = p * (2 / screenSize) * clip.w因此 Shader 里乘以 centerClip.w,使星点半径以屏幕像素为单位稳定,而不是随深度或 FOV 产生不期望的世界空间缩放。
Shader 设置:
xxxxxxxxxxBlend One OneZWrite OffCull OffLighting OffQueue = Transparent含义:
Blend One One:输出颜色与 framebuffer 中已有颜色相加,模拟光源叠加。
ZWrite Off:星点不写深度,避免互相遮挡或污染后续透明渲染。
Cull Off:四边形双面可见,尽管屏幕空间展开通常不依赖背面剔除。
Lighting Off:星点自发光,不受场景光照影响。
输出颜色为:
xxxxxxxxxxrgbOut = starRgb * alpha * IntensityalphaOut = alpha在 additive blending 下,alpha 主要作为 profile 权重的一部分参与颜色强度控制,而不是传统透明混合中的覆盖权重。
Fragment shader 提供两种 profile。
Core/glow 模式:
xxxxxxxxxxd = length(uv * 2 - 1)glow = saturate(1 - d)core = smoothstep(CoreSize, 0, d)profile = glow^2 * 0.75 + coreGaussian / PSF 模式:
xxxxxxxxxxgaussian = exp(-0.5 * d^2 / sigma^2)edgeFade = 1 - smoothstep(0.82, 1.0, d)profile = gaussian * edgeFade其中 edgeFade 用于让单位圆边缘平滑衰减,避免正方形 billboard 的边界被看见。
星空 Mesh 不是每帧重建。它在以下情况下重建:
GaiaSkySphereRenderer.Start() 中,且 rebuildOnStart = true。
Inspector context menu:Rebuild Visual Star Meshes。
运行时面板点击 Apply Visual Rebuild。
运行时面板点击 Rebuild From Current Observer。
运行时面板点击 Rebuild From UTC。
运行时面板点击 Rebuild From TT JD。
编辑器验证或导出预览工具显式调用 sky.Rebuild()。
材质参数,例如 _PixelScale、_MinPixelRadius、_Intensity、_CoreSize、_Profile、_GaussianSigma,可每帧更新,不需要重建 Mesh。
GaiaSkySphereRenderer路径:
xxxxxxxxxxAssets/StarSky/Runtime/Visualization/GaiaSkySphereRenderer.cs职责:
加载 StreamingAssets 中的二进制星表。
解析可视化时间。
解析观察者 AU 位置。
将星表记录转换为可视恒星。
按 magnitude limit 和 max count 过滤。
根据可选 cube split 分组。
生成 Mesh chunk 和子 GameObject。
让星空对象跟随目标位置。
关键字段:
| 字段 | 默认值 | 含义 |
|---|---|---|
catalogStreamingAssetsPath | StarSky/gaiadr3_icrs_j2016.bin | StreamingAssets 下的星表路径 |
rebuildOnStart | true | Play Mode 开始时是否自动重建 |
propagateToVisualizationTime | true | 是否传播到可视化时间 |
visualizationTimeSource | IsoUtc | 使用 UTC 字符串或 TT JD |
visualizationUtcIso8601 | 2026-01-01T00:00:00Z | 默认 UTC 时间 |
visualizationTtJulianDate | 2457389.0 | 默认 TT JD |
visualizationTaiMinusUtcSeconds | 37.0 | UTC 到 TT 转换参数 |
observerBcrsAuX/Y/Z | 0 | 观察者位置,单位 AU |
centerTarget | null | 星空跟随的目标 Transform |
visualizationRadius | 100.0 | 可视化天球半径 |
visualMagnitudeLimit | 8.0 | G 星等过滤上限 |
maxVisualStars | 0 | 0 表示不过滤数量 |
useCubeSplitting | true | 是否按立方体主轴拆分 |
starMaterial | null | 星点材质 |
sizeByMagnitude | 曲线 | 星等到屏幕尺寸 |
sizeScale | 1.0 | 星点大小倍率 |
minimumAlpha | 0.08 | 最暗星点 alpha 下限 |
xxxxxxxxxxMaxStarsPerMesh = 15000每颗星 4 个顶点,所以单个 Mesh 最多:
xxxxxxxxxx15000 * 4 = 60000 vertices这低于 16-bit index buffer 的常见上限 65535,避免必须切换到 32-bit index format。同时每颗星 2 个三角形,单 chunk 最多:
xxxxxxxxxx15000 * 2 = 30000 trianglesCubeSplit() 根据方向向量绝对值最大的轴将恒星分到 6 个列表:
+X
-X
+Y
-Y
+Z
-Z
判定:
xxxxxxxxxxif abs(x) >= abs(y) and abs(x) >= abs(z): face = sign(x)else if abs(y) >= abs(x) and abs(y) >= abs(z): face = sign(y)else: face = sign(z)意义:
把全天球拆为几个空间区域。
每个 Mesh 的 bounds 更局部,有机会改善 Unity 的视锥剔除。
减少单一巨大 Mesh 的管理压力。
StarRenderCameraController路径:
xxxxxxxxxxAssets/StarSky/Runtime/Visualization/StarRenderCameraController.cs职责:
提供 Demo 用相机移动与鼠标环视。
将 Unity Transform 位置映射到观察者 AU。
自动寻找场景中的 GaiaSkySphereRenderer。
按住右键时:
xxxxxxxxxxyaw = MouseX * mouseLookDegreesPerPixelpitch = -MouseY * mouseLookDegreesPerPixelrotation = yawAroundWorldUp * pitchAroundCameraRight * rotation这里 yaw 采用 Unity Vector3.up,pitch 采用相机自身 right。由于 ICRS 世界使用 +Z 表示天球北极,而 Demo 控制器仍采用常规 Unity +Y yaw 轴,这是一种用于交互便利的相机控制约定,不应被误解为天文学坐标变换。
局部输入方向:
xxxxxxxxxxW/S -> local forward/backA/D -> local left/rightQ/E -> local down/upLeft Shift -> speed *= fastMoveMultiplier位移:
xxxxxxxxxxtransform.position += transform.rotation * normalizedLocalDirection * speed * deltaTime若 syncTransformPositionToObserverAu = true:
xxxxxxxxxxoffset = transform.position - unityPositionOriginobserverAU = observerAuAtOrigin + offset * auPerUnityUnit默认:
xxxxxxxxxxauPerUnityUnit = 0.01也就是相机移动 1 Unity unit,对应观察者位置改变 0.01 AU。注意,改变观察者字段本身不会自动重建星表;需要通过面板或代码调用 Rebuild() 才会把新观察者位置应用到恒星方向。
StarVisualSettingsPanel路径:
xxxxxxxxxxAssets/StarSky/Runtime/Visualization/StarVisualSettingsPanel.cs职责:
提供运行时 IMGUI 调参面板。
克隆材质,避免直接修改项目资源材质。
每帧应用 Shader 参数。
允许用户触发星等过滤、观察者位置和时间改变后的重建。
运行时默认参数:
| 控件 | 默认值 | 作用 |
|---|---|---|
Pixel Scale | 1.0 | 星点半径全局倍率 |
Min Pixel Radius | 1.15 | 最小屏幕像素半径 |
Intensity | 2.6 | additive 输出强度 |
Gaussian / PSF Profile | true | 是否使用 Gaussian 模型 |
Gaussian Sigma | 0.42 | Gaussian 宽度 |
Core Size | 0.18 | Core/glow 模式核心大小 |
Magnitude Limit | 8.0 | 可视 G 星等上限 |
GaiaCatalog路径:
xxxxxxxxxxAssets/StarSky/Runtime/Catalog/GaiaCatalog.cs职责:
包装 GaiaStarRecord[]。
提供 Count、Stars 和 indexer。
从任意文件路径或 StreamingAssets 相对路径加载星表。
GaiaCatalogBinary路径:
xxxxxxxxxxAssets/StarSky/Runtime/Catalog/GaiaCatalogBinary.cs职责:
写入 StarSky 二进制星表。
读取并验证 StarSky 二进制星表。
管理 magic、version 和参考历元检查。
GaiaStarRecord路径:
xxxxxxxxxxAssets/StarSky/Runtime/Catalog/GaiaStarRecord.cs职责:
存储单颗恒星的天体测量与光度字段。
判断视差是否可用。
计算 BP-RP 颜色指数。
GaiaStarPropagator路径:
xxxxxxxxxxAssets/StarSky/Runtime/Catalog/GaiaStarPropagator.cs职责:
将 RA/Dec 转为 ICRS 单位方向。
构造 east/north 切向基。
将 Gaia 自行转换为方向导数。
传播无限远方向。
根据视差构造有限距离 AU 位置。
从观察者位置得到观测方向。
JulianDateTT路径:
xxxxxxxxxxAssets/StarSky/Runtime/JulianDateTT.cs职责:
表示 TT 儒略日。
在儒略年与 TT JD 之间转换。
将 UTC DateTime 近似转换为 TT JD。
计算相对 Gaia J2016.0 的年差。
DVector3路径:
xxxxxxxxxxAssets/StarSky/Runtime/Math/DVector3.cs职责:
提供 double 精度三维向量。
支持 dot、cross、normalize、标量运算。
与 Unity Vector3 互转。
使用 double 的原因是天体测量计算涉及极小角度、AU、parsec 等尺度,若过早使用 float 容易积累精度误差。最终进入 Unity Mesh 前再转为 float。
GaiaDr3CsvImporterWindow路径:
xxxxxxxxxxAssets/StarSky/Editor/GaiaDr3CsvImporterWindow.cs菜单:
xxxxxxxxxxStarSky > Gaia DR3 ImporterStarSky > Import gaiadr3.csv From Project Root窗口功能:
选择 CSV 输入路径。
选择二进制输出路径。
控制是否保留非正视差。
显示导入进度。
输出导入统计。
默认导入函数:
xxxxxxxxxxGaiaDr3CsvImporterWindow.ImportDefault()默认路径:
xxxxxxxxxxInput: <ProjectRoot>/gaiadr3.csvOutput: <ProjectRoot>/Assets/StreamingAssets/StarSky/gaiadr3_icrs_j2016.binImportStats导入统计结构:
| 字段 | 含义 |
|---|---|
readRows | 已读取的数据行数,不包含表头 |
importedRows | 成功写入记录数 |
invalidRows | 空行、字段不足或解析失败行数 |
nonPositiveParallaxRows | 非正视差行数 |
StarSkyDemoSceneBuilder路径:
xxxxxxxxxxAssets/StarSky/Editor/Demo/StarSkyDemoSceneBuilder.cs菜单:
xxxxxxxxxxStarSky > Create Demo SceneStarSky > Validate Demo SceneStarSky > Export Demo Preview PNGCreateDemoScene() 会:
创建空场景。
创建 StarSky Render Camera。
设置相机黑色背景、FOV、裁剪面。
添加 AudioListener。
创建 Gaia Visual Sky。
添加并配置 GaiaSkySphereRenderer。
给相机添加 StarRenderCameraController。
给相机添加 StarVisualSettingsPanel。
保存场景到 Assets/StarSky/Scenes/StarSkyDemo.unity。
将该场景写入 EditorBuildSettings.scenes。
Demo 初始朝向由:
xxxxxxxxxxCameraToIcrsRotation(60.0, 30.0)构造。其 forward 为:
xxxxxxxxxxforward = direction(RA=60 deg, Dec=30 deg)其 up 使用局部 north 向量:
xxxxxxxxxxnorth =[ -sin(dec) cos(ra), -sin(dec) sin(ra), cos(dec)]最终:
xxxxxxxxxxQuaternion.LookRotation(forward, north)这样相机初始画面不仅看向指定天球方向,还尽量让画面竖直方向对应天球北。
ValidateDemoScene() 执行:
打开 Demo 场景。
查找 GaiaSkySphereRenderer。
调用 sky.Rebuild()。
如果没有生成子 chunk,则抛出异常。
ExportDemoPreviewPng() 执行:
打开 Demo 场景。
查找 Camera 和 GaiaSkySphereRenderer。
调用 sky.Rebuild()。
创建 1280 x 720 RenderTexture。
调用 camera.Render()。
ReadPixels() 到 Texture2D。
ImageConversion.EncodeToPNG() 写入 PNG。
Shader 路径:
xxxxxxxxxxAssets/StarSky/Runtime/Visualization/Shaders/StarSkyAdditiveStarBillboard.shaderShader 名称:
xxxxxxxxxxStarSky/Visualization/Additive Star Billboard| Property | 默认值 | 范围 | 作用 |
|---|---|---|---|
_Intensity | 2.5 | [0.1, 8] | additive 亮度倍率 |
_CoreSize | 0.18 | [0.01, 0.8] | Core/glow 模式核心半径 |
_Profile | 1 | float | <0.5 为 core/glow,否则 Gaussian |
_GaussianSigma | 0.42 | [0.12, 0.85] | Gaussian 标准差 |
_PixelScale | 1.0 | [0.1, 8] | 星点像素半径倍率 |
_MinPixelRadius | 1.15 | [0, 4] | 最小像素半径 |
默认材质:
xxxxxxxxxxAssets/StarSky/Runtime/Visualization/Materials/GaiaStarVisualMaterial.mat材质当前保存值:
xxxxxxxxxx_CoreSize = 0.18_GaussianSigma = 0.42_Intensity = 2.6_MinPixelRadius = 1.15_PixelScale = 1.0_Profile = 1.0xxxxxxxxxxstruct appdata{ float4 vertex : POSITION; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; fixed4 color : COLOR;};语义:
vertex:星点中心,四个顶点相同。
uv:四边形角坐标。
uv2.x:CPU 计算出的半径像素值。
color:RGB 颜色和基础 alpha。
xxxxxxxxxxstruct v2f{ float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; fixed4 color : COLOR;};输出中不需要传递世界坐标或法线,因为星点不参与光照。
Unity 将 object space 顶点变换到 clip space:
xxxxxxxxxxcenterClip = MVP * centerObject透视除法后:
xxxxxxxxxxndc = centerClip.xy / centerClip.w屏幕宽度为 W,高度为 H。若希望 NDC 中移动半径 r 像素:
xxxxxxxxxxdeltaNdc = (2r / W, 2r / H)对应 clip space:
xxxxxxxxxxdeltaClip = deltaNdc * centerClip.w这就是 Shader 中:
xxxxxxxxxxfloat2 pixelToClip = float2(2.0 / _ScreenParams.x, 2.0 / _ScreenParams.y) * centerClip.w;centerClip.xy += corner * halfSizePixels * pixelToClip;的来源。
片元阶段将 uv 映射到以中心为原点的单位方形:
xxxxxxxxxxp = uv * 2 - 1d = length(p)当 d > 1 附近,edge fade 让 Gaussian profile 平滑消失。由于四边形本身仍覆盖一个正方形,profile 的圆形衰减负责让星点视觉上成为圆形。
xxxxxxxxxxQueue = TransparentZWrite OffBlend One One这意味着:
渲染顺序可能受透明队列排序影响。
由于 additive blending 可交换性较强,排序问题比传统 alpha blend 小。
不写深度适合天球背景,但若未来与不透明场景混合,需要明确星空与场景的渲染层级。
运行时:namespace StarSky
编辑器:namespace StarSky.Editor
Assets/StarSky/Runtime:运行时逻辑。
Assets/StarSky/Editor:Unity Editor 专用逻辑。
Assets/StarSky/Runtime/Catalog:星表结构、读写和天体测量传播。
Assets/StarSky/Runtime/Math:数学基础类型。
Assets/StarSky/Runtime/Visualization:渲染组件、相机控制和 UI 面板。
Assets/StreamingAssets/StarSky:运行时数据文件。
内部星表参考系:ICRS。
内部星表参考历元:Gaia J2016.0。
参考历元 TT JD:2457389.0。
自行单位:mas/year。
pmra 解释:Gaia mu_alpha_star,即 d(alpha)/dt * cos(delta)。
正视差:可构造有限距离位置。
非正视差:可保留为无限远方向,或在导入时丢弃。
径向速度:当前输入不包含,算法不建模。
传播时间使用 TT。
UTC 输入需通过 TAI-UTC + 32.184s 转为 TT。
默认 TAI-UTC = 37s。
年差使用儒略年 365.25 天。
天体测量计算使用 double 和 DVector3。
Unity Mesh 和 Shader 输入使用 float。
从 double 到 float 的转换发生在方向归一化后,主要用于单位天球渲染。
GaiaSkySphereRenderer 生成的星点子对象:
名称为 Gaia Visual Stars。
被加入 generatedChildren 列表。
设置 HideFlags.DontSave。
每次重建前先清理。
这样避免运行时重建生成的临时 Mesh 污染场景文件。
StarVisualSettingsPanel 在运行时克隆材质:
xxxxxxxxxxruntimeMaterial = new Material(skyRenderer.starMaterial)随后将 skyRenderer.starMaterial 指向克隆材质。这样滑块调整不会直接覆盖项目里的 GaiaStarVisualMaterial.mat。
改变 Shader 参数不需要重建 Mesh。
改变 magnitude limit、观察者 AU、时间源,需要重建 Mesh 才能反映到星点集合和方向。
maxVisualStars = 0 表示不按数量截断。
useCubeSplitting = true 表示先按 6 个主方向分桶,再按 chunk 大小建 Mesh。
CSV 导入:
xxxxxxxxxxTime: O(N)Space: O(N)其中 N 为 CSV 数据行数量。导入器会将有效记录累积到 List<GaiaStarRecord> 后一次性写入二进制文件。
二进制加载:
xxxxxxxxxxTime: O(N)Space: O(N)读取时创建 GaiaStarRecord[],每条记录约 60 字节载荷,不含数组对象开销。
GaiaSkySphereRenderer.Rebuild():
xxxxxxxxxxBuildVisualStars: O(N)Sort: O(M log M)Mesh generation: O(M)其中:
N:星表总记录数。
M:通过 magnitude limit 后的可视记录数。
当前实现会对可视星排序,以便 maxVisualStars 截断时保留最亮星。若未来星表更大,且只需要 top K,可以改为 partial selection 或 heap。
每颗星 4 个顶点。每顶点至少包含:
position:3 floats = 12 bytes。
color:Unity Color 通常 4 floats = 16 bytes。
uv:2 floats = 8 bytes。
uv2:2 floats = 8 bytes。
仅这些数组近似:
xxxxxxxxxxper vertex = 44 bytesper star = 4 * 44 = 176 bytes再加 triangle index:
xxxxxxxxxx6 indices per starUnity 内部 Mesh 上传和托管数组还有额外开销。因此 magnitude limit 和 maxVisualStars 是实际项目中控制内存与渲染成本的关键参数。
Unity 常规 Mesh 点图元和不同图形 API 对 point size 的支持并不稳定,而且很难实现跨平台一致的柔和星点 profile。使用四边形 billboard 的优势是:
可控的屏幕像素大小。
可控的 Gaussian / glow profile。
与普通透明渲染管线兼容。
可在 fragment shader 中执行更丰富的视觉模型。
每帧对几十万颗星执行时间传播、视差观测和 Mesh 更新成本很高,且星空变化在短时间交互中通常不可见。StarSky 选择:
材质视觉参数每帧更新。
星表方向和可见集合按需重建。
这符合“交互调参”和“天文时间切换”两个使用场景。
推荐最小验证:
执行 StarSky > Import gaiadr3.csv From Project Root。
确认 console 输出 imported star 数量。
执行 StarSky > Create Demo Scene。
执行 StarSky > Validate Demo Scene。
打开 Demo 场景进入 Play Mode。
使用 F1 调节 Magnitude Limit 与 Pixel Scale,检查星点密度和大小变化。
在 Windows 上,可使用 Unity batchmode 调用静态编辑器方法。根据本仓库的 Unity 版本,示例为:
xxxxxxxxxx& "C:\Program Files\Unity\Hub\Editor\6000.4.8f1\Editor\Unity.com" ` -batchmode ` -quit ` -projectPath "C:\Users\luwei\Desktop\StarSky" ` -executeMethod StarSky.Editor.GaiaDr3CsvImporterWindow.ImportDefault ` -logFile "C:\Users\luwei\Desktop\StarSky\unity-import-catalog.log"创建 Demo 场景:
xxxxxxxxxx& "C:\Program Files\Unity\Hub\Editor\6000.4.8f1\Editor\Unity.com" ` -batchmode ` -quit ` -projectPath "C:\Users\luwei\Desktop\StarSky" ` -executeMethod StarSky.Editor.StarSkyDemoSceneBuilder.CreateDemoScene ` -logFile "C:\Users\luwei\Desktop\StarSky\unity-demo-scene.log"验证 Demo 场景:
xxxxxxxxxx& "C:\Program Files\Unity\Hub\Editor\6000.4.8f1\Editor\Unity.com" ` -batchmode ` -quit ` -projectPath "C:\Users\luwei\Desktop\StarSky" ` -executeMethod StarSky.Editor.StarSkyDemoSceneBuilder.ValidateDemoScene ` -logFile "C:\Users\luwei\Desktop\StarSky\unity-demo-validate.log"导出预览:
xxxxxxxxxx& "C:\Program Files\Unity\Hub\Editor\6000.4.8f1\Editor\Unity.com" ` -batchmode ` -quit ` -projectPath "C:\Users\luwei\Desktop\StarSky" ` -executeMethod StarSky.Editor.StarSkyDemoSceneBuilder.ExportDemoPreviewPng ` -logFile "C:\Users\luwei\Desktop\StarSky\unity-demo-preview.log"当前二进制星表头应满足:
xxxxxxxxxxMagic SSKYGAIAVersion 1ReferenceEpochJd 2457389.0Count 291270若运行时报错:
xxxxxxxxxxUnexpected StarSky catalog magicUnsupported StarSky catalog versionCatalog reference epoch is ...说明运行时文件不是当前格式,或被旧版本/其他工具覆盖。
可以用以下经验检查结果是否合理:
调低 Magnitude Limit:星星数量明显减少,亮星仍保留。
调高 Pixel Scale:所有星点半径变大。
调高 Intensity:星空整体更亮。
切换 Gaussian / core profile:星点边缘形态发生变化。
修改 UTC 或 TT JD 并 rebuild:高自行恒星方向应发生极小变化,整体星空不应剧烈跳变。
改变观察者 AU 并 rebuild:有正视差的近距离恒星应产生相对更明显的方向变化,但大多数远星变化很小。
当前实现:
使用一阶切平面自行传播。
不使用径向速度。
不建模透视加速度。
不建模光行时。
不建模引力透镜或相对论修正。
不执行 ICRS 到 CIRS、GCRS、topocentric、horizontal 的变换。
因此它适合星空背景、视觉演示和交互探索,不适合作为高精度天文测量工具(需要额外根据星图数据进行实现,可视化渲染层与天文导航测量层应进行分离设计)。
当前实现:
使用 Gaia G 星等控制大小和 alpha。
使用 BP-RP 近似色温。
使用 additive blending 产生视觉亮度。
不进行物理曝光、HDR 色调映射或真实光谱积分。
这意味着星点视觉效果是“科学数据驱动的艺术化可视化”,不是严格的辐射传输结果。
当前实现:
所有星点投放到固定半径天球。
星点大小以屏幕像素为单位。
不使用真实角直径。
不做遮挡、星际尘埃、银河背景或大气散射。
对于沉浸式星空显示,这些选择可获得更好的稳定性和实时性。
当前实现:
不做异步加载。
不做运行时增量 streaming。
不做对象池化。
不做 compute shader 粒子渲染。
不做 Addressables 或 AssetBundle 管理。
CSV parser 不支持复杂 quoted CSV。
暂时不做计划。
可扩展项:
引入 radial velocity。
使用完整 3D 空间速度传播。
加入 perspective acceleration。
加入光行时迭代。
加入 ICRS 到地平坐标的完整变换链。
引入 SOFA/ERFA 级别的时间和坐标模型。
可扩展项:
用 Gaia passband 做更严谨的颜色校正。
建立 G/BP/RP 到显示 RGB 的标定。
引入 HDR render texture 与曝光控制。
加入 bloom、diffraction spikes、镜头像差。
加入银河背景、尘埃消光和星云层。
可扩展项:
使用 GPU instancing。
使用 StructuredBuffer + DrawProcedural。
使用 compute shader 做可见性过滤。
建立按 HEALPix、octree 或 cube map tile 的空间索引。
支持星表按 magnitude 或 tile 分级加载。
可扩展项:
导入器支持字段映射配置。
导入时生成统计报告。
导入时按星等预排序或建立索引。
自动检测 Unity 版本和数据文件。
添加 EditMode / PlayMode 测试。
增加二进制格式迁移工具。
检查:
Assets/StreamingAssets/StarSky/gaiadr3_icrs_j2016.bin 是否存在。
Gaia Visual Sky 上的 starMaterial 是否已赋值。
visualMagnitudeLimit 是否过低。
Console 是否出现 catalog magic、version 或 file not found 错误。
GaiaSkySphereRenderer.rebuildOnStart 是否为 true。
调整:
增大 Pixel Scale。
增大 Min Pixel Radius。
调低 Magnitude Limit,减少暗星密度。
使用 Gaussian / PSF profile。
调整:
降低 Intensity。
降低 Pixel Scale。
降低 Min Pixel Radius。
调低 Magnitude Limit。
原因:
时间和观察者影响的是 Mesh 中保存的星点方向。
需要点击面板中的 rebuild 按钮,或调用 GaiaSkySphereRenderer.Rebuild()。
检查:
CSV 是否在项目根目录。
表头是否包含全部必需列名。
小数点是否为 . 而不是本地化逗号。
文件是否被其他程序占用。
CSV 是否包含 quoted comma 等当前 parser 不支持的复杂格式。
xxxxxxxxxxu =[ cos(delta) cos(alpha), cos(delta) sin(alpha), sin(delta)]xxxxxxxxxxeast =[ -sin(alpha), cos(alpha), 0]xxxxxxxxxxnorth =[ -sin(delta) cos(alpha), -sin(delta) sin(alpha), cos(delta)]xxxxxxxxxxtangentRate = (east * pmra + north * pmdec) * (pi / 180 / 3600000)xxxxxxxxxxDeltaYears = (JD_TT - 2457389.0) / 365.25xxxxxxxxxxu(t) = normalize(u0 + tangentRate * DeltaYears)xxxxxxxxxxdistanceParsec = 1000 / parallaxMasdistanceAu = distanceParsec * 206264.80624709636xxxxxxxxxxpositionAu(t) = u0 * distanceAu + tangentRate * distanceAu * DeltaYearsxxxxxxxxxxobservedUnit = normalize(positionAu(t) - observerBcrsAu)xxxxxxxxxxJD_TT = JD_UTC + (TAI_minus_UTC + 32.184) / 86400xxxxxxxxxxT = 4600 * (1 / (0.92 * c + 1.7) + 1 / (0.92 * c + 0.62))其中:
xxxxxxxxxxc = clamp(BP - RP, -0.4, 2.8)xxxxxxxxxxpixelToClip = (2 / screenSize) * clip.wclip.xy += corner * halfSizePixels * pixelToClip| 文件 | 职责 |
|---|---|
Assets/StarSky/Runtime/Catalog/GaiaStarRecord.cs | 单颗恒星数据结构 |
Assets/StarSky/Runtime/Catalog/GaiaCatalogBinary.cs | 二进制星表读写 |
Assets/StarSky/Runtime/Catalog/GaiaCatalog.cs | 星表数组封装和加载入口 |
Assets/StarSky/Runtime/Catalog/GaiaStarPropagator.cs | ICRS 方向、自行、视差、观察方向传播 |
Assets/StarSky/Runtime/JulianDateTT.cs | TT 儒略日、UTC 转 TT、J2016 年差 |
Assets/StarSky/Runtime/Math/DVector3.cs | double 精度三维向量 |
Assets/StarSky/Runtime/Visualization/GaiaSkySphereRenderer.cs | 星表加载、过滤、可视星生成、Mesh chunk 构建 |
Assets/StarSky/Runtime/Visualization/StarRenderCameraController.cs | Demo 相机控制和观察者 AU 同步 |
Assets/StarSky/Runtime/Visualization/StarVisualSettingsPanel.cs | 运行时 IMGUI 参数面板 |
Assets/StarSky/Runtime/Visualization/Shaders/StarSkyAdditiveStarBillboard.shader | 屏幕空间 billboard 展开和 additive 星点着色 |
Assets/StarSky/Runtime/Visualization/Materials/GaiaStarVisualMaterial.mat | 默认星点材质 |
Assets/StarSky/Editor/GaiaDr3CsvImporterWindow.cs | CSV 导入窗口与默认导入菜单 |
Assets/StarSky/Editor/Demo/StarSkyDemoSceneBuilder.cs | Demo 场景创建、验证和 PNG 导出 |
Assets/StarSky/Runtime/StarSky.Runtime.asmdef | Runtime assembly 定义 |
Assets/StarSky/Editor/StarSky.Editor.asmdef | Editor assembly 定义 |
| 术语 | 说明 |
|---|---|
| Gaia DR3 | Gaia mission 的第三次数据发布 |
| ICRS | International Celestial Reference System,国际天球参考系 |
| BCRS | Barycentric Celestial Reference System,太阳系质心天球参考系 |
| RA / alpha | Right Ascension,赤经 |
| Dec / delta | Declination,赤纬 |
| Parallax | 视差,用于估计距离 |
| Proper motion | 自行,恒星在天球上的角速度 |
pmra | Gaia 中的 mu_alpha_star,即 d(alpha)/dt * cos(delta) |
pmdec | 赤纬方向自行 |
| TT | Terrestrial Time,地球时 |
| TAI | International Atomic Time,国际原子时 |
| JD | Julian Date,儒略日 |
| AU | Astronomical Unit,天文单位 |
| parsec | 秒差距,约等于 206264.806 AU |
| BP-RP | Gaia 蓝光度与红光度星等差,用作颜色指数 |
| Billboard | 始终面向屏幕或相机的二维图元 |
| Clip space | 顶点经 MVP 矩阵变换后的裁剪空间 |
| NDC | Normalized Device Coordinates,透视除法后的规范化设备坐标 |
| Additive blending | 加法混合,常用于光源、辉光和星点叠加 |