In Unity, the Frame Debugger is widely regarded as one of the most effective graphic debugging tools. It not only furnishes data such as the current rendering target, associated input parameters, and Keywords, but also delivers real-time rendering results. Nevertheless, there are occasions when it can become cumbersome, particularly when we need to compare between multiple passes to quickly identify bugs.
One method involves presenting all rendering pass results simultaneously on the screen. This enables us to directly compare rendering outcomes, thus facilitating the swift identification of bugs. After all, debugging shaders often necessitates pinpointing discrepancies in visual output.
Based on the illustration above, it is evident that the rendering process progresses as follows: AfterSkyBox (including Opaque) => After Transparency => After Post-Effect (bloom). This approach enables us to scrutinize the process for any anomalies, proving particularly valuable when comparing the outcomes of a specific pass with our expectations. This is especially relevant when designing our custom RenderPass.As for the implementation approach, we simply need to write a RenderFeature and create corresponding RenderPasses for the rendering events we wish to monitor. Then, we enqueue them in sequence.
public class HandleURPRenderStepFeature : ScriptableRendererFeature
{
public override void Create()
{
m_AfterSkyPass = new AppendColorBufferPass(RenderPassEvent.AfterRenderingSkybox);
m_AfterTransparencyPass = new AppendColorBufferPass(RenderPassEvent.AfterRenderingTransparents);
m_AfterPostProcessingPass = new AppendColorBufferPass(RenderPassEvent.AfterRenderingPostProcessing);
}
public override void AddRenderPasses(ScriptableRenderer renderer,
ref RenderingData renderingData)
{
renderer.EnqueuePass(m_AfterSkyPass);
renderer.EnqueuePass(m_AfterTransparencyPass);
renderer.EnqueuePass(m_AfterPostProcessingPass);
}
private AppendColorBufferPass m_AfterSkyPass = null;
private AppendColorBufferPass m_AfterTransparencyPass = null;
private AppendColorBufferPass m_AfterPostProcessingPass = null;
}
{
public override void Create()
{
m_AfterSkyPass = new AppendColorBufferPass(RenderPassEvent.AfterRenderingSkybox);
m_AfterTransparencyPass = new AppendColorBufferPass(RenderPassEvent.AfterRenderingTransparents);
m_AfterPostProcessingPass = new AppendColorBufferPass(RenderPassEvent.AfterRenderingPostProcessing);
}
public override void AddRenderPasses(ScriptableRenderer renderer,
ref RenderingData renderingData)
{
renderer.EnqueuePass(m_AfterSkyPass);
renderer.EnqueuePass(m_AfterTransparencyPass);
renderer.EnqueuePass(m_AfterPostProcessingPass);
}
private AppendColorBufferPass m_AfterSkyPass = null;
private AppendColorBufferPass m_AfterTransparencyPass = null;
private AppendColorBufferPass m_AfterPostProcessingPass = null;
}
As for copying rendering results, we have implemented an AppendColorBufferPass for this purpose. Its content is straightforward: it transfers the results to the DrawDebugRenderTexturePass. This pass is managed by the DebugRenderTextureFeature, which drives its rendering. The rendering event of DrawDebugRenderTexturePass is set to RenderPassEvent.AfterRendering + 2, indicating that the rendering process has been completed at this point.
public class DebugRenderTextureFeature : ScriptableRendererFeature
{
public override void Create()
{
ResourceReloader.ReloadAllNullIn(this,
UniversalRenderPipelineAsset.packagePath);
m_BlitMaterial = CoreUtils.CreateEngineMaterial(m_Shaders.m_BltPS);
m_DrawDebugRenderTexturePass.ReInitialize(
RenderPassEvent.AfterRendering + 2, m_BlitMaterial,
m_DisplayRatio, m_ColumnCount, m_StepSize);
}
protected override void Dispose(bool disposing)
{
m_DrawDebugRenderTexturePass.Release();
CoreUtils.Destroy(m_BlitMaterial);
}
public override void AddRenderPasses(ScriptableRenderer renderer,
ref RenderingData renderingData)
{
if (m_DrawDebugRenderTexturePass != null)
{
m_DrawDebugRenderTexturePass.SetupRenderer(renderer);
renderer.EnqueuePass(m_DrawDebugRenderTexturePass);
}
}
//...
{
public override void Create()
{
ResourceReloader.ReloadAllNullIn(this,
UniversalRenderPipelineAsset.packagePath);
m_BlitMaterial = CoreUtils.CreateEngineMaterial(m_Shaders.m_BltPS);
m_DrawDebugRenderTexturePass.ReInitialize(
RenderPassEvent.AfterRendering + 2, m_BlitMaterial,
m_DisplayRatio, m_ColumnCount, m_StepSize);
}
protected override void Dispose(bool disposing)
{
m_DrawDebugRenderTexturePass.Release();
CoreUtils.Destroy(m_BlitMaterial);
}
public override void AddRenderPasses(ScriptableRenderer renderer,
ref RenderingData renderingData)
{
if (m_DrawDebugRenderTexturePass != null)
{
m_DrawDebugRenderTexturePass.SetupRenderer(renderer);
renderer.EnqueuePass(m_DrawDebugRenderTexturePass);
}
}
//...
Additionally, the implementation of the DrawDebugRenderTexturePass is also straightforward. It simply involves drawing all the RenderTextures copied previously in the List<RenderTexture> ms_DebugRTs. The relevant execution code is as follows:
public override void Execute(ScriptableRenderContext context,
ref RenderingData renderingData)
{
RenderTargetIdentifier targetIdentifier = Texture2D.blackTexture;
Add(ref context, ref targetIdentifier);
targetIdentifier = Texture2D.whiteTexture;
Add(ref context, ref targetIdentifier);
if (!m_TargetBlitMaterial)
return;
CommandBuffer command = CommandBufferPool.Get(mc_ProfilerTag);
using (new ProfilingScope(command, m_ProfilingSampler))
{
var cameraData = renderingData.cameraData;
var camera = cameraData.camera;
var origionViewMatrix = cameraData.GetViewMatrix();
var origionProjectionMatrix = camera.projectionMatrix;
command.SetViewProjectionMatrices(Matrix4x4.identity,
Matrix4x4.identity);
Vector2 RectSize = new Vector2(
camera.pixelRect.width * m_DisplayRatio,
camera.pixelRect.height * m_DisplayRatio);
Rect displayRect = new Rect(0.0f, 0.0f, RectSize.x, RectSize.y);
uint index = 0;
uint columnIndex, rowIndex;
var element = ms_DebugRTs.GetEnumerator();
while (element.MoveNext())
{
rowIndex = index / m_ColumnCount;
columnIndex = index % m_ColumnCount;
displayRect.x = (RectSize.x + m_StepSize) * columnIndex;
displayRect.y = camera.pixelRect.height -
((RectSize.y + m_StepSize) * rowIndex + RectSize.y);
command.SetViewport(displayRect);
command.SetGlobalTexture("_SourceTex", element.Current);
command.DrawMesh(RenderingUtils.fullscreenMesh,
Matrix4x4.identity, m_TargetBlitMaterial);
++index;
}
element.Dispose();
//restore
command.SetViewProjectionMatrices(origionViewMatrix,
origionProjectionMatrix);
}
context.ExecuteCommandBuffer(command);
CommandBufferPool.Release(command);
ClearRenderTextures();
}
ref RenderingData renderingData)
{
RenderTargetIdentifier targetIdentifier = Texture2D.blackTexture;
Add(ref context, ref targetIdentifier);
targetIdentifier = Texture2D.whiteTexture;
Add(ref context, ref targetIdentifier);
if (!m_TargetBlitMaterial)
return;
CommandBuffer command = CommandBufferPool.Get(mc_ProfilerTag);
using (new ProfilingScope(command, m_ProfilingSampler))
{
var cameraData = renderingData.cameraData;
var camera = cameraData.camera;
var origionViewMatrix = cameraData.GetViewMatrix();
var origionProjectionMatrix = camera.projectionMatrix;
command.SetViewProjectionMatrices(Matrix4x4.identity,
Matrix4x4.identity);
Vector2 RectSize = new Vector2(
camera.pixelRect.width * m_DisplayRatio,
camera.pixelRect.height * m_DisplayRatio);
Rect displayRect = new Rect(0.0f, 0.0f, RectSize.x, RectSize.y);
uint index = 0;
uint columnIndex, rowIndex;
var element = ms_DebugRTs.GetEnumerator();
while (element.MoveNext())
{
rowIndex = index / m_ColumnCount;
columnIndex = index % m_ColumnCount;
displayRect.x = (RectSize.x + m_StepSize) * columnIndex;
displayRect.y = camera.pixelRect.height -
((RectSize.y + m_StepSize) * rowIndex + RectSize.y);
command.SetViewport(displayRect);
command.SetGlobalTexture("_SourceTex", element.Current);
command.DrawMesh(RenderingUtils.fullscreenMesh,
Matrix4x4.identity, m_TargetBlitMaterial);
++index;
}
element.Dispose();
//restore
command.SetViewProjectionMatrices(origionViewMatrix,
origionProjectionMatrix);
}
context.ExecuteCommandBuffer(command);
CommandBufferPool.Release(command);
ClearRenderTextures();
}
Here you can find the corresponding GitHub repository:
沒有留言:
張貼留言