2024.12 补充提示,BUG和踩坑:
- BUG:换场景有的时候Blitter的生命周期会乱掉导致报空错误,解决方案如下
if (!Application.isPlaying)
{
UnityEditor.SceneManagement.EditorSceneManager.sceneOpened += OnEditorSceneChanged;
}
public void OnEditorSceneChanged(UnityEngine.SceneManagement.Scene scene, UnityEditor.SceneManagement.OpenSceneMode mode)
{
Blitter.Cleanup();
Blitter.Initialize(Shader.Find("Hidden/Universal/CoreBlit"), Shader.Find("Hidden/Universal/CoreBlitColorAndDepth"));
}
- 踩坑:运行时Unity会根据VolumeProfile中的全部VolumeComponent另实例化新的VolumeComponent用于运行,实例化VolumeComponent参数与VolumeProfile中的参数不一致,化分为两个对象后,从VolumeManager.instance.stack获取的是运行时实例化的新组件,从profile.TryGet获取的是原始组件
- 踩坑:VolumeComponent自带参数间差值的方法Override(VolumeComponent state, float interpFactor),是对传入的state组件的参数进行覆写,在Override方法外无法对运行时实例化的VolumeComponent的全部VolumeParameter做任何修改。
CommandBuffer、Blitter、RTHandle、RenderPass更新
官方文档:
https://docs.unity3d.com/Manual/urp/upgrade-guide-unity-6.html
RenderPass大更新,取消OnCameraSetup和Execute方法,换成了新版api方法RecordRenderGraph。
- 官方案例:
https://docs.unity3d.com/Manual/urp/renderer-features/create-custom-renderer-feature.html#code-render-pass
- RTHandle换成了TextureHandle,TextureHandle不需要手动释放。
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
// 获取临时TextureHandle
var descriptor = frameData.Get<UniversalCameraData>().cameraTargetDescriptor;
descriptor.depthBufferBits = 0;
var tempTex = UniversalRenderer.CreateRenderGraphTexture(renderGraph, descriptor, "_RT_NAME", false);
// 外部RTHandle转TextureHandle,需要手动释放RTHandles.Alloc创建的RT
var whiteTex = renderGraph.ImportTexture(RTHandles.Alloc(Texture2D.whiteTexture))
}
- 获取Camera
frameData.Get<UniversalCameraData>().camera
- ScriptableRenderer.cameraColorTargetHandle换成了
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
var colTex = frameData.Get<UniversalResourceData>().activeColorTexture;
}
- 在RecordRenderGraph方法中使用CommandBuffer
- 无法直接获取CommandBuffer,需要再套一层RenderGraphBuilder。
- 泛型为 class PassData {} 就可以
using (var builder = renderGraph.AddRasterRenderPass<PassData>("pass name", out var passData))
{
builder.AllowPassCulling(false);
builder.AllowGlobalStateModification(true);
// 获取屏幕颜色输入
var src = frameData.Get<UniversalResourceData>().activeColorTexture;
// 创建输出的目标图片
var dst = UniversalRenderer.CreateRenderGraphTexture(renderGraph, descriptor, "__DST", false);
// 设置pass中用到的图片
builder.UseTexture(src);
// 在这里设置相当于之前Blit的dst渲染目标
builder.SetRenderAttachment(dst, 0);
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
RasterCommandBuffer cmd = context.cmd;
// 拿到cmd后和之前类似,但有些功能缺失,比如DispatchCompute只能在renderGraph.AddComputePass的context中获取
cmd.SetGlobalTexture("tex_src", src);
// 相当于之前的Blitter.BlitCameraTexture(cmd, src, dst, material, 0);
Blitter.BlitTexture(cmd, src, new Vector4(1, 1, 0, 0), material, 0);
});
}
- 在RenderGraph中使用ComputeShader
using (var builder = renderGraph.AddComputePass<PassData>("xxx compute", out var passData))
{
// 设置pass中用到的图片
builder.UseTexture(src);
builder.AllowPassCulling(false);
builder.AllowGlobalStateModification(true);
builder.SetRenderFunc<PassData>((data, context) =>
{
ComputeCommandBuffer cmd = context.cmd;
// set shader props ...
cmd.DispatchCompute(compute, 0, groupsX, groupsY, groupsZ);
// cmd.DispatchCompute(compute1, 0, groupsX, groupsY, groupsZ);
// ...
});
}
- 复制TextureHandle到另一个TextureHandle,以及不用builder直接Blit方法
// 复制
renderGraph.AddBlitPass(src, dst, Vector2.one, Vector2.zero);
// 直接Blit
renderGraph.AddBlitPass(new(src, dst, upscaleMaterial, 0));
- 在renderGraph添加多个pass后不用做其他操作,在RecordRenderGraph方法结束后会按顺序调用全部添加的pass。
知乎大佬写的例子:https://zhuanlan.zhihu.com/p/721313939