MIT 许可证 NuGet

首页 / 功能 / 天空与大气

天空、大气与天气

天空是计算出来的,不是贴图出来的。散射 LUT 支撑着完整的昼夜循环: 太阳与月亮位置、月相、天空颜色、环境辐照度和空气透视全都源自 一个相位值。

大气通道产生什么

SkyAtmosphereEffect 在 FrameStart compute 阶段运行,并发布五张纹理。下游的一切——天空本身、远处几何体上的雾、 模型上的环境光——都采样它们,这就是它们不可能失去一致性的原因。

  • 透射率 LUT——多少光能穿过一段空气路径存活下来。
  • 多次散射 LUT——让蓝天呈现蓝色而不是黑色加一条亮带的二阶项。
  • 天空视图 LUT——每个方向上的天空辐射度,默认 256×128。
  • 云噪声——云层采样的 512×512 噪声纹理。
  • 空气透视 LUT——按距离分布的内散射 3D 体积。

可阅读的类型:Rendering/Atmosphere.cs、 DayNightCycle.cs、 SkyState.cs、 Effects/SkyAtmosphere.cs。

海面上的程序化日出天空 天空大气
参考应用中海上日出。

一个真实的星球,以公里计

大气按物理而非艺术方式参数化。默认值描述地球: 6360 km 地面半径、6460 km 大气壳层、8 km 瑞利标高, 观察者在地面以上 200 m。

Atmosphere 上的字段默认值含义
GroundRadiusKm6360星球半径。缩小它,地平线会明显弯曲。
AtmosphereRadiusKm6460大气壳层的顶部。
ViewAltitudeKm0.2喂给 LUT 的相机海拔。
RayleighHeightKm8分子散射的指数标高。
MiePhaseG0.8气溶胶的前向散射各向异性——太阳周围的光晕。
GroundAlbedo0.1多少光反射回天空。
MultiScatterGain1.0缩放多次散射项。低于 1 会得到更生硬、更稀薄的天空。

Atmosphere 是静态类,这也是一种刻意的收窄: 每个应用一个天空,而不是每个相机或每个场景一个。这让 LUT 保持单一集合。

太阳、月亮与星星

两个天体都是具有真实角尺寸的真实圆盘,这让它们的阴影和镜面高光 无需调参就是正确的大小。

字段默认值含义
SunIrradiance12以引擎单位计的太阳亮度。
SunAngularRadiusDeg0.2665从地球看到的太阳真实角半径。
SunDiskRadiance30圆盘本身的辐射度,与它的光照贡献分开。
MoonIrradiance0.6月光贡献。
MoonAngularRadiusDeg0.259月亮的真实角半径。
MoonColor(0.55, 0.68, 1.0)冷色调,因为对暗适应的眼睛来说月光是蓝色的。
StarRadiance0.15星星亮度。
StarVisibilityTwilightDeg18星星完全出现的太阳下沉角——天文暮光。
StarRotation, StarPoleAxis—天空绕哪里旋转,如果你想要不同的纬度或不同的星球。
NightAirglow0.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 采样。 这是让场景显得宏大所能启用的最便宜的东西。

设置默认值含义
SkyProcedural天空模式;初始化时读取。
SkyViewLutWidth / Height256 / 128天空视图 LUT 分辨率。
SkyRayMarchSteps16每条 LUT 光线的步数。天空质量/成本的主旋钮。
CloudNoiseSize512云噪声纹理边长。
AerialPerspectiveon是否构建并应用该 LUT。
AerialMaxDistanceKm32LUT 覆盖的距离。超出后保持远端值。
AerialIntensity1.0插值权重:1 是物理值,更高则夸张它。

AerialIntensity 高于 1 不是修 bug,而是对尺度的 让步。一个 200 m 宽的场景几乎得不到物理内散射;如果你仍然希望 它读起来像风景,就夸张权重并接受这是个谎言。

已知缺口

  • 部分 体积云。 云层是根据噪声纹理对照层模型着色的, 而不是作为体积进行光线步进。从地面看效果不错,但飞入其中就无法维持。
  • 缺失 降水、植被上的风、湿润表面。 天气影响光照和云量, 而不是地面。
  • 缺失 体积雾与光束。 空气透视是逐像素内散射, 不是太阳可以穿透的参与介质。