URP10->14(RTHandle)升级总结
壹拾肆Channel
编辑于 2024年03月13日 23:49

ScriptableRendererFeature 升级

1. SetupPass拆分

在Urp12之后提供了新的接口SetupRenderPasses,对Pass的设置应当在SetupRenderPasses中进行

代码块
C#
自动换行
复制代码
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
		// The target is used before allocation
		m_CustomPass.Setup(renderer.cameraColorTarget);
		 // Letting the renderer know which passes are used before allocation
		renderer.EnqueuePass(m_ScriptablePass);
}
复制成功

代码块
C#
自动换行
复制代码
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
		// Letting the renderer know which passes are used before allocation
		renderer.EnqueuePass(m_ScriptablePass);
}

public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
{
		// The target is used after allocation
		m_CustomPass.Setup(renderer.cameraColorTarget);
}
复制成功

注:此处调用的m_CustomPass.Setup方法为约定的初始化方法,可以自己定义(也可叫别的名字),一般用于将RenderTexture引用传入ScriptableRendererPass

2. 使用Dispose方法进行纹理释放

1) 在ScriptableRendererPass中定义Dispose方法 并将未释放的RTHandle调用其方法

代码块
C#
自动换行
复制代码
public void Dispose()
{
	_customOpaqueTexture?.Release();
}
复制成功

2) 在ScriptableRendererFeature中override Dispose方法 并调用Pass的Dispose方法

代码块
C#
自动换行
复制代码
protected override void Dispose(bool disposing)
{
	renderObjectsPass.Dispose();
}
复制成功

3. 一些接口调整

  • public static readonly RenderTargetHandle CameraTarget不再存在 使用k_CameraTarget(在ScriptableRenderPass直接使用,或在外部使用ScriptableRenderPass.k_CameraTarget)替代

  • scriptableRenderer.cameraColorTarget现已废弃 使用scriptableRenderer.cameraColorTargetHandle替代

  • scriptableRenderer.cameraDepthTarget 现已废弃 使用 scriptableRenderer.cameraDepthTargetHandle代替

ScriptableRenderPass升级

1. RenderTarget & RenderTargetIdentifier 统一

现在两者统一使用新接口  旧

代码块
C#
自动换行
复制代码
private RenderTargetHandle _cameraOpaqueTexture;
复制成功

代码块
C#
自动换行
复制代码
private RTHandle _cameraOpaqueTexture;
复制成功

2. Identifier - Color & Depth 拆分

示例: 旧

代码块
C#
自动换行
复制代码
 RenderTargetIdentifier m_Destination;
复制成功

代码块
C#
自动换行
复制代码
 RTHandle m_DestinationColor;
 RTHandle m_DestinationDepth;
复制成功

3. 初始化RenderTexture

 一并替换为 或  如果为则使用

If the render target does not change within the lifetime of the application, use the  method to allocate an RTHandle target. 文档链接

中不需要设置分辨率,分辨率由统一自动控制,在申请时只需要传入格式的降采样参数即可,原始分辨率可传入

代码块
C#
自动换行
复制代码
private RenderTargetHandle _opaqueMap;

public override void OnCameraSetup( CommandBuffer cmd, ref RenderingData renderingData )
{
	var cameraTextureDescriptor = renderingData.cameraData.cameraTargetDescriptor;
	opaqueMap.Init( _textureName );
	int width = DownSampleUtil.GetLength( cameraTextureDescriptor.width, downSample );
	int height = DownSampleUtil.GetLength( cameraTextureDescriptor.height, downSample );
	cmd.GetTemporaryRT( _opaqueMap.id, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBHalf );
	this.ConfigureTarget( _opaqueMap.Identifier() );
	this.ConfigureClear( ClearFlag.All, Color.clear );
}
复制成功

代码块
C#
自动换行
复制代码
private RTHandle _opaqueMap;

public override void OnCameraSetup( CommandBuffer cmd, ref RenderingData renderingData )
{
	var cameraTextureDescriptor = renderingData.cameraData.cameraTargetDescriptor;
	cameraTextureDescriptor.colorFormat = RenderTextureFormat.ARGBHalf;
	cameraTextureDescriptor.depthBufferBits = 0;
	RenderingUtils.ReAllocateIfNeeded(
		ref _opaqueMap,
		Vector2.one * 0.5f, 
		cameraTextureDescriptor,
		FilterMode.Bilinear,
		TextureWrapMode.Clamp,
		false,
		1,
		0f,
		"_OpaqueMap"
	);
	this.ConfigureTarget( _opaqueMap );
	this.ConfigureClear( ClearFlag.All, Color.clear );
}
复制成功

注:和相比,RTHandle初始化时会在name(如)后追加描述字符串,所以无法再从全局中取到名为的纹理,如果需要将RTHandle生成的纹理全局使用(如交给Shader),可用下述写法

代码块
C#
自动换行
复制代码
  Shader.SetGlobalTexture("_OpaqueMap", _opaqueMap);
复制成功

 另外,如果需要将现有RenderTexture作为RTHandle的纹理,可用下述写法 

代码块
C#
自动换行
复制代码
  _opaqueMap = RTHandles.Alloc(Shader.GetGlobalTexture("_OpaqueMap"));
复制成功

4. 释放RenderTexture

如果该RTHandle由Feature传入,则只需在方法中将其置为即可

代码块
C#
自动换行
复制代码
public override void OnCameraCleanup( CommandBuffer cmd )
{
	_transparentObjectsTexture = null;
	_transparentObjectsDepthAttachment = null;
}
复制成功

如果该RTHandle由当前Pass初始化并不会被后续代码引用(如非全局Texture),则可在中Release掉

代码块
C#
自动换行
复制代码
public override void OnCameraCleanup( CommandBuffer cmd )
{
	cmd.ReleaseTemporaryRT( _opaqueMap.id );
}
复制成功

代码块
C#
自动换行
复制代码
public override void OnCameraCleanup( CommandBuffer cmd )
{
	_opaqueMap?.Release();
}
复制成功

commandBuffer.Blit替换

官方不再推荐在URP管线中使用 commandBuffer.Blit(Blit) 进行渲染 现在使用Blitter类实现相应功能

不使用material全屏渲染

代码块
C#
自动换行
复制代码
cmd.Blit( _transparentObjectsTexture.Identifier(), _cameraOpaqueTexture.Identifier() );
复制成功

代码块
C#
自动换行
复制代码
Blitter.BlitCameraTexture2D(cmd,_transparentObjectsTexture, _cameraOpaqueTexture);
复制成功

使用material全屏渲染

代码块
C#
自动换行
复制代码
Blit( cmd, tempTarget.Identifier(), target.Identifier(), _blurMaterial )
复制成功

代码块
C#
自动换行
复制代码
Blitter.BlitCameraTexture(cmd, tempTarget, target, _blurMaterial, 0);
复制成功

Blitter使用Material时对应Shader修改

如果此前使用CG,需要改为HLSL

使用Blitter后,会将Source的纹理传递给名为的Texture(也可将RTHandle传递为GlobalTexture,进而在Shader中按新名称引用,需注意纹理回收),且在Shader中对其采样需要使用SAMPLE_TEXTURE2D方法

在Shader中需要引入以下两个HLSL文件(不能再引用UnityCG.cginc 请慎重)

代码块
C++
自动换行
复制代码
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
复制成功

注: _BlitTexture已在Blit.hlsl中定义,不需要重复定义

Vertex 修改

该示例以直接采样输出全屏图为例

代码块
C++
自动换行
复制代码
struct Attributes
{
#if SHADER_API_GLES
		float4 positionOS : POSITION;
		float2 uv : TEXCOORD0;
#else
		uint vertexID : SV_VertexID;
#endif
		UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
		float2 texcoord : TEXCOORD0;
		// UNITY_FOG_COORDS(1) //目前没找到可以替代的
		float4 positionCS : SV_POSITION;
		UNITY_VERTEX_OUTPUT_STEREO
};
Varyings vert(Attributes v)
{
		Varyings o;
		UNITY_SETUP_INSTANCE_ID(v);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if SHADER_API_GLES
		float4 pos = v.positionOS;
		float2 uv  = v.uv;
#else
		float4 pos = GetFullScreenTriangleVertexPosition(v.vertexID);
		float2 uv = GetFullScreenTriangleTexCoord(v.vertexID);
#endif

		o.positionCS = pos;
		o.texcoord = uv * _BlitScaleBias.xy + _BlitScaleBias.zw;
		return o;
}
复制成功

Fragment修改

代码块
C++
自动换行
复制代码
half4 frag(Varyings i) : SV_Target
{
	half4 col = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearRepeat, i.uv);
	return col;
}
复制成功


参考文献

  • https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/upgrade-guide-2022-2.html

  • https://zenn.dev/sakutaro/articles/convert_blitter

  • https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/renderer-features/how-to-fullscreen-blit.html

  • https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@13.1/api/UnityEngine.Rendering.Blitter.html

  • https://forum.unity.com/threads/rendertargethandle-is-obsolete-deprecated-in-favor-of-rthandle.1211052/

  • https://teodutra.com/unity/shaders/urp/graphics/2020/05/18/From-Built-in-to-URP/