天空是计算出来的,不是贴图出来的。散射 LUT 支撑着完整的昼夜循环: 太阳与月亮位置、月相、天空颜色、环境辐照度和空气透视全都源自 一个相位值。
SkyAtmosphereEffect 在 FrameStart compute
阶段运行,并发布五张纹理。下游的一切——天空本身、远处几何体上的雾、
模型上的环境光——都采样它们,这就是它们不可能失去一致性的原因。
可阅读的类型:Rendering/Atmosphere.cs、
DayNightCycle.cs、
SkyState.cs、
Effects/SkyAtmosphere.cs。
天空大气
大气按物理而非艺术方式参数化。默认值描述地球: 6360 km 地面半径、6460 km 大气壳层、8 km 瑞利标高, 观察者在地面以上 200 m。
Atmosphere 上的字段 | 默认值 | 含义 |
|---|---|---|
GroundRadiusKm | 6360 | 星球半径。缩小它,地平线会明显弯曲。 |
AtmosphereRadiusKm | 6460 | 大气壳层的顶部。 |
ViewAltitudeKm | 0.2 | 喂给 LUT 的相机海拔。 |
RayleighHeightKm | 8 | 分子散射的指数标高。 |
MiePhaseG | 0.8 | 气溶胶的前向散射各向异性——太阳周围的光晕。 |
GroundAlbedo | 0.1 | 多少光反射回天空。 |
MultiScatterGain | 1.0 | 缩放多次散射项。低于 1 会得到更生硬、更稀薄的天空。 |
Atmosphere 是静态类,这也是一种刻意的收窄:
每个应用一个天空,而不是每个相机或每个场景一个。这让 LUT 保持单一集合。
两个天体都是具有真实角尺寸的真实圆盘,这让它们的阴影和镜面高光 无需调参就是正确的大小。
| 字段 | 默认值 | 含义 |
|---|---|---|
SunIrradiance | 12 | 以引擎单位计的太阳亮度。 |
SunAngularRadiusDeg | 0.2665 | 从地球看到的太阳真实角半径。 |
SunDiskRadiance | 30 | 圆盘本身的辐射度,与它的光照贡献分开。 |
MoonIrradiance | 0.6 | 月光贡献。 |
MoonAngularRadiusDeg | 0.259 | 月亮的真实角半径。 |
MoonColor | (0.55, 0.68, 1.0) | 冷色调,因为对暗适应的眼睛来说月光是蓝色的。 |
StarRadiance | 0.15 | 星星亮度。 |
StarVisibilityTwilightDeg | 18 | 星星完全出现的太阳下沉角——天文暮光。 |
StarRotation, StarPoleAxis | — | 天空绕哪里旋转,如果你想要不同的纬度或不同的星球。 |
NightAirglow | 0.004 | 让无月之夜不至于纯黑的微弱发射。 |
DayNightCycle 把一个相位值转换成一切依赖
时间的事物。Evaluate 是入口;类的其余部分是
你需要的各种转换。
// A day takes 100 seconds at the default speed of 0.01.
WorldSettings.DefaultDayNightSpeed = 0.004f; // slower
WorldSettings.DefaultStartHour = 5.5f; // just before sunrise
// Anywhere afterwards:
float phase = DayNightCycle.PhaseFromHour(18f); // dusk
float hour = DayNightCycle.HourFromPhase(phase);
| 成员 | 它给你什么 |
|---|---|
Evaluate | 为某个相位驱动太阳与月亮方向、色调和环境光。 |
BodyPosition | 某相位下指向太阳或月亮的方向。 |
MoonPhaseFactor | 月面照度,来自 SynodicDays 周期——月亮在真实月份里盈缺。 |
SkyTint, AmbientScale | 一天中的色调偏移和环境光强度。 |
StarAngle | 星空旋转。 |
SunriseHour | 太阳越过地平线的时刻,用于调度与之相关的事物。 |
CelestialPole | 天空绕其旋转的轴。 |
速度和起始时刻位于 WorldSettings 上,它从应用的
设置对象读取,因此如果你持久化设置,重启后仍然有效。
SkyState 是一个结构体,持有云层和少数几个
让云读起来像天气而不是纹理的标量。附带了四个预设,在它们之间
Lerp 就是锋面来袭的方式。
// Hold a settled state:
Atmosphere.Clouds = SkyState.Overcast;
// Or move between two over a minute:
float t = MathF.Min(1f, elapsed / 60f);
Atmosphere.Clouds = SkyState.Lerp(SkyState.Fair, SkyState.Storm, t);
| 字段 | 含义 |
|---|---|
Layers, LayerCount | 最多几条 SkyCloudLayer 条目,各自有自己的海拔和风。 |
Albedo | 云材质有多亮。 |
ShadowStrength | 云层把下方的太阳压暗多少。 |
PhaseG | 云内部的前向散射——乌云的金边。 |
AmbientFloor | 厚云层下的最低环境光,让阴天场景不至于一片死黑。 |
ForwardGain | 朝向观察者散射的光的额外增益。 |
每一层都是一个 SkyCloudLayer:
AltitudeKm、
ThicknessKm、
TileKm、
Coverage、
Density、
Detail 和
WindKmPerSec。风累积进
Atmosphere.CloudWindOffsetKm,因此云无需你
做任何逐帧工作就会漂移。
远处几何体拾取它前方空气的颜色,从空气 LUT 采样。 这是让场景显得宏大所能启用的最便宜的东西。
| 设置 | 默认值 | 含义 |
|---|---|---|
Sky | Procedural | 天空模式;初始化时读取。 |
SkyViewLutWidth / Height | 256 / 128 | 天空视图 LUT 分辨率。 |
SkyRayMarchSteps | 16 | 每条 LUT 光线的步数。天空质量/成本的主旋钮。 |
CloudNoiseSize | 512 | 云噪声纹理边长。 |
AerialPerspective | on | 是否构建并应用该 LUT。 |
AerialMaxDistanceKm | 32 | LUT 覆盖的距离。超出后保持远端值。 |
AerialIntensity | 1.0 | 插值权重:1 是物理值,更高则夸张它。 |
AerialIntensity 高于 1 不是修 bug,而是对尺度的
让步。一个 200 m 宽的场景几乎得不到物理内散射;如果你仍然希望
它读起来像风景,就夸张权重并接受这是个谎言。