1.简介

随着Unity6的发布,URP17也已经可以上手使用,相对旧的版本改动较大的是加入了

RenderGraph、STP、Foveated rendering、GPU Resident Drawer等功能,部分功能只需要开关参数即可使用,

而GRD更像是Gpu driven管线下的SRP Batches升级,RenderGraph相较于HDRP之前使用的版本换了一套API。

最大的不同是,使用URP17编写Feature时,必须依赖于RenderGraph进行编写,接下来就来介绍一下。

1.1 相关Demo

目前URP17比较容易找到的学习Demo如下:

2.RenderGraph

打开任意URP的示例场景查看,RenderGraphView上各图标含义如下:

  1. 说明这是一个外部置入的RenderTexture
  2. 红色方块说明存在写入操作
  3. 绿色方块指存在读取操作(红绿方块说明读写操作)
  4. 该图标说明标记了全局RenderTexture

而顶部表明当前渲染一帧的各个Pass,左侧是各类RT。

URP17同时保留了旧的Feature逻辑与RenderGraph逻辑(打开任意pass文件为例):

public classDistortTunnelPass_Tunnel : ScriptableRenderPass
{
classPassData
{
publicRenderer tunnelObject;publicMaterial tunnelMaterial;
}
#pragma warning disable 618, 672 //Type or member is obsolete, Member overrides obsolete member //Unity calls the Configure method in the Compatibility mode (non-RenderGraph path) public override voidConfigure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescripor)
{
}
//Unity calls the Execute method in the Compatibility mode public override void Execute(ScriptableRenderContext context, refRenderingData renderingData)
{
}
#pragma warning restore 618, 672 //Unity calls the RecordRenderGraph method to add and configure one or more render passes in the render graph system. public override voidRecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
}
}

参考时忽略掉Configure和Execute的逻辑,执行逻辑关注RecordRenderGraph函数。

2.1 操作方式的改变

在RenderGraph中,之前的RTHandle由于不在该系统中托管,进入RenderGraph的材质都需要调用API进行转换,

转换为RendeGraph的RT后,无需考虑释放操作:

RenderTextureDescriptor textureProperties = new RenderTextureDescriptor(Screen.width, Screen.height, RenderTextureFormat.Default, 0);
TextureHandle textureHandle
= UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "My texture", false);

相关文档:

https://docs.unity3d.com/Manual/urp/render-graph-create-a-texture.html

此外RenderGraph对于空调用的pass,也会剔除进行优化,使用者需要手动标记以防止被剔除。

2.1 RecordRenderGraph

在该函数内可组织渲染逻辑,pass相关的逻辑需放在对应的代码块中,例如:

using (var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out_))
{
builder.UseTexture(rt1);
builder.SetRenderAttachment(resourceData.activeColorTexture,
0);

builder.SetRenderFunc
<PassData>((data, context) =>{
MaterialPropertyBlock materialPropertyBlock
= newMaterialPropertyBlock();
materialPropertyBlock.SetTexture(
"_BlitTexture", rt1);
materialPropertyBlock.SetVector(
"_BlitScaleBias", new Vector4(1, 1, 0, 0));

context.cmd.DrawProcedural(Matrix4x4.identity, material,
0, MeshTopology.Triangles, 3, 1, materialPropertyBlock);
});
}

URP提供了多种RenderPass,例如处理光栅化相关逻辑使用RasterRenderPass组织相关逻辑。

在RenderPass的代码块中可使用builder对象配置RenderTarget、标记材质的读写等

而具体的pass绘制逻辑则在SetRenderFunc代码块中。

RecordRenderGraph内可以调用多次AddRenderPass,但URP并没有整理旧API的代码和相关工具类,

以至于容易使用旧的API导致报错,这点需要注意。

3.编写Feature

3.1 Blit与SetTarget

从前有句俗话“切RT的性能消耗相当于半个pass”,Unity SRP在几个版本的升级都在逐渐强调不切RenderTarget直接绘制,

如Cockpit Demo的屏幕空间描边。

3.2 屏幕模糊Demo

下面通过屏幕模糊Demo案例,演示URP17下pass的编写。

通过外部EnqueuePass的方式,在场景中通过控制器脚本添加该Pass,

MyBlurSceneController.cs:

usingUnityEngine;usingUnityEngine.Rendering.Universal;usingUnityEngine.Rendering;public classMyBlurSceneController : MonoBehaviour
{
publicMaterial material;
[Range(
2, 15)] public int blurPasses = 3;
[Range(
0, 4)] public int downSample = 0;
[Range(
0.0f, 10f)] public float offset = 0.2f;public RenderPassEvent injectionPoint =RenderPassEvent.BeforeRenderingPostProcessing;public int injectionPointOffset = 0;public ScriptableRenderPassInput inputRequirements =ScriptableRenderPassInput.Color;public CameraType cameraType =CameraType.Game;privateMyBlurPass mMyBlurPass;private voidOnEnable()
{
SetupPass();

RenderPipelineManager.beginCameraRendering
+=OnBeginCamera;
}
private voidOnDisable()
{
RenderPipelineManager.beginCameraRendering
-=OnBeginCamera;
}
public virtual voidSetupPass()
{
mMyBlurPass
= newMyBlurPass();

mMyBlurPass.renderPassEvent
= injectionPoint +injectionPointOffset;
mMyBlurPass.material
=material;

mMyBlurPass.ConfigureInput(inputRequirements);
}
public virtual voidOnBeginCamera(ScriptableRenderContext ctx, Camera cam)
{
if (mMyBlurPass == null || material == null)return;if ((cam.cameraType & cameraType) == 0) return;

mMyBlurPass.blurPasses
=blurPasses;
mMyBlurPass.downSample
=downSample;
mMyBlurPass.offset
=offset;

cam.GetUniversalAdditionalCameraData().scriptableRenderer.EnqueuePass(mMyBlurPass);
}
}

MyBlurPass.cs:

usingUnityEngine;usingUnityEngine.Rendering.RenderGraphModule;usingUnityEngine.Rendering;usingUnityEngine.Rendering.Universal;usingUnityEngine.Rendering.RenderGraphModule.Util;public classMyBlurPass : ScriptableRenderPass
{
public classPassData
{
publicTextureHandle tempRt1;publicTextureHandle tempRt2;
}
publicMaterial material;
[Range(
2, 15)] public int blurPasses = 3;
[Range(
1, 4)] public int downSample = 1;
[Range(
0.0f, 10f)] public float offset = 0.2f;public override voidRecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
var resourceData = frameData.Get<UniversalResourceData>();var passData = newPassData();var w = Screen.width >>downSample;var h = Screen.height >>downSample;

RenderTextureDescriptor textureProperties
= new RenderTextureDescriptor(w, h, RenderTextureFormat.Default, 0);
passData.tempRt1
= UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "MyBlurPassTempRt1", false);

textureProperties
= new RenderTextureDescriptor(w, h, RenderTextureFormat.Default, 0);
passData.tempRt2
= UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "MyBlurPassTempRt2", false);var rt1 =passData.tempRt1;var rt2 =passData.tempRt2;//将屏幕RT Blit到rt1上 var para = new RenderGraphUtils.BlitMaterialParameters(resourceData.activeColorTexture, rt1, material, 0);
renderGraph.AddBlitPass(para,
"MyBlurPassBlitFirst");

material.SetFloat(
"_SampleOffset", offset);//模糊迭代 for (int i = 0; i < blurPasses - 1; ++i)
{
para
= new RenderGraphUtils.BlitMaterialParameters(rt1, rt2, material, 0);
renderGraph.AddBlitPass(para, $
"MyBlurPassBlit_{i}");var tmp =rt1;
rt1
=rt2;
rt2
=tmp;
}
//通过直接绘制的方式,将模糊RT绘制到屏幕上 using (var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out_))
{
builder.UseTexture(rt1);
builder.SetRenderAttachment(resourceData.activeColorTexture,
0);

builder.SetRenderFunc
<PassData>((data, context) =>{
MaterialPropertyBlock materialPropertyBlock
= newMaterialPropertyBlock();
materialPropertyBlock.SetTexture(
"_BlitTexture", rt1);
materialPropertyBlock.SetVector(
"_BlitScaleBias", new Vector4(1, 1, 0, 0));

context.cmd.DrawProcedural(Matrix4x4.identity, material,
0, MeshTopology.Triangles, 3, 1, materialPropertyBlock);
});
}
}
}

接着在ShaderGraph中连出模糊的逻辑,注意Blit对应的参数_BlitTexture、_BlitScaleBias:

最后在场景中挂载控制器以及材质球,即可使用该模糊Pass。

标签: none

添加新评论