大致流程是:
一、DrawOldFramePass:用上一帧的RenderTanget进行旋转偏移之类的操作
二、DrawTransparentObjectPass:绘制场景物件,叠加到DrawOldFramePass绘制的网格上
三、CopyFramePass:生成RenderTarget缓存给下一帧使用
一、RenderFeature
从KeepFrameFeature.cs中看到KeepFrameFeature包含两个PASS,一个是CopyFramePass,另一个是DrawOldFramePass。
CopyFramePass是在AfterRenderingTransparents的时候执行,DrawOldFramePass是在BeforeRenderingOpaques的时候执行,所以DrawOldFramePass优先执行。
public override void Create()
{
m_CopyFrame = new CopyFramePass();
m_CopyFrame.renderPassEvent = RenderPassEvent.AfterRenderingTransparents; //Frame color is copied late in the frame
m_DrawOldFame = new DrawOldFramePass();
m_DrawOldFame.renderPassEvent = RenderPassEvent.BeforeRenderingOpaques; //Old frame is drawn early in the frame
}
CopyFramePass的作用是把当前相机的RenderTarget保持到缓存m_OldFrameHandle中
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (renderingData.cameraData.camera.cameraType != CameraType.Game)
return;
CommandBuffer cmd = CommandBufferPool.Get("CopyFramePass");
RenderTargetIdentifier opaqueColorRT = destination.Identifier();
Blit(cmd, source, opaqueColorRT);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
DrawOldFramePass是使用上一帧的m_OldFrameHandle传给displayMaterial渲染到一个全屏的长方形面片。
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (m_DrawOldFrameMaterial != null)
{
CommandBuffer cmd = CommandBufferPool.Get("DrawOldFramePass");
cmd.SetGlobalTexture(m_textureName, m_handle.id);
cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_DrawOldFrameMaterial, 0, 0);
cmd.SetViewProjectionMatrices(renderingData.cameraData.camera.worldToCameraMatrix, renderingData.cameraData.camera.projectionMatrix);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
通过FrameDebug也可以观察到大致流程是先执行DrawOldFramePass,再DrawTransparentObjects画场景物,再CopyFramePass。
二、Shader实现
KeepFrameFeature使用的材质是SwirlyFrame,SwirlyFrame使用的shader是SwirlyFrame_Graph。
这里面的_FrameCopyTex就是CopyFramePass传递给DrawOldFramePass用的缓存m_OldFrameHandle。可以看出这个shader就是大致对传入的贴图进行UV旋转、平移和重复展开,然后进行百分比混合。
可以看出大致流程是先对上一帧的RT进行旋转偏移,再画场景物,再缓存当选相机RT,然后得到一种画面残留的感觉
可以通过修改一些设置更容易观察这中间的过程。关闭后处理、阴影、SRPBatch,创建一个简单的模型,对它使用一个unlit材质,场景关闭特效、UI,调整SwirlyFrame参数
可以看到画面有调整
这时候再FrameDebug可以看到流程简化很多,更容易分析。但个人认为这里面的_OldFrameRenderTarget应该是错误的,应该是上一帧的画面才对。:
可以通过打包成exe用RenderDoc分析核对一下渲染过程:
DrawOldFramePass画的是全屏面片,用的是上一帧的RenderTarget
2.在此基础上绘制场景物件
3.CopyFramePass:拷贝RenderTarget操作