class in UnityEngine.Experimental.Rendering
封装含一个或多个子通道的单个渲染通道的持续时间的对象。
渲染通道对象是一种在可编程渲染管线环境中切换渲染目标的全新方式。与 SetRenderTargets 函数不同,渲染通道对象指定了明确的渲染开头和结尾以及渲染表面上的显式加载/存储操作。
渲染通道对象还允许在同一渲染通道中运行多个子通道,其中,像素着色器能够读取渲染通道中的当前像素值。这样可以高效实现基于区块的 GPU 上的各种渲染方法,例如延迟渲染。
渲染通道在 Metal (iOS) 和 Vulkan 上本机实现,但 API 能够通过仿真在所有渲染后端上完全正常运行(使用旧版 SetRenderTargets 调用并通过纹素抓取读取当前像素值)。
一个有关如何在可编程渲染管线中使用渲染通道 API 实现延迟渲染的简单示例:
渲染通道机制具有以下限制:
- 所有附件必须拥有相同的分辨率和 MSAA 样本数
- 先前子通道的渲染结果仅通过着色器中的 UNITY_READ_FRAMEBUFFER_INPUT(x) 宏在相同的屏幕空间像素
坐标中可用;附件不能绑定为
纹理或直到渲染通道结束才能访问。
- iOS Metal 不允许从 Z 缓冲区读取,因此需要其他渲染目标来执行这项操作
- 每个渲染通道允许的最大附件数量目前是 8 + 深,但请注意,不同的 GPU 可能
有更严格的限制。
using UnityEngine; using UnityEngine.Experimental.Rendering;
public class DeferredRenderer { private RenderPassAttachment m_Albedo; private RenderPassAttachment m_SpecRough; private RenderPassAttachment m_Normal; private RenderPassAttachment m_Emission; private RenderPassAttachment m_Depth;
public DeferredRenderer() { // Create the attachment objects. If these attachments are not specifically bound to any RenderTexture using the BindSurface calls, // these are treated as temporary surfaces that are discarded at the end of the renderpass // NOTE: DO NOT ALLOCATE NEW RENDERPASSATTACHMENTS EVERY FRAME! // These objects only get garbage collected when a scene is unloaded, so you'll leak a lot of objects. m_Albedo = new RenderPassAttachment(RenderTextureFormat.ARGB32); m_SpecRough = new RenderPassAttachment(RenderTextureFormat.ARGB32); m_Normal = new RenderPassAttachment(RenderTextureFormat.ARGB2101010); m_Emission = new RenderPassAttachment(RenderTextureFormat.ARGBHalf); m_Depth = new RenderPassAttachment(RenderTextureFormat.Depth);
// At the beginning of the render pass, clear the emission buffer to all black, and the depth buffer to 1.0f m_Emission.Clear(new Color(0.0f, 0.0f, 0.0f, 0.0f), 1.0f, 0); m_Depth.Clear(new Color(), 1.0f, 0); }
public void ExecuteRenderLoop(Camera camera, CullResults cullResults, ScriptableRenderContext scriptableRenderContext) { // Bind the albedo surface to the current camera target, so the final pass will render the scene to the screen backbuffer // The second argument specifies whether the existing contents of the surface need to be loaded as the initial values; // in our case we do not need that because we'll be clearing the attachment anyway. This saves a lot of memory // bandwidth on tiled GPUs. // The third argument specifies whether the rendering results need to be written out to memory at the end of // the renderpass. We need this as we'll be generating the final image there. // We could do this in the constructor already, but the camera target may change on the fly, esp. in the editor m_Albedo.BindSurface(BuiltinRenderTextureType.CameraTarget, false, true);
// All other attachments are transient surfaces that are not stored anywhere. If the renderer allows, // those surfaces do not even have a memory allocated for the pixel values, saving RAM usage.
// Start the renderpass using the given scriptable rendercontext, resolution, samplecount, array of attachments that will be used within the renderpass and the depth surface using (RenderPass rp = new RenderPass(scriptableRenderContext, camera.pixelWidth, camera.pixelHeight, 1, new[] { m_Albedo, m_SpecRough, m_Normal, m_Emission }, m_Depth)) { // Start the first subpass, GBuffer creation: render to albedo, specRough, normal and emission, no need to read any input attachments using (new RenderPass.SubPass(rp, new[] { m_Albedo, m_SpecRough, m_Normal, m_Emission }, null)) { // Render the deferred G-Buffer RenderGBuffer(cullResults, camera, scriptableRenderContext); } // Second subpass, lighting: Render to the emission buffer, read from albedo, specRough, normal and depth. // The last parameter indicates whether the depth buffer can be bound as read-only. // Note that some renderers (notably iOS Metal) won't allow reading from the depth buffer while it's bound as Z-buffer, // so those renderers should write the Z into an additional FP32 render target manually in the pixel shader and read from it instead using (new RenderPass.SubPass(rp, new[] { m_Emission }, new[] { m_Albedo, m_SpecRough, m_Normal, m_Depth }, true)) { PushGlobalShadowParams(scriptableRenderContext);
RenderLighting(camera, cullResults, scriptableRenderContext);
scriptableRenderContext.DrawSkybox(camera); } // Third subpass, tonemapping: Render to albedo (which is bound to the camera target), read from emission. using (new RenderPass.SubPass(rp, new[] { m_Albedo }, new[] { m_Emission }, true)) { // present frame buffer. FinalPass(scriptableRenderContext); } } } }
colorAttachments | 只读:RenderPassAttachment 对象数组目前绑定到此渲染通道。 |
context | 只读:为其创建渲染通道的 ScriptableRenderContext 对象。 |
depthAttachment | 只读:渲染通道中使用的深度/模板附件,如果没有,则为空。 |
height | 只读:渲染通道表面的高度(以像素为单位)。 |
sampleCount | 只读:渲染通道的 MSAA 样本数。 |
width | 只读:渲染通道表面的宽度(以像素为单位)。 |
RenderPass | 创建渲染通道并在 ScriptableRenderContext 中启动。 |
Dispose | 结束渲染通道。 |