技术说明
UDS 与 UDW 的蓝图结构:启动流程、静态与动态属性、缓存系统、时间与光照的推导、云移动、材质状态管理,以及多人复制方式。
这一页面向需要改蓝图、或想弄清“为什么改了这个值要等一下才生效”的人。 不理解也不影响正常使用。
UDS 的蓝图结构
启动
Startup Sky 函数包含全部启动逻辑:编辑器里由 Construction Script 调用,
运行时由 Begin Play 调用,另外在运行时重启天空(套用配置、切换 Sky Mode)时也会调用。
它负责一次性设置,并执行一遍 Update 函数。
两个 Update 函数
| 函数 | 职责 |
|---|---|
Update Active Variables |
应用随时间、天气等经常变化的属性。运行时频繁调用。 |
Update Static Variables |
应用不预期在运行时变化的属性。只在 Construction Script 与 Begin Play 各跑一次, 之后除非手动调用,否则不再执行。 |
这也是“改静态属性没反应”的根源:它们属于 Update Static Variables 的管辖范围,
改完要调对应的 Static Properties - XXX 函数。
函数按功能分类命名,例如镜头光晕的静态属性函数就叫 Static Properties - Lens Flare,
放在 Lens Flare 分类下。几乎每个函数都有说明。
缓存系统
Project Mode 为 Game / Real-Time 时,UDS 用一套缓存把复杂计算摊开:
Cache Properties 把不同类型的数据缓存成“新旧两组值”的数组,两次缓存更新之间在新旧值之间插值。
- 更新周期不是固定的:变化越快,缓存刷新越频繁。
Monitor for Changes每帧观察时间与天气变量的变化速度,必要时立刻调整缓存节奏; 节奏本身由Increment Cache Timer管理。- 缓存独立于 Update 函数运行,因此它自己有
Cached Sun Vector、Cached Moon Phase这类变量——这些值需要被多处共享,但不一定等于当前的真实值。 - 应用缓存值的函数统一以
AP(Apply Properties)开头,由Update Active Variables触发的事件分发器调用。
时间与光照的实现
时间由 Time of Day 与 Date 两个变量驱动。日月旋转由时间推导(除非启用手动定位),
而它们的旋转又被缓存系统与 Update 函数用来推导雾色、光照强度等。
Time of Day在 Tick 里由Time of Day Animation与Apply System Time推进(对应功能开启时)。Date只在午夜由Offset Date推进一天。- 日月旋转是缓存值,在
Cache Sun and Moon Orientation里计算;启用模拟时改由Approximate Real Sun Moon and Stars依据时间、日期与经纬度计算。 - 缓存出来的朝向只写入
Sun World Rotation与Moon World Rotation两个“视觉用”变量。 灯光本体有自己的Lights Update设置,可以只按周期改变朝向——这两个变量就是中间层。 Update Active Variables再用这两个旋转的前向量推导各种随光照朝向变化的属性。
云移动的实现
云的移动单独处理,不在 Update 函数里:
Increment Cloud Movement Cache默认每秒执行几次,算出当前位置应按什么速度、朝什么方向偏移,缓存新旧位置。Update Cloud Movement每帧把缓存值写进材质参数。
体积云相关属性写入共享材质参数集合 UDS_VolumetricClouds_MPC,
这样云雾、云影等其它材质也能用同一批参数近似云量。
雾色与环境光色
雾与环境光的颜色主要由 Get Current Base Fog Colors 计算,输出环境雾色、方向雾色,
以及太阳与月亮各自的贡献。这些颜色既写进雾组件,也被其它逻辑复用——例如天光模式为
Cubemap with Dynamic Color Tinting 时,环境雾色会参与天光的颜色与强度计算。
UDS 的复制(Replication)
多人环境下 Time of Day 与 Date 会复制。做法不是每帧同步时间,而是:
- 服务端周期性更新
Replicated Time of Day变量,通知客户端用这个值校正; Day Length、Night Length、Time Speed、Simulation Speed这些“决定时间走多快”的参数本身也复制。
这样客户端大多数时候可以像服务端一样本地推进时间,只在收到新值时重新对齐。
UDW 的蓝图结构
UDW 的结构参照 UDS 设计。
| 函数 | 职责 |
|---|---|
Start Weather System | 对应 UDS 的 Startup Sky:创建天气设置对象等必要对象、启动随机天气等系统,并跑一遍 Update。 |
Update Current Global and Local Weather State | 每帧构造全局状态,以及(需要时)局部状态。 |
Monitor Local Weather Changes | 局部状态生成后检查各项是否越过阈值,越过的项会把相应函数绑定到
Update Active Variables 里的分发器上,以驱动所有响应这些值的系统。 |
Update Active Variables | 把变化应用到 Niagara、声音组件与材质效果。 |
Update Static Variables | 应用不随天气变化的属性,例如粒子的最大生成距离。 |
天气状态的构造
天气状态分两级构造:
全局状态(Global Weather State)
由 UDW 自身的设置决定:天气预设、Change Weather 函数、随机天气变化。
当影响全局状态的东西发生变化(例如开始一次过渡)时,Bind Global State Update Functions
会把需要的更新函数绑定到 Construct Global Weather 分发器,该分发器由
Update Current Global and Local Weather State 调用。
可绑定的函数负责:应用预设、处理过渡、应用随机状态、推进全局材质状态模拟等。
局部状态(Local Weather State)
构造方式一致:按需绑定函数到 Construct Local Weather。局部绑定处理
天气覆盖体积、径向风暴、云层之上的调整等。
Update Active Variables 里设置的属性几乎都在读取 Local Weather State 对象的值——
因为它代表玩家所在位置的天气。
Niagara 系统
UDW 使用的 Niagara 系统都在 Particles 文件夹。Rain、Dust、Snow、Wind Debris
共享大量模块与父发射器,行为大体相同。
它们都包含一个 CPU 碰撞发射器与一个 GPU 碰撞发射器,用来把有效的粒子路径填进 Niagara 数组;
UDW 在构造系统时按 Particle Collision Mode 关掉其中一个。
其余发射器从数组里随机取一条有效路径,据此决定位置、速度与寿命。
闪电方面:Lightning Strike 系统负责有可见闪电柱的落雷,
Obscured Lightning 负责只在云层里闪一下的被动效果。
天气粒子与云中闪电的 Niagara 组件主要由 Update 函数控制,落雷则由
Lightning Flash 图表生成。
声音的实现
大部分音效逻辑在 MetaSound 资产里(Sound/MetaSounds)。UDW 只负责周期性把天气状态值、
遮挡值与音量写进音频组件,插值在 MetaSound 图里按更新周期完成。
- 天气声分 Global 与 Directional 两路:Global 不做声像/空间化, Directional 会空间化,并且按方向应用遮挡(+X 方向被挡,则来自该方向的定向声衰减)。
- 两路都输出到音频总线
UDS_Weather_AudioBus,再由 UDW 上的 Sound Mixer 统一做立体声像与遮挡处理, 输出到 Base Submix。 - 遮挡值由 UDS 的 Player Occlusion 组件计算。
材质状态管理
Material State Manager(Blueprints/Weather_Effects/System)负责在开启
“Simulate Changing Material State Over Time” 时随时间推进全局材质状态。
关闭该选项时,材质状态直接取自参与构造全局状态的天气对象。
UDW 的复制
UDW 复制的是全局天气状态,以及天气覆盖体积与径向风暴各自的状态。 客户端据此各自计算自己的局部天气——所以每个玩家的“身边天气”可以不同, 但体积/风暴内外的状态是一致的。
全局状态本身不是逐值同步,而是同步“过渡系统使用的天气预设资产、随机天气变化、覆盖体积”这些输入。 这样客户端只在某个来源开始变化时收到更新,其余时间按与服务端相同的逻辑本地推算。