4
\$\begingroup\$

I'm trying to copy the scene rendered by a particular camera to a render target. I know this should be possible to do without using the camera's target texture as I read through this official Unity article about Command Buffers which avoids any use of them.

Instead, I found that they use the following code in the renderer for blurry refractions (CommandBufferBlurRefraction.cs) to copy the scene to a render target.

    buf = new CommandBuffer();
    buf.name = "Grab screen and blur";
    m_Cameras[cam] = buf;

    // copy screen into temporary RT
    int screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");
    buf.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear);
    buf.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);

The problem is that I can't get this to work for myself using a very simple scenario of:

  • Camera renders the entire scene which is a single hexagonal sprite
  • The command buffer assigned to the camera grabs the BuiltinRenderTextureType.CurrentActive (Scene Render Target)
  • The command buffer then copies that to another render target
  • That render target is then drawn in the upper left of the screen on a yellow background

This results in the scene render target being completely blank and not including the white hexagon.

CopySceneRTToRenderTargetFail

The code I am using is

Camera cameraUsedToRender;
CommandBuffer commandBuffer;
RenderTexture debugRT;
Texture2D debugRTBackground;

void Awake()
{
    // Create debug texture to render
    debugRTBackground = new Texture2D(2, 2);
    debugRTBackground.SetPixels(new Color[4] { Color.yellow, Color.yellow, Color.yellow, Color.yellow });
    debugRTBackground.Apply();

    cameraUsedToRender = Camera.main;
    cameraUsedToRender.orthographicSize = 10f;

    // Create debug render texture to render to using our camera
    debugRT = new RenderTexture(cameraUsedToRender.pixelWidth, cameraUsedToRender.pixelHeight, 16);
    debugRT.Create();

    // Create command buffer
    commandBuffer = new CommandBuffer();
    commandBuffer.name = "Debug";

    // Add the camera buffer to the main camera
    cameraUsedToRender.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, commandBuffer);
}

void OnRenderObject()
{
    // Clear the command buffer
    commandBuffer.Clear();

    // Set the render target
    commandBuffer.SetRenderTarget(debugRT);

    // Clear the render target
    commandBuffer.ClearRenderTarget(true, true, Color.blue);

    // Copy scene into a render target
    // RenderTarget.active = SceneView RT (UnityEngine.RenderTexture)
    commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, debugRT);

    // Release the render target
    commandBuffer.SetRenderTarget(null as RenderTexture);
}

void OnGUI()
{
    // Draw the debug render target (which should have the SceneView RT copied to it)
    GUI.DrawTexture(new Rect(0, 0, 130, 130), debugRTBackground);
    GUI.DrawTexture(new Rect(1, 1, 128, 128), debugRT);
}

The complete small, simple project that demonstrates this issue can be found here.

Does anyone have an idea how to resolve this as I'm finding the Unity rendering pipeline to be rather confusing at this point?

\$\endgroup\$
1
\$\begingroup\$

Try to remove all calls in OnRenderObject except

commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, debugRT);

And I believe you don't have to call that one even every time, because it is a state call, so you only have to call it on initialization (in your Awake function. (Maybe don't initialize in Awake, but in Start?)).

\$\endgroup\$
1
\$\begingroup\$
// Set the render target
commandBuffer.SetRenderTarget(debugRT);

Here you're setting your current render target tl be the debug RenderTexture.

// Copy scene into a render target 
// RenderTarget.active = SceneView RT (UnityEngine.RenderTexture) 
commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, debugRT); 

Here you're copying from the current render target into the debug RenderTexture.

But wait, the current render target is the debug RenderTexture! That's what we set it to just a few lines above. So this call is asking to copy from one buffer into the same buffer, never looking at the scene render target's contents at all.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.