AI教我UE渲染-学习笔记(7):PS输出到多个RT
0. 画多个RT
根据AI之前给到的路线,下面是要让PS输出到多个RT
AI也很快实现了代码。然后在RenderDoc中截帧,可以看到结果输出到了多个RT中:

相比之前几篇,本篇涉及的新内容很少,下面快速过下代码修改:
1. 着色器修改
着色器代码修改如下:
对于顶点着色器:
- 多了一个输入
in float3 InNormal : ATTRIBUTE2,,可以留意之后传入的顶点数据也会多一个Normal。 - 多了一个输出
out float3 OutNormal : TEXCOORD1,,可以留意之后传入像素着色器中的数据多了一个Normal
对于像素着色器:
- 多了一个输入
in float3 InNormal : TEXCOORD1,,这对应于顶点着色器。 - 多了一个输出
out float4 OutNormalEncoded : SV_Target1,可以留意在C++代码中像素着色器的绑定。
这里语法上我有些不确定的,所以问了下AI:
对于像素着色器的语法我有些想问的。
我留意到改之前像素着色器返回值是float4,然后函数声明的末尾是: SV_Target0。而现在像素着色器是void类型,SV_Target0和SV_Target1都变成了out 参数。所以返回值和out参数是等效的吗?你也可以再补充一些关于像素着色器与RT对应关系的一些知识。
AI回答:(仅供参考)
可以这么理解:在只写一路颜色时,return float4(...) : SV_Target0 和 void + out float4 X : SV_Target0 在语义上等价——都是给 RT 槽位 0 提供最终颜色。
单路输出:return 与 out
| 写法 | 含义 |
|---|---|
float4 MainPS(...) : SV_Target0 { return c; } |
单返回值,绑定到 SV_Target0 |
void MainPS(..., out float4 O : SV_Target0) { O = c; } |
通过 out 参数 写出 SV_Target0 |
编译器都会生成「PS 向第 0 个渲染目标写 float4」的接口。选哪种多半是风格和是否需要多路输出。
多路输出(MRT)为什么常用 void + 多个 out
HLSL 里一个函数不能 return 两个独立的 float4(不像有些语言的多返回值)。MRT 需要 多个独立语义,常见写法就是:
void MainPS(...,
out float4 Out0 : SV_Target0,
out float4 Out1 : SV_Target1)
也可以用 带语义的结构体 作为输出,本质一样,仍是多个 SV_TargetN 槽位。
所以:不是「return 和 out 在所有情况下都等价」,而是——单路时 return 可以看成 out 的语法糖;多路时通常用 void + 多个 out(或 struct)。
像素着色器与 RT 的对应关系(补充)
-
SV_TargetN里的 N 对应 PSO / 绑定里的 第 N 个颜色渲染目标(从 0 开始)。你在 C++ 里RenderTargets[0]、RenderTargets[1]就要和SV_Target0、SV_Target1顺序一致。 -
格式要匹配:每个 RT 的格式(如
PF_FloatRGBA)必须和 PS 里该路输出的类型兼容(一般是float4或可归约到 4 通道的向量)。 -
未声明的槽位:若 PSO 只绑了 2 张 RT,PS 里就不应再写
SV_Target2,否则未定义/编译错误。 -
深度:深度缓冲不是
SV_Target,而是 深度/模板子通道;深度来自SV_Position算出的深度,或由 PS 写SV_Depth(覆盖)。你当前学习路径里用的是默认深度,没有额外SV_Depth。 -
discard / clip:若像素被丢弃,所有 RT 都不会写入该像素(和深度规则一起由硬件处理)。
一句话:单路时 return ... : SV_Target0 ≈ out ... : SV_Target0;多路时必须用多个输出(多个 out 或带语义的 struct),这和 C++ 里 RenderTargets[0..1] 一一对应。
2. 顶点数据多Normal
不需要什么解释,之前已学习过相关概念
3. 创建法线的RT纹理
不需要什么解释,之前已学习过相关概念:
4. 绑定法线RT
这里的代码是:
这里问了AI俩问题:
- RenderTargets[0]和[1]是否完全对应于像素着色器里的SV_Target0和SV_Target1
- 我没有在我的像素着色器中定义RenderTargets这个变量,这个变量是哪来的?
AI回答:(仅供参考)
1. RenderTargets[0] / [1] 和 SV_Target0 / SV_Target1 是否一一对应?
是的。 在 UE / D3D 这条管线上,颜色 RT 绑定的顺序和 PS 里 SV_TargetN 的 N 一致:
RenderTargets[0]→ 绑定到 第 0 路颜色输出 → 对应SV_Target0RenderTargets[1]→ 绑定到 第 1 路 → 对应SV_Target1
深度/模板不占用这些下标,它们走的是 RenderTargets.DepthStencil,对应的是 DSV,不是 SV_Target*。
2. 没在 .usf 里写 RenderTargets,它从哪来?
RenderTargets 根本不在 HLSL 里,只在 C++ 的参数结构体里。
你在 FSceneLearningPS 里写了 RENDER_TARGET_BINDING_SLOTS(),宏会展开成固定名字的成员,类型是 FRenderTargetBindingSlots:
/** Adds bindings slots for render targets on the structure. This is important for rasterizer based pass bind the
* render target at the RHI pass creation. The name of the struct member will forced to be RenderTargets, and
* its type is a FRenderTargetBindingSlots.
* ...
*/
#define RENDER_TARGET_BINDING_SLOTS() \
INTERNAL_SHADER_PARAMETER_EXPLICIT(UBMT_RENDER_TARGET_BINDING_SLOTS, FRenderTargetBindingSlots::FTypeInfo, FRenderTargetBindingSlots,RenderTargets,,,EShaderPrecisionModifier::Float,TEXT(""),false)
也就是说:
- C++:
PSParameters->RenderTargets[0]告诉 RDG / RHI「这个 pass 要把第 0 路颜色写到哪张纹理、LoadAction 是什么」。 - HLSL:只声明
out float4 ... : SV_Target0/1,表示「PS 往第几路颜色输出写数据」。
两边通过 槽位编号 对上,而不是通过同名变量。RenderTargets 是 RDG 资源依赖 + RHI 绑 RT 用的;shader 里永远不会出现一个叫 RenderTargets 的变量。
5. SV_Target的SV是啥意思?
AI回答:
SV 是 System Value(系统值语义)的缩写。
在 HLSL 里,带 SV_ 前缀的语义表示:这个输入/输出由图形管线约定含义,由硬件或驱动按固定规则解释,而不是普通用户自定义的插值数据。
例如:
SV_Target0:第 0 路渲染目标(颜色输出)SV_Position:顶点阶段是裁剪空间位置;像素阶段常表示像素位置SV_Depth:可写深度(若使用)
所以 SV_Target = “系统约定的渲染目标输出槽位”。
AI这个解释得到了官方文档的证实:
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)