虚幻引擎RDG图形管线调用流程
前言
这是我在学习 Unreal 渲染依赖图(RDG)过程中的踩坑与总结笔记(二),本篇主要记录在虚幻引擎中调用图形管线的实践过程。
虚幻版本5.7
本篇主要介绍如何通过 AddPass() 调用图形管线,Unreal 引擎的配置与上一篇相同。
在 UE 中使用 RDG 构建图形管线
编写顶点和像素着色器的usf文件
在工程目录下的Shaders创建一个名为GraphicsShader.usf的文件,编写以下代码:
1 | |
在 .usf 文件中,顶点输入必须通过 ATTRIBUTE 语义与顶点缓冲进行绑定。除系统语义外,着色器阶段之间只能使用 TEXCOORD 和 COLOR 作为中间语义。
创建顶点和像素着色器的Global Shader
接下来我们将回到上一篇中的 LearnRDGShader.cpp,在此基础上继续完善代码。
在LearnRDGShader.cpp中添加以下代码:
1 | |
这段代码的作用是将 .usf 文件中定义的着色器注册为 Unreal 引擎可识别和使用的全局着色器。
使用FRDGBuilder添加计算Pass
在LearnRDGShader.h中添加函数声明
1 | |
这里的 FRDGTextureRef 作为我们的渲染目标使用,本质上是一块存放在显存中的纹理缓冲区。
在LearnRDGShader.cpp中实现函数:
1 | |
和计算着色器相比,图形管线的配置会麻烦不少。我们需要依次配置图形管线的各个部分,比如顶点缓冲区、全局缓冲区,以及图形管线本身的各种选项。
接下来我们先来配置顶点缓冲区,整体流程可以分为以下几个步骤:
- 在 GPU 侧创建顶点缓冲区;
- 在 CPU 侧声明并准备具体的顶点数据;
- 将 CPU 端的数据上传到刚刚创建的 GPU 顶点缓冲区中;
- 配置对应的
FVertexDeclarationRHIRef; - 将其绑定到
FGraphicsPipelineStateInitializer的BoundShaderState.VertexDeclarationRHI中; - 指定所需的缓冲区。
相关代码如下:
1 | |
我们通过 FRDGBuilder 的成员函数 CreateBuffer() 来创建缓冲区,随后调用 QueueBufferUpload() 将 CPU 端的数据上传到顶点缓冲区中。
索引缓冲区的处理方式与此相同,按照同样的流程进行创建和数据上传即可。
配置管线的各种选项,包括视口大小、深度模板测试、混合方式、剔除方式、图元类型等等,完整代码如下:
1 | |
在Actor中的BeginPlay()中调用
新建一个 C++ 类,父类选择 Actor,并命名为 GraphicsRDGHelper。
随后在 GraphicsRDGHelper 类的 BeginPlay() 生命周期函数中,调用前面实现的用于向 RDG 添加计算 Pass 的函数。
GraphicsRDGHelper.h的内容如下:
1 | |
GraphicsRDGHelper.cpp的内容如下:
1 | |
在编辑器中创建蓝图
接下来为刚刚编写的 C++ 类创建对应的 UE 蓝图,并新建一个 Material 和一个 RenderTarget。将该 RenderTarget 连接到 Material 的 Base Color(基础色)输入上,然后将该 Material 指定给对应的 UE 蓝图进行使用。
点击模拟,可以看到颜色已经正确地输入到纹理
AddFullScreenPass
对于仅包含全屏两个三角形的顶点数据,可以直接使用 Unreal 提供的 AddFullScreenPass 辅助函数来简化代码实现,具体用法可以参考 UE 的相关源码实现。需要注意的是,在使用该辅助函数时,像素着色器在通常情况下只能接收一个 float4 类型的“位置”输入。
一个简单的例子:
1 | |
需要注意的是,与 GLSL 中的用法不同,这里的 SV_POSITION 表示的是屏幕空间下的像素位置,而非归一化后的 [-1, 1] NDC 坐标。