2026-04-09 23:40:43 +08:00
|
|
|
|
# VolumeRendererComponent
|
|
|
|
|
|
|
|
|
|
|
|
**命名空间**: `XCEngine::Components`
|
|
|
|
|
|
|
|
|
|
|
|
**类型**: `class`
|
|
|
|
|
|
|
|
|
|
|
|
**头文件**: `XCEngine/Components/VolumeRendererComponent.h`
|
|
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
**描述**: 体积渲染组件,保存 `VolumeField` 与 `Material` 的运行时句柄、项目资源身份与序列化路径,并暴露阴影相关开关。
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
|
|
|
|
|
## 角色概述
|
|
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
`VolumeRendererComponent` 是当前场景里体积对象进入渲染链路的组件侧入口。它回答的是:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 这个 `GameObject` 当前绑定的是哪份体积资源?
|
|
|
|
|
|
- 这个体积资源应当使用哪份材质参与 `BuiltinVolumetricPass`?
|
|
|
|
|
|
- 反序列化后是立即同步加载,还是在 deferred scene load 模式下延迟到首次访问时异步兑现?
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
按当前实现,它同时维护两组并行状态:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- `VolumeField`
|
|
|
|
|
|
- 运行时 `ResourceHandle`
|
|
|
|
|
|
- 路径缓存 `m_volumeFieldPath`
|
|
|
|
|
|
- 项目资源身份 `m_volumeFieldRef`
|
|
|
|
|
|
- deferred async load 挂起状态
|
|
|
|
|
|
- `Material`
|
|
|
|
|
|
- 运行时 `ResourceHandle`
|
|
|
|
|
|
- 路径缓存 `m_materialPath`
|
|
|
|
|
|
- 项目资源身份 `m_materialRef`
|
|
|
|
|
|
- deferred async load 挂起状态
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
## 当前实现语义
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
### 资源绑定
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- `SetVolumeFieldPath(...)` / `SetMaterialPath(...)`
|
|
|
|
|
|
- 立即清空挂起异步状态
|
|
|
|
|
|
- 同步调用 `ResourceManager::Load<T>(path)`
|
|
|
|
|
|
- 尝试把路径回填成稳定的 `AssetRef`
|
|
|
|
|
|
- `SetVolumeField(...)` / `SetMaterial(...)`
|
|
|
|
|
|
- 从句柄反推当前路径
|
|
|
|
|
|
- 如果路径可解析为项目资源,则同步回填 `AssetRef`
|
|
|
|
|
|
- `ClearVolumeField()` / `ClearMaterial()`
|
|
|
|
|
|
- 同时清空句柄、路径、`AssetRef` 与挂起异步状态
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
### 序列化与反序列化
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
当前序列化优先级是:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 对有有效 `AssetRef` 的项目资源,优先写 `volumeRef=` / `materialRef=`
|
|
|
|
|
|
- 只有在没有有效 `AssetRef` 且路径带虚拟 scheme 时,才额外写 `volumePath=` / `materialPath=`
|
|
|
|
|
|
- 阴影标志始终写为 `castShadows=` 与 `receiveShadows=`
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
`Deserialize(...)` 的恢复顺序是:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
1. 先重置当前绑定与阴影标志。
|
|
|
|
|
|
2. 如果存在有效 `AssetRef`,优先按 `AssetRef` 恢复。
|
|
|
|
|
|
3. 在 deferred scene load 模式下,优先只恢复可解析路径,不立刻加载资源。
|
|
|
|
|
|
4. 只有虚拟路径在没有 `AssetRef` 时会被保留并作为恢复入口。
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
这意味着:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 普通项目资源的正式持久化协议是 `AssetRef`
|
|
|
|
|
|
- `test://`、`builtin://` 这类虚拟路径才长期依赖路径文本本身
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
### deferred async load
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
`GetVolumeField()` / `GetVolumeFieldHandle()` 与 `GetMaterial()` / `GetMaterialHandle()` 都带副作用:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 如果当前只有路径没有已兑现句柄,会先触发 `EnsureDeferredAsync*LoadStarted()`
|
|
|
|
|
|
- 如果异步结果已经完成,会在读取前调用 `ResolvePending*()` 收口结果
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
因此在 deferred scene load 模式下,组件常见的中间状态是:
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 路径与 `AssetRef` 已恢复
|
|
|
|
|
|
- 运行时句柄仍为空
|
|
|
|
|
|
- 首次读取句柄时才真正发起或收口异步加载
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
## 公开接口
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
| 接口 | 作用 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `GetVolumeField()` / `GetVolumeFieldHandle()` | 读取体积资源,并在需要时触发 deferred async load 收口 |
|
|
|
|
|
|
| `GetVolumeFieldPath()` / `GetVolumeFieldAssetRef()` | 读取体积资源元数据,不直接暴露 GPU/渲染行为 |
|
|
|
|
|
|
| `SetVolumeFieldPath(...)` / `SetVolumeField(...)` / `ClearVolumeField()` | 绑定或清空体积资源 |
|
|
|
|
|
|
| `GetMaterial()` / `GetMaterialHandle()` | 读取材质,并在需要时触发 deferred async load 收口 |
|
|
|
|
|
|
| `GetMaterialPath()` / `GetMaterialAssetRef()` | 读取材质元数据 |
|
|
|
|
|
|
| `SetMaterialPath(...)` / `SetMaterial(...)` / `ClearMaterial()` | 绑定或清空材质 |
|
|
|
|
|
|
| `GetCastShadows()` / `SetCastShadows(...)` | 控制组件层阴影投射标志 |
|
|
|
|
|
|
| `GetReceiveShadows()` / `SetReceiveShadows(...)` | 控制组件层阴影接收标志 |
|
|
|
|
|
|
| `Serialize(...)` / `Deserialize(...)` | 负责场景文本中的体积/材质引用恢复协议 |
|
|
|
|
|
|
|
|
|
|
|
|
## 测试与调用链
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
|
|
|
|
|
- `tests/Components/test_volume_renderer_component.cpp`
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 覆盖句柄/路径缓存
|
|
|
|
|
|
- 覆盖虚拟路径序列化
|
|
|
|
|
|
- 覆盖 deferred scene load 下按路径异步恢复体积资源
|
|
|
|
|
|
- `engine/src/Rendering/Extraction/RenderSceneUtility.cpp`
|
|
|
|
|
|
- 当前通过本组件读取 `VolumeField` 与 `Material`,组装 `VisibleVolumeItem`
|
|
|
|
|
|
- `editor/src/ComponentEditors/VolumeRendererComponentEditor.h`
|
|
|
|
|
|
- 当前 Inspector 里的 Volume Renderer 面板直接调用本组件的路径与阴影接口
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
|
|
|
|
|
## 当前实现边界
|
|
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- 组件只负责 CPU 侧资源引用与场景序列化,不负责 GPU 上传。
|
|
|
|
|
|
- 当前 `Get*Handle()` / `Get*()` 不是纯读取器,调用方要接受其会触发异步加载状态推进。
|
|
|
|
|
|
- 没有有效 `AssetRef` 的普通项目路径不会被当成正式持久化协议长期保留。
|
|
|
|
|
|
- 阴影标志当前在组件侧可读写可序列化,但具体是否在所有渲染路径都生效,要看上游提取与 pass 实现。
|
2026-04-09 23:40:43 +08:00
|
|
|
|
|
|
|
|
|
|
## 相关文档
|
|
|
|
|
|
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- [Components](../Components.md)
|
2026-04-09 23:40:43 +08:00
|
|
|
|
- [VolumeField](../../Resources/Volume/VolumeField/VolumeField.md)
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- [Material](../../Resources/Material/Material/Material.md)
|
2026-04-09 23:40:43 +08:00
|
|
|
|
- [VisibleVolumeItem](../../Rendering/FrameData/VisibleVolumeItem/VisibleVolumeItem.md)
|
|
|
|
|
|
- [BuiltinVolumetricPass](../../Rendering/Passes/BuiltinVolumetricPass/BuiltinVolumetricPass.md)
|
2026-04-09 23:50:33 +08:00
|
|
|
|
- [VolumeRendererComponentEditor](../../Editor/ComponentEditors/VolumeRendererComponentEditor/VolumeRendererComponentEditor.md)
|