11 KiB
SRP Runtime v2 计划 2026-04-18
1. 结论
当前阶段的下一步,不是继续做 editor 对接,也不是直接开做 deferred,更不是马上把阴影、体积、高斯这些效果全部搬到 C#。
下一阶段的正确主线是:
Native RenderGraph / Native Scene Renderer
-> Managed SRP Runtime v2
-> Managed Renderer / Feature / Pass 组织层
-> 之后再开正式的 URP-like package
换句话说,SRP runtime v1 已经把“managed pipeline 能创建、能被 native 持有、能参与 stage record”这条链路打通了;
SRP runtime v2 要解决的是另一件更关键的事:
让 managed 侧不再只是“在 ScriptableRenderPipeline 里手写 stage”,而是正式进入 Unity/URP 风格的 Renderer / Feature / Pass 组织模型。
2. 当前状态判断
从现有代码看,下面这些能力已经成立:
RenderGraph、CameraFramePlan、stage dispatch、compile、execute 已经是工作状态。ScriptableRenderPipelineHost已经能作为 native 宿主,组合stage recorder + fallback renderer。ManagedScriptableRenderPipelineAsset已经不只是 descriptor 空壳,能够通过 bridge 创建 managed asset runtime。MonoScriptRuntime已经提供真实的ManagedRenderPipelineBridge,不再只是测试 seam。ScriptableRenderContext已经有最小可用能力,能:RecordScene()RecordScenePhase(...)RecordSceneInjectionPoint(...)RecordFullscreenPass(...)
- managed pipeline 已经能通过
ScriptableRenderContext驱动 nativeNativeSceneRecorder和 fullscreen pass sequence。 ScriptableRenderPipelineAsset已经可以参与:ConfigureCameraRenderRequest(...)ConfigureCameraFramePlan(...)GetDefaultFinalColorSettings()
也就是说,SRP runtime 的“宿主打通”问题已经不是主矛盾了。
当前真正的主矛盾变成了:
- managed 侧还没有
ScriptableRenderer - managed 侧还没有
ScriptableRendererFeature - managed 侧还没有
ScriptableRenderPass - managed 侧还没有
RenderPassEvent - pipeline 仍然直接在自己内部录制 stage,缺少可组合的 renderer 层
这意味着你现在虽然已经能“用 C# 自定义渲染”,但它还不是 Unity/URP 那种成熟形态。
现在的形态更接近:
Pipeline 直接写 RenderGraph 录制逻辑
而不是:
Pipeline -> Renderer -> Feature -> Pass
3. 为什么下一步必须先做这个
如果这一层不先补起来,后面会出现三个结构性问题:
3.1 自定义能力会卡死在 ScriptableRenderPipeline
当前用户要改渲染逻辑,主要方式还是:
- 继承
ScriptableRenderPipeline - 覆盖
SupportsStageRenderGraph(...) - 覆盖
RecordStageRenderGraph(...) - 直接手写
RecordScenePhase / RecordSceneInjectionPoint / RecordFullscreenPass
这条路能做 demo,但不能支撑成熟工程。
因为它缺少:
- renderer 内部 pass 队列
- feature 注入点
- renderer data / pipeline data
- 面向 camera/frame 的稳定数据载体
继续沿这条路堆功能,最后只会变成“能工作的脚本版 builtin forward”,而不是 Unity 意义上的 SRP/URP。
3.2 未来的阴影、后处理、体积、高斯没地方上移
你之前关心的那些东西,长期来看确实应该逐步从 C++ builtin 组织层往更高层移动,但它们要上移的不是裸 Pipeline,而是:
RendererRendererFeatureRenderPassRendererData
如果这层不存在,那后面谈“把 shadow 组织权搬到 URP 层”“把 volumetric/gassian 搬到包层”,都会没有落点。
3.3 未来正式做 URP-like package 会缺承接面
真正的 URP-like package 不是只多几个 C# 类名,而是至少要有:
PipelineAssetRendererDataRendererRendererFeatureRenderPassEventRenderPass
这几个层次如果不先在 SRP runtime 里长出来,后面直接开做 URP-like package 只会是壳子工程。
4. 本阶段目标
本阶段只做一件事:
把当前“managed pipeline 直接录 stage”的模型,升级成“managed pipeline 驱动 managed renderer,renderer 再组织 feature/pass”的模型。
收口后应该形成这样的关系:
ScriptableRenderPipelineAsset
-> ScriptableRenderPipeline
-> ScriptableRenderer
-> ScriptableRendererFeature
-> ScriptableRenderPass
-> ScriptableRenderContext
-> Native RenderGraph / NativeSceneRenderer
这一步完成后,你这个引擎才算真正进入“能继续往 Unity SRP/URP 方向长”的状态。
5. 本阶段明确不做的内容
这一阶段不做下面这些事:
- 不做 deferred pipeline。
- 不做 lightmap / baking。
- 不做 editor 侧 inspector、资源面板、renderer asset 可视化编辑。
- 不把阴影、体积、高斯、后处理全部迁到 C#。
- 不直接暴露 raw RHI、raw RenderGraph handle 给脚本层。
- 不为了兼容临时方案而长期保留双轨 API。
注意:
这不是说这些东西以后不做,而是说现在最值钱的一刀不是它们。
现在最值钱的是先把 renderer 组织层做对。
6. 目标架构
6.1 继续留在 C++ 的部分
RHIRenderGraph- frame planning / stage dispatch / graph compile / execute
- scene extraction / culling / frame data
- native scene renderer 执行内核
- shadow / fullscreen / scene phase 的底层执行 primitive
6.2 开始在 managed 侧稳定下来的部分
ScriptableRenderPipelineAssetScriptableRenderPipelineScriptableRendererScriptableRendererFeatureScriptableRenderPassRenderPassEventRenderingData / CameraData这类组织层数据
6.3 这一阶段的核心原则
- C++ 负责执行内核,不负责未来用户级管线组织。
- managed 负责 renderer 组织,不直接持有底层 RHI 细节。
BuiltinForwardPipeline继续做默认 native backend,但不再是未来自定义渲染的最终承载层。- shadow / volumetric / gaussian 这类东西后续上移时,上移的是“组织权”,不是把所有 draw code 都改成 C#。
7. 分阶段实施
Phase A: 建立 managed renderer 基础抽象
先把 managed 侧最基础的几块搭出来:
ScriptableRendererScriptableRendererFeatureScriptableRenderPassRenderPassEventRenderingData v1CameraData v1
第一版不要追求大而全,只解决最小闭环:
- pass 能声明执行时机
- renderer 能收集 pass
- feature 能往 renderer 注入 pass
- pipeline 能把 camera/frame 数据传给 renderer
Phase B: 建立 renderer 的执行骨架
这一阶段要解决的是:
ScriptableRenderer.EnqueuePass(...)- pass 按
RenderPassEvent排序 - renderer 根据 event 把 pass 映射到当前已有的 native 能力:
RecordScenePhase(...)RecordSceneInjectionPoint(...)RecordFullscreenPass(...)
- renderer 能组织默认的主场景录制顺序
这里的关键不是“把所有 pass 都写复杂”,而是先把组织模型做出来。
Phase C: 做一个最小前向 renderer
在 managed 侧做第一条真正能跑的 renderer 主链:
- 默认 opaque pass
- 默认 skybox pass
- 默认 transparent pass
- 默认 post-process/fullscreen pass
- 允许 feature 在标准 injection point 前后插入 pass
注意这里的“前向 renderer”还不是最终版 URP,只是:
一个 SRP runtime v2 上的 first-party renderer 验证样板。
Phase D: 把 pipeline asset 和 renderer data 关系收清楚
这一阶段要让 ScriptableRenderPipelineAsset 不再只是“创建 pipeline”,还要能稳定持有 renderer 配置关系。
第一版建议先做到:
- asset 持有一个默认 renderer data
- pipeline 从 asset 创建 renderer
- renderer feature 由 renderer data 决定启用顺序
- camera/frame 规划仍然通过现有 planning context 接入
也就是说,要先有:
PipelineAsset -> RendererData -> Renderer
这条关系。
Phase E: 替换 probe 级实现,形成正式 smoke path
这一阶段不再满足于 probe/demo,而是要形成正式可回归的主链:
- 用 renderer/pass 模型重做当前 managed forward probe
- 验证主场景 + fullscreen 仍然能工作
- 验证 pipeline 切换时生命周期正确
- 验证 native fallback 路径仍然可用
这一步收口后,才算本阶段真正完成。
8. 第一批要改的文件
Managed 侧
优先会落在这些位置:
managed/XCEngine.ScriptCore/ScriptableRenderPipelineAsset.csmanaged/XCEngine.ScriptCore/ScriptableRenderPipeline.csmanaged/XCEngine.ScriptCore/ScriptableRenderContext.cs- 新增
managed/XCEngine.ScriptCore/Rendering/*或等价目录 managed/GameScripts/RenderPipelineApiProbe.cs
第一批大概率会新增这些类型:
ScriptableRendererScriptableRendererFeatureScriptableRenderPassRenderPassEventRenderingDataCameraData
Native 侧
native 这一阶段不是主战场,但仍可能需要补桥接:
engine/src/Scripting/Mono/MonoScriptRuntime.cppengine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.hengine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp
只有当 managed renderer 需要额外上下文时,才增加新的 internal call / bridge 数据。
原则是:
能用现有 ScriptableRenderContext 表达的,就不继续扩 raw native API。
9. 验收标准
这一阶段收口时,至少要同时满足下面这些条件:
- managed 侧存在正式的
Renderer / Feature / Pass基础抽象。 ScriptableRenderPipeline不再是唯一的直接录制组织层。- 一个 managed forward renderer 能通过 pass 队列稳定跑通主场景和 fullscreen。
- feature 可以在标准 injection point 上插入 pass。
- pipeline asset 能稳定持有 renderer 配置关系。
- native
RenderGraph、NativeSceneRenderer、fallback renderer 路径不被破坏。 - editor 编译通过,并完成基础 smoke test。
只要上面任意一条不成立,这一阶段都不能算收口。
10. 完成本阶段之后,下一步才是什么
等这一阶段收口之后,下一步才适合正式进入更像 URP 的层级:
UniversalRenderPipelineAssetUniversalRendererDataUniversalRenderer- 官方 first-party
RendererFeature - 更成熟的
RenderPassEvent - 逐步把 shadow / volumetric / gaussian / post-process 的组织权上移
也就是说:
不是现在不能往 Unity 的 SRP/URP 方向走,而是现在要先把“SRP runtime 的 renderer 层”补齐。
这一步做对了,后面你再做:
- URP-like package
- deferred
- lightmap
- renderer asset 资源化
- editor 可视化配置
都会顺很多。
11. 下一刀从哪里下
下一步建议直接从 managed 侧开刀,顺序如下:
- 先加
ScriptableRenderer / ScriptableRenderPass / RenderPassEvent基础类型。 - 再把当前 probe 级
ManagedForwardRenderPipelineProbe改造成 renderer 驱动。 - 确认 renderer/pass 模型能复用现有
ScriptableRenderContext。 - 只有在 managed 侧明确缺上下文时,再补 native internal call。
简单说,下一刀不是继续修 C++ 渲染内核,而是:
开始正式搭 managed renderer 组织层。